Ejemplo n.º 1
0
        public static void UseHealthEndpoint(this IApplicationBuilder app)
        {
            app.Use(async(context, next) =>
            {
                if (context.Request.Path.Value.Equals("/health"))
                {
                    // Perform IP access check
                    if (MicroserviceConfiguration.AllowedIpAddresses != null &&
                        context.Request.HttpContext.Connection.RemoteIpAddress != null
                        &&
                        !MicroserviceConfiguration.AllowedIpAddresses.Contains(
                            context.Request.HttpContext.Connection.RemoteIpAddress))
                    {
                        context.Response.StatusCode = 403;
                        await next();
                    }

                    var status = HealthCheckRegistry.GetStatus();

                    if (!status.IsHealthy)
                    {
                        // Return a service unavailable status code if any of the checks fail
                        context.Response.StatusCode = 503;
                    }

                    context.Response.Headers["Content-Type"] = "application/json";
                    await context.Response.WriteAsync(JsonConvert.SerializeObject(status));
                }
                else
                {
                    await next();
                }
            });
        }
Ejemplo n.º 2
0
        public void Correctly_Report_When_There_Are_HealthChecks()
        {
            HealthCheckRegistry registry = new HealthCheckRegistry();

            registry.Register("test-health-check", new HealthCheck(() => HealthCheck.Result.Healthy()));
            Assert.That(registry.HasHealthChecks, Is.True);
        }
Ejemplo n.º 3
0
        public HealthFixture()
        {
            HealthCheckRegistry = new HealthCheckRegistry();

            var healthStatusProvider = new DefaultHealthProvider(
                _loggerFactory.CreateLogger <DefaultHealthProvider>(),
                HealthCheckRegistry);
        }
        public void HealthCheck_RegistryDoesNotThrowOnDuplicateRegistration()
        {
            HealthCheckRegistry registry = new HealthCheckRegistry();

            registry.RegisterHealthCheck(new HealthCheck("test", () => { }));

            Action action = () => registry.RegisterHealthCheck(new HealthCheck("test", () => { }));
            action.ShouldNotThrow<InvalidOperationException>();
        }
        public void HealthCheck_RegistryStatusIsHealthyIfAllChecksAreHealthy()
        {
            HealthCheckRegistry registry = new HealthCheckRegistry();

            registry.RegisterHealthCheck(new HealthCheck("ok", () => { }));
            registry.RegisterHealthCheck(new HealthCheck("another", () => HealthCheckResult.Healthy()));

            var status = registry.GetStatus();

            status.IsHealthy.Should().BeTrue();
            status.Results.Length.Should().Be(2);
        }
        public void HealthCheck_RegistryStatusIsFailedIfOneCheckFails()
        {
            HealthCheckRegistry registry = new HealthCheckRegistry();

            registry.RegisterHealthCheck(new HealthCheck("ok", () => { }));
            registry.RegisterHealthCheck(new HealthCheck("bad", () => HealthCheckResult.Unhealthy()));

            var status = registry.GetStatus();

            status.IsHealthy.Should().BeFalse();
            status.Results.Length.Should().Be(2);
        }
Ejemplo n.º 7
0
        public void Can_register_process_virtual_memory_check()
        {
            var healthChecks = Enumerable.Empty <HealthCheck>();
            var name         = "virtual memory";

            var registry = new HealthCheckRegistry(healthChecks);

            registry.AddProcessVirtualMemorySizeCheck(name, 100);

            registry.Checks.Should().NotBeEmpty();
            registry.Checks.Single().Value.Name.Should().Be(name);
        }
