HealthCheckerSharedPtr HealthCheckerFactory::create(
    const envoy::config::core::v3::HealthCheck& health_check_config, Upstream::Cluster& cluster,
    Runtime::Loader& runtime, Event::Dispatcher& dispatcher,
    AccessLog::AccessLogManager& log_manager,
    ProtobufMessage::ValidationVisitor& validation_visitor, Api::Api& api) {
  HealthCheckEventLoggerPtr event_logger;
  if (!health_check_config.event_log_path().empty()) {
    event_logger = std::make_unique<HealthCheckEventLoggerImpl>(
        log_manager, dispatcher.timeSource(), health_check_config.event_log_path());
  }
  switch (health_check_config.health_checker_case()) {
  case envoy::config::core::v3::HealthCheck::HealthCheckerCase::HEALTH_CHECKER_NOT_SET:
    throw EnvoyException("invalid cluster config");
  case envoy::config::core::v3::HealthCheck::HealthCheckerCase::kHttpHealthCheck:
    return std::make_shared<ProdHttpHealthCheckerImpl>(cluster, health_check_config, dispatcher,
                                                       runtime, api.randomGenerator(),
                                                       std::move(event_logger));
  case envoy::config::core::v3::HealthCheck::HealthCheckerCase::kTcpHealthCheck:
    return std::make_shared<TcpHealthCheckerImpl>(cluster, health_check_config, dispatcher, runtime,
                                                  api.randomGenerator(), std::move(event_logger));
  case envoy::config::core::v3::HealthCheck::HealthCheckerCase::kGrpcHealthCheck:
    if (!(cluster.info()->features() & Upstream::ClusterInfo::Features::HTTP2)) {
      throw EnvoyException(fmt::format("{} cluster must support HTTP/2 for gRPC healthchecking",
                                       cluster.info()->name()));
    }
    return std::make_shared<ProdGrpcHealthCheckerImpl>(cluster, health_check_config, dispatcher,
                                                       runtime, api.randomGenerator(),
                                                       std::move(event_logger));
  case envoy::config::core::v3::HealthCheck::HealthCheckerCase::kCustomHealthCheck: {
    auto& factory =
        Config::Utility::getAndCheckFactory<Server::Configuration::CustomHealthCheckerFactory>(
            health_check_config.custom_health_check());
    std::unique_ptr<Server::Configuration::HealthCheckerFactoryContext> context(
        new HealthCheckerFactoryContextImpl(cluster, runtime, dispatcher, std::move(event_logger),
                                            validation_visitor, api));
    return factory.createCustomHealthChecker(health_check_config, *context);
  }
  }
  PANIC_DUE_TO_CORRUPT_ENUM;
}
HealthCheckerSharedPtr HealthCheckerFactory::create(
    const envoy::config::core::v3::HealthCheck& health_check_config, Upstream::Cluster& cluster,
    Runtime::Loader& runtime, Event::Dispatcher& dispatcher,
    AccessLog::AccessLogManager& log_manager,
    ProtobufMessage::ValidationVisitor& validation_visitor, Api::Api& api) {
  HealthCheckEventLoggerPtr event_logger;
  if (!health_check_config.event_log_path().empty()) {
    event_logger = std::make_unique<HealthCheckEventLoggerImpl>(
        log_manager, dispatcher.timeSource(), health_check_config.event_log_path());
  }
  switch (health_check_config.health_checker_case()) {
  case envoy::config::core::v3::HealthCheck::HealthCheckerCase::HEALTH_CHECKER_NOT_SET:
    throw EnvoyException("invalid cluster config");
  case envoy::config::core::v3::HealthCheck::HealthCheckerCase::kHttpHealthCheck:
    return std::make_shared<ProdHttpHealthCheckerImpl>(cluster, health_check_config, dispatcher,
                                                       runtime, api.randomGenerator(),
                                                       std::move(event_logger));
  case envoy::config::core::v3::HealthCheck::HealthCheckerCase::kTcpHealthCheck:
    return std::make_shared<TcpHealthCheckerImpl>(cluster, health_check_config, dispatcher, runtime,
                                                  api.randomGenerator(), std::move(event_logger));
  case envoy::config::core::v3::HealthCheck::HealthCheckerCase::kGrpcHealthCheck:
    if (!(cluster.info()->features() & Upstream::ClusterInfo::Features::HTTP2)) {
      throw EnvoyException(fmt::format("{} cluster must support HTTP/2 for gRPC healthchecking",
                                       cluster.info()->name()));
    }
    return std::make_shared<ProdGrpcHealthCheckerImpl>(cluster, health_check_config, dispatcher,
                                                       runtime, api.randomGenerator(),
                                                       std::move(event_logger));
  case envoy::config::core::v3::HealthCheck::HealthCheckerCase::kCustomHealthCheck: {
    auto& factory =
        Config::Utility::getAndCheckFactory<Server::Configuration::CustomHealthCheckerFactory>(
            health_check_config.custom_health_check());
    std::unique_ptr<Server::Configuration::HealthCheckerFactoryContext> context(
        new HealthCheckerFactoryContextImpl(cluster, runtime, dispatcher, std::move(event_logger),
                                            validation_visitor, api));
    return factory.createCustomHealthChecker(health_check_config, *context);
  }
  }
  PANIC_DUE_TO_CORRUPT_ENUM;
}