func incErrCounter(logURL string, endpoint string, rspErr error) {
	if rspErr == nil {
		return
	}
	err, ok := rspErr.(client.RspError)
	switch {
	case !ok:
		glog.Errorf("unknown_error (%s, %s) => %v", logURL, endpoint, rspErr)
		errCounter.Inc(logURL, endpoint, "unknown_error")
	case err.Err != nil && err.StatusCode == http.StatusOK:
		glog.Errorf("invalid_sct (%s, %s) => HTTP details: status=%d, body:\n%s", logURL, endpoint, err.StatusCode, err.Body)
		errCounter.Inc(logURL, endpoint, "invalid_sct")
	case err.Err != nil:  
		glog.Errorf("connection_error (%s, %s) => HTTP details: status=%d, body:\n%s", logURL, endpoint, err.StatusCode, err.Body)
		errCounter.Inc(logURL, endpoint, "connection_error")
	}
}
incErrCounter increments corresponding errCounter if any error occurred during
submission to a Log.
package submission
import (
	"context"
	"fmt"
	"net/http"
	"net/url"
	"strconv"
	"sync"
	"time"
	"github.com/golang/glog"
	"github.com/google/certificate-transparency-go/client"
	"github.com/google/certificate-transparency-go/ctpolicy"
	"github.com/google/certificate-transparency-go/jsonclient"
	"github.com/google/certificate-transparency-go/loglist2"
	"github.com/google/certificate-transparency-go/trillian/ctfe"
	"github.com/google/certificate-transparency-go/x509"
	"github.com/google/trillian/monitoring"
	ct "github.com/google/certificate-transparency-go"
)
var (
	distOnce      sync.Once
	reqsCounter   monitoring.Counter    
	rspsCounter   monitoring.Counter    
	errCounter    monitoring.Counter    
	logRspLatency monitoring.Histogram  
	lastGetRootsSuccess monitoring.Gauge  
)
func distInitMetrics(mf monitoring.MetricFactory) {
	reqsCounter = mf.NewCounter("http_reqs", "Number of requests", "logurl", "ep")
	rspsCounter = mf.NewCounter("http_rsps", "Number of responses", "logurl", "ep", "httpstatus")
	errCounter = mf.NewCounter("err_count", "Number of errors", "logurl", "ep", "errtype")
	logRspLatency = mf.NewHistogram("http_log_latency", "Latency of responses in seconds", "logurl", "ep")
	lastGetRootsSuccess = mf.NewGauge("last_get_roots_success", "Unix timestamp for last successful get-roots request", "logurl")
}
const (
	getRootsTimeout = time.Second * 10
)
type pendingLogsPolicy struct {
}
func (stubP pendingLogsPolicy) LogsByGroup(cert *x509.Certificate, approved *loglist2.LogList) (ctpolicy.LogPolicyData, error) {
	baseGroup, err := ctpolicy.BaseGroupFor(approved, 1)
	groups := ctpolicy.LogPolicyData{baseGroup.Name: baseGroup}
	return groups, err
}
func (stubP pendingLogsPolicy) Name() string {
	return "Pending/Qualified Policy"
}
type Distributor struct {
	ll                 *loglist2.LogList
	usableLl           *loglist2.LogList
	pendingQualifiedLl *loglist2.LogList
	mu sync.RWMutex
	logClients map[string]client.AddLogClient
	logRoots   loglist2.LogRoots
	rootPool   *ctfe.PEMCertPool
	rootDataFull bool
	policy            ctpolicy.CTPolicy
	pendingLogsPolicy ctpolicy.CTPolicy
}
func (d *Distributor) RefreshRoots(ctx context.Context) map[string]error {
	type RootsResult struct {
		LogURL string
		Roots  *ctfe.PEMCertPool
		Err    error
	}
	ch := make(chan RootsResult, len(d.logClients))
	rctx, cancel := context.WithTimeout(ctx, getRootsTimeout)
	defer cancel()
	for logURL, lc := range d.logClients {
		go func(logURL string, lc client.AddLogClient) {
			res := RootsResult{LogURL: logURL}
			roots, err := lc.GetAcceptedRoots(rctx)
			if err != nil {
				res.Err = fmt.Errorf("roots refresh for %s: couldn't collect roots. %s", logURL, err)
				ch <- res
				return
			}
			res.Roots = ctfe.NewPEMCertPool()
			for _, r := range roots {
				parsed, err := x509.ParseCertificate(r.Data)
				if x509.IsFatal(err) {
					errS := fmt.Errorf("roots refresh for %s: unable to parse root cert: %s", logURL, err)
					if res.Err != nil {
						res.Err = fmt.Errorf("%s\n%s", res.Err, errS)
					} else {
						res.Err = errS
					}
					continue
				}
				res.Roots.AddCert(parsed)
			}
			ch <- res
		}(logURL, lc)
	}
	freshRoots := make(loglist2.LogRoots)
	errors := make(map[string]error)
	for range d.logClients {
		r := <-ch
		if r.Err != nil {
			errors[r.LogURL] = r.Err
		}
		if r.Roots != nil {
			freshRoots[r.LogURL] = r.Roots
			lastGetRootsSuccess.Set(float64(time.Now().Unix()), r.LogURL)
		}
	}
	d.mu.Lock()
	defer d.mu.Unlock()
	d.logRoots = freshRoots
	d.rootDataFull = len(d.logRoots) == len(d.logClients)
	d.rootPool = ctfe.NewPEMCertPool()
	for _, pool := range d.logRoots {
		for _, c := range pool.RawCertificates() {
			d.rootPool.AddCert(c)
		}
	}
	return errors
}
func incRspsCounter(logURL string, endpoint string, rspErr error) {
	status := http.StatusOK
	if rspErr != nil {
		status = http.StatusBadRequest  
		if err, ok := rspErr.(client.RspError); ok {
			status = err.StatusCode
		}
	}
	rspsCounter.Inc(logURL, endpoint, strconv.Itoa(status))
}