Ejemplo n.º 8
0
        public void Configuration(IAppBuilder app)
        {
            // Setup logging
            ApplicationLog.AddConsole();
            Logger logger = ApplicationLog.CreateLogger <Startup>();

            logger.Info("Initializing service");

            // Build an IConfiguration instance using the ConfigurationBuilder as normal
            Dictionary <string, string> collection = new Dictionary <string, string>()
            {
                { "key1", "value1" }, { "key2", "value2" }
            };
            var config1 = new ConfigurationBuilder().AddInMemoryCollection(collection).Build();
            var config3 = new ConfigurationBuilder().AddJsonFile("Config.json").Build();

            // AppConfig is a static class that groups together instances of IConfiguration and makes them available statically anywhere in the application
            AppConfig.AddConfigurationObject(config1, "memorySource");
            AppConfig.AddConfigurationObject(config3, "jsonSource");

            // The above configuration sources can now be referenced easily with a static helper function
            Console.WriteLine("key1 key in memorySource: " + AppConfig.Get("memorySource", "key1"));
            Console.WriteLine("config:setting key in jsonSource: " + AppConfig.Get("jsonSource", "config:setting"));

            // Runtime configuration can be updated easily as well
            AppConfig.Set("jsonSource", "config:setting", "http://localhost:5001");
            Console.WriteLine("Modified config:setting key in jsonSource: " + AppConfig.Get("jsonSource", "config:setting"));

            // Redis health check (Requires StackExchange.Redis)
            //HealthCheckRegistry.RegisterHealthCheck("Redis", () => RedisHealthCheck.CheckHealth("localhost"));
            // PostgreSQL health check (Requires Npgsql)
            //HealthCheckRegistry.RegisterHealthCheck("Postgresql", () => PostgresqlHealthCheck.CheckHealth("Host=localhost;Username=postgres;Password=postgres;Database=postgres"));
            // SQL Server health check (Requires System.Data.SqlClient)
            //HealthCheckRegistry.RegisterHealthCheck("SqlServer", () => SqlServerCheck.CheckHealth("Server=localhost;Database=master;User Id=sa;Password=password; "));
            // HealthCheckRegistry.RegisterHealthCheck("mongodb", () => MongoHealthCheck.CheckHealth("mongodb://localhost:27017"));

            /*
             *   Health checks are simply functions that return either healthy or unhealthy with an optional message string
             */
            HealthCheckRegistry.RegisterHealthCheck("MyCustomMonitor", () => HealthResponse.Healthy("Test Message"));
            HealthCheckRegistry.RegisterHealthCheck("MyCustomMonitor2", () => HealthResponse.Healthy("Test Message2"));
            HealthCheckRegistry.RegisterHealthCheck("SampleOperation", () => SampleHealthCheckOperation());

            // Activate the info endpoint
            app.UseInfoEndpoint();

            // Activate the environment endpoint
            app.UseEnvironmentEndpoint();

            // Activate the health endpoint
            app.UseHealthEndpoint();
        }
Ejemplo n.º 9
0
        public async Task Can_execute_process_virtual_memory_check()
        {
            var healthChecks = Enumerable.Empty <HealthCheck>();
            var name         = "virtual memory";

            var registry = new HealthCheckRegistry(healthChecks);

            registry.AddProcessVirtualMemorySizeCheck(name, long.MaxValue);

            var check  = registry.Checks.FirstOrDefault();
            var result = await check.Value.ExecuteAsync().ConfigureAwait(false);

            result.Check.Status.Should().Be(HealthCheckStatus.Healthy);
        }
Ejemplo n.º 10
0
        public async Task Can_execute_ping_check()
        {
            var healthChecks = Enumerable.Empty <HealthCheck>();
            var name         = "github ping";

            var registry = new HealthCheckRegistry(healthChecks);

            registry.AddPingCheck(name, "github.com", TimeSpan.FromSeconds(10));

            var check  = registry.Checks.FirstOrDefault();
            var result = await check.Value.ExecuteAsync().ConfigureAwait(false);

            result.Check.Status.Should().Be(HealthCheckStatus.Healthy);
        }
Ejemplo n.º 11
0
        public void HealthCheck_RegistryExecutesCheckOnEachGetStatus()
        {
            HealthCheckRegistry registry = new HealthCheckRegistry();
            int count = 0;

            registry.RegisterHealthCheck(new HealthCheck("test", () => { count++; }));

            count.Should().Be(0);

            registry.GetStatus();

            count.Should().Be(1);

            registry.GetStatus();

            count.Should().Be(2);
        }
Ejemplo n.º 12
0
        public static void UseHealthEndpoint(this IAppBuilder app)
        {
            app.Use(async(context, next) =>
            {
                if (context.Request.Path.Value.StartsWith("/health"))
                {
                    HealthCheckRegistry.HealthStatus status = HealthCheckRegistry.GetStatus();

                    if (!status.IsHealthy)
                    {
                        // Return a service unavailable status code if any of the checks fail
                        context.Response.StatusCode = 503;
                    }

                    context.Response.Headers.Set("Content-Type", "application/json");
                    await context.Response.WriteAsync(JsonConvert.SerializeObject(status));
                }
                else
                {
                    await next();
                }
            });
        }
