DnsDiagnostics.java

package redis.clients.jedis.scenario;

import java.net.InetAddress;
import java.util.Arrays;
import java.util.Properties;

import javax.naming.directory.InitialDirContext;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Follows an endpoint's DNS resolution on a daemon thread, sampling once per second from two views:
 * the JVM's {@link InetAddress} (subject to the JVM cache) and a direct query to the system
 * resolver (JNDI, JVM cache bypassed). A diverging pair of samples is direct evidence of stale
 * client-side resolution around an endpoint rebind.
 * <p>
 * Messages log at TRACE and {@link #follow} is a no-op unless TRACE is enabled for this class ���
 * enable it in the logging configuration to trigger the diagnostics.
 */
final class DnsDiagnostics implements AutoCloseable {

  private static final Logger logger = LoggerFactory.getLogger(DnsDiagnostics.class);
  private static final DnsDiagnostics DISABLED = new DnsDiagnostics(null);

  private final Thread sampler;

  private DnsDiagnostics(Thread sampler) {
    this.sampler = sampler;
  }

  /** Starts following {@code host}; no-op unless TRACE is enabled for this logger. */
  static DnsDiagnostics follow(String host) {
    if (!logger.isTraceEnabled()) {
      return DISABLED;
    }
    Thread thread = new Thread(() -> {
      while (!Thread.currentThread().isInterrupted()) {
        sample(host);
        try {
          Thread.sleep(1_000);
        } catch (InterruptedException e) {
          Thread.currentThread().interrupt();
        }
      }
    }, "dns-diag");
    thread.setDaemon(true);
    thread.start();
    return new DnsDiagnostics(thread);
  }

  private static void sample(String host) {
    try {
      logger.trace("jvm {} -> {}", host, Arrays.toString(InetAddress.getAllByName(host)));
    } catch (Exception e) {
      logger.trace("jvm {} -> {}", host, e.toString());
    }
    try {
      Properties env = new Properties();
      env.put("java.naming.factory.initial", "com.sun.jndi.dns.DnsContextFactory");
      logger.trace("dns {} -> {}", host,
        new InitialDirContext(env).getAttributes(host, new String[] { "A" }).get("A"));
    } catch (Exception e) {
      logger.trace("dns {} -> {}", host, e.toString());
    }
  }

  @Override
  public void close() {
    if (sampler != null) {
      sampler.interrupt();
    }
  }
}