diff --git a/vendor/git.autistici.org/ai3/go-common/ldap/pool.go b/vendor/git.autistici.org/ai3/go-common/ldap/pool.go index 520dcf2bdcdb719873315324477cbae09aa902ca..854c49416cfe5acb61d33f15a01816662b1c64a1 100644 --- a/vendor/git.autistici.org/ai3/go-common/ldap/pool.go +++ b/vendor/git.autistici.org/ai3/go-common/ldap/pool.go @@ -8,6 +8,7 @@ import ( "time" "github.com/cenkalti/backoff" + "go.opencensus.io/trace" "gopkg.in/ldap.v2" ) @@ -147,9 +148,18 @@ func NewConnectionPool(uri, bindDN, bindPw string, cacheSize int) (*ConnectionPo }, nil } -func (p *ConnectionPool) doRequest(ctx context.Context, fn func(*ldap.Conn) error) error { - return backoff.Retry(func() error { - conn, err := p.Get(ctx) +func (p *ConnectionPool) doRequest(ctx context.Context, name string, attrs []trace.Attribute, fn func(*ldap.Conn) error) error { + // Tracing: initialize a new client span. + sctx, span := trace.StartSpan(ctx, name, + trace.WithSpanKind(trace.SpanKindClient)) + defer span.End() + + if len(attrs) > 0 { + span.AddAttributes(attrs...) + } + + rerr := backoff.Retry(func() error { + conn, err := p.Get(sctx) if err != nil { // Here conn is nil, so we don't need to Release it. if isTemporaryLDAPError(err) { @@ -158,7 +168,7 @@ func (p *ConnectionPool) doRequest(ctx context.Context, fn func(*ldap.Conn) erro return backoff.Permanent(err) } - if deadline, ok := ctx.Deadline(); ok { + if deadline, ok := sctx.Deadline(); ok { conn.SetTimeout(time.Until(deadline)) } @@ -169,30 +179,42 @@ func (p *ConnectionPool) doRequest(ctx context.Context, fn func(*ldap.Conn) erro } return err }, backoff.WithContext(newExponentialBackOff(), ctx)) + + // Tracing: set the final status. + span.SetStatus(errorToTraceStatus(rerr)) + + return rerr } // Search performs the given search request. It will retry the request // on temporary errors. func (p *ConnectionPool) Search(ctx context.Context, searchRequest *ldap.SearchRequest) (*ldap.SearchResult, error) { var result *ldap.SearchResult - err := p.doRequest(ctx, func(conn *ldap.Conn) error { - var err error - result, err = conn.Search(searchRequest) - return err + err := p.doRequest(ctx, "ldap.Search", []trace.Attribute{ + trace.StringAttribute("ldap.base", searchRequest.BaseDN), + trace.StringAttribute("ldap.filter", searchRequest.Filter), + trace.Int64Attribute("ldap.scope", int64(searchRequest.Scope)), + }, func(conn *ldap.Conn) (cerr error) { + result, cerr = conn.Search(searchRequest) + return }) return result, err } // Modify issues a ModifyRequest to the LDAP server. func (p *ConnectionPool) Modify(ctx context.Context, modifyRequest *ldap.ModifyRequest) error { - return p.doRequest(ctx, func(conn *ldap.Conn) error { + return p.doRequest(ctx, "ldap.Modify", []trace.Attribute{ + trace.StringAttribute("ldap.dn", modifyRequest.DN), + }, func(conn *ldap.Conn) error { return conn.Modify(modifyRequest) }) } // Add issues an AddRequest to the LDAP server. func (p *ConnectionPool) Add(ctx context.Context, addRequest *ldap.AddRequest) error { - return p.doRequest(ctx, func(conn *ldap.Conn) error { + return p.doRequest(ctx, "ldap.Add", []trace.Attribute{ + trace.StringAttribute("ldap.dn", addRequest.DN), + }, func(conn *ldap.Conn) error { return conn.Add(addRequest) }) } @@ -219,3 +241,16 @@ func isTemporaryLDAPError(err error) bool { return false } } + +func errorToTraceStatus(err error) trace.Status { + switch err { + case nil: + return trace.Status{Code: trace.StatusCodeOK, Message: "OK"} + case context.Canceled: + return trace.Status{Code: trace.StatusCodeCancelled, Message: "CANCELED"} + case context.DeadlineExceeded: + return trace.Status{Code: trace.StatusCodeDeadlineExceeded, Message: "DEADLINE_EXCEEDED"} + default: + return trace.Status{Code: trace.StatusCodeUnknown, Message: err.Error()} + } +} diff --git a/vendor/git.autistici.org/ai3/go-common/tracing/tracing.go b/vendor/git.autistici.org/ai3/go-common/tracing/tracing.go index df6144b7dd054b4dfde6640d95351f872050275a..544ca1a0a0d917e47e7f06af2b75915fe4530f3b 100644 --- a/vendor/git.autistici.org/ai3/go-common/tracing/tracing.go +++ b/vendor/git.autistici.org/ai3/go-common/tracing/tracing.go @@ -8,6 +8,7 @@ import ( "net/http" "os" "path/filepath" + "strconv" "sync" openzipkin "github.com/openzipkin/zipkin-go" @@ -31,6 +32,7 @@ const globalTracingConfigPath = "/etc/tracing/client.conf" type tracingConfig struct { ReportURL string `json:"report_url"` + Sample string `json:"sample"` } // Read the global tracing configuration file. Its location is @@ -100,9 +102,23 @@ func initTracing(endpointAddr string) { reporter := zipkinHTTP.NewReporter(config.ReportURL) ze := zipkin.NewExporter(reporter, localEndpoint) - trace.RegisterExporter(ze) - trace.ApplyConfig(trace.Config{DefaultSampler: trace.AlwaysSample()}) + + var tc trace.Config + switch config.Sample { + case "", "always": + tc.DefaultSampler = trace.AlwaysSample() + case "never": + tc.DefaultSampler = trace.NeverSample() + default: + frac, err := strconv.ParseFloat(config.Sample, 64) + if err != nil { + log.Printf("warning: error in tracing configuration: sample: %v, tracing disabled", err) + return + } + tc.DefaultSampler = trace.ProbabilitySampler(frac) + } + trace.ApplyConfig(tc) log.Printf("tracing enabled (report_url %s)", config.ReportURL) diff --git a/vendor/git.autistici.org/ai3/go-common/unix/server.go b/vendor/git.autistici.org/ai3/go-common/unix/server.go index 0bb6e2e2d5ae8e973739fa5009dd9e10200c3f43..b5d92e1ca61517865f194d0b97dbfa96b99a3168 100644 --- a/vendor/git.autistici.org/ai3/go-common/unix/server.go +++ b/vendor/git.autistici.org/ai3/go-common/unix/server.go @@ -14,6 +14,7 @@ import ( "time" "github.com/coreos/go-systemd/activation" + "github.com/prometheus/client_golang/prometheus" "github.com/theckman/go-flock" ) @@ -51,7 +52,7 @@ func NewUNIXSocketServer(socketPath string, h Handler) (*SocketServer, error) { // successfully. We could remove it before starting, but that // would be dangerous if another instance was listening on // that socket. So we wrap socket access with a file lock. - lock := flock.NewFlock(socketPath + ".lock") + lock := flock.New(socketPath + ".lock") locked, err := lock.TryLock() if err != nil { return nil, err @@ -66,7 +67,7 @@ func NewUNIXSocketServer(socketPath string, h Handler) (*SocketServer, error) { } // Always try to unlink the socket before creating it. - os.Remove(socketPath) + os.Remove(socketPath) // nolint l, err := net.ListenUnix("unix", addr) if err != nil { @@ -98,10 +99,10 @@ func NewSystemdSocketServer(h Handler) (*SocketServer, error) { // Waits for active connections to terminate before returning. func (s *SocketServer) Close() { s.closing.Store(true) - s.l.Close() + s.l.Close() // nolint s.wg.Wait() if s.lock != nil { - s.lock.Unlock() + s.lock.Unlock() // nolint } } @@ -122,7 +123,7 @@ func (s *SocketServer) Serve() error { s.wg.Add(1) go func() { s.handler.ServeConnection(conn) - conn.Close() + conn.Close() // nolint s.wg.Done() }() } @@ -198,11 +199,15 @@ func (w *lrWriter) WriteLineCRLF(data []byte) error { return w.Writer.Flush() } +// ServeConnection handles a new connection. It will accept multiple +// requests on the same connection (or not, depending on the client +// preference). func (l *LineServer) ServeConnection(nc net.Conn) { + totalConnections.Inc() c := textproto.NewConn(nc) rw := &lrWriter{bufio.NewWriter(nc)} for { - nc.SetReadDeadline(time.Now().Add(l.IdleTimeout)) + nc.SetReadDeadline(time.Now().Add(l.IdleTimeout)) // nolint line, err := c.ReadLineBytes() if err == io.EOF { break @@ -215,17 +220,59 @@ func (l *LineServer) ServeConnection(nc net.Conn) { // handler with it. Set a write deadline on the // connection to allow the full RequestTimeout time to // generate the response. - nc.SetWriteDeadline(time.Now().Add(l.RequestTimeout + l.WriteTimeout)) + start := time.Now() + nc.SetWriteDeadline(start.Add(l.RequestTimeout + l.WriteTimeout)) // nolint ctx, cancel := context.WithTimeout(context.Background(), l.RequestTimeout) err = l.handler.ServeLine(ctx, rw, line) + elapsedMs := time.Since(start).Nanoseconds() / 1000000 + requestLatencyHist.Observe(float64(elapsedMs)) cancel() // Close the connection on error, or on empty response. if err != nil { + totalRequests.With(prometheus.Labels{ + "status": "error", + }).Inc() if err != ErrCloseConnection { log.Printf("request error: %v", err) } break } + totalRequests.With(prometheus.Labels{ + "status": "ok", + }).Inc() } } + +// Instrumentation metrics. +var ( + totalConnections = prometheus.NewCounter( + prometheus.CounterOpts{ + Name: "unix_connections_total", + Help: "Total number of connections.", + }, + ) + totalRequests = prometheus.NewCounterVec( + prometheus.CounterOpts{ + Name: "unix_requests_total", + Help: "Total number of requests.", + }, + []string{"status"}, + ) + // Histogram buckets are tuned for the low-milliseconds range + // (the largest bucket sits at ~1s). + requestLatencyHist = prometheus.NewHistogram( + prometheus.HistogramOpts{ + Name: "unix_requests_latency_ms", + Help: "Latency of requests.", + Buckets: prometheus.ExponentialBuckets(5, 1.4142, 16), + }, + ) +) + +func init() { + prometheus.MustRegister(totalConnections) + prometheus.MustRegister(totalRequests) + prometheus.MustRegister(requestLatencyHist) + +} diff --git a/vendor/vendor.json b/vendor/vendor.json index 41eda6239e384224767225ac0374e268a6b869e5..e1e35fc3ff1f5309026632a3e444b6aea42e3d3a 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -5,44 +5,44 @@ { "checksumSHA1": "pLvPnUablirQucyALgrso9hLG4E=", "path": "git.autistici.org/ai3/go-common", - "revision": "1f95fcdd58ebf63d338f05ceae29d2de811a2d2f", - "revisionTime": "2018-11-18T16:11:30Z" + "revision": "438dda6c699e73e612d0b16143076998d77c03ac", + "revisionTime": "2018-11-22T23:09:18Z" }, { "checksumSHA1": "1ChQcW9Biu/AgiKjsbJFg/+WhjQ=", "path": "git.autistici.org/ai3/go-common/clientutil", - "revision": "1f95fcdd58ebf63d338f05ceae29d2de811a2d2f", - "revisionTime": "2018-11-18T16:11:30Z" + "revision": "438dda6c699e73e612d0b16143076998d77c03ac", + "revisionTime": "2018-11-22T23:09:18Z" }, { - "checksumSHA1": "kQbBWZqrXc95wodlrOKEshQVaBo=", + "checksumSHA1": "npDdYYmInhdVxcCpOQ844cVlfzQ=", "path": "git.autistici.org/ai3/go-common/ldap", - "revision": "1f95fcdd58ebf63d338f05ceae29d2de811a2d2f", - "revisionTime": "2018-11-18T16:11:30Z" + "revision": "438dda6c699e73e612d0b16143076998d77c03ac", + "revisionTime": "2018-11-22T23:09:18Z" }, { "checksumSHA1": "TKGUNmKxj7KH3qhwiCh/6quUnwc=", "path": "git.autistici.org/ai3/go-common/serverutil", - "revision": "1f95fcdd58ebf63d338f05ceae29d2de811a2d2f", - "revisionTime": "2018-11-18T16:11:30Z" + "revision": "438dda6c699e73e612d0b16143076998d77c03ac", + "revisionTime": "2018-11-22T23:09:18Z" }, { - "checksumSHA1": "WvuSF0pz3rk7bu+5g9lqTqq97Ow=", + "checksumSHA1": "tWzCSEieYFl5VnKhFTosgveO6Ys=", "path": "git.autistici.org/ai3/go-common/tracing", - "revision": "1f95fcdd58ebf63d338f05ceae29d2de811a2d2f", - "revisionTime": "2018-11-18T16:11:30Z" + "revision": "438dda6c699e73e612d0b16143076998d77c03ac", + "revisionTime": "2018-11-22T23:09:18Z" }, { - "checksumSHA1": "Okvoje2tgehkMo1N9Q601JPgGoE=", + "checksumSHA1": "R18oCPkWjuPqDxPgKvG1KhiSJns=", "path": "git.autistici.org/ai3/go-common/unix", - "revision": "1f95fcdd58ebf63d338f05ceae29d2de811a2d2f", - "revisionTime": "2018-11-18T16:11:30Z" + "revision": "438dda6c699e73e612d0b16143076998d77c03ac", + "revisionTime": "2018-11-22T23:09:18Z" }, { "checksumSHA1": "witSYnNsDhNaoA85UYilt17H+ng=", "path": "git.autistici.org/ai3/go-common/userenckey", - "revision": "1f95fcdd58ebf63d338f05ceae29d2de811a2d2f", - "revisionTime": "2018-11-18T16:11:30Z" + "revision": "438dda6c699e73e612d0b16143076998d77c03ac", + "revisionTime": "2018-11-22T23:09:18Z" }, { "checksumSHA1": "MszadHmYMr3JQMX2gRg7TfsQWVc=",