Ejemplo n.º 13
0
        private static IHealthCheckRegistry RegisterHealthCheckRegistry(IServiceProvider provider, Action <IHealthCheckRegistry> setupAction = null)
        {
            var logFactory = provider.GetRequiredService <ILoggerFactory>();
            var logger     = logFactory.CreateLogger <HealthCheckRegistry>();

            var autoScannedHealthChecks = Enumerable.Empty <HealthCheck>();

            try
            {
                autoScannedHealthChecks = provider.GetRequiredService <IEnumerable <HealthCheck> >();
            }
            catch (InvalidOperationException ex)
            {
                logger.LogError(
                    new EventId(5000),
                    ex,
                    "Failed to load auto scanned health checks, health checks won't be registered");
            }

            var factory = new HealthCheckRegistry(autoScannedHealthChecks);

            setupAction?.Invoke(factory);
            return(factory);
        }
Ejemplo n.º 14
0
        public async Task Should_be_unhealthy_when_task_is_cancelled()
        {
            var healthChecks = Enumerable.Empty <HealthCheck>();
            var name         = "custom with cancellation token";

            var registry = new HealthCheckRegistry(healthChecks);

            registry.Register(
                name,
                async cancellationToken =>
            {
                await Task.Delay(2000, cancellationToken);
                return(HealthCheckResult.Healthy());
            });

            var token = new CancellationTokenSource();

            token.CancelAfter(200);

            var check  = registry.Checks.FirstOrDefault();
            var result = await check.Value.ExecuteAsync(token.Token).ConfigureAwait(false);

            result.Check.Status.Should().Be(HealthCheckStatus.Unhealthy);
        }
        /// <summary>
        /// Add services to the application and configure service provider
        /// </summary>
        /// <param name="services">Collection of service descriptors</param>
        /// <param name="configuration">Configuration root of the application</param>
        /// <returns>Configured service provider</returns>
        public static (IEngine, NetProOption) ConfigureApplicationServices(this IServiceCollection services,
                                                                           IConfiguration configuration, IHostEnvironment hostEnvironment)
        {
            //文件查找组件注入
            services.AddFileProcessService();
            var netProOption = services.ConfigureStartupConfig <NetProOption>(configuration.GetSection(nameof(NetProOption)));

            services.ConfigureStartupConfig <HostingConfig>(configuration.GetSection("Hosting"));
            if (string.IsNullOrWhiteSpace(netProOption.ApplicationName))
            {
                netProOption.ApplicationName = hostEnvironment.ApplicationName;
            }

            if (hostEnvironment.EnvironmentName == Environments.Development)
            {
                Console.Title           = hostEnvironment.ApplicationName;
                Console.ForegroundColor = ConsoleColor.Cyan;
                Console.WriteLine(Figgle.FiggleFonts.Varsity.Render(new string(new char[] { 'N', 'e', 't', 'P', 'r', 'o' })));
                Console.ResetColor();
                //使用dotnet watch run  启动后可以调试此进程id
                Console.WriteLine($"[{DateTime.Now:HH:mm:ss} {hostEnvironment.EnvironmentName}] dotnet process id:{Process.GetCurrentProcess().Id}");
            }

            //most of API providers require TLS 1.2 nowadays
            ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

            services.AddHttpContextAccessor();
            services.AddHttpClient();
            ////create default file provider
            //CoreHelper.DefaultFileProvider = new NetProFileProvider(hostEnvironment);

            //日志初始化配置
            services.ConfigureSerilogConfig(configuration);
            //create, initialize and configure the engine
            var engine = EngineContext.Create();

            engine.ConfigureServices(services, configuration, netProOption);

            if (netProOption.ThreadMinCount > 2)
            {
                if (ThreadPool.SetMinThreads(Environment.ProcessorCount * netProOption.ThreadMinCount, Environment.ProcessorCount * netProOption.ThreadMinCount))
                {
                    ThreadPool.GetMinThreads(out int work, out int comple);
                    ThreadPool.GetAvailableThreads(out int worktemp, out int completemp);
                    Console.WriteLine($"[{DateTime.Now:HH:mm:ss} 核心数为:{Environment.ProcessorCount}--默认线程最小为:{work}--Available:{worktemp}");
                }
                else
                {
                    Console.WriteLine($"[{DateTime.Now:HH:mm:ss} 最小线程数设置大于系统提供,设置失效!!");
                }
            }

            if (configuration.GetValue <bool>("Apollo:Enabled", false))
            {
                Console.WriteLine($"[{DateTime.Now:HH:mm:ss}] apollo已开启");
                Console.WriteLine($"[{DateTime.Now:HH:mm:ss}] Apollo MetaServer={configuration.GetValue<string>("Apollo:MetaServer")}");

                HealthCheckRegistry.RegisterHealthCheck("apollo", () =>
                {
                    var uri = new Uri(configuration.GetValue <string>("Apollo:MetaServer"));
                    using (var tcpClient = new System.Net.Sockets.TcpClient(uri.Host, uri.Port))
                    {
                        if (tcpClient.Connected)
                        {
                            Console.WriteLine($"[{DateTime.Now:HH:mm:ss}] pollo:Env={configuration.GetValue<string>("Apollo:Env")}");
                            Console.WriteLine($"[{DateTime.Now:HH:mm:ss}] Apollo:Cluster={configuration.GetValue<string>("Apollo:Cluster")}");
                            return(HealthResponse.Healthy($"{uri.Host}:{uri.Port}connection successful; pollo:Env={configuration.GetValue<string>("Apollo:Env")}--Apollo:Cluster={configuration.GetValue<string>("Apollo:Cluster")}"));
                        }
                        return(HealthResponse.Unhealthy($"Apollo{uri.Host}:{uri.Port} connection failed"));
                    }
Ejemplo n.º 16
0
        /// <summary>
        /// Add services to the application and configure service provider
        /// </summary>
        /// <param name="services">Collection of service descriptors</param>
        /// <param name="configuration">Configuration root of the application</param>
        /// <returns>Configured service provider</returns>
        public static (IEngine, NetProOption) ConfigureApplicationServices(this IServiceCollection services,
                                                                           IConfiguration configuration, IHostEnvironment hostEnvironment)
        {
            var netProOption = services.ConfigureStartupConfig <NetProOption>(configuration.GetSection(nameof(NetProOption)));

            services.ConfigureStartupConfig <HostingConfig>(configuration.GetSection("Hosting"));
            if (string.IsNullOrWhiteSpace(netProOption.ApplicationName))
            {
                netProOption.ApplicationName = hostEnvironment.ApplicationName;
            }

            if (hostEnvironment.EnvironmentName == Environments.Development)
            {
                Console.WriteAscii("Hello NetPro", Color.FromArgb(244, 212, 255));
                //使用dotnet watch run  启动后可以调试此进程id
                Console.WriteLine($"[{DateTime.Now:HH:mm:ss} {hostEnvironment.EnvironmentName}] dotnet process id:{Process.GetCurrentProcess().Id}");
            }

            //most of API providers require TLS 1.2 nowadays
            ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

            services.AddHttpContextAccessor();

            //create default file provider
            CoreHelper.DefaultFileProvider = new NetProFileProvider(hostEnvironment);

            //日志初始化配置
            services.ConfigureSerilogConfig(configuration);
            //create, initialize and configure the engine
            var engine = EngineContext.Create();

            engine.ConfigureServices(services, configuration, netProOption);

            if (int.TryParse(configuration.GetValue <string>("NetPro:ThreadMinCount"), out int threadMinCount) && threadMinCount > 2)
            {
                if (ThreadPool.SetMinThreads(Environment.ProcessorCount * threadMinCount, Environment.ProcessorCount * threadMinCount))
                {
                    ThreadPool.GetMinThreads(out int work, out int comple);
                    ThreadPool.GetAvailableThreads(out int worktemp, out int completemp);
                    Console.WriteLine($"核心数为:{Environment.ProcessorCount}--默认线程最小为:{work}--Available:{worktemp}");
                }
                else
                {
                    Console.WriteLine("最小线程数设置大于系统提供,设置失效!!");
                }
            }

            if (!configuration.GetValue <bool>("Apollo:Enabled", false))
            {
                HealthCheckRegistry.RegisterHealthCheck("apollo", () =>
                {
                    var uri = new Uri(configuration.GetValue <string>("Apollo:MetaServer"));
                    using (var tcpClient = new System.Net.Sockets.TcpClient(uri.Host, uri.Port))
                    {
                        if (tcpClient.Connected)
                        {
                            Console.WriteLine($"pollo:Env:{configuration.GetValue<string>("Apollo:Env")}");
                            Console.WriteLine($"Apollo:Cluster:{configuration.GetValue<string>("Apollo:Cluster")}");
                            return(HealthResponse.Healthy($"{uri.Host}:{uri.Port}连接正常--pollo:Env:{configuration.GetValue<string>("Apollo:Env")}--Apollo:Cluster:{configuration.GetValue<string>("Apollo:Cluster")}"));
                        }
                        return(HealthResponse.Unhealthy($"Apollo{uri.Host}:{uri.Port}连接不正常"));
                    }
                });
            }
            return(engine, netProOption);
        }
Ejemplo n.º 17
0
        public void Configure(IApplicationBuilder app)
        {
            // Add logging
            ApplicationLog.AddConsole();
            ApplicationLog.AddFile("Test.log");
            Logger logger = ApplicationLog.CreateLogger <Startup>();

            logger.Info("Initializing service");

            // Build an IConfiguration instance using the ConfigurationBuilder as normal
            Dictionary <string, string> collection = new Dictionary <string, string>()
            {
                { "key1", "value1" }, { "key2", "value2" }
            };
            var config1 = new ConfigurationBuilder().AddInMemoryCollection(collection).Build();
            var config2 = new ConfigurationBuilder().SetBasePath(_env.ContentRootPath).AddIniFile("hosting.ini").Build();
            var config3 = new ConfigurationBuilder().SetBasePath(_env.ContentRootPath).AddJsonFile("config.json").Build();

            // AppConfig is a static class that groups together instances of IConfiguration and makes them available statically anywhere in the application
            AppConfig.AddConfigurationObject(config1, "memorySource");
            AppConfig.AddConfigurationObject(config2, "iniSource");
            AppConfig.AddConfigurationObject(config3, "jsonSource");

            // The above configuration sources can now be referenced easily with a static helper function
            Console.WriteLine("key1 key in memorySource: " + AppConfig.Get("memorySource", "key1"));
            Console.WriteLine("server.urls key in iniSource: " + AppConfig.Get("iniSource", "server.urls"));

            // Runtime configuration can be updated easily as well
            AppConfig.Set("iniSource", "server.urls", "http://localhost:5001");
            Console.WriteLine("Modified server.urls key in iniSource: " + AppConfig.Get("iniSource", "server.urls"));

            /*
             *   Health checks are simply functions that return either healthy or unhealthy with an optional message string
             */
            HealthCheckRegistry.RegisterHealthCheck("MyCustomMonitor", () => HealthResponse.Healthy("Test Message"));
            HealthCheckRegistry.RegisterHealthCheck("MyCustomMonitor2", () => HealthResponse.Healthy("Test Message2"));
            HealthCheckRegistry.RegisterHealthCheck("SampleOperation", () => SampleHealthCheckOperation());

            /*
             *   Some bundled health checks that can be used
             */
            // Redis health check (Requires StackExchange.Redis)
            //HealthCheckRegistry.RegisterHealthCheck("Redis", () => RedisHealthCheck.CheckHealth("localhost"));
            // PostgreSQL health check (Requires Npgsql)
            //HealthCheckRegistry.RegisterHealthCheck("Postgresql", () => PostgresqlHealthCheck.CheckHealth("Host=localhost;Username=postgres;Password=postgres;Database=postgres"));
            // SQL Server health check (Requires System.Data.SqlClient)
            //HealthCheckRegistry.RegisterHealthCheck("SqlServer", () => SqlServerCheck.CheckHealth("Server=localhost;Database=master;User Id=sa;Password=password; "));
            // RavenDB health check
            //HealthCheckRegistry.RegisterHealthCheck("ravendb", () => RavenDbHealthCheck.CheckHealth("Url=http://192.168.153.55:8080;DefaultDatabase=<system>"));
            // MongoDB health check
            //HealthCheckRegistry.RegisterHealthCheck("mongodb", () => MongoHealthCheck.CheckHealth("mongodb://localhost:27017"));

            /*
             *  Uncomment the below line to only allow access to the actuator endpoints from localhost
             *
             *  Allowed patterns are:
             *
             *  1. CIDR range: "192.168.0.0/24", "fe80::/10"
             *  2. Single address: "127.0.0.1", ":;1"
             *  3. Begin end range: "169.258.0.0-169.258.0.255"
             *  4. Bit mask range: "192.168.0.0/255.255.255.0"
             *
             *  NOTE: Currently this feature is not supported under Kestrel self-host as it does not set the client's IP address in HttpContext
             */

            //MicroserviceBootstrap.AllowedIpAddresses = IpAddressRange.Parse("127.0.0.0/8");

            // Activate /health endpoint
            app.UseHealthEndpoint();

            /*
             * Activate /env endpoint
             *
             * The ApplicationConfiguration element of the env endpoint will only contain data if the AppConfig helper class is
             * used to manage application configuration
             */
            app.UseEnvironmentEndpoint();

            /*
             *   The compiler directive below is only required if you plan to target .NET core as well as the full CLR
             *   If you don't target dnxcore50 in your project.json you can remove the below #if and just call UseInfoEndpoint()
             *   without any parameters
             */

            // Activate /info endpoint
#if NETCOREAPP1_0
            // Required for .NET Core until the relevant APIs are added
            app.UseInfoEndpoint(typeof(Startup).GetTypeInfo().Assembly.GetName());
#else
            app.UseInfoEndpoint();
#endif
        }