func SetSnifferInterval(interval time.Duration) ClientOptionFunc {
	return func(c *Client) error {
		c.snifferInterval = interval
		return nil
	}
}
SetSnifferInterval sets the interval between two sniffing processes.
The default interval is 15 minutes.
package elastic
import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"math/rand"
	"net/http"
	"net/http/httputil"
	"net/url"
	"regexp"
	"strings"
	"sync"
	"time"
	"github.com/smartystreets/go-aws-auth"
)
const (
	Version = "3.0.45"
	DefaultURL = "http://127.0.0.1:9200"
	DefaultScheme = "http"
	DefaultHealthcheckEnabled = true
	DefaultHealthcheckTimeoutStartup = 5 * time.Second
	DefaultHealthcheckTimeout = 1 * time.Second
	DefaultHealthcheckInterval = 60 * time.Second
	DefaultSnifferEnabled = true
	DefaultSnifferInterval = 15 * time.Minute
	DefaultSnifferTimeoutStartup = 5 * time.Second
	DefaultSnifferTimeout = 2 * time.Second
	DefaultMaxRetries = 0
	DefaultSendGetBodyAs = "GET"
	DefaultGzipEnabled = false
	off = -1 * time.Second
)
var (
	ErrNoClient = errors.New("no Elasticsearch node available")
	ErrRetry = errors.New("cannot connect after several retries")
	ErrTimeout = errors.New("timeout")
)
type ClientOptionFunc func(*Client) error
type Client struct {
	c *http.Client  
	connsMu sync.RWMutex  
	conns   []*conn       
	cindex  int           
	mu                        sync.RWMutex   
	urls                      []string       
	running                   bool           
	errorlog                  Logger         
	infolog                   Logger         
	tracelog                  Logger         
	maxRetries                int            
	scheme                    string         
	healthcheckEnabled        bool           
	healthcheckTimeoutStartup time.Duration  
	healthcheckTimeout        time.Duration  
	healthcheckInterval       time.Duration  
	healthcheckStop           chan bool      
	snifferEnabled            bool           
	snifferTimeoutStartup     time.Duration  
	snifferTimeout            time.Duration  
	snifferInterval           time.Duration  
	snifferStop               chan bool      
	decoder                   Decoder        
	basicAuth                 bool           
	basicAuthUsername         string         
	basicAuthPassword         string         
	sendGetBodyAs             string         
	requiredPlugins           []string       
	gzipEnabled               bool           
}
func NewClient(options ...ClientOptionFunc) (*Client, error) {
	c := &Client{
		c:                         http.DefaultClient,
		conns:                     make([]*conn, 0),
		cindex:                    -1,
		scheme:                    DefaultScheme,
		decoder:                   &DefaultDecoder{},
		maxRetries:                DefaultMaxRetries,
		healthcheckEnabled:        DefaultHealthcheckEnabled,
		healthcheckTimeoutStartup: DefaultHealthcheckTimeoutStartup,
		healthcheckTimeout:        DefaultHealthcheckTimeout,
		healthcheckInterval:       DefaultHealthcheckInterval,
		healthcheckStop:           make(chan bool),
		snifferEnabled:            DefaultSnifferEnabled,
		snifferTimeoutStartup:     DefaultSnifferTimeoutStartup,
		snifferTimeout:            DefaultSnifferTimeout,
		snifferInterval:           DefaultSnifferInterval,
		snifferStop:               make(chan bool),
		sendGetBodyAs:             DefaultSendGetBodyAs,
		gzipEnabled:               DefaultGzipEnabled,
	}
	for _, option := range options {
		if err := option(c); err != nil {
			return nil, err
		}
	}
	if len(c.urls) == 0 {
		c.urls = []string{DefaultURL}
	}
	c.urls = canonicalize(c.urls...)
	if c.healthcheckEnabled {
		if err := c.startupHealthcheck(c.healthcheckTimeoutStartup); err != nil {
			return nil, err
		}
	}
	if c.snifferEnabled {
		if err := c.sniff(c.snifferTimeoutStartup); err != nil {
			return nil, err
		}
	} else {
		for _, url := range c.urls {
			c.conns = append(c.conns, newConn(url, url))
		}
	}
	if c.healthcheckEnabled {
		c.healthcheck(c.healthcheckTimeoutStartup, true)
	}
	if err := c.mustActiveConn(); err != nil {
		return nil, err
	}
	for _, plugin := range c.requiredPlugins {
		found, err := c.HasPlugin(plugin)
		if err != nil {
			return nil, err
		}
		if !found {
			return nil, fmt.Errorf("elastic: plugin %s not found", plugin)
		}
	}
	if c.snifferEnabled {
		go c.sniffer()  
	}
	if c.healthcheckEnabled {
		go c.healthchecker()  
	}
	c.mu.Lock()
	c.running = true
	c.mu.Unlock()
	return c, nil
}
func NewSimpleClient(options ...ClientOptionFunc) (*Client, error) {
	c := &Client{
		c:                         http.DefaultClient,
		conns:                     make([]*conn, 0),
		cindex:                    -1,
		scheme:                    DefaultScheme,
		decoder:                   &DefaultDecoder{},
		maxRetries:                1,
		healthcheckEnabled:        false,
		healthcheckTimeoutStartup: off,
		healthcheckTimeout:        off,
		healthcheckInterval:       off,
		healthcheckStop:           make(chan bool),
		snifferEnabled:            false,
		snifferTimeoutStartup:     off,
		snifferTimeout:            off,
		snifferInterval:           off,
		snifferStop:               make(chan bool),
		sendGetBodyAs:             DefaultSendGetBodyAs,
		gzipEnabled:               DefaultGzipEnabled,
	}
	for _, option := range options {
		if err := option(c); err != nil {
			return nil, err
		}
	}
	if len(c.urls) == 0 {
		c.urls = []string{DefaultURL}
	}
	c.urls = canonicalize(c.urls...)
	for _, url := range c.urls {
		c.conns = append(c.conns, newConn(url, url))
	}
	if err := c.mustActiveConn(); err != nil {
		return nil, err
	}
	for _, plugin := range c.requiredPlugins {
		found, err := c.HasPlugin(plugin)
		if err != nil {
			return nil, err
		}
		if !found {
			return nil, fmt.Errorf("elastic: plugin %s not found", plugin)
		}
	}
	c.mu.Lock()
	c.running = true
	c.mu.Unlock()
	return c, nil
}
func SetHttpClient(httpClient *http.Client) ClientOptionFunc {
	return func(c *Client) error {
		if httpClient != nil {
			c.c = httpClient
		} else {
			c.c = http.DefaultClient
		}
		return nil
	}
}
func SetBasicAuth(username, password string) ClientOptionFunc {
	return func(c *Client) error {
		c.basicAuthUsername = username
		c.basicAuthPassword = password
		c.basicAuth = c.basicAuthUsername != "" || c.basicAuthPassword != ""
		return nil
	}
}
func SetURL(urls ...string) ClientOptionFunc {
	return func(c *Client) error {
		switch len(urls) {
		case 0:
			c.urls = []string{DefaultURL}
		default:
			c.urls = urls
		}
		return nil
	}
}
func SetScheme(scheme string) ClientOptionFunc {
	return func(c *Client) error {
		c.scheme = scheme
		return nil
	}
}
func SetSniff(enabled bool) ClientOptionFunc {
	return func(c *Client) error {
		c.snifferEnabled = enabled
		return nil
	}
}
func SetSnifferTimeoutStartup(timeout time.Duration) ClientOptionFunc {
	return func(c *Client) error {
		c.snifferTimeoutStartup = timeout
		return nil
	}
}
func SetSnifferTimeout(timeout time.Duration) ClientOptionFunc {
	return func(c *Client) error {
		c.snifferTimeout = timeout
		return nil
	}
}