+
+Notes:
+
+1. Large messages are fragmented in [Chrome's new WebSocket implementation](http://www.ietf.org/mail-archive/web/hybi/current/msg10503.html).
+2. The application can get the type of a received data message by implementing
+ a [Codec marshal](http://godoc.org/golang.org/x/net/websocket#Codec.Marshal)
+ function.
+3. The go.net io.Reader and io.Writer operate across WebSocket frame boundaries.
+ Read returns when the input buffer is full or a frame boundary is
+ encountered. Each call to Write sends a single frame message. The Gorilla
+ io.Reader and io.WriteCloser operate on a single WebSocket message.
+
diff --git a/vendor/github.com/gorilla/websocket/client.go b/vendor/github.com/gorilla/websocket/client.go
new file mode 100644
index 0000000..2e32fd5
--- /dev/null
+++ b/vendor/github.com/gorilla/websocket/client.go
@@ -0,0 +1,395 @@
+// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package websocket
+
+import (
+ "bytes"
+ "context"
+ "crypto/tls"
+ "errors"
+ "io"
+ "io/ioutil"
+ "net"
+ "net/http"
+ "net/http/httptrace"
+ "net/url"
+ "strings"
+ "time"
+)
+
+// ErrBadHandshake is returned when the server response to opening handshake is
+// invalid.
+var ErrBadHandshake = errors.New("websocket: bad handshake")
+
+var errInvalidCompression = errors.New("websocket: invalid compression negotiation")
+
+// NewClient creates a new client connection using the given net connection.
+// The URL u specifies the host and request URI. Use requestHeader to specify
+// the origin (Origin), subprotocols (Sec-WebSocket-Protocol) and cookies
+// (Cookie). Use the response.Header to get the selected subprotocol
+// (Sec-WebSocket-Protocol) and cookies (Set-Cookie).
+//
+// If the WebSocket handshake fails, ErrBadHandshake is returned along with a
+// non-nil *http.Response so that callers can handle redirects, authentication,
+// etc.
+//
+// Deprecated: Use Dialer instead.
+func NewClient(netConn net.Conn, u *url.URL, requestHeader http.Header, readBufSize, writeBufSize int) (c *Conn, response *http.Response, err error) {
+ d := Dialer{
+ ReadBufferSize: readBufSize,
+ WriteBufferSize: writeBufSize,
+ NetDial: func(net, addr string) (net.Conn, error) {
+ return netConn, nil
+ },
+ }
+ return d.Dial(u.String(), requestHeader)
+}
+
+// A Dialer contains options for connecting to WebSocket server.
+type Dialer struct {
+ // NetDial specifies the dial function for creating TCP connections. If
+ // NetDial is nil, net.Dial is used.
+ NetDial func(network, addr string) (net.Conn, error)
+
+ // NetDialContext specifies the dial function for creating TCP connections. If
+ // NetDialContext is nil, net.DialContext is used.
+ NetDialContext func(ctx context.Context, network, addr string) (net.Conn, error)
+
+ // Proxy specifies a function to return a proxy for a given
+ // Request. If the function returns a non-nil error, the
+ // request is aborted with the provided error.
+ // If Proxy is nil or returns a nil *URL, no proxy is used.
+ Proxy func(*http.Request) (*url.URL, error)
+
+ // TLSClientConfig specifies the TLS configuration to use with tls.Client.
+ // If nil, the default configuration is used.
+ TLSClientConfig *tls.Config
+
+ // HandshakeTimeout specifies the duration for the handshake to complete.
+ HandshakeTimeout time.Duration
+
+ // ReadBufferSize and WriteBufferSize specify I/O buffer sizes. If a buffer
+ // size is zero, then a useful default size is used. The I/O buffer sizes
+ // do not limit the size of the messages that can be sent or received.
+ ReadBufferSize, WriteBufferSize int
+
+ // WriteBufferPool is a pool of buffers for write operations. If the value
+ // is not set, then write buffers are allocated to the connection for the
+ // lifetime of the connection.
+ //
+ // A pool is most useful when the application has a modest volume of writes
+ // across a large number of connections.
+ //
+ // Applications should use a single pool for each unique value of
+ // WriteBufferSize.
+ WriteBufferPool BufferPool
+
+ // Subprotocols specifies the client's requested subprotocols.
+ Subprotocols []string
+
+ // EnableCompression specifies if the client should attempt to negotiate
+ // per message compression (RFC 7692). Setting this value to true does not
+ // guarantee that compression will be supported. Currently only "no context
+ // takeover" modes are supported.
+ EnableCompression bool
+
+ // Jar specifies the cookie jar.
+ // If Jar is nil, cookies are not sent in requests and ignored
+ // in responses.
+ Jar http.CookieJar
+}
+
+// Dial creates a new client connection by calling DialContext with a background context.
+func (d *Dialer) Dial(urlStr string, requestHeader http.Header) (*Conn, *http.Response, error) {
+ return d.DialContext(context.Background(), urlStr, requestHeader)
+}
+
+var errMalformedURL = errors.New("malformed ws or wss URL")
+
+func hostPortNoPort(u *url.URL) (hostPort, hostNoPort string) {
+ hostPort = u.Host
+ hostNoPort = u.Host
+ if i := strings.LastIndex(u.Host, ":"); i > strings.LastIndex(u.Host, "]") {
+ hostNoPort = hostNoPort[:i]
+ } else {
+ switch u.Scheme {
+ case "wss":
+ hostPort += ":443"
+ case "https":
+ hostPort += ":443"
+ default:
+ hostPort += ":80"
+ }
+ }
+ return hostPort, hostNoPort
+}
+
+// DefaultDialer is a dialer with all fields set to the default values.
+var DefaultDialer = &Dialer{
+ Proxy: http.ProxyFromEnvironment,
+ HandshakeTimeout: 45 * time.Second,
+}
+
+// nilDialer is dialer to use when receiver is nil.
+var nilDialer = *DefaultDialer
+
+// DialContext creates a new client connection. Use requestHeader to specify the
+// origin (Origin), subprotocols (Sec-WebSocket-Protocol) and cookies (Cookie).
+// Use the response.Header to get the selected subprotocol
+// (Sec-WebSocket-Protocol) and cookies (Set-Cookie).
+//
+// The context will be used in the request and in the Dialer
+//
+// If the WebSocket handshake fails, ErrBadHandshake is returned along with a
+// non-nil *http.Response so that callers can handle redirects, authentication,
+// etcetera. The response body may not contain the entire response and does not
+// need to be closed by the application.
+func (d *Dialer) DialContext(ctx context.Context, urlStr string, requestHeader http.Header) (*Conn, *http.Response, error) {
+ if d == nil {
+ d = &nilDialer
+ }
+
+ challengeKey, err := generateChallengeKey()
+ if err != nil {
+ return nil, nil, err
+ }
+
+ u, err := url.Parse(urlStr)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ switch u.Scheme {
+ case "ws":
+ u.Scheme = "http"
+ case "wss":
+ u.Scheme = "https"
+ default:
+ return nil, nil, errMalformedURL
+ }
+
+ if u.User != nil {
+ // User name and password are not allowed in websocket URIs.
+ return nil, nil, errMalformedURL
+ }
+
+ req := &http.Request{
+ Method: "GET",
+ URL: u,
+ Proto: "HTTP/1.1",
+ ProtoMajor: 1,
+ ProtoMinor: 1,
+ Header: make(http.Header),
+ Host: u.Host,
+ }
+ req = req.WithContext(ctx)
+
+ // Set the cookies present in the cookie jar of the dialer
+ if d.Jar != nil {
+ for _, cookie := range d.Jar.Cookies(u) {
+ req.AddCookie(cookie)
+ }
+ }
+
+ // Set the request headers using the capitalization for names and values in
+ // RFC examples. Although the capitalization shouldn't matter, there are
+ // servers that depend on it. The Header.Set method is not used because the
+ // method canonicalizes the header names.
+ req.Header["Upgrade"] = []string{"websocket"}
+ req.Header["Connection"] = []string{"Upgrade"}
+ req.Header["Sec-WebSocket-Key"] = []string{challengeKey}
+ req.Header["Sec-WebSocket-Version"] = []string{"13"}
+ if len(d.Subprotocols) > 0 {
+ req.Header["Sec-WebSocket-Protocol"] = []string{strings.Join(d.Subprotocols, ", ")}
+ }
+ for k, vs := range requestHeader {
+ switch {
+ case k == "Host":
+ if len(vs) > 0 {
+ req.Host = vs[0]
+ }
+ case k == "Upgrade" ||
+ k == "Connection" ||
+ k == "Sec-Websocket-Key" ||
+ k == "Sec-Websocket-Version" ||
+ k == "Sec-Websocket-Extensions" ||
+ (k == "Sec-Websocket-Protocol" && len(d.Subprotocols) > 0):
+ return nil, nil, errors.New("websocket: duplicate header not allowed: " + k)
+ case k == "Sec-Websocket-Protocol":
+ req.Header["Sec-WebSocket-Protocol"] = vs
+ default:
+ req.Header[k] = vs
+ }
+ }
+
+ if d.EnableCompression {
+ req.Header["Sec-WebSocket-Extensions"] = []string{"permessage-deflate; server_no_context_takeover; client_no_context_takeover"}
+ }
+
+ if d.HandshakeTimeout != 0 {
+ var cancel func()
+ ctx, cancel = context.WithTimeout(ctx, d.HandshakeTimeout)
+ defer cancel()
+ }
+
+ // Get network dial function.
+ var netDial func(network, add string) (net.Conn, error)
+
+ if d.NetDialContext != nil {
+ netDial = func(network, addr string) (net.Conn, error) {
+ return d.NetDialContext(ctx, network, addr)
+ }
+ } else if d.NetDial != nil {
+ netDial = d.NetDial
+ } else {
+ netDialer := &net.Dialer{}
+ netDial = func(network, addr string) (net.Conn, error) {
+ return netDialer.DialContext(ctx, network, addr)
+ }
+ }
+
+ // If needed, wrap the dial function to set the connection deadline.
+ if deadline, ok := ctx.Deadline(); ok {
+ forwardDial := netDial
+ netDial = func(network, addr string) (net.Conn, error) {
+ c, err := forwardDial(network, addr)
+ if err != nil {
+ return nil, err
+ }
+ err = c.SetDeadline(deadline)
+ if err != nil {
+ c.Close()
+ return nil, err
+ }
+ return c, nil
+ }
+ }
+
+ // If needed, wrap the dial function to connect through a proxy.
+ if d.Proxy != nil {
+ proxyURL, err := d.Proxy(req)
+ if err != nil {
+ return nil, nil, err
+ }
+ if proxyURL != nil {
+ dialer, err := proxy_FromURL(proxyURL, netDialerFunc(netDial))
+ if err != nil {
+ return nil, nil, err
+ }
+ netDial = dialer.Dial
+ }
+ }
+
+ hostPort, hostNoPort := hostPortNoPort(u)
+ trace := httptrace.ContextClientTrace(ctx)
+ if trace != nil && trace.GetConn != nil {
+ trace.GetConn(hostPort)
+ }
+
+ netConn, err := netDial("tcp", hostPort)
+ if trace != nil && trace.GotConn != nil {
+ trace.GotConn(httptrace.GotConnInfo{
+ Conn: netConn,
+ })
+ }
+ if err != nil {
+ return nil, nil, err
+ }
+
+ defer func() {
+ if netConn != nil {
+ netConn.Close()
+ }
+ }()
+
+ if u.Scheme == "https" {
+ cfg := cloneTLSConfig(d.TLSClientConfig)
+ if cfg.ServerName == "" {
+ cfg.ServerName = hostNoPort
+ }
+ tlsConn := tls.Client(netConn, cfg)
+ netConn = tlsConn
+
+ var err error
+ if trace != nil {
+ err = doHandshakeWithTrace(trace, tlsConn, cfg)
+ } else {
+ err = doHandshake(tlsConn, cfg)
+ }
+
+ if err != nil {
+ return nil, nil, err
+ }
+ }
+
+ conn := newConn(netConn, false, d.ReadBufferSize, d.WriteBufferSize, d.WriteBufferPool, nil, nil)
+
+ if err := req.Write(netConn); err != nil {
+ return nil, nil, err
+ }
+
+ if trace != nil && trace.GotFirstResponseByte != nil {
+ if peek, err := conn.br.Peek(1); err == nil && len(peek) == 1 {
+ trace.GotFirstResponseByte()
+ }
+ }
+
+ resp, err := http.ReadResponse(conn.br, req)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ if d.Jar != nil {
+ if rc := resp.Cookies(); len(rc) > 0 {
+ d.Jar.SetCookies(u, rc)
+ }
+ }
+
+ if resp.StatusCode != 101 ||
+ !strings.EqualFold(resp.Header.Get("Upgrade"), "websocket") ||
+ !strings.EqualFold(resp.Header.Get("Connection"), "upgrade") ||
+ resp.Header.Get("Sec-Websocket-Accept") != computeAcceptKey(challengeKey) {
+ // Before closing the network connection on return from this
+ // function, slurp up some of the response to aid application
+ // debugging.
+ buf := make([]byte, 1024)
+ n, _ := io.ReadFull(resp.Body, buf)
+ resp.Body = ioutil.NopCloser(bytes.NewReader(buf[:n]))
+ return nil, resp, ErrBadHandshake
+ }
+
+ for _, ext := range parseExtensions(resp.Header) {
+ if ext[""] != "permessage-deflate" {
+ continue
+ }
+ _, snct := ext["server_no_context_takeover"]
+ _, cnct := ext["client_no_context_takeover"]
+ if !snct || !cnct {
+ return nil, resp, errInvalidCompression
+ }
+ conn.newCompressionWriter = compressNoContextTakeover
+ conn.newDecompressionReader = decompressNoContextTakeover
+ break
+ }
+
+ resp.Body = ioutil.NopCloser(bytes.NewReader([]byte{}))
+ conn.subprotocol = resp.Header.Get("Sec-Websocket-Protocol")
+
+ netConn.SetDeadline(time.Time{})
+ netConn = nil // to avoid close in defer.
+ return conn, resp, nil
+}
+
+func doHandshake(tlsConn *tls.Conn, cfg *tls.Config) error {
+ if err := tlsConn.Handshake(); err != nil {
+ return err
+ }
+ if !cfg.InsecureSkipVerify {
+ if err := tlsConn.VerifyHostname(cfg.ServerName); err != nil {
+ return err
+ }
+ }
+ return nil
+}
diff --git a/vendor/github.com/gorilla/websocket/client_clone.go b/vendor/github.com/gorilla/websocket/client_clone.go
new file mode 100644
index 0000000..4f0d943
--- /dev/null
+++ b/vendor/github.com/gorilla/websocket/client_clone.go
@@ -0,0 +1,16 @@
+// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build go1.8
+
+package websocket
+
+import "crypto/tls"
+
+func cloneTLSConfig(cfg *tls.Config) *tls.Config {
+ if cfg == nil {
+ return &tls.Config{}
+ }
+ return cfg.Clone()
+}
diff --git a/vendor/github.com/gorilla/websocket/client_clone_legacy.go b/vendor/github.com/gorilla/websocket/client_clone_legacy.go
new file mode 100644
index 0000000..babb007
--- /dev/null
+++ b/vendor/github.com/gorilla/websocket/client_clone_legacy.go
@@ -0,0 +1,38 @@
+// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !go1.8
+
+package websocket
+
+import "crypto/tls"
+
+// cloneTLSConfig clones all public fields except the fields
+// SessionTicketsDisabled and SessionTicketKey. This avoids copying the
+// sync.Mutex in the sync.Once and makes it safe to call cloneTLSConfig on a
+// config in active use.
+func cloneTLSConfig(cfg *tls.Config) *tls.Config {
+ if cfg == nil {
+ return &tls.Config{}
+ }
+ return &tls.Config{
+ Rand: cfg.Rand,
+ Time: cfg.Time,
+ Certificates: cfg.Certificates,
+ NameToCertificate: cfg.NameToCertificate,
+ GetCertificate: cfg.GetCertificate,
+ RootCAs: cfg.RootCAs,
+ NextProtos: cfg.NextProtos,
+ ServerName: cfg.ServerName,
+ ClientAuth: cfg.ClientAuth,
+ ClientCAs: cfg.ClientCAs,
+ InsecureSkipVerify: cfg.InsecureSkipVerify,
+ CipherSuites: cfg.CipherSuites,
+ PreferServerCipherSuites: cfg.PreferServerCipherSuites,
+ ClientSessionCache: cfg.ClientSessionCache,
+ MinVersion: cfg.MinVersion,
+ MaxVersion: cfg.MaxVersion,
+ CurvePreferences: cfg.CurvePreferences,
+ }
+}
diff --git a/vendor/github.com/gorilla/websocket/compression.go b/vendor/github.com/gorilla/websocket/compression.go
new file mode 100644
index 0000000..813ffb1
--- /dev/null
+++ b/vendor/github.com/gorilla/websocket/compression.go
@@ -0,0 +1,148 @@
+// Copyright 2017 The Gorilla WebSocket Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package websocket
+
+import (
+ "compress/flate"
+ "errors"
+ "io"
+ "strings"
+ "sync"
+)
+
+const (
+ minCompressionLevel = -2 // flate.HuffmanOnly not defined in Go < 1.6
+ maxCompressionLevel = flate.BestCompression
+ defaultCompressionLevel = 1
+)
+
+var (
+ flateWriterPools [maxCompressionLevel - minCompressionLevel + 1]sync.Pool
+ flateReaderPool = sync.Pool{New: func() interface{} {
+ return flate.NewReader(nil)
+ }}
+)
+
+func decompressNoContextTakeover(r io.Reader) io.ReadCloser {
+ const tail =
+ // Add four bytes as specified in RFC
+ "\x00\x00\xff\xff" +
+ // Add final block to squelch unexpected EOF error from flate reader.
+ "\x01\x00\x00\xff\xff"
+
+ fr, _ := flateReaderPool.Get().(io.ReadCloser)
+ fr.(flate.Resetter).Reset(io.MultiReader(r, strings.NewReader(tail)), nil)
+ return &flateReadWrapper{fr}
+}
+
+func isValidCompressionLevel(level int) bool {
+ return minCompressionLevel <= level && level <= maxCompressionLevel
+}
+
+func compressNoContextTakeover(w io.WriteCloser, level int) io.WriteCloser {
+ p := &flateWriterPools[level-minCompressionLevel]
+ tw := &truncWriter{w: w}
+ fw, _ := p.Get().(*flate.Writer)
+ if fw == nil {
+ fw, _ = flate.NewWriter(tw, level)
+ } else {
+ fw.Reset(tw)
+ }
+ return &flateWriteWrapper{fw: fw, tw: tw, p: p}
+}
+
+// truncWriter is an io.Writer that writes all but the last four bytes of the
+// stream to another io.Writer.
+type truncWriter struct {
+ w io.WriteCloser
+ n int
+ p [4]byte
+}
+
+func (w *truncWriter) Write(p []byte) (int, error) {
+ n := 0
+
+ // fill buffer first for simplicity.
+ if w.n < len(w.p) {
+ n = copy(w.p[w.n:], p)
+ p = p[n:]
+ w.n += n
+ if len(p) == 0 {
+ return n, nil
+ }
+ }
+
+ m := len(p)
+ if m > len(w.p) {
+ m = len(w.p)
+ }
+
+ if nn, err := w.w.Write(w.p[:m]); err != nil {
+ return n + nn, err
+ }
+
+ copy(w.p[:], w.p[m:])
+ copy(w.p[len(w.p)-m:], p[len(p)-m:])
+ nn, err := w.w.Write(p[:len(p)-m])
+ return n + nn, err
+}
+
+type flateWriteWrapper struct {
+ fw *flate.Writer
+ tw *truncWriter
+ p *sync.Pool
+}
+
+func (w *flateWriteWrapper) Write(p []byte) (int, error) {
+ if w.fw == nil {
+ return 0, errWriteClosed
+ }
+ return w.fw.Write(p)
+}
+
+func (w *flateWriteWrapper) Close() error {
+ if w.fw == nil {
+ return errWriteClosed
+ }
+ err1 := w.fw.Flush()
+ w.p.Put(w.fw)
+ w.fw = nil
+ if w.tw.p != [4]byte{0, 0, 0xff, 0xff} {
+ return errors.New("websocket: internal error, unexpected bytes at end of flate stream")
+ }
+ err2 := w.tw.w.Close()
+ if err1 != nil {
+ return err1
+ }
+ return err2
+}
+
+type flateReadWrapper struct {
+ fr io.ReadCloser
+}
+
+func (r *flateReadWrapper) Read(p []byte) (int, error) {
+ if r.fr == nil {
+ return 0, io.ErrClosedPipe
+ }
+ n, err := r.fr.Read(p)
+ if err == io.EOF {
+ // Preemptively place the reader back in the pool. This helps with
+ // scenarios where the application does not call NextReader() soon after
+ // this final read.
+ r.Close()
+ }
+ return n, err
+}
+
+func (r *flateReadWrapper) Close() error {
+ if r.fr == nil {
+ return io.ErrClosedPipe
+ }
+ err := r.fr.Close()
+ flateReaderPool.Put(r.fr)
+ r.fr = nil
+ return err
+}
diff --git a/vendor/github.com/gorilla/websocket/conn.go b/vendor/github.com/gorilla/websocket/conn.go
new file mode 100644
index 0000000..d2a21c1
--- /dev/null
+++ b/vendor/github.com/gorilla/websocket/conn.go
@@ -0,0 +1,1165 @@
+// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package websocket
+
+import (
+ "bufio"
+ "encoding/binary"
+ "errors"
+ "io"
+ "io/ioutil"
+ "math/rand"
+ "net"
+ "strconv"
+ "sync"
+ "time"
+ "unicode/utf8"
+)
+
+const (
+ // Frame header byte 0 bits from Section 5.2 of RFC 6455
+ finalBit = 1 << 7
+ rsv1Bit = 1 << 6
+ rsv2Bit = 1 << 5
+ rsv3Bit = 1 << 4
+
+ // Frame header byte 1 bits from Section 5.2 of RFC 6455
+ maskBit = 1 << 7
+
+ maxFrameHeaderSize = 2 + 8 + 4 // Fixed header + length + mask
+ maxControlFramePayloadSize = 125
+
+ writeWait = time.Second
+
+ defaultReadBufferSize = 4096
+ defaultWriteBufferSize = 4096
+
+ continuationFrame = 0
+ noFrame = -1
+)
+
+// Close codes defined in RFC 6455, section 11.7.
+const (
+ CloseNormalClosure = 1000
+ CloseGoingAway = 1001
+ CloseProtocolError = 1002
+ CloseUnsupportedData = 1003
+ CloseNoStatusReceived = 1005
+ CloseAbnormalClosure = 1006
+ CloseInvalidFramePayloadData = 1007
+ ClosePolicyViolation = 1008
+ CloseMessageTooBig = 1009
+ CloseMandatoryExtension = 1010
+ CloseInternalServerErr = 1011
+ CloseServiceRestart = 1012
+ CloseTryAgainLater = 1013
+ CloseTLSHandshake = 1015
+)
+
+// The message types are defined in RFC 6455, section 11.8.
+const (
+ // TextMessage denotes a text data message. The text message payload is
+ // interpreted as UTF-8 encoded text data.
+ TextMessage = 1
+
+ // BinaryMessage denotes a binary data message.
+ BinaryMessage = 2
+
+ // CloseMessage denotes a close control message. The optional message
+ // payload contains a numeric code and text. Use the FormatCloseMessage
+ // function to format a close message payload.
+ CloseMessage = 8
+
+ // PingMessage denotes a ping control message. The optional message payload
+ // is UTF-8 encoded text.
+ PingMessage = 9
+
+ // PongMessage denotes a pong control message. The optional message payload
+ // is UTF-8 encoded text.
+ PongMessage = 10
+)
+
+// ErrCloseSent is returned when the application writes a message to the
+// connection after sending a close message.
+var ErrCloseSent = errors.New("websocket: close sent")
+
+// ErrReadLimit is returned when reading a message that is larger than the
+// read limit set for the connection.
+var ErrReadLimit = errors.New("websocket: read limit exceeded")
+
+// netError satisfies the net Error interface.
+type netError struct {
+ msg string
+ temporary bool
+ timeout bool
+}
+
+func (e *netError) Error() string { return e.msg }
+func (e *netError) Temporary() bool { return e.temporary }
+func (e *netError) Timeout() bool { return e.timeout }
+
+// CloseError represents a close message.
+type CloseError struct {
+ // Code is defined in RFC 6455, section 11.7.
+ Code int
+
+ // Text is the optional text payload.
+ Text string
+}
+
+func (e *CloseError) Error() string {
+ s := []byte("websocket: close ")
+ s = strconv.AppendInt(s, int64(e.Code), 10)
+ switch e.Code {
+ case CloseNormalClosure:
+ s = append(s, " (normal)"...)
+ case CloseGoingAway:
+ s = append(s, " (going away)"...)
+ case CloseProtocolError:
+ s = append(s, " (protocol error)"...)
+ case CloseUnsupportedData:
+ s = append(s, " (unsupported data)"...)
+ case CloseNoStatusReceived:
+ s = append(s, " (no status)"...)
+ case CloseAbnormalClosure:
+ s = append(s, " (abnormal closure)"...)
+ case CloseInvalidFramePayloadData:
+ s = append(s, " (invalid payload data)"...)
+ case ClosePolicyViolation:
+ s = append(s, " (policy violation)"...)
+ case CloseMessageTooBig:
+ s = append(s, " (message too big)"...)
+ case CloseMandatoryExtension:
+ s = append(s, " (mandatory extension missing)"...)
+ case CloseInternalServerErr:
+ s = append(s, " (internal server error)"...)
+ case CloseTLSHandshake:
+ s = append(s, " (TLS handshake error)"...)
+ }
+ if e.Text != "" {
+ s = append(s, ": "...)
+ s = append(s, e.Text...)
+ }
+ return string(s)
+}
+
+// IsCloseError returns boolean indicating whether the error is a *CloseError
+// with one of the specified codes.
+func IsCloseError(err error, codes ...int) bool {
+ if e, ok := err.(*CloseError); ok {
+ for _, code := range codes {
+ if e.Code == code {
+ return true
+ }
+ }
+ }
+ return false
+}
+
+// IsUnexpectedCloseError returns boolean indicating whether the error is a
+// *CloseError with a code not in the list of expected codes.
+func IsUnexpectedCloseError(err error, expectedCodes ...int) bool {
+ if e, ok := err.(*CloseError); ok {
+ for _, code := range expectedCodes {
+ if e.Code == code {
+ return false
+ }
+ }
+ return true
+ }
+ return false
+}
+
+var (
+ errWriteTimeout = &netError{msg: "websocket: write timeout", timeout: true, temporary: true}
+ errUnexpectedEOF = &CloseError{Code: CloseAbnormalClosure, Text: io.ErrUnexpectedEOF.Error()}
+ errBadWriteOpCode = errors.New("websocket: bad write message type")
+ errWriteClosed = errors.New("websocket: write closed")
+ errInvalidControlFrame = errors.New("websocket: invalid control frame")
+)
+
+func newMaskKey() [4]byte {
+ n := rand.Uint32()
+ return [4]byte{byte(n), byte(n >> 8), byte(n >> 16), byte(n >> 24)}
+}
+
+func hideTempErr(err error) error {
+ if e, ok := err.(net.Error); ok && e.Temporary() {
+ err = &netError{msg: e.Error(), timeout: e.Timeout()}
+ }
+ return err
+}
+
+func isControl(frameType int) bool {
+ return frameType == CloseMessage || frameType == PingMessage || frameType == PongMessage
+}
+
+func isData(frameType int) bool {
+ return frameType == TextMessage || frameType == BinaryMessage
+}
+
+var validReceivedCloseCodes = map[int]bool{
+ // see http://www.iana.org/assignments/websocket/websocket.xhtml#close-code-number
+
+ CloseNormalClosure: true,
+ CloseGoingAway: true,
+ CloseProtocolError: true,
+ CloseUnsupportedData: true,
+ CloseNoStatusReceived: false,
+ CloseAbnormalClosure: false,
+ CloseInvalidFramePayloadData: true,
+ ClosePolicyViolation: true,
+ CloseMessageTooBig: true,
+ CloseMandatoryExtension: true,
+ CloseInternalServerErr: true,
+ CloseServiceRestart: true,
+ CloseTryAgainLater: true,
+ CloseTLSHandshake: false,
+}
+
+func isValidReceivedCloseCode(code int) bool {
+ return validReceivedCloseCodes[code] || (code >= 3000 && code <= 4999)
+}
+
+// BufferPool represents a pool of buffers. The *sync.Pool type satisfies this
+// interface. The type of the value stored in a pool is not specified.
+type BufferPool interface {
+ // Get gets a value from the pool or returns nil if the pool is empty.
+ Get() interface{}
+ // Put adds a value to the pool.
+ Put(interface{})
+}
+
+// writePoolData is the type added to the write buffer pool. This wrapper is
+// used to prevent applications from peeking at and depending on the values
+// added to the pool.
+type writePoolData struct{ buf []byte }
+
+// The Conn type represents a WebSocket connection.
+type Conn struct {
+ conn net.Conn
+ isServer bool
+ subprotocol string
+
+ // Write fields
+ mu chan bool // used as mutex to protect write to conn
+ writeBuf []byte // frame is constructed in this buffer.
+ writePool BufferPool
+ writeBufSize int
+ writeDeadline time.Time
+ writer io.WriteCloser // the current writer returned to the application
+ isWriting bool // for best-effort concurrent write detection
+
+ writeErrMu sync.Mutex
+ writeErr error
+
+ enableWriteCompression bool
+ compressionLevel int
+ newCompressionWriter func(io.WriteCloser, int) io.WriteCloser
+
+ // Read fields
+ reader io.ReadCloser // the current reader returned to the application
+ readErr error
+ br *bufio.Reader
+ readRemaining int64 // bytes remaining in current frame.
+ readFinal bool // true the current message has more frames.
+ readLength int64 // Message size.
+ readLimit int64 // Maximum message size.
+ readMaskPos int
+ readMaskKey [4]byte
+ handlePong func(string) error
+ handlePing func(string) error
+ handleClose func(int, string) error
+ readErrCount int
+ messageReader *messageReader // the current low-level reader
+
+ readDecompress bool // whether last read frame had RSV1 set
+ newDecompressionReader func(io.Reader) io.ReadCloser
+}
+
+func newConn(conn net.Conn, isServer bool, readBufferSize, writeBufferSize int, writeBufferPool BufferPool, br *bufio.Reader, writeBuf []byte) *Conn {
+
+ if br == nil {
+ if readBufferSize == 0 {
+ readBufferSize = defaultReadBufferSize
+ } else if readBufferSize < maxControlFramePayloadSize {
+ // must be large enough for control frame
+ readBufferSize = maxControlFramePayloadSize
+ }
+ br = bufio.NewReaderSize(conn, readBufferSize)
+ }
+
+ if writeBufferSize <= 0 {
+ writeBufferSize = defaultWriteBufferSize
+ }
+ writeBufferSize += maxFrameHeaderSize
+
+ if writeBuf == nil && writeBufferPool == nil {
+ writeBuf = make([]byte, writeBufferSize)
+ }
+
+ mu := make(chan bool, 1)
+ mu <- true
+ c := &Conn{
+ isServer: isServer,
+ br: br,
+ conn: conn,
+ mu: mu,
+ readFinal: true,
+ writeBuf: writeBuf,
+ writePool: writeBufferPool,
+ writeBufSize: writeBufferSize,
+ enableWriteCompression: true,
+ compressionLevel: defaultCompressionLevel,
+ }
+ c.SetCloseHandler(nil)
+ c.SetPingHandler(nil)
+ c.SetPongHandler(nil)
+ return c
+}
+
+// Subprotocol returns the negotiated protocol for the connection.
+func (c *Conn) Subprotocol() string {
+ return c.subprotocol
+}
+
+// Close closes the underlying network connection without sending or waiting
+// for a close message.
+func (c *Conn) Close() error {
+ return c.conn.Close()
+}
+
+// LocalAddr returns the local network address.
+func (c *Conn) LocalAddr() net.Addr {
+ return c.conn.LocalAddr()
+}
+
+// RemoteAddr returns the remote network address.
+func (c *Conn) RemoteAddr() net.Addr {
+ return c.conn.RemoteAddr()
+}
+
+// Write methods
+
+func (c *Conn) writeFatal(err error) error {
+ err = hideTempErr(err)
+ c.writeErrMu.Lock()
+ if c.writeErr == nil {
+ c.writeErr = err
+ }
+ c.writeErrMu.Unlock()
+ return err
+}
+
+func (c *Conn) read(n int) ([]byte, error) {
+ p, err := c.br.Peek(n)
+ if err == io.EOF {
+ err = errUnexpectedEOF
+ }
+ c.br.Discard(len(p))
+ return p, err
+}
+
+func (c *Conn) write(frameType int, deadline time.Time, buf0, buf1 []byte) error {
+ <-c.mu
+ defer func() { c.mu <- true }()
+
+ c.writeErrMu.Lock()
+ err := c.writeErr
+ c.writeErrMu.Unlock()
+ if err != nil {
+ return err
+ }
+
+ c.conn.SetWriteDeadline(deadline)
+ if len(buf1) == 0 {
+ _, err = c.conn.Write(buf0)
+ } else {
+ err = c.writeBufs(buf0, buf1)
+ }
+ if err != nil {
+ return c.writeFatal(err)
+ }
+ if frameType == CloseMessage {
+ c.writeFatal(ErrCloseSent)
+ }
+ return nil
+}
+
+// WriteControl writes a control message with the given deadline. The allowed
+// message types are CloseMessage, PingMessage and PongMessage.
+func (c *Conn) WriteControl(messageType int, data []byte, deadline time.Time) error {
+ if !isControl(messageType) {
+ return errBadWriteOpCode
+ }
+ if len(data) > maxControlFramePayloadSize {
+ return errInvalidControlFrame
+ }
+
+ b0 := byte(messageType) | finalBit
+ b1 := byte(len(data))
+ if !c.isServer {
+ b1 |= maskBit
+ }
+
+ buf := make([]byte, 0, maxFrameHeaderSize+maxControlFramePayloadSize)
+ buf = append(buf, b0, b1)
+
+ if c.isServer {
+ buf = append(buf, data...)
+ } else {
+ key := newMaskKey()
+ buf = append(buf, key[:]...)
+ buf = append(buf, data...)
+ maskBytes(key, 0, buf[6:])
+ }
+
+ d := time.Hour * 1000
+ if !deadline.IsZero() {
+ d = deadline.Sub(time.Now())
+ if d < 0 {
+ return errWriteTimeout
+ }
+ }
+
+ timer := time.NewTimer(d)
+ select {
+ case <-c.mu:
+ timer.Stop()
+ case <-timer.C:
+ return errWriteTimeout
+ }
+ defer func() { c.mu <- true }()
+
+ c.writeErrMu.Lock()
+ err := c.writeErr
+ c.writeErrMu.Unlock()
+ if err != nil {
+ return err
+ }
+
+ c.conn.SetWriteDeadline(deadline)
+ _, err = c.conn.Write(buf)
+ if err != nil {
+ return c.writeFatal(err)
+ }
+ if messageType == CloseMessage {
+ c.writeFatal(ErrCloseSent)
+ }
+ return err
+}
+
+func (c *Conn) prepWrite(messageType int) error {
+ // Close previous writer if not already closed by the application. It's
+ // probably better to return an error in this situation, but we cannot
+ // change this without breaking existing applications.
+ if c.writer != nil {
+ c.writer.Close()
+ c.writer = nil
+ }
+
+ if !isControl(messageType) && !isData(messageType) {
+ return errBadWriteOpCode
+ }
+
+ c.writeErrMu.Lock()
+ err := c.writeErr
+ c.writeErrMu.Unlock()
+ if err != nil {
+ return err
+ }
+
+ if c.writeBuf == nil {
+ wpd, ok := c.writePool.Get().(writePoolData)
+ if ok {
+ c.writeBuf = wpd.buf
+ } else {
+ c.writeBuf = make([]byte, c.writeBufSize)
+ }
+ }
+ return nil
+}
+
+// NextWriter returns a writer for the next message to send. The writer's Close
+// method flushes the complete message to the network.
+//
+// There can be at most one open writer on a connection. NextWriter closes the
+// previous writer if the application has not already done so.
+//
+// All message types (TextMessage, BinaryMessage, CloseMessage, PingMessage and
+// PongMessage) are supported.
+func (c *Conn) NextWriter(messageType int) (io.WriteCloser, error) {
+ if err := c.prepWrite(messageType); err != nil {
+ return nil, err
+ }
+
+ mw := &messageWriter{
+ c: c,
+ frameType: messageType,
+ pos: maxFrameHeaderSize,
+ }
+ c.writer = mw
+ if c.newCompressionWriter != nil && c.enableWriteCompression && isData(messageType) {
+ w := c.newCompressionWriter(c.writer, c.compressionLevel)
+ mw.compress = true
+ c.writer = w
+ }
+ return c.writer, nil
+}
+
+type messageWriter struct {
+ c *Conn
+ compress bool // whether next call to flushFrame should set RSV1
+ pos int // end of data in writeBuf.
+ frameType int // type of the current frame.
+ err error
+}
+
+func (w *messageWriter) fatal(err error) error {
+ if w.err != nil {
+ w.err = err
+ w.c.writer = nil
+ }
+ return err
+}
+
+// flushFrame writes buffered data and extra as a frame to the network. The
+// final argument indicates that this is the last frame in the message.
+func (w *messageWriter) flushFrame(final bool, extra []byte) error {
+ c := w.c
+ length := w.pos - maxFrameHeaderSize + len(extra)
+
+ // Check for invalid control frames.
+ if isControl(w.frameType) &&
+ (!final || length > maxControlFramePayloadSize) {
+ return w.fatal(errInvalidControlFrame)
+ }
+
+ b0 := byte(w.frameType)
+ if final {
+ b0 |= finalBit
+ }
+ if w.compress {
+ b0 |= rsv1Bit
+ }
+ w.compress = false
+
+ b1 := byte(0)
+ if !c.isServer {
+ b1 |= maskBit
+ }
+
+ // Assume that the frame starts at beginning of c.writeBuf.
+ framePos := 0
+ if c.isServer {
+ // Adjust up if mask not included in the header.
+ framePos = 4
+ }
+
+ switch {
+ case length >= 65536:
+ c.writeBuf[framePos] = b0
+ c.writeBuf[framePos+1] = b1 | 127
+ binary.BigEndian.PutUint64(c.writeBuf[framePos+2:], uint64(length))
+ case length > 125:
+ framePos += 6
+ c.writeBuf[framePos] = b0
+ c.writeBuf[framePos+1] = b1 | 126
+ binary.BigEndian.PutUint16(c.writeBuf[framePos+2:], uint16(length))
+ default:
+ framePos += 8
+ c.writeBuf[framePos] = b0
+ c.writeBuf[framePos+1] = b1 | byte(length)
+ }
+
+ if !c.isServer {
+ key := newMaskKey()
+ copy(c.writeBuf[maxFrameHeaderSize-4:], key[:])
+ maskBytes(key, 0, c.writeBuf[maxFrameHeaderSize:w.pos])
+ if len(extra) > 0 {
+ return c.writeFatal(errors.New("websocket: internal error, extra used in client mode"))
+ }
+ }
+
+ // Write the buffers to the connection with best-effort detection of
+ // concurrent writes. See the concurrency section in the package
+ // documentation for more info.
+
+ if c.isWriting {
+ panic("concurrent write to websocket connection")
+ }
+ c.isWriting = true
+
+ err := c.write(w.frameType, c.writeDeadline, c.writeBuf[framePos:w.pos], extra)
+
+ if !c.isWriting {
+ panic("concurrent write to websocket connection")
+ }
+ c.isWriting = false
+
+ if err != nil {
+ return w.fatal(err)
+ }
+
+ if final {
+ c.writer = nil
+ if c.writePool != nil {
+ c.writePool.Put(writePoolData{buf: c.writeBuf})
+ c.writeBuf = nil
+ }
+ return nil
+ }
+
+ // Setup for next frame.
+ w.pos = maxFrameHeaderSize
+ w.frameType = continuationFrame
+ return nil
+}
+
+func (w *messageWriter) ncopy(max int) (int, error) {
+ n := len(w.c.writeBuf) - w.pos
+ if n <= 0 {
+ if err := w.flushFrame(false, nil); err != nil {
+ return 0, err
+ }
+ n = len(w.c.writeBuf) - w.pos
+ }
+ if n > max {
+ n = max
+ }
+ return n, nil
+}
+
+func (w *messageWriter) Write(p []byte) (int, error) {
+ if w.err != nil {
+ return 0, w.err
+ }
+
+ if len(p) > 2*len(w.c.writeBuf) && w.c.isServer {
+ // Don't buffer large messages.
+ err := w.flushFrame(false, p)
+ if err != nil {
+ return 0, err
+ }
+ return len(p), nil
+ }
+
+ nn := len(p)
+ for len(p) > 0 {
+ n, err := w.ncopy(len(p))
+ if err != nil {
+ return 0, err
+ }
+ copy(w.c.writeBuf[w.pos:], p[:n])
+ w.pos += n
+ p = p[n:]
+ }
+ return nn, nil
+}
+
+func (w *messageWriter) WriteString(p string) (int, error) {
+ if w.err != nil {
+ return 0, w.err
+ }
+
+ nn := len(p)
+ for len(p) > 0 {
+ n, err := w.ncopy(len(p))
+ if err != nil {
+ return 0, err
+ }
+ copy(w.c.writeBuf[w.pos:], p[:n])
+ w.pos += n
+ p = p[n:]
+ }
+ return nn, nil
+}
+
+func (w *messageWriter) ReadFrom(r io.Reader) (nn int64, err error) {
+ if w.err != nil {
+ return 0, w.err
+ }
+ for {
+ if w.pos == len(w.c.writeBuf) {
+ err = w.flushFrame(false, nil)
+ if err != nil {
+ break
+ }
+ }
+ var n int
+ n, err = r.Read(w.c.writeBuf[w.pos:])
+ w.pos += n
+ nn += int64(n)
+ if err != nil {
+ if err == io.EOF {
+ err = nil
+ }
+ break
+ }
+ }
+ return nn, err
+}
+
+func (w *messageWriter) Close() error {
+ if w.err != nil {
+ return w.err
+ }
+ if err := w.flushFrame(true, nil); err != nil {
+ return err
+ }
+ w.err = errWriteClosed
+ return nil
+}
+
+// WritePreparedMessage writes prepared message into connection.
+func (c *Conn) WritePreparedMessage(pm *PreparedMessage) error {
+ frameType, frameData, err := pm.frame(prepareKey{
+ isServer: c.isServer,
+ compress: c.newCompressionWriter != nil && c.enableWriteCompression && isData(pm.messageType),
+ compressionLevel: c.compressionLevel,
+ })
+ if err != nil {
+ return err
+ }
+ if c.isWriting {
+ panic("concurrent write to websocket connection")
+ }
+ c.isWriting = true
+ err = c.write(frameType, c.writeDeadline, frameData, nil)
+ if !c.isWriting {
+ panic("concurrent write to websocket connection")
+ }
+ c.isWriting = false
+ return err
+}
+
+// WriteMessage is a helper method for getting a writer using NextWriter,
+// writing the message and closing the writer.
+func (c *Conn) WriteMessage(messageType int, data []byte) error {
+
+ if c.isServer && (c.newCompressionWriter == nil || !c.enableWriteCompression) {
+ // Fast path with no allocations and single frame.
+
+ if err := c.prepWrite(messageType); err != nil {
+ return err
+ }
+ mw := messageWriter{c: c, frameType: messageType, pos: maxFrameHeaderSize}
+ n := copy(c.writeBuf[mw.pos:], data)
+ mw.pos += n
+ data = data[n:]
+ return mw.flushFrame(true, data)
+ }
+
+ w, err := c.NextWriter(messageType)
+ if err != nil {
+ return err
+ }
+ if _, err = w.Write(data); err != nil {
+ return err
+ }
+ return w.Close()
+}
+
+// SetWriteDeadline sets the write deadline on the underlying network
+// connection. After a write has timed out, the websocket state is corrupt and
+// all future writes will return an error. A zero value for t means writes will
+// not time out.
+func (c *Conn) SetWriteDeadline(t time.Time) error {
+ c.writeDeadline = t
+ return nil
+}
+
+// Read methods
+
+func (c *Conn) advanceFrame() (int, error) {
+ // 1. Skip remainder of previous frame.
+
+ if c.readRemaining > 0 {
+ if _, err := io.CopyN(ioutil.Discard, c.br, c.readRemaining); err != nil {
+ return noFrame, err
+ }
+ }
+
+ // 2. Read and parse first two bytes of frame header.
+
+ p, err := c.read(2)
+ if err != nil {
+ return noFrame, err
+ }
+
+ final := p[0]&finalBit != 0
+ frameType := int(p[0] & 0xf)
+ mask := p[1]&maskBit != 0
+ c.readRemaining = int64(p[1] & 0x7f)
+
+ c.readDecompress = false
+ if c.newDecompressionReader != nil && (p[0]&rsv1Bit) != 0 {
+ c.readDecompress = true
+ p[0] &^= rsv1Bit
+ }
+
+ if rsv := p[0] & (rsv1Bit | rsv2Bit | rsv3Bit); rsv != 0 {
+ return noFrame, c.handleProtocolError("unexpected reserved bits 0x" + strconv.FormatInt(int64(rsv), 16))
+ }
+
+ switch frameType {
+ case CloseMessage, PingMessage, PongMessage:
+ if c.readRemaining > maxControlFramePayloadSize {
+ return noFrame, c.handleProtocolError("control frame length > 125")
+ }
+ if !final {
+ return noFrame, c.handleProtocolError("control frame not final")
+ }
+ case TextMessage, BinaryMessage:
+ if !c.readFinal {
+ return noFrame, c.handleProtocolError("message start before final message frame")
+ }
+ c.readFinal = final
+ case continuationFrame:
+ if c.readFinal {
+ return noFrame, c.handleProtocolError("continuation after final message frame")
+ }
+ c.readFinal = final
+ default:
+ return noFrame, c.handleProtocolError("unknown opcode " + strconv.Itoa(frameType))
+ }
+
+ // 3. Read and parse frame length.
+
+ switch c.readRemaining {
+ case 126:
+ p, err := c.read(2)
+ if err != nil {
+ return noFrame, err
+ }
+ c.readRemaining = int64(binary.BigEndian.Uint16(p))
+ case 127:
+ p, err := c.read(8)
+ if err != nil {
+ return noFrame, err
+ }
+ c.readRemaining = int64(binary.BigEndian.Uint64(p))
+ }
+
+ // 4. Handle frame masking.
+
+ if mask != c.isServer {
+ return noFrame, c.handleProtocolError("incorrect mask flag")
+ }
+
+ if mask {
+ c.readMaskPos = 0
+ p, err := c.read(len(c.readMaskKey))
+ if err != nil {
+ return noFrame, err
+ }
+ copy(c.readMaskKey[:], p)
+ }
+
+ // 5. For text and binary messages, enforce read limit and return.
+
+ if frameType == continuationFrame || frameType == TextMessage || frameType == BinaryMessage {
+
+ c.readLength += c.readRemaining
+ if c.readLimit > 0 && c.readLength > c.readLimit {
+ c.WriteControl(CloseMessage, FormatCloseMessage(CloseMessageTooBig, ""), time.Now().Add(writeWait))
+ return noFrame, ErrReadLimit
+ }
+
+ return frameType, nil
+ }
+
+ // 6. Read control frame payload.
+
+ var payload []byte
+ if c.readRemaining > 0 {
+ payload, err = c.read(int(c.readRemaining))
+ c.readRemaining = 0
+ if err != nil {
+ return noFrame, err
+ }
+ if c.isServer {
+ maskBytes(c.readMaskKey, 0, payload)
+ }
+ }
+
+ // 7. Process control frame payload.
+
+ switch frameType {
+ case PongMessage:
+ if err := c.handlePong(string(payload)); err != nil {
+ return noFrame, err
+ }
+ case PingMessage:
+ if err := c.handlePing(string(payload)); err != nil {
+ return noFrame, err
+ }
+ case CloseMessage:
+ closeCode := CloseNoStatusReceived
+ closeText := ""
+ if len(payload) >= 2 {
+ closeCode = int(binary.BigEndian.Uint16(payload))
+ if !isValidReceivedCloseCode(closeCode) {
+ return noFrame, c.handleProtocolError("invalid close code")
+ }
+ closeText = string(payload[2:])
+ if !utf8.ValidString(closeText) {
+ return noFrame, c.handleProtocolError("invalid utf8 payload in close frame")
+ }
+ }
+ if err := c.handleClose(closeCode, closeText); err != nil {
+ return noFrame, err
+ }
+ return noFrame, &CloseError{Code: closeCode, Text: closeText}
+ }
+
+ return frameType, nil
+}
+
+func (c *Conn) handleProtocolError(message string) error {
+ c.WriteControl(CloseMessage, FormatCloseMessage(CloseProtocolError, message), time.Now().Add(writeWait))
+ return errors.New("websocket: " + message)
+}
+
+// NextReader returns the next data message received from the peer. The
+// returned messageType is either TextMessage or BinaryMessage.
+//
+// There can be at most one open reader on a connection. NextReader discards
+// the previous message if the application has not already consumed it.
+//
+// Applications must break out of the application's read loop when this method
+// returns a non-nil error value. Errors returned from this method are
+// permanent. Once this method returns a non-nil error, all subsequent calls to
+// this method return the same error.
+func (c *Conn) NextReader() (messageType int, r io.Reader, err error) {
+ // Close previous reader, only relevant for decompression.
+ if c.reader != nil {
+ c.reader.Close()
+ c.reader = nil
+ }
+
+ c.messageReader = nil
+ c.readLength = 0
+
+ for c.readErr == nil {
+ frameType, err := c.advanceFrame()
+ if err != nil {
+ c.readErr = hideTempErr(err)
+ break
+ }
+ if frameType == TextMessage || frameType == BinaryMessage {
+ c.messageReader = &messageReader{c}
+ c.reader = c.messageReader
+ if c.readDecompress {
+ c.reader = c.newDecompressionReader(c.reader)
+ }
+ return frameType, c.reader, nil
+ }
+ }
+
+ // Applications that do handle the error returned from this method spin in
+ // tight loop on connection failure. To help application developers detect
+ // this error, panic on repeated reads to the failed connection.
+ c.readErrCount++
+ if c.readErrCount >= 1000 {
+ panic("repeated read on failed websocket connection")
+ }
+
+ return noFrame, nil, c.readErr
+}
+
+type messageReader struct{ c *Conn }
+
+func (r *messageReader) Read(b []byte) (int, error) {
+ c := r.c
+ if c.messageReader != r {
+ return 0, io.EOF
+ }
+
+ for c.readErr == nil {
+
+ if c.readRemaining > 0 {
+ if int64(len(b)) > c.readRemaining {
+ b = b[:c.readRemaining]
+ }
+ n, err := c.br.Read(b)
+ c.readErr = hideTempErr(err)
+ if c.isServer {
+ c.readMaskPos = maskBytes(c.readMaskKey, c.readMaskPos, b[:n])
+ }
+ c.readRemaining -= int64(n)
+ if c.readRemaining > 0 && c.readErr == io.EOF {
+ c.readErr = errUnexpectedEOF
+ }
+ return n, c.readErr
+ }
+
+ if c.readFinal {
+ c.messageReader = nil
+ return 0, io.EOF
+ }
+
+ frameType, err := c.advanceFrame()
+ switch {
+ case err != nil:
+ c.readErr = hideTempErr(err)
+ case frameType == TextMessage || frameType == BinaryMessage:
+ c.readErr = errors.New("websocket: internal error, unexpected text or binary in Reader")
+ }
+ }
+
+ err := c.readErr
+ if err == io.EOF && c.messageReader == r {
+ err = errUnexpectedEOF
+ }
+ return 0, err
+}
+
+func (r *messageReader) Close() error {
+ return nil
+}
+
+// ReadMessage is a helper method for getting a reader using NextReader and
+// reading from that reader to a buffer.
+func (c *Conn) ReadMessage() (messageType int, p []byte, err error) {
+ var r io.Reader
+ messageType, r, err = c.NextReader()
+ if err != nil {
+ return messageType, nil, err
+ }
+ p, err = ioutil.ReadAll(r)
+ return messageType, p, err
+}
+
+// SetReadDeadline sets the read deadline on the underlying network connection.
+// After a read has timed out, the websocket connection state is corrupt and
+// all future reads will return an error. A zero value for t means reads will
+// not time out.
+func (c *Conn) SetReadDeadline(t time.Time) error {
+ return c.conn.SetReadDeadline(t)
+}
+
+// SetReadLimit sets the maximum size for a message read from the peer. If a
+// message exceeds the limit, the connection sends a close message to the peer
+// and returns ErrReadLimit to the application.
+func (c *Conn) SetReadLimit(limit int64) {
+ c.readLimit = limit
+}
+
+// CloseHandler returns the current close handler
+func (c *Conn) CloseHandler() func(code int, text string) error {
+ return c.handleClose
+}
+
+// SetCloseHandler sets the handler for close messages received from the peer.
+// The code argument to h is the received close code or CloseNoStatusReceived
+// if the close message is empty. The default close handler sends a close
+// message back to the peer.
+//
+// The handler function is called from the NextReader, ReadMessage and message
+// reader Read methods. The application must read the connection to process
+// close messages as described in the section on Control Messages above.
+//
+// The connection read methods return a CloseError when a close message is
+// received. Most applications should handle close messages as part of their
+// normal error handling. Applications should only set a close handler when the
+// application must perform some action before sending a close message back to
+// the peer.
+func (c *Conn) SetCloseHandler(h func(code int, text string) error) {
+ if h == nil {
+ h = func(code int, text string) error {
+ message := FormatCloseMessage(code, "")
+ c.WriteControl(CloseMessage, message, time.Now().Add(writeWait))
+ return nil
+ }
+ }
+ c.handleClose = h
+}
+
+// PingHandler returns the current ping handler
+func (c *Conn) PingHandler() func(appData string) error {
+ return c.handlePing
+}
+
+// SetPingHandler sets the handler for ping messages received from the peer.
+// The appData argument to h is the PING message application data. The default
+// ping handler sends a pong to the peer.
+//
+// The handler function is called from the NextReader, ReadMessage and message
+// reader Read methods. The application must read the connection to process
+// ping messages as described in the section on Control Messages above.
+func (c *Conn) SetPingHandler(h func(appData string) error) {
+ if h == nil {
+ h = func(message string) error {
+ err := c.WriteControl(PongMessage, []byte(message), time.Now().Add(writeWait))
+ if err == ErrCloseSent {
+ return nil
+ } else if e, ok := err.(net.Error); ok && e.Temporary() {
+ return nil
+ }
+ return err
+ }
+ }
+ c.handlePing = h
+}
+
+// PongHandler returns the current pong handler
+func (c *Conn) PongHandler() func(appData string) error {
+ return c.handlePong
+}
+
+// SetPongHandler sets the handler for pong messages received from the peer.
+// The appData argument to h is the PONG message application data. The default
+// pong handler does nothing.
+//
+// The handler function is called from the NextReader, ReadMessage and message
+// reader Read methods. The application must read the connection to process
+// pong messages as described in the section on Control Messages above.
+func (c *Conn) SetPongHandler(h func(appData string) error) {
+ if h == nil {
+ h = func(string) error { return nil }
+ }
+ c.handlePong = h
+}
+
+// UnderlyingConn returns the internal net.Conn. This can be used to further
+// modifications to connection specific flags.
+func (c *Conn) UnderlyingConn() net.Conn {
+ return c.conn
+}
+
+// EnableWriteCompression enables and disables write compression of
+// subsequent text and binary messages. This function is a noop if
+// compression was not negotiated with the peer.
+func (c *Conn) EnableWriteCompression(enable bool) {
+ c.enableWriteCompression = enable
+}
+
+// SetCompressionLevel sets the flate compression level for subsequent text and
+// binary messages. This function is a noop if compression was not negotiated
+// with the peer. See the compress/flate package for a description of
+// compression levels.
+func (c *Conn) SetCompressionLevel(level int) error {
+ if !isValidCompressionLevel(level) {
+ return errors.New("websocket: invalid compression level")
+ }
+ c.compressionLevel = level
+ return nil
+}
+
+// FormatCloseMessage formats closeCode and text as a WebSocket close message.
+// An empty message is returned for code CloseNoStatusReceived.
+func FormatCloseMessage(closeCode int, text string) []byte {
+ if closeCode == CloseNoStatusReceived {
+ // Return empty message because it's illegal to send
+ // CloseNoStatusReceived. Return non-nil value in case application
+ // checks for nil.
+ return []byte{}
+ }
+ buf := make([]byte, 2+len(text))
+ binary.BigEndian.PutUint16(buf, uint16(closeCode))
+ copy(buf[2:], text)
+ return buf
+}
diff --git a/vendor/github.com/gorilla/websocket/conn_write.go b/vendor/github.com/gorilla/websocket/conn_write.go
new file mode 100644
index 0000000..a509a21
--- /dev/null
+++ b/vendor/github.com/gorilla/websocket/conn_write.go
@@ -0,0 +1,15 @@
+// Copyright 2016 The Gorilla WebSocket Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build go1.8
+
+package websocket
+
+import "net"
+
+func (c *Conn) writeBufs(bufs ...[]byte) error {
+ b := net.Buffers(bufs)
+ _, err := b.WriteTo(c.conn)
+ return err
+}
diff --git a/vendor/github.com/gorilla/websocket/conn_write_legacy.go b/vendor/github.com/gorilla/websocket/conn_write_legacy.go
new file mode 100644
index 0000000..37edaff
--- /dev/null
+++ b/vendor/github.com/gorilla/websocket/conn_write_legacy.go
@@ -0,0 +1,18 @@
+// Copyright 2016 The Gorilla WebSocket Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !go1.8
+
+package websocket
+
+func (c *Conn) writeBufs(bufs ...[]byte) error {
+ for _, buf := range bufs {
+ if len(buf) > 0 {
+ if _, err := c.conn.Write(buf); err != nil {
+ return err
+ }
+ }
+ }
+ return nil
+}
diff --git a/vendor/github.com/gorilla/websocket/doc.go b/vendor/github.com/gorilla/websocket/doc.go
new file mode 100644
index 0000000..dcce1a6
--- /dev/null
+++ b/vendor/github.com/gorilla/websocket/doc.go
@@ -0,0 +1,180 @@
+// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package websocket implements the WebSocket protocol defined in RFC 6455.
+//
+// Overview
+//
+// The Conn type represents a WebSocket connection. A server application calls
+// the Upgrader.Upgrade method from an HTTP request handler to get a *Conn:
+//
+// var upgrader = websocket.Upgrader{
+// ReadBufferSize: 1024,
+// WriteBufferSize: 1024,
+// }
+//
+// func handler(w http.ResponseWriter, r *http.Request) {
+// conn, err := upgrader.Upgrade(w, r, nil)
+// if err != nil {
+// log.Println(err)
+// return
+// }
+// ... Use conn to send and receive messages.
+// }
+//
+// Call the connection's WriteMessage and ReadMessage methods to send and
+// receive messages as a slice of bytes. This snippet of code shows how to echo
+// messages using these methods:
+//
+// for {
+// messageType, p, err := conn.ReadMessage()
+// if err != nil {
+// log.Println(err)
+// return
+// }
+// if err := conn.WriteMessage(messageType, p); err != nil {
+// log.Println(err)
+// return
+// }
+// }
+//
+// In above snippet of code, p is a []byte and messageType is an int with value
+// websocket.BinaryMessage or websocket.TextMessage.
+//
+// An application can also send and receive messages using the io.WriteCloser
+// and io.Reader interfaces. To send a message, call the connection NextWriter
+// method to get an io.WriteCloser, write the message to the writer and close
+// the writer when done. To receive a message, call the connection NextReader
+// method to get an io.Reader and read until io.EOF is returned. This snippet
+// shows how to echo messages using the NextWriter and NextReader methods:
+//
+// for {
+// messageType, r, err := conn.NextReader()
+// if err != nil {
+// return
+// }
+// w, err := conn.NextWriter(messageType)
+// if err != nil {
+// return err
+// }
+// if _, err := io.Copy(w, r); err != nil {
+// return err
+// }
+// if err := w.Close(); err != nil {
+// return err
+// }
+// }
+//
+// Data Messages
+//
+// The WebSocket protocol distinguishes between text and binary data messages.
+// Text messages are interpreted as UTF-8 encoded text. The interpretation of
+// binary messages is left to the application.
+//
+// This package uses the TextMessage and BinaryMessage integer constants to
+// identify the two data message types. The ReadMessage and NextReader methods
+// return the type of the received message. The messageType argument to the
+// WriteMessage and NextWriter methods specifies the type of a sent message.
+//
+// It is the application's responsibility to ensure that text messages are
+// valid UTF-8 encoded text.
+//
+// Control Messages
+//
+// The WebSocket protocol defines three types of control messages: close, ping
+// and pong. Call the connection WriteControl, WriteMessage or NextWriter
+// methods to send a control message to the peer.
+//
+// Connections handle received close messages by calling the handler function
+// set with the SetCloseHandler method and by returning a *CloseError from the
+// NextReader, ReadMessage or the message Read method. The default close
+// handler sends a close message to the peer.
+//
+// Connections handle received ping messages by calling the handler function
+// set with the SetPingHandler method. The default ping handler sends a pong
+// message to the peer.
+//
+// Connections handle received pong messages by calling the handler function
+// set with the SetPongHandler method. The default pong handler does nothing.
+// If an application sends ping messages, then the application should set a
+// pong handler to receive the corresponding pong.
+//
+// The control message handler functions are called from the NextReader,
+// ReadMessage and message reader Read methods. The default close and ping
+// handlers can block these methods for a short time when the handler writes to
+// the connection.
+//
+// The application must read the connection to process close, ping and pong
+// messages sent from the peer. If the application is not otherwise interested
+// in messages from the peer, then the application should start a goroutine to
+// read and discard messages from the peer. A simple example is:
+//
+// func readLoop(c *websocket.Conn) {
+// for {
+// if _, _, err := c.NextReader(); err != nil {
+// c.Close()
+// break
+// }
+// }
+// }
+//
+// Concurrency
+//
+// Connections support one concurrent reader and one concurrent writer.
+//
+// Applications are responsible for ensuring that no more than one goroutine
+// calls the write methods (NextWriter, SetWriteDeadline, WriteMessage,
+// WriteJSON, EnableWriteCompression, SetCompressionLevel) concurrently and
+// that no more than one goroutine calls the read methods (NextReader,
+// SetReadDeadline, ReadMessage, ReadJSON, SetPongHandler, SetPingHandler)
+// concurrently.
+//
+// The Close and WriteControl methods can be called concurrently with all other
+// methods.
+//
+// Origin Considerations
+//
+// Web browsers allow Javascript applications to open a WebSocket connection to
+// any host. It's up to the server to enforce an origin policy using the Origin
+// request header sent by the browser.
+//
+// The Upgrader calls the function specified in the CheckOrigin field to check
+// the origin. If the CheckOrigin function returns false, then the Upgrade
+// method fails the WebSocket handshake with HTTP status 403.
+//
+// If the CheckOrigin field is nil, then the Upgrader uses a safe default: fail
+// the handshake if the Origin request header is present and the Origin host is
+// not equal to the Host request header.
+//
+// The deprecated package-level Upgrade function does not perform origin
+// checking. The application is responsible for checking the Origin header
+// before calling the Upgrade function.
+//
+// Compression EXPERIMENTAL
+//
+// Per message compression extensions (RFC 7692) are experimentally supported
+// by this package in a limited capacity. Setting the EnableCompression option
+// to true in Dialer or Upgrader will attempt to negotiate per message deflate
+// support.
+//
+// var upgrader = websocket.Upgrader{
+// EnableCompression: true,
+// }
+//
+// If compression was successfully negotiated with the connection's peer, any
+// message received in compressed form will be automatically decompressed.
+// All Read methods will return uncompressed bytes.
+//
+// Per message compression of messages written to a connection can be enabled
+// or disabled by calling the corresponding Conn method:
+//
+// conn.EnableWriteCompression(false)
+//
+// Currently this package does not support compression with "context takeover".
+// This means that messages must be compressed and decompressed in isolation,
+// without retaining sliding window or dictionary state across messages. For
+// more details refer to RFC 7692.
+//
+// Use of compression is experimental and may result in decreased performance.
+package websocket
diff --git a/vendor/github.com/gorilla/websocket/json.go b/vendor/github.com/gorilla/websocket/json.go
new file mode 100644
index 0000000..dc2c1f6
--- /dev/null
+++ b/vendor/github.com/gorilla/websocket/json.go
@@ -0,0 +1,60 @@
+// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package websocket
+
+import (
+ "encoding/json"
+ "io"
+)
+
+// WriteJSON writes the JSON encoding of v as a message.
+//
+// Deprecated: Use c.WriteJSON instead.
+func WriteJSON(c *Conn, v interface{}) error {
+ return c.WriteJSON(v)
+}
+
+// WriteJSON writes the JSON encoding of v as a message.
+//
+// See the documentation for encoding/json Marshal for details about the
+// conversion of Go values to JSON.
+func (c *Conn) WriteJSON(v interface{}) error {
+ w, err := c.NextWriter(TextMessage)
+ if err != nil {
+ return err
+ }
+ err1 := json.NewEncoder(w).Encode(v)
+ err2 := w.Close()
+ if err1 != nil {
+ return err1
+ }
+ return err2
+}
+
+// ReadJSON reads the next JSON-encoded message from the connection and stores
+// it in the value pointed to by v.
+//
+// Deprecated: Use c.ReadJSON instead.
+func ReadJSON(c *Conn, v interface{}) error {
+ return c.ReadJSON(v)
+}
+
+// ReadJSON reads the next JSON-encoded message from the connection and stores
+// it in the value pointed to by v.
+//
+// See the documentation for the encoding/json Unmarshal function for details
+// about the conversion of JSON to a Go value.
+func (c *Conn) ReadJSON(v interface{}) error {
+ _, r, err := c.NextReader()
+ if err != nil {
+ return err
+ }
+ err = json.NewDecoder(r).Decode(v)
+ if err == io.EOF {
+ // One value is expected in the message.
+ err = io.ErrUnexpectedEOF
+ }
+ return err
+}
diff --git a/vendor/github.com/gorilla/websocket/mask.go b/vendor/github.com/gorilla/websocket/mask.go
new file mode 100644
index 0000000..577fce9
--- /dev/null
+++ b/vendor/github.com/gorilla/websocket/mask.go
@@ -0,0 +1,54 @@
+// Copyright 2016 The Gorilla WebSocket Authors. All rights reserved. Use of
+// this source code is governed by a BSD-style license that can be found in the
+// LICENSE file.
+
+// +build !appengine
+
+package websocket
+
+import "unsafe"
+
+const wordSize = int(unsafe.Sizeof(uintptr(0)))
+
+func maskBytes(key [4]byte, pos int, b []byte) int {
+ // Mask one byte at a time for small buffers.
+ if len(b) < 2*wordSize {
+ for i := range b {
+ b[i] ^= key[pos&3]
+ pos++
+ }
+ return pos & 3
+ }
+
+ // Mask one byte at a time to word boundary.
+ if n := int(uintptr(unsafe.Pointer(&b[0]))) % wordSize; n != 0 {
+ n = wordSize - n
+ for i := range b[:n] {
+ b[i] ^= key[pos&3]
+ pos++
+ }
+ b = b[n:]
+ }
+
+ // Create aligned word size key.
+ var k [wordSize]byte
+ for i := range k {
+ k[i] = key[(pos+i)&3]
+ }
+ kw := *(*uintptr)(unsafe.Pointer(&k))
+
+ // Mask one word at a time.
+ n := (len(b) / wordSize) * wordSize
+ for i := 0; i < n; i += wordSize {
+ *(*uintptr)(unsafe.Pointer(uintptr(unsafe.Pointer(&b[0])) + uintptr(i))) ^= kw
+ }
+
+ // Mask one byte at a time for remaining bytes.
+ b = b[n:]
+ for i := range b {
+ b[i] ^= key[pos&3]
+ pos++
+ }
+
+ return pos & 3
+}
diff --git a/vendor/github.com/gorilla/websocket/mask_safe.go b/vendor/github.com/gorilla/websocket/mask_safe.go
new file mode 100644
index 0000000..2aac060
--- /dev/null
+++ b/vendor/github.com/gorilla/websocket/mask_safe.go
@@ -0,0 +1,15 @@
+// Copyright 2016 The Gorilla WebSocket Authors. All rights reserved. Use of
+// this source code is governed by a BSD-style license that can be found in the
+// LICENSE file.
+
+// +build appengine
+
+package websocket
+
+func maskBytes(key [4]byte, pos int, b []byte) int {
+ for i := range b {
+ b[i] ^= key[pos&3]
+ pos++
+ }
+ return pos & 3
+}
diff --git a/vendor/github.com/gorilla/websocket/prepared.go b/vendor/github.com/gorilla/websocket/prepared.go
new file mode 100644
index 0000000..74ec565
--- /dev/null
+++ b/vendor/github.com/gorilla/websocket/prepared.go
@@ -0,0 +1,102 @@
+// Copyright 2017 The Gorilla WebSocket Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package websocket
+
+import (
+ "bytes"
+ "net"
+ "sync"
+ "time"
+)
+
+// PreparedMessage caches on the wire representations of a message payload.
+// Use PreparedMessage to efficiently send a message payload to multiple
+// connections. PreparedMessage is especially useful when compression is used
+// because the CPU and memory expensive compression operation can be executed
+// once for a given set of compression options.
+type PreparedMessage struct {
+ messageType int
+ data []byte
+ mu sync.Mutex
+ frames map[prepareKey]*preparedFrame
+}
+
+// prepareKey defines a unique set of options to cache prepared frames in PreparedMessage.
+type prepareKey struct {
+ isServer bool
+ compress bool
+ compressionLevel int
+}
+
+// preparedFrame contains data in wire representation.
+type preparedFrame struct {
+ once sync.Once
+ data []byte
+}
+
+// NewPreparedMessage returns an initialized PreparedMessage. You can then send
+// it to connection using WritePreparedMessage method. Valid wire
+// representation will be calculated lazily only once for a set of current
+// connection options.
+func NewPreparedMessage(messageType int, data []byte) (*PreparedMessage, error) {
+ pm := &PreparedMessage{
+ messageType: messageType,
+ frames: make(map[prepareKey]*preparedFrame),
+ data: data,
+ }
+
+ // Prepare a plain server frame.
+ _, frameData, err := pm.frame(prepareKey{isServer: true, compress: false})
+ if err != nil {
+ return nil, err
+ }
+
+ // To protect against caller modifying the data argument, remember the data
+ // copied to the plain server frame.
+ pm.data = frameData[len(frameData)-len(data):]
+ return pm, nil
+}
+
+func (pm *PreparedMessage) frame(key prepareKey) (int, []byte, error) {
+ pm.mu.Lock()
+ frame, ok := pm.frames[key]
+ if !ok {
+ frame = &preparedFrame{}
+ pm.frames[key] = frame
+ }
+ pm.mu.Unlock()
+
+ var err error
+ frame.once.Do(func() {
+ // Prepare a frame using a 'fake' connection.
+ // TODO: Refactor code in conn.go to allow more direct construction of
+ // the frame.
+ mu := make(chan bool, 1)
+ mu <- true
+ var nc prepareConn
+ c := &Conn{
+ conn: &nc,
+ mu: mu,
+ isServer: key.isServer,
+ compressionLevel: key.compressionLevel,
+ enableWriteCompression: true,
+ writeBuf: make([]byte, defaultWriteBufferSize+maxFrameHeaderSize),
+ }
+ if key.compress {
+ c.newCompressionWriter = compressNoContextTakeover
+ }
+ err = c.WriteMessage(pm.messageType, pm.data)
+ frame.data = nc.buf.Bytes()
+ })
+ return pm.messageType, frame.data, err
+}
+
+type prepareConn struct {
+ buf bytes.Buffer
+ net.Conn
+}
+
+func (pc *prepareConn) Write(p []byte) (int, error) { return pc.buf.Write(p) }
+func (pc *prepareConn) SetWriteDeadline(t time.Time) error { return nil }
diff --git a/vendor/github.com/gorilla/websocket/proxy.go b/vendor/github.com/gorilla/websocket/proxy.go
new file mode 100644
index 0000000..bf2478e
--- /dev/null
+++ b/vendor/github.com/gorilla/websocket/proxy.go
@@ -0,0 +1,77 @@
+// Copyright 2017 The Gorilla WebSocket Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package websocket
+
+import (
+ "bufio"
+ "encoding/base64"
+ "errors"
+ "net"
+ "net/http"
+ "net/url"
+ "strings"
+)
+
+type netDialerFunc func(network, addr string) (net.Conn, error)
+
+func (fn netDialerFunc) Dial(network, addr string) (net.Conn, error) {
+ return fn(network, addr)
+}
+
+func init() {
+ proxy_RegisterDialerType("http", func(proxyURL *url.URL, forwardDialer proxy_Dialer) (proxy_Dialer, error) {
+ return &httpProxyDialer{proxyURL: proxyURL, fowardDial: forwardDialer.Dial}, nil
+ })
+}
+
+type httpProxyDialer struct {
+ proxyURL *url.URL
+ fowardDial func(network, addr string) (net.Conn, error)
+}
+
+func (hpd *httpProxyDialer) Dial(network string, addr string) (net.Conn, error) {
+ hostPort, _ := hostPortNoPort(hpd.proxyURL)
+ conn, err := hpd.fowardDial(network, hostPort)
+ if err != nil {
+ return nil, err
+ }
+
+ connectHeader := make(http.Header)
+ if user := hpd.proxyURL.User; user != nil {
+ proxyUser := user.Username()
+ if proxyPassword, passwordSet := user.Password(); passwordSet {
+ credential := base64.StdEncoding.EncodeToString([]byte(proxyUser + ":" + proxyPassword))
+ connectHeader.Set("Proxy-Authorization", "Basic "+credential)
+ }
+ }
+
+ connectReq := &http.Request{
+ Method: "CONNECT",
+ URL: &url.URL{Opaque: addr},
+ Host: addr,
+ Header: connectHeader,
+ }
+
+ if err := connectReq.Write(conn); err != nil {
+ conn.Close()
+ return nil, err
+ }
+
+ // Read response. It's OK to use and discard buffered reader here becaue
+ // the remote server does not speak until spoken to.
+ br := bufio.NewReader(conn)
+ resp, err := http.ReadResponse(br, connectReq)
+ if err != nil {
+ conn.Close()
+ return nil, err
+ }
+
+ if resp.StatusCode != 200 {
+ conn.Close()
+ f := strings.SplitN(resp.Status, " ", 2)
+ return nil, errors.New(f[1])
+ }
+ return conn, nil
+}
diff --git a/vendor/github.com/gorilla/websocket/server.go b/vendor/github.com/gorilla/websocket/server.go
new file mode 100644
index 0000000..a761824
--- /dev/null
+++ b/vendor/github.com/gorilla/websocket/server.go
@@ -0,0 +1,363 @@
+// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package websocket
+
+import (
+ "bufio"
+ "errors"
+ "io"
+ "net/http"
+ "net/url"
+ "strings"
+ "time"
+)
+
+// HandshakeError describes an error with the handshake from the peer.
+type HandshakeError struct {
+ message string
+}
+
+func (e HandshakeError) Error() string { return e.message }
+
+// Upgrader specifies parameters for upgrading an HTTP connection to a
+// WebSocket connection.
+type Upgrader struct {
+ // HandshakeTimeout specifies the duration for the handshake to complete.
+ HandshakeTimeout time.Duration
+
+ // ReadBufferSize and WriteBufferSize specify I/O buffer sizes. If a buffer
+ // size is zero, then buffers allocated by the HTTP server are used. The
+ // I/O buffer sizes do not limit the size of the messages that can be sent
+ // or received.
+ ReadBufferSize, WriteBufferSize int
+
+ // WriteBufferPool is a pool of buffers for write operations. If the value
+ // is not set, then write buffers are allocated to the connection for the
+ // lifetime of the connection.
+ //
+ // A pool is most useful when the application has a modest volume of writes
+ // across a large number of connections.
+ //
+ // Applications should use a single pool for each unique value of
+ // WriteBufferSize.
+ WriteBufferPool BufferPool
+
+ // Subprotocols specifies the server's supported protocols in order of
+ // preference. If this field is not nil, then the Upgrade method negotiates a
+ // subprotocol by selecting the first match in this list with a protocol
+ // requested by the client. If there's no match, then no protocol is
+ // negotiated (the Sec-Websocket-Protocol header is not included in the
+ // handshake response).
+ Subprotocols []string
+
+ // Error specifies the function for generating HTTP error responses. If Error
+ // is nil, then http.Error is used to generate the HTTP response.
+ Error func(w http.ResponseWriter, r *http.Request, status int, reason error)
+
+ // CheckOrigin returns true if the request Origin header is acceptable. If
+ // CheckOrigin is nil, then a safe default is used: return false if the
+ // Origin request header is present and the origin host is not equal to
+ // request Host header.
+ //
+ // A CheckOrigin function should carefully validate the request origin to
+ // prevent cross-site request forgery.
+ CheckOrigin func(r *http.Request) bool
+
+ // EnableCompression specify if the server should attempt to negotiate per
+ // message compression (RFC 7692). Setting this value to true does not
+ // guarantee that compression will be supported. Currently only "no context
+ // takeover" modes are supported.
+ EnableCompression bool
+}
+
+func (u *Upgrader) returnError(w http.ResponseWriter, r *http.Request, status int, reason string) (*Conn, error) {
+ err := HandshakeError{reason}
+ if u.Error != nil {
+ u.Error(w, r, status, err)
+ } else {
+ w.Header().Set("Sec-Websocket-Version", "13")
+ http.Error(w, http.StatusText(status), status)
+ }
+ return nil, err
+}
+
+// checkSameOrigin returns true if the origin is not set or is equal to the request host.
+func checkSameOrigin(r *http.Request) bool {
+ origin := r.Header["Origin"]
+ if len(origin) == 0 {
+ return true
+ }
+ u, err := url.Parse(origin[0])
+ if err != nil {
+ return false
+ }
+ return equalASCIIFold(u.Host, r.Host)
+}
+
+func (u *Upgrader) selectSubprotocol(r *http.Request, responseHeader http.Header) string {
+ if u.Subprotocols != nil {
+ clientProtocols := Subprotocols(r)
+ for _, serverProtocol := range u.Subprotocols {
+ for _, clientProtocol := range clientProtocols {
+ if clientProtocol == serverProtocol {
+ return clientProtocol
+ }
+ }
+ }
+ } else if responseHeader != nil {
+ return responseHeader.Get("Sec-Websocket-Protocol")
+ }
+ return ""
+}
+
+// Upgrade upgrades the HTTP server connection to the WebSocket protocol.
+//
+// The responseHeader is included in the response to the client's upgrade
+// request. Use the responseHeader to specify cookies (Set-Cookie) and the
+// application negotiated subprotocol (Sec-WebSocket-Protocol).
+//
+// If the upgrade fails, then Upgrade replies to the client with an HTTP error
+// response.
+func (u *Upgrader) Upgrade(w http.ResponseWriter, r *http.Request, responseHeader http.Header) (*Conn, error) {
+ const badHandshake = "websocket: the client is not using the websocket protocol: "
+
+ if !tokenListContainsValue(r.Header, "Connection", "upgrade") {
+ return u.returnError(w, r, http.StatusBadRequest, badHandshake+"'upgrade' token not found in 'Connection' header")
+ }
+
+ if !tokenListContainsValue(r.Header, "Upgrade", "websocket") {
+ return u.returnError(w, r, http.StatusBadRequest, badHandshake+"'websocket' token not found in 'Upgrade' header")
+ }
+
+ if r.Method != "GET" {
+ return u.returnError(w, r, http.StatusMethodNotAllowed, badHandshake+"request method is not GET")
+ }
+
+ if !tokenListContainsValue(r.Header, "Sec-Websocket-Version", "13") {
+ return u.returnError(w, r, http.StatusBadRequest, "websocket: unsupported version: 13 not found in 'Sec-Websocket-Version' header")
+ }
+
+ if _, ok := responseHeader["Sec-Websocket-Extensions"]; ok {
+ return u.returnError(w, r, http.StatusInternalServerError, "websocket: application specific 'Sec-WebSocket-Extensions' headers are unsupported")
+ }
+
+ checkOrigin := u.CheckOrigin
+ if checkOrigin == nil {
+ checkOrigin = checkSameOrigin
+ }
+ if !checkOrigin(r) {
+ return u.returnError(w, r, http.StatusForbidden, "websocket: request origin not allowed by Upgrader.CheckOrigin")
+ }
+
+ challengeKey := r.Header.Get("Sec-Websocket-Key")
+ if challengeKey == "" {
+ return u.returnError(w, r, http.StatusBadRequest, "websocket: not a websocket handshake: `Sec-WebSocket-Key' header is missing or blank")
+ }
+
+ subprotocol := u.selectSubprotocol(r, responseHeader)
+
+ // Negotiate PMCE
+ var compress bool
+ if u.EnableCompression {
+ for _, ext := range parseExtensions(r.Header) {
+ if ext[""] != "permessage-deflate" {
+ continue
+ }
+ compress = true
+ break
+ }
+ }
+
+ h, ok := w.(http.Hijacker)
+ if !ok {
+ return u.returnError(w, r, http.StatusInternalServerError, "websocket: response does not implement http.Hijacker")
+ }
+ var brw *bufio.ReadWriter
+ netConn, brw, err := h.Hijack()
+ if err != nil {
+ return u.returnError(w, r, http.StatusInternalServerError, err.Error())
+ }
+
+ if brw.Reader.Buffered() > 0 {
+ netConn.Close()
+ return nil, errors.New("websocket: client sent data before handshake is complete")
+ }
+
+ var br *bufio.Reader
+ if u.ReadBufferSize == 0 && bufioReaderSize(netConn, brw.Reader) > 256 {
+ // Reuse hijacked buffered reader as connection reader.
+ br = brw.Reader
+ }
+
+ buf := bufioWriterBuffer(netConn, brw.Writer)
+
+ var writeBuf []byte
+ if u.WriteBufferPool == nil && u.WriteBufferSize == 0 && len(buf) >= maxFrameHeaderSize+256 {
+ // Reuse hijacked write buffer as connection buffer.
+ writeBuf = buf
+ }
+
+ c := newConn(netConn, true, u.ReadBufferSize, u.WriteBufferSize, u.WriteBufferPool, br, writeBuf)
+ c.subprotocol = subprotocol
+
+ if compress {
+ c.newCompressionWriter = compressNoContextTakeover
+ c.newDecompressionReader = decompressNoContextTakeover
+ }
+
+ // Use larger of hijacked buffer and connection write buffer for header.
+ p := buf
+ if len(c.writeBuf) > len(p) {
+ p = c.writeBuf
+ }
+ p = p[:0]
+
+ p = append(p, "HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: "...)
+ p = append(p, computeAcceptKey(challengeKey)...)
+ p = append(p, "\r\n"...)
+ if c.subprotocol != "" {
+ p = append(p, "Sec-WebSocket-Protocol: "...)
+ p = append(p, c.subprotocol...)
+ p = append(p, "\r\n"...)
+ }
+ if compress {
+ p = append(p, "Sec-WebSocket-Extensions: permessage-deflate; server_no_context_takeover; client_no_context_takeover\r\n"...)
+ }
+ for k, vs := range responseHeader {
+ if k == "Sec-Websocket-Protocol" {
+ continue
+ }
+ for _, v := range vs {
+ p = append(p, k...)
+ p = append(p, ": "...)
+ for i := 0; i < len(v); i++ {
+ b := v[i]
+ if b <= 31 {
+ // prevent response splitting.
+ b = ' '
+ }
+ p = append(p, b)
+ }
+ p = append(p, "\r\n"...)
+ }
+ }
+ p = append(p, "\r\n"...)
+
+ // Clear deadlines set by HTTP server.
+ netConn.SetDeadline(time.Time{})
+
+ if u.HandshakeTimeout > 0 {
+ netConn.SetWriteDeadline(time.Now().Add(u.HandshakeTimeout))
+ }
+ if _, err = netConn.Write(p); err != nil {
+ netConn.Close()
+ return nil, err
+ }
+ if u.HandshakeTimeout > 0 {
+ netConn.SetWriteDeadline(time.Time{})
+ }
+
+ return c, nil
+}
+
+// Upgrade upgrades the HTTP server connection to the WebSocket protocol.
+//
+// Deprecated: Use websocket.Upgrader instead.
+//
+// Upgrade does not perform origin checking. The application is responsible for
+// checking the Origin header before calling Upgrade. An example implementation
+// of the same origin policy check is:
+//
+// if req.Header.Get("Origin") != "http://"+req.Host {
+// http.Error(w, "Origin not allowed", http.StatusForbidden)
+// return
+// }
+//
+// If the endpoint supports subprotocols, then the application is responsible
+// for negotiating the protocol used on the connection. Use the Subprotocols()
+// function to get the subprotocols requested by the client. Use the
+// Sec-Websocket-Protocol response header to specify the subprotocol selected
+// by the application.
+//
+// The responseHeader is included in the response to the client's upgrade
+// request. Use the responseHeader to specify cookies (Set-Cookie) and the
+// negotiated subprotocol (Sec-Websocket-Protocol).
+//
+// The connection buffers IO to the underlying network connection. The
+// readBufSize and writeBufSize parameters specify the size of the buffers to
+// use. Messages can be larger than the buffers.
+//
+// If the request is not a valid WebSocket handshake, then Upgrade returns an
+// error of type HandshakeError. Applications should handle this error by
+// replying to the client with an HTTP error response.
+func Upgrade(w http.ResponseWriter, r *http.Request, responseHeader http.Header, readBufSize, writeBufSize int) (*Conn, error) {
+ u := Upgrader{ReadBufferSize: readBufSize, WriteBufferSize: writeBufSize}
+ u.Error = func(w http.ResponseWriter, r *http.Request, status int, reason error) {
+ // don't return errors to maintain backwards compatibility
+ }
+ u.CheckOrigin = func(r *http.Request) bool {
+ // allow all connections by default
+ return true
+ }
+ return u.Upgrade(w, r, responseHeader)
+}
+
+// Subprotocols returns the subprotocols requested by the client in the
+// Sec-Websocket-Protocol header.
+func Subprotocols(r *http.Request) []string {
+ h := strings.TrimSpace(r.Header.Get("Sec-Websocket-Protocol"))
+ if h == "" {
+ return nil
+ }
+ protocols := strings.Split(h, ",")
+ for i := range protocols {
+ protocols[i] = strings.TrimSpace(protocols[i])
+ }
+ return protocols
+}
+
+// IsWebSocketUpgrade returns true if the client requested upgrade to the
+// WebSocket protocol.
+func IsWebSocketUpgrade(r *http.Request) bool {
+ return tokenListContainsValue(r.Header, "Connection", "upgrade") &&
+ tokenListContainsValue(r.Header, "Upgrade", "websocket")
+}
+
+// bufioReaderSize size returns the size of a bufio.Reader.
+func bufioReaderSize(originalReader io.Reader, br *bufio.Reader) int {
+ // This code assumes that peek on a reset reader returns
+ // bufio.Reader.buf[:0].
+ // TODO: Use bufio.Reader.Size() after Go 1.10
+ br.Reset(originalReader)
+ if p, err := br.Peek(0); err == nil {
+ return cap(p)
+ }
+ return 0
+}
+
+// writeHook is an io.Writer that records the last slice passed to it vio
+// io.Writer.Write.
+type writeHook struct {
+ p []byte
+}
+
+func (wh *writeHook) Write(p []byte) (int, error) {
+ wh.p = p
+ return len(p), nil
+}
+
+// bufioWriterBuffer grabs the buffer from a bufio.Writer.
+func bufioWriterBuffer(originalWriter io.Writer, bw *bufio.Writer) []byte {
+ // This code assumes that bufio.Writer.buf[:1] is passed to the
+ // bufio.Writer's underlying writer.
+ var wh writeHook
+ bw.Reset(&wh)
+ bw.WriteByte(0)
+ bw.Flush()
+
+ bw.Reset(originalWriter)
+
+ return wh.p[:cap(wh.p)]
+}
diff --git a/vendor/github.com/gorilla/websocket/trace.go b/vendor/github.com/gorilla/websocket/trace.go
new file mode 100644
index 0000000..834f122
--- /dev/null
+++ b/vendor/github.com/gorilla/websocket/trace.go
@@ -0,0 +1,19 @@
+// +build go1.8
+
+package websocket
+
+import (
+ "crypto/tls"
+ "net/http/httptrace"
+)
+
+func doHandshakeWithTrace(trace *httptrace.ClientTrace, tlsConn *tls.Conn, cfg *tls.Config) error {
+ if trace.TLSHandshakeStart != nil {
+ trace.TLSHandshakeStart()
+ }
+ err := doHandshake(tlsConn, cfg)
+ if trace.TLSHandshakeDone != nil {
+ trace.TLSHandshakeDone(tlsConn.ConnectionState(), err)
+ }
+ return err
+}
diff --git a/vendor/github.com/gorilla/websocket/trace_17.go b/vendor/github.com/gorilla/websocket/trace_17.go
new file mode 100644
index 0000000..77d05a0
--- /dev/null
+++ b/vendor/github.com/gorilla/websocket/trace_17.go
@@ -0,0 +1,12 @@
+// +build !go1.8
+
+package websocket
+
+import (
+ "crypto/tls"
+ "net/http/httptrace"
+)
+
+func doHandshakeWithTrace(trace *httptrace.ClientTrace, tlsConn *tls.Conn, cfg *tls.Config) error {
+ return doHandshake(tlsConn, cfg)
+}
diff --git a/vendor/github.com/gorilla/websocket/util.go b/vendor/github.com/gorilla/websocket/util.go
new file mode 100644
index 0000000..354001e
--- /dev/null
+++ b/vendor/github.com/gorilla/websocket/util.go
@@ -0,0 +1,237 @@
+// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package websocket
+
+import (
+ "crypto/rand"
+ "crypto/sha1"
+ "encoding/base64"
+ "io"
+ "net/http"
+ "strings"
+ "unicode/utf8"
+)
+
+var keyGUID = []byte("258EAFA5-E914-47DA-95CA-C5AB0DC85B11")
+
+func computeAcceptKey(challengeKey string) string {
+ h := sha1.New()
+ h.Write([]byte(challengeKey))
+ h.Write(keyGUID)
+ return base64.StdEncoding.EncodeToString(h.Sum(nil))
+}
+
+func generateChallengeKey() (string, error) {
+ p := make([]byte, 16)
+ if _, err := io.ReadFull(rand.Reader, p); err != nil {
+ return "", err
+ }
+ return base64.StdEncoding.EncodeToString(p), nil
+}
+
+// Octet types from RFC 2616.
+var octetTypes [256]byte
+
+const (
+ isTokenOctet = 1 << iota
+ isSpaceOctet
+)
+
+func init() {
+ // From RFC 2616
+ //
+ // OCTET =
+ // CHAR =
+ // CTL =
+ // CR =
+ // LF =
+ // SP =
+ // HT =
+ // <"> =
+ // CRLF = CR LF
+ // LWS = [CRLF] 1*( SP | HT )
+ // TEXT =
+ // separators = "(" | ")" | "<" | ">" | "@" | "," | ";" | ":" | "\" | <">
+ // | "/" | "[" | "]" | "?" | "=" | "{" | "}" | SP | HT
+ // token = 1*
+ // qdtext = >
+
+ for c := 0; c < 256; c++ {
+ var t byte
+ isCtl := c <= 31 || c == 127
+ isChar := 0 <= c && c <= 127
+ isSeparator := strings.IndexRune(" \t\"(),/:;<=>?@[]\\{}", rune(c)) >= 0
+ if strings.IndexRune(" \t\r\n", rune(c)) >= 0 {
+ t |= isSpaceOctet
+ }
+ if isChar && !isCtl && !isSeparator {
+ t |= isTokenOctet
+ }
+ octetTypes[c] = t
+ }
+}
+
+func skipSpace(s string) (rest string) {
+ i := 0
+ for ; i < len(s); i++ {
+ if octetTypes[s[i]]&isSpaceOctet == 0 {
+ break
+ }
+ }
+ return s[i:]
+}
+
+func nextToken(s string) (token, rest string) {
+ i := 0
+ for ; i < len(s); i++ {
+ if octetTypes[s[i]]&isTokenOctet == 0 {
+ break
+ }
+ }
+ return s[:i], s[i:]
+}
+
+func nextTokenOrQuoted(s string) (value string, rest string) {
+ if !strings.HasPrefix(s, "\"") {
+ return nextToken(s)
+ }
+ s = s[1:]
+ for i := 0; i < len(s); i++ {
+ switch s[i] {
+ case '"':
+ return s[:i], s[i+1:]
+ case '\\':
+ p := make([]byte, len(s)-1)
+ j := copy(p, s[:i])
+ escape := true
+ for i = i + 1; i < len(s); i++ {
+ b := s[i]
+ switch {
+ case escape:
+ escape = false
+ p[j] = b
+ j++
+ case b == '\\':
+ escape = true
+ case b == '"':
+ return string(p[:j]), s[i+1:]
+ default:
+ p[j] = b
+ j++
+ }
+ }
+ return "", ""
+ }
+ }
+ return "", ""
+}
+
+// equalASCIIFold returns true if s is equal to t with ASCII case folding.
+func equalASCIIFold(s, t string) bool {
+ for s != "" && t != "" {
+ sr, size := utf8.DecodeRuneInString(s)
+ s = s[size:]
+ tr, size := utf8.DecodeRuneInString(t)
+ t = t[size:]
+ if sr == tr {
+ continue
+ }
+ if 'A' <= sr && sr <= 'Z' {
+ sr = sr + 'a' - 'A'
+ }
+ if 'A' <= tr && tr <= 'Z' {
+ tr = tr + 'a' - 'A'
+ }
+ if sr != tr {
+ return false
+ }
+ }
+ return s == t
+}
+
+// tokenListContainsValue returns true if the 1#token header with the given
+// name contains a token equal to value with ASCII case folding.
+func tokenListContainsValue(header http.Header, name string, value string) bool {
+headers:
+ for _, s := range header[name] {
+ for {
+ var t string
+ t, s = nextToken(skipSpace(s))
+ if t == "" {
+ continue headers
+ }
+ s = skipSpace(s)
+ if s != "" && s[0] != ',' {
+ continue headers
+ }
+ if equalASCIIFold(t, value) {
+ return true
+ }
+ if s == "" {
+ continue headers
+ }
+ s = s[1:]
+ }
+ }
+ return false
+}
+
+// parseExtensions parses WebSocket extensions from a header.
+func parseExtensions(header http.Header) []map[string]string {
+ // From RFC 6455:
+ //
+ // Sec-WebSocket-Extensions = extension-list
+ // extension-list = 1#extension
+ // extension = extension-token *( ";" extension-param )
+ // extension-token = registered-token
+ // registered-token = token
+ // extension-param = token [ "=" (token | quoted-string) ]
+ // ;When using the quoted-string syntax variant, the value
+ // ;after quoted-string unescaping MUST conform to the
+ // ;'token' ABNF.
+
+ var result []map[string]string
+headers:
+ for _, s := range header["Sec-Websocket-Extensions"] {
+ for {
+ var t string
+ t, s = nextToken(skipSpace(s))
+ if t == "" {
+ continue headers
+ }
+ ext := map[string]string{"": t}
+ for {
+ s = skipSpace(s)
+ if !strings.HasPrefix(s, ";") {
+ break
+ }
+ var k string
+ k, s = nextToken(skipSpace(s[1:]))
+ if k == "" {
+ continue headers
+ }
+ s = skipSpace(s)
+ var v string
+ if strings.HasPrefix(s, "=") {
+ v, s = nextTokenOrQuoted(skipSpace(s[1:]))
+ s = skipSpace(s)
+ }
+ if s != "" && s[0] != ',' && s[0] != ';' {
+ continue headers
+ }
+ ext[k] = v
+ }
+ if s != "" && s[0] != ',' {
+ continue headers
+ }
+ result = append(result, ext)
+ if s == "" {
+ continue headers
+ }
+ s = s[1:]
+ }
+ }
+ return result
+}
diff --git a/vendor/github.com/gorilla/websocket/x_net_proxy.go b/vendor/github.com/gorilla/websocket/x_net_proxy.go
new file mode 100644
index 0000000..2e668f6
--- /dev/null
+++ b/vendor/github.com/gorilla/websocket/x_net_proxy.go
@@ -0,0 +1,473 @@
+// Code generated by golang.org/x/tools/cmd/bundle. DO NOT EDIT.
+//go:generate bundle -o x_net_proxy.go golang.org/x/net/proxy
+
+// Package proxy provides support for a variety of protocols to proxy network
+// data.
+//
+
+package websocket
+
+import (
+ "errors"
+ "io"
+ "net"
+ "net/url"
+ "os"
+ "strconv"
+ "strings"
+ "sync"
+)
+
+type proxy_direct struct{}
+
+// Direct is a direct proxy: one that makes network connections directly.
+var proxy_Direct = proxy_direct{}
+
+func (proxy_direct) Dial(network, addr string) (net.Conn, error) {
+ return net.Dial(network, addr)
+}
+
+// A PerHost directs connections to a default Dialer unless the host name
+// requested matches one of a number of exceptions.
+type proxy_PerHost struct {
+ def, bypass proxy_Dialer
+
+ bypassNetworks []*net.IPNet
+ bypassIPs []net.IP
+ bypassZones []string
+ bypassHosts []string
+}
+
+// NewPerHost returns a PerHost Dialer that directs connections to either
+// defaultDialer or bypass, depending on whether the connection matches one of
+// the configured rules.
+func proxy_NewPerHost(defaultDialer, bypass proxy_Dialer) *proxy_PerHost {
+ return &proxy_PerHost{
+ def: defaultDialer,
+ bypass: bypass,
+ }
+}
+
+// Dial connects to the address addr on the given network through either
+// defaultDialer or bypass.
+func (p *proxy_PerHost) Dial(network, addr string) (c net.Conn, err error) {
+ host, _, err := net.SplitHostPort(addr)
+ if err != nil {
+ return nil, err
+ }
+
+ return p.dialerForRequest(host).Dial(network, addr)
+}
+
+func (p *proxy_PerHost) dialerForRequest(host string) proxy_Dialer {
+ if ip := net.ParseIP(host); ip != nil {
+ for _, net := range p.bypassNetworks {
+ if net.Contains(ip) {
+ return p.bypass
+ }
+ }
+ for _, bypassIP := range p.bypassIPs {
+ if bypassIP.Equal(ip) {
+ return p.bypass
+ }
+ }
+ return p.def
+ }
+
+ for _, zone := range p.bypassZones {
+ if strings.HasSuffix(host, zone) {
+ return p.bypass
+ }
+ if host == zone[1:] {
+ // For a zone ".example.com", we match "example.com"
+ // too.
+ return p.bypass
+ }
+ }
+ for _, bypassHost := range p.bypassHosts {
+ if bypassHost == host {
+ return p.bypass
+ }
+ }
+ return p.def
+}
+
+// AddFromString parses a string that contains comma-separated values
+// specifying hosts that should use the bypass proxy. Each value is either an
+// IP address, a CIDR range, a zone (*.example.com) or a host name
+// (localhost). A best effort is made to parse the string and errors are
+// ignored.
+func (p *proxy_PerHost) AddFromString(s string) {
+ hosts := strings.Split(s, ",")
+ for _, host := range hosts {
+ host = strings.TrimSpace(host)
+ if len(host) == 0 {
+ continue
+ }
+ if strings.Contains(host, "/") {
+ // We assume that it's a CIDR address like 127.0.0.0/8
+ if _, net, err := net.ParseCIDR(host); err == nil {
+ p.AddNetwork(net)
+ }
+ continue
+ }
+ if ip := net.ParseIP(host); ip != nil {
+ p.AddIP(ip)
+ continue
+ }
+ if strings.HasPrefix(host, "*.") {
+ p.AddZone(host[1:])
+ continue
+ }
+ p.AddHost(host)
+ }
+}
+
+// AddIP specifies an IP address that will use the bypass proxy. Note that
+// this will only take effect if a literal IP address is dialed. A connection
+// to a named host will never match an IP.
+func (p *proxy_PerHost) AddIP(ip net.IP) {
+ p.bypassIPs = append(p.bypassIPs, ip)
+}
+
+// AddNetwork specifies an IP range that will use the bypass proxy. Note that
+// this will only take effect if a literal IP address is dialed. A connection
+// to a named host will never match.
+func (p *proxy_PerHost) AddNetwork(net *net.IPNet) {
+ p.bypassNetworks = append(p.bypassNetworks, net)
+}
+
+// AddZone specifies a DNS suffix that will use the bypass proxy. A zone of
+// "example.com" matches "example.com" and all of its subdomains.
+func (p *proxy_PerHost) AddZone(zone string) {
+ if strings.HasSuffix(zone, ".") {
+ zone = zone[:len(zone)-1]
+ }
+ if !strings.HasPrefix(zone, ".") {
+ zone = "." + zone
+ }
+ p.bypassZones = append(p.bypassZones, zone)
+}
+
+// AddHost specifies a host name that will use the bypass proxy.
+func (p *proxy_PerHost) AddHost(host string) {
+ if strings.HasSuffix(host, ".") {
+ host = host[:len(host)-1]
+ }
+ p.bypassHosts = append(p.bypassHosts, host)
+}
+
+// A Dialer is a means to establish a connection.
+type proxy_Dialer interface {
+ // Dial connects to the given address via the proxy.
+ Dial(network, addr string) (c net.Conn, err error)
+}
+
+// Auth contains authentication parameters that specific Dialers may require.
+type proxy_Auth struct {
+ User, Password string
+}
+
+// FromEnvironment returns the dialer specified by the proxy related variables in
+// the environment.
+func proxy_FromEnvironment() proxy_Dialer {
+ allProxy := proxy_allProxyEnv.Get()
+ if len(allProxy) == 0 {
+ return proxy_Direct
+ }
+
+ proxyURL, err := url.Parse(allProxy)
+ if err != nil {
+ return proxy_Direct
+ }
+ proxy, err := proxy_FromURL(proxyURL, proxy_Direct)
+ if err != nil {
+ return proxy_Direct
+ }
+
+ noProxy := proxy_noProxyEnv.Get()
+ if len(noProxy) == 0 {
+ return proxy
+ }
+
+ perHost := proxy_NewPerHost(proxy, proxy_Direct)
+ perHost.AddFromString(noProxy)
+ return perHost
+}
+
+// proxySchemes is a map from URL schemes to a function that creates a Dialer
+// from a URL with such a scheme.
+var proxy_proxySchemes map[string]func(*url.URL, proxy_Dialer) (proxy_Dialer, error)
+
+// RegisterDialerType takes a URL scheme and a function to generate Dialers from
+// a URL with that scheme and a forwarding Dialer. Registered schemes are used
+// by FromURL.
+func proxy_RegisterDialerType(scheme string, f func(*url.URL, proxy_Dialer) (proxy_Dialer, error)) {
+ if proxy_proxySchemes == nil {
+ proxy_proxySchemes = make(map[string]func(*url.URL, proxy_Dialer) (proxy_Dialer, error))
+ }
+ proxy_proxySchemes[scheme] = f
+}
+
+// FromURL returns a Dialer given a URL specification and an underlying
+// Dialer for it to make network requests.
+func proxy_FromURL(u *url.URL, forward proxy_Dialer) (proxy_Dialer, error) {
+ var auth *proxy_Auth
+ if u.User != nil {
+ auth = new(proxy_Auth)
+ auth.User = u.User.Username()
+ if p, ok := u.User.Password(); ok {
+ auth.Password = p
+ }
+ }
+
+ switch u.Scheme {
+ case "socks5":
+ return proxy_SOCKS5("tcp", u.Host, auth, forward)
+ }
+
+ // If the scheme doesn't match any of the built-in schemes, see if it
+ // was registered by another package.
+ if proxy_proxySchemes != nil {
+ if f, ok := proxy_proxySchemes[u.Scheme]; ok {
+ return f(u, forward)
+ }
+ }
+
+ return nil, errors.New("proxy: unknown scheme: " + u.Scheme)
+}
+
+var (
+ proxy_allProxyEnv = &proxy_envOnce{
+ names: []string{"ALL_PROXY", "all_proxy"},
+ }
+ proxy_noProxyEnv = &proxy_envOnce{
+ names: []string{"NO_PROXY", "no_proxy"},
+ }
+)
+
+// envOnce looks up an environment variable (optionally by multiple
+// names) once. It mitigates expensive lookups on some platforms
+// (e.g. Windows).
+// (Borrowed from net/http/transport.go)
+type proxy_envOnce struct {
+ names []string
+ once sync.Once
+ val string
+}
+
+func (e *proxy_envOnce) Get() string {
+ e.once.Do(e.init)
+ return e.val
+}
+
+func (e *proxy_envOnce) init() {
+ for _, n := range e.names {
+ e.val = os.Getenv(n)
+ if e.val != "" {
+ return
+ }
+ }
+}
+
+// SOCKS5 returns a Dialer that makes SOCKSv5 connections to the given address
+// with an optional username and password. See RFC 1928 and RFC 1929.
+func proxy_SOCKS5(network, addr string, auth *proxy_Auth, forward proxy_Dialer) (proxy_Dialer, error) {
+ s := &proxy_socks5{
+ network: network,
+ addr: addr,
+ forward: forward,
+ }
+ if auth != nil {
+ s.user = auth.User
+ s.password = auth.Password
+ }
+
+ return s, nil
+}
+
+type proxy_socks5 struct {
+ user, password string
+ network, addr string
+ forward proxy_Dialer
+}
+
+const proxy_socks5Version = 5
+
+const (
+ proxy_socks5AuthNone = 0
+ proxy_socks5AuthPassword = 2
+)
+
+const proxy_socks5Connect = 1
+
+const (
+ proxy_socks5IP4 = 1
+ proxy_socks5Domain = 3
+ proxy_socks5IP6 = 4
+)
+
+var proxy_socks5Errors = []string{
+ "",
+ "general failure",
+ "connection forbidden",
+ "network unreachable",
+ "host unreachable",
+ "connection refused",
+ "TTL expired",
+ "command not supported",
+ "address type not supported",
+}
+
+// Dial connects to the address addr on the given network via the SOCKS5 proxy.
+func (s *proxy_socks5) Dial(network, addr string) (net.Conn, error) {
+ switch network {
+ case "tcp", "tcp6", "tcp4":
+ default:
+ return nil, errors.New("proxy: no support for SOCKS5 proxy connections of type " + network)
+ }
+
+ conn, err := s.forward.Dial(s.network, s.addr)
+ if err != nil {
+ return nil, err
+ }
+ if err := s.connect(conn, addr); err != nil {
+ conn.Close()
+ return nil, err
+ }
+ return conn, nil
+}
+
+// connect takes an existing connection to a socks5 proxy server,
+// and commands the server to extend that connection to target,
+// which must be a canonical address with a host and port.
+func (s *proxy_socks5) connect(conn net.Conn, target string) error {
+ host, portStr, err := net.SplitHostPort(target)
+ if err != nil {
+ return err
+ }
+
+ port, err := strconv.Atoi(portStr)
+ if err != nil {
+ return errors.New("proxy: failed to parse port number: " + portStr)
+ }
+ if port < 1 || port > 0xffff {
+ return errors.New("proxy: port number out of range: " + portStr)
+ }
+
+ // the size here is just an estimate
+ buf := make([]byte, 0, 6+len(host))
+
+ buf = append(buf, proxy_socks5Version)
+ if len(s.user) > 0 && len(s.user) < 256 && len(s.password) < 256 {
+ buf = append(buf, 2 /* num auth methods */, proxy_socks5AuthNone, proxy_socks5AuthPassword)
+ } else {
+ buf = append(buf, 1 /* num auth methods */, proxy_socks5AuthNone)
+ }
+
+ if _, err := conn.Write(buf); err != nil {
+ return errors.New("proxy: failed to write greeting to SOCKS5 proxy at " + s.addr + ": " + err.Error())
+ }
+
+ if _, err := io.ReadFull(conn, buf[:2]); err != nil {
+ return errors.New("proxy: failed to read greeting from SOCKS5 proxy at " + s.addr + ": " + err.Error())
+ }
+ if buf[0] != 5 {
+ return errors.New("proxy: SOCKS5 proxy at " + s.addr + " has unexpected version " + strconv.Itoa(int(buf[0])))
+ }
+ if buf[1] == 0xff {
+ return errors.New("proxy: SOCKS5 proxy at " + s.addr + " requires authentication")
+ }
+
+ // See RFC 1929
+ if buf[1] == proxy_socks5AuthPassword {
+ buf = buf[:0]
+ buf = append(buf, 1 /* password protocol version */)
+ buf = append(buf, uint8(len(s.user)))
+ buf = append(buf, s.user...)
+ buf = append(buf, uint8(len(s.password)))
+ buf = append(buf, s.password...)
+
+ if _, err := conn.Write(buf); err != nil {
+ return errors.New("proxy: failed to write authentication request to SOCKS5 proxy at " + s.addr + ": " + err.Error())
+ }
+
+ if _, err := io.ReadFull(conn, buf[:2]); err != nil {
+ return errors.New("proxy: failed to read authentication reply from SOCKS5 proxy at " + s.addr + ": " + err.Error())
+ }
+
+ if buf[1] != 0 {
+ return errors.New("proxy: SOCKS5 proxy at " + s.addr + " rejected username/password")
+ }
+ }
+
+ buf = buf[:0]
+ buf = append(buf, proxy_socks5Version, proxy_socks5Connect, 0 /* reserved */)
+
+ if ip := net.ParseIP(host); ip != nil {
+ if ip4 := ip.To4(); ip4 != nil {
+ buf = append(buf, proxy_socks5IP4)
+ ip = ip4
+ } else {
+ buf = append(buf, proxy_socks5IP6)
+ }
+ buf = append(buf, ip...)
+ } else {
+ if len(host) > 255 {
+ return errors.New("proxy: destination host name too long: " + host)
+ }
+ buf = append(buf, proxy_socks5Domain)
+ buf = append(buf, byte(len(host)))
+ buf = append(buf, host...)
+ }
+ buf = append(buf, byte(port>>8), byte(port))
+
+ if _, err := conn.Write(buf); err != nil {
+ return errors.New("proxy: failed to write connect request to SOCKS5 proxy at " + s.addr + ": " + err.Error())
+ }
+
+ if _, err := io.ReadFull(conn, buf[:4]); err != nil {
+ return errors.New("proxy: failed to read connect reply from SOCKS5 proxy at " + s.addr + ": " + err.Error())
+ }
+
+ failure := "unknown error"
+ if int(buf[1]) < len(proxy_socks5Errors) {
+ failure = proxy_socks5Errors[buf[1]]
+ }
+
+ if len(failure) > 0 {
+ return errors.New("proxy: SOCKS5 proxy at " + s.addr + " failed to connect: " + failure)
+ }
+
+ bytesToDiscard := 0
+ switch buf[3] {
+ case proxy_socks5IP4:
+ bytesToDiscard = net.IPv4len
+ case proxy_socks5IP6:
+ bytesToDiscard = net.IPv6len
+ case proxy_socks5Domain:
+ _, err := io.ReadFull(conn, buf[:1])
+ if err != nil {
+ return errors.New("proxy: failed to read domain length from SOCKS5 proxy at " + s.addr + ": " + err.Error())
+ }
+ bytesToDiscard = int(buf[0])
+ default:
+ return errors.New("proxy: got unknown address type " + strconv.Itoa(int(buf[3])) + " from SOCKS5 proxy at " + s.addr)
+ }
+
+ if cap(buf) < bytesToDiscard {
+ buf = make([]byte, bytesToDiscard)
+ } else {
+ buf = buf[:bytesToDiscard]
+ }
+ if _, err := io.ReadFull(conn, buf); err != nil {
+ return errors.New("proxy: failed to read address from SOCKS5 proxy at " + s.addr + ": " + err.Error())
+ }
+
+ // Also need to discard the port number
+ if _, err := io.ReadFull(conn, buf[:2]); err != nil {
+ return errors.New("proxy: failed to read port from SOCKS5 proxy at " + s.addr + ": " + err.Error())
+ }
+
+ return nil
+}
diff --git a/vendor/github.com/grpc-ecosystem/grpc-gateway/LICENSE.txt b/vendor/github.com/grpc-ecosystem/grpc-gateway/LICENSE.txt
new file mode 100644
index 0000000..3645162
--- /dev/null
+++ b/vendor/github.com/grpc-ecosystem/grpc-gateway/LICENSE.txt
@@ -0,0 +1,27 @@
+Copyright (c) 2015, Gengo, Inc.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ * Neither the name of Gengo, Inc. nor the names of its
+ contributors may be used to endorse or promote products derived from this
+ software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/vendor/github.com/grpc-ecosystem/grpc-gateway/internal/BUILD.bazel b/vendor/github.com/grpc-ecosystem/grpc-gateway/internal/BUILD.bazel
new file mode 100644
index 0000000..5242751
--- /dev/null
+++ b/vendor/github.com/grpc-ecosystem/grpc-gateway/internal/BUILD.bazel
@@ -0,0 +1,23 @@
+load("@rules_proto//proto:defs.bzl", "proto_library")
+load("@io_bazel_rules_go//go:def.bzl", "go_library")
+load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library")
+
+package(default_visibility = ["//visibility:public"])
+
+proto_library(
+ name = "internal_proto",
+ srcs = ["errors.proto"],
+ deps = ["@com_google_protobuf//:any_proto"],
+)
+
+go_proto_library(
+ name = "internal_go_proto",
+ importpath = "github.com/grpc-ecosystem/grpc-gateway/internal",
+ proto = ":internal_proto",
+)
+
+go_library(
+ name = "go_default_library",
+ embed = [":internal_go_proto"],
+ importpath = "github.com/grpc-ecosystem/grpc-gateway/internal",
+)
diff --git a/vendor/github.com/grpc-ecosystem/grpc-gateway/internal/errors.pb.go b/vendor/github.com/grpc-ecosystem/grpc-gateway/internal/errors.pb.go
new file mode 100644
index 0000000..61101d7
--- /dev/null
+++ b/vendor/github.com/grpc-ecosystem/grpc-gateway/internal/errors.pb.go
@@ -0,0 +1,189 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// source: internal/errors.proto
+
+package internal
+
+import (
+ fmt "fmt"
+ proto "github.com/golang/protobuf/proto"
+ any "github.com/golang/protobuf/ptypes/any"
+ math "math"
+)
+
+// Reference imports to suppress errors if they are not otherwise used.
+var _ = proto.Marshal
+var _ = fmt.Errorf
+var _ = math.Inf
+
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the proto package it is being compiled against.
+// A compilation error at this line likely means your copy of the
+// proto package needs to be updated.
+const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
+
+// Error is the generic error returned from unary RPCs.
+type Error struct {
+ Error string `protobuf:"bytes,1,opt,name=error,proto3" json:"error,omitempty"`
+ // This is to make the error more compatible with users that expect errors to be Status objects:
+ // https://github.com/grpc/grpc/blob/master/src/proto/grpc/status/status.proto
+ // It should be the exact same message as the Error field.
+ Code int32 `protobuf:"varint,2,opt,name=code,proto3" json:"code,omitempty"`
+ Message string `protobuf:"bytes,3,opt,name=message,proto3" json:"message,omitempty"`
+ Details []*any.Any `protobuf:"bytes,4,rep,name=details,proto3" json:"details,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *Error) Reset() { *m = Error{} }
+func (m *Error) String() string { return proto.CompactTextString(m) }
+func (*Error) ProtoMessage() {}
+func (*Error) Descriptor() ([]byte, []int) {
+ return fileDescriptor_9b093362ca6d1e03, []int{0}
+}
+
+func (m *Error) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_Error.Unmarshal(m, b)
+}
+func (m *Error) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_Error.Marshal(b, m, deterministic)
+}
+func (m *Error) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_Error.Merge(m, src)
+}
+func (m *Error) XXX_Size() int {
+ return xxx_messageInfo_Error.Size(m)
+}
+func (m *Error) XXX_DiscardUnknown() {
+ xxx_messageInfo_Error.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_Error proto.InternalMessageInfo
+
+func (m *Error) GetError() string {
+ if m != nil {
+ return m.Error
+ }
+ return ""
+}
+
+func (m *Error) GetCode() int32 {
+ if m != nil {
+ return m.Code
+ }
+ return 0
+}
+
+func (m *Error) GetMessage() string {
+ if m != nil {
+ return m.Message
+ }
+ return ""
+}
+
+func (m *Error) GetDetails() []*any.Any {
+ if m != nil {
+ return m.Details
+ }
+ return nil
+}
+
+// StreamError is a response type which is returned when
+// streaming rpc returns an error.
+type StreamError struct {
+ GrpcCode int32 `protobuf:"varint,1,opt,name=grpc_code,json=grpcCode,proto3" json:"grpc_code,omitempty"`
+ HttpCode int32 `protobuf:"varint,2,opt,name=http_code,json=httpCode,proto3" json:"http_code,omitempty"`
+ Message string `protobuf:"bytes,3,opt,name=message,proto3" json:"message,omitempty"`
+ HttpStatus string `protobuf:"bytes,4,opt,name=http_status,json=httpStatus,proto3" json:"http_status,omitempty"`
+ Details []*any.Any `protobuf:"bytes,5,rep,name=details,proto3" json:"details,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *StreamError) Reset() { *m = StreamError{} }
+func (m *StreamError) String() string { return proto.CompactTextString(m) }
+func (*StreamError) ProtoMessage() {}
+func (*StreamError) Descriptor() ([]byte, []int) {
+ return fileDescriptor_9b093362ca6d1e03, []int{1}
+}
+
+func (m *StreamError) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_StreamError.Unmarshal(m, b)
+}
+func (m *StreamError) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_StreamError.Marshal(b, m, deterministic)
+}
+func (m *StreamError) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_StreamError.Merge(m, src)
+}
+func (m *StreamError) XXX_Size() int {
+ return xxx_messageInfo_StreamError.Size(m)
+}
+func (m *StreamError) XXX_DiscardUnknown() {
+ xxx_messageInfo_StreamError.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_StreamError proto.InternalMessageInfo
+
+func (m *StreamError) GetGrpcCode() int32 {
+ if m != nil {
+ return m.GrpcCode
+ }
+ return 0
+}
+
+func (m *StreamError) GetHttpCode() int32 {
+ if m != nil {
+ return m.HttpCode
+ }
+ return 0
+}
+
+func (m *StreamError) GetMessage() string {
+ if m != nil {
+ return m.Message
+ }
+ return ""
+}
+
+func (m *StreamError) GetHttpStatus() string {
+ if m != nil {
+ return m.HttpStatus
+ }
+ return ""
+}
+
+func (m *StreamError) GetDetails() []*any.Any {
+ if m != nil {
+ return m.Details
+ }
+ return nil
+}
+
+func init() {
+ proto.RegisterType((*Error)(nil), "grpc.gateway.runtime.Error")
+ proto.RegisterType((*StreamError)(nil), "grpc.gateway.runtime.StreamError")
+}
+
+func init() { proto.RegisterFile("internal/errors.proto", fileDescriptor_9b093362ca6d1e03) }
+
+var fileDescriptor_9b093362ca6d1e03 = []byte{
+ // 252 bytes of a gzipped FileDescriptorProto
+ 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x90, 0xc1, 0x4a, 0xc4, 0x30,
+ 0x10, 0x86, 0x89, 0xbb, 0x75, 0xdb, 0xe9, 0x2d, 0x54, 0x88, 0xee, 0xc1, 0xb2, 0xa7, 0x9e, 0x52,
+ 0xd0, 0x27, 0xd0, 0xc5, 0x17, 0xe8, 0xde, 0xbc, 0x2c, 0xd9, 0xdd, 0x31, 0x16, 0xda, 0xa4, 0x24,
+ 0x53, 0xa4, 0xf8, 0x56, 0x3e, 0xa1, 0x24, 0xa5, 0xb0, 0x27, 0xf1, 0xd6, 0xf9, 0xfb, 0xcf, 0x7c,
+ 0x1f, 0x81, 0xbb, 0xd6, 0x10, 0x3a, 0xa3, 0xba, 0x1a, 0x9d, 0xb3, 0xce, 0xcb, 0xc1, 0x59, 0xb2,
+ 0xbc, 0xd0, 0x6e, 0x38, 0x4b, 0xad, 0x08, 0xbf, 0xd4, 0x24, 0xdd, 0x68, 0xa8, 0xed, 0xf1, 0xe1,
+ 0x5e, 0x5b, 0xab, 0x3b, 0xac, 0x63, 0xe7, 0x34, 0x7e, 0xd4, 0xca, 0x4c, 0xf3, 0xc2, 0xee, 0x1b,
+ 0x92, 0xb7, 0x70, 0x80, 0x17, 0x90, 0xc4, 0x4b, 0x82, 0x95, 0xac, 0xca, 0x9a, 0x79, 0xe0, 0x1c,
+ 0xd6, 0x67, 0x7b, 0x41, 0x71, 0x53, 0xb2, 0x2a, 0x69, 0xe2, 0x37, 0x17, 0xb0, 0xe9, 0xd1, 0x7b,
+ 0xa5, 0x51, 0xac, 0x62, 0x77, 0x19, 0xb9, 0x84, 0xcd, 0x05, 0x49, 0xb5, 0x9d, 0x17, 0xeb, 0x72,
+ 0x55, 0xe5, 0x4f, 0x85, 0x9c, 0xc9, 0x72, 0x21, 0xcb, 0x17, 0x33, 0x35, 0x4b, 0x69, 0xf7, 0xc3,
+ 0x20, 0x3f, 0x90, 0x43, 0xd5, 0xcf, 0x0e, 0x5b, 0xc8, 0x82, 0xff, 0x31, 0x22, 0x59, 0x44, 0xa6,
+ 0x21, 0xd8, 0x07, 0xec, 0x16, 0xb2, 0x4f, 0xa2, 0xe1, 0x78, 0xe5, 0x93, 0x86, 0x60, 0xff, 0xb7,
+ 0xd3, 0x23, 0xe4, 0x71, 0xcd, 0x93, 0xa2, 0x31, 0x78, 0x85, 0xbf, 0x10, 0xa2, 0x43, 0x4c, 0xae,
+ 0xa5, 0x93, 0x7f, 0x48, 0xbf, 0xc2, 0x7b, 0xba, 0xbc, 0xfd, 0xe9, 0x36, 0x56, 0x9e, 0x7f, 0x03,
+ 0x00, 0x00, 0xff, 0xff, 0xde, 0x72, 0x6b, 0x83, 0x8e, 0x01, 0x00, 0x00,
+}
diff --git a/vendor/github.com/grpc-ecosystem/grpc-gateway/internal/errors.proto b/vendor/github.com/grpc-ecosystem/grpc-gateway/internal/errors.proto
new file mode 100644
index 0000000..4fb212c
--- /dev/null
+++ b/vendor/github.com/grpc-ecosystem/grpc-gateway/internal/errors.proto
@@ -0,0 +1,26 @@
+syntax = "proto3";
+package grpc.gateway.runtime;
+option go_package = "internal";
+
+import "google/protobuf/any.proto";
+
+// Error is the generic error returned from unary RPCs.
+message Error {
+ string error = 1;
+ // This is to make the error more compatible with users that expect errors to be Status objects:
+ // https://github.com/grpc/grpc/blob/master/src/proto/grpc/status/status.proto
+ // It should be the exact same message as the Error field.
+ int32 code = 2;
+ string message = 3;
+ repeated google.protobuf.Any details = 4;
+}
+
+// StreamError is a response type which is returned when
+// streaming rpc returns an error.
+message StreamError {
+ int32 grpc_code = 1;
+ int32 http_code = 2;
+ string message = 3;
+ string http_status = 4;
+ repeated google.protobuf.Any details = 5;
+}
diff --git a/vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/BUILD.bazel b/vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/BUILD.bazel
new file mode 100644
index 0000000..c4d18f6
--- /dev/null
+++ b/vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/BUILD.bazel
@@ -0,0 +1,86 @@
+load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
+
+package(default_visibility = ["//visibility:public"])
+
+go_library(
+ name = "go_default_library",
+ srcs = [
+ "context.go",
+ "convert.go",
+ "doc.go",
+ "errors.go",
+ "fieldmask.go",
+ "handler.go",
+ "marshal_httpbodyproto.go",
+ "marshal_json.go",
+ "marshal_jsonpb.go",
+ "marshal_proto.go",
+ "marshaler.go",
+ "marshaler_registry.go",
+ "mux.go",
+ "pattern.go",
+ "proto2_convert.go",
+ "proto_errors.go",
+ "query.go",
+ ],
+ importpath = "github.com/grpc-ecosystem/grpc-gateway/runtime",
+ deps = [
+ "//internal:go_default_library",
+ "//utilities:go_default_library",
+ "@com_github_golang_protobuf//descriptor:go_default_library_gen",
+ "@com_github_golang_protobuf//jsonpb:go_default_library_gen",
+ "@com_github_golang_protobuf//proto:go_default_library",
+ "@go_googleapis//google/api:httpbody_go_proto",
+ "@io_bazel_rules_go//proto/wkt:any_go_proto",
+ "@io_bazel_rules_go//proto/wkt:descriptor_go_proto",
+ "@io_bazel_rules_go//proto/wkt:duration_go_proto",
+ "@io_bazel_rules_go//proto/wkt:field_mask_go_proto",
+ "@io_bazel_rules_go//proto/wkt:timestamp_go_proto",
+ "@io_bazel_rules_go//proto/wkt:wrappers_go_proto",
+ "@org_golang_google_grpc//codes:go_default_library",
+ "@org_golang_google_grpc//grpclog:go_default_library",
+ "@org_golang_google_grpc//metadata:go_default_library",
+ "@org_golang_google_grpc//status:go_default_library",
+ ],
+)
+
+go_test(
+ name = "go_default_test",
+ size = "small",
+ srcs = [
+ "context_test.go",
+ "convert_test.go",
+ "errors_test.go",
+ "fieldmask_test.go",
+ "handler_test.go",
+ "marshal_httpbodyproto_test.go",
+ "marshal_json_test.go",
+ "marshal_jsonpb_test.go",
+ "marshal_proto_test.go",
+ "marshaler_registry_test.go",
+ "mux_test.go",
+ "pattern_test.go",
+ "query_test.go",
+ ],
+ embed = [":go_default_library"],
+ deps = [
+ "//internal:go_default_library",
+ "//runtime/internal/examplepb:go_default_library",
+ "//utilities:go_default_library",
+ "@com_github_golang_protobuf//jsonpb:go_default_library_gen",
+ "@com_github_golang_protobuf//proto:go_default_library",
+ "@com_github_golang_protobuf//ptypes:go_default_library_gen",
+ "@go_googleapis//google/api:httpbody_go_proto",
+ "@go_googleapis//google/rpc:errdetails_go_proto",
+ "@io_bazel_rules_go//proto/wkt:duration_go_proto",
+ "@io_bazel_rules_go//proto/wkt:empty_go_proto",
+ "@io_bazel_rules_go//proto/wkt:field_mask_go_proto",
+ "@io_bazel_rules_go//proto/wkt:struct_go_proto",
+ "@io_bazel_rules_go//proto/wkt:timestamp_go_proto",
+ "@io_bazel_rules_go//proto/wkt:wrappers_go_proto",
+ "@org_golang_google_grpc//:go_default_library",
+ "@org_golang_google_grpc//codes:go_default_library",
+ "@org_golang_google_grpc//metadata:go_default_library",
+ "@org_golang_google_grpc//status:go_default_library",
+ ],
+)
diff --git a/vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/context.go b/vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/context.go
new file mode 100644
index 0000000..f808382
--- /dev/null
+++ b/vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/context.go
@@ -0,0 +1,236 @@
+package runtime
+
+import (
+ "context"
+ "encoding/base64"
+ "fmt"
+ "net"
+ "net/http"
+ "net/textproto"
+ "strconv"
+ "strings"
+ "time"
+
+ "google.golang.org/grpc/codes"
+ "google.golang.org/grpc/grpclog"
+ "google.golang.org/grpc/metadata"
+ "google.golang.org/grpc/status"
+)
+
+// MetadataHeaderPrefix is the http prefix that represents custom metadata
+// parameters to or from a gRPC call.
+const MetadataHeaderPrefix = "Grpc-Metadata-"
+
+// MetadataPrefix is prepended to permanent HTTP header keys (as specified
+// by the IANA) when added to the gRPC context.
+const MetadataPrefix = "grpcgateway-"
+
+// MetadataTrailerPrefix is prepended to gRPC metadata as it is converted to
+// HTTP headers in a response handled by grpc-gateway
+const MetadataTrailerPrefix = "Grpc-Trailer-"
+
+const metadataGrpcTimeout = "Grpc-Timeout"
+const metadataHeaderBinarySuffix = "-Bin"
+
+const xForwardedFor = "X-Forwarded-For"
+const xForwardedHost = "X-Forwarded-Host"
+
+var (
+ // DefaultContextTimeout is used for gRPC call context.WithTimeout whenever a Grpc-Timeout inbound
+ // header isn't present. If the value is 0 the sent `context` will not have a timeout.
+ DefaultContextTimeout = 0 * time.Second
+)
+
+func decodeBinHeader(v string) ([]byte, error) {
+ if len(v)%4 == 0 {
+ // Input was padded, or padding was not necessary.
+ return base64.StdEncoding.DecodeString(v)
+ }
+ return base64.RawStdEncoding.DecodeString(v)
+}
+
+/*
+AnnotateContext adds context information such as metadata from the request.
+
+At a minimum, the RemoteAddr is included in the fashion of "X-Forwarded-For",
+except that the forwarded destination is not another HTTP service but rather
+a gRPC service.
+*/
+func AnnotateContext(ctx context.Context, mux *ServeMux, req *http.Request) (context.Context, error) {
+ ctx, md, err := annotateContext(ctx, mux, req)
+ if err != nil {
+ return nil, err
+ }
+ if md == nil {
+ return ctx, nil
+ }
+
+ return metadata.NewOutgoingContext(ctx, md), nil
+}
+
+// AnnotateIncomingContext adds context information such as metadata from the request.
+// Attach metadata as incoming context.
+func AnnotateIncomingContext(ctx context.Context, mux *ServeMux, req *http.Request) (context.Context, error) {
+ ctx, md, err := annotateContext(ctx, mux, req)
+ if err != nil {
+ return nil, err
+ }
+ if md == nil {
+ return ctx, nil
+ }
+
+ return metadata.NewIncomingContext(ctx, md), nil
+}
+
+func annotateContext(ctx context.Context, mux *ServeMux, req *http.Request) (context.Context, metadata.MD, error) {
+ var pairs []string
+ timeout := DefaultContextTimeout
+ if tm := req.Header.Get(metadataGrpcTimeout); tm != "" {
+ var err error
+ timeout, err = timeoutDecode(tm)
+ if err != nil {
+ return nil, nil, status.Errorf(codes.InvalidArgument, "invalid grpc-timeout: %s", tm)
+ }
+ }
+
+ for key, vals := range req.Header {
+ for _, val := range vals {
+ key = textproto.CanonicalMIMEHeaderKey(key)
+ // For backwards-compatibility, pass through 'authorization' header with no prefix.
+ if key == "Authorization" {
+ pairs = append(pairs, "authorization", val)
+ }
+ if h, ok := mux.incomingHeaderMatcher(key); ok {
+ // Handles "-bin" metadata in grpc, since grpc will do another base64
+ // encode before sending to server, we need to decode it first.
+ if strings.HasSuffix(key, metadataHeaderBinarySuffix) {
+ b, err := decodeBinHeader(val)
+ if err != nil {
+ return nil, nil, status.Errorf(codes.InvalidArgument, "invalid binary header %s: %s", key, err)
+ }
+
+ val = string(b)
+ }
+ pairs = append(pairs, h, val)
+ }
+ }
+ }
+ if host := req.Header.Get(xForwardedHost); host != "" {
+ pairs = append(pairs, strings.ToLower(xForwardedHost), host)
+ } else if req.Host != "" {
+ pairs = append(pairs, strings.ToLower(xForwardedHost), req.Host)
+ }
+
+ if addr := req.RemoteAddr; addr != "" {
+ if remoteIP, _, err := net.SplitHostPort(addr); err == nil {
+ if fwd := req.Header.Get(xForwardedFor); fwd == "" {
+ pairs = append(pairs, strings.ToLower(xForwardedFor), remoteIP)
+ } else {
+ pairs = append(pairs, strings.ToLower(xForwardedFor), fmt.Sprintf("%s, %s", fwd, remoteIP))
+ }
+ } else {
+ grpclog.Infof("invalid remote addr: %s", addr)
+ }
+ }
+
+ if timeout != 0 {
+ ctx, _ = context.WithTimeout(ctx, timeout)
+ }
+ if len(pairs) == 0 {
+ return ctx, nil, nil
+ }
+ md := metadata.Pairs(pairs...)
+ for _, mda := range mux.metadataAnnotators {
+ md = metadata.Join(md, mda(ctx, req))
+ }
+ return ctx, md, nil
+}
+
+// ServerMetadata consists of metadata sent from gRPC server.
+type ServerMetadata struct {
+ HeaderMD metadata.MD
+ TrailerMD metadata.MD
+}
+
+type serverMetadataKey struct{}
+
+// NewServerMetadataContext creates a new context with ServerMetadata
+func NewServerMetadataContext(ctx context.Context, md ServerMetadata) context.Context {
+ return context.WithValue(ctx, serverMetadataKey{}, md)
+}
+
+// ServerMetadataFromContext returns the ServerMetadata in ctx
+func ServerMetadataFromContext(ctx context.Context) (md ServerMetadata, ok bool) {
+ md, ok = ctx.Value(serverMetadataKey{}).(ServerMetadata)
+ return
+}
+
+func timeoutDecode(s string) (time.Duration, error) {
+ size := len(s)
+ if size < 2 {
+ return 0, fmt.Errorf("timeout string is too short: %q", s)
+ }
+ d, ok := timeoutUnitToDuration(s[size-1])
+ if !ok {
+ return 0, fmt.Errorf("timeout unit is not recognized: %q", s)
+ }
+ t, err := strconv.ParseInt(s[:size-1], 10, 64)
+ if err != nil {
+ return 0, err
+ }
+ return d * time.Duration(t), nil
+}
+
+func timeoutUnitToDuration(u uint8) (d time.Duration, ok bool) {
+ switch u {
+ case 'H':
+ return time.Hour, true
+ case 'M':
+ return time.Minute, true
+ case 'S':
+ return time.Second, true
+ case 'm':
+ return time.Millisecond, true
+ case 'u':
+ return time.Microsecond, true
+ case 'n':
+ return time.Nanosecond, true
+ default:
+ }
+ return
+}
+
+// isPermanentHTTPHeader checks whether hdr belongs to the list of
+// permenant request headers maintained by IANA.
+// http://www.iana.org/assignments/message-headers/message-headers.xml
+func isPermanentHTTPHeader(hdr string) bool {
+ switch hdr {
+ case
+ "Accept",
+ "Accept-Charset",
+ "Accept-Language",
+ "Accept-Ranges",
+ "Authorization",
+ "Cache-Control",
+ "Content-Type",
+ "Cookie",
+ "Date",
+ "Expect",
+ "From",
+ "Host",
+ "If-Match",
+ "If-Modified-Since",
+ "If-None-Match",
+ "If-Schedule-Tag-Match",
+ "If-Unmodified-Since",
+ "Max-Forwards",
+ "Origin",
+ "Pragma",
+ "Referer",
+ "User-Agent",
+ "Via",
+ "Warning":
+ return true
+ }
+ return false
+}
diff --git a/vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/convert.go b/vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/convert.go
new file mode 100644
index 0000000..2c27934
--- /dev/null
+++ b/vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/convert.go
@@ -0,0 +1,318 @@
+package runtime
+
+import (
+ "encoding/base64"
+ "fmt"
+ "strconv"
+ "strings"
+
+ "github.com/golang/protobuf/jsonpb"
+ "github.com/golang/protobuf/ptypes/duration"
+ "github.com/golang/protobuf/ptypes/timestamp"
+ "github.com/golang/protobuf/ptypes/wrappers"
+)
+
+// String just returns the given string.
+// It is just for compatibility to other types.
+func String(val string) (string, error) {
+ return val, nil
+}
+
+// StringSlice converts 'val' where individual strings are separated by
+// 'sep' into a string slice.
+func StringSlice(val, sep string) ([]string, error) {
+ return strings.Split(val, sep), nil
+}
+
+// Bool converts the given string representation of a boolean value into bool.
+func Bool(val string) (bool, error) {
+ return strconv.ParseBool(val)
+}
+
+// BoolSlice converts 'val' where individual booleans are separated by
+// 'sep' into a bool slice.
+func BoolSlice(val, sep string) ([]bool, error) {
+ s := strings.Split(val, sep)
+ values := make([]bool, len(s))
+ for i, v := range s {
+ value, err := Bool(v)
+ if err != nil {
+ return values, err
+ }
+ values[i] = value
+ }
+ return values, nil
+}
+
+// Float64 converts the given string representation into representation of a floating point number into float64.
+func Float64(val string) (float64, error) {
+ return strconv.ParseFloat(val, 64)
+}
+
+// Float64Slice converts 'val' where individual floating point numbers are separated by
+// 'sep' into a float64 slice.
+func Float64Slice(val, sep string) ([]float64, error) {
+ s := strings.Split(val, sep)
+ values := make([]float64, len(s))
+ for i, v := range s {
+ value, err := Float64(v)
+ if err != nil {
+ return values, err
+ }
+ values[i] = value
+ }
+ return values, nil
+}
+
+// Float32 converts the given string representation of a floating point number into float32.
+func Float32(val string) (float32, error) {
+ f, err := strconv.ParseFloat(val, 32)
+ if err != nil {
+ return 0, err
+ }
+ return float32(f), nil
+}
+
+// Float32Slice converts 'val' where individual floating point numbers are separated by
+// 'sep' into a float32 slice.
+func Float32Slice(val, sep string) ([]float32, error) {
+ s := strings.Split(val, sep)
+ values := make([]float32, len(s))
+ for i, v := range s {
+ value, err := Float32(v)
+ if err != nil {
+ return values, err
+ }
+ values[i] = value
+ }
+ return values, nil
+}
+
+// Int64 converts the given string representation of an integer into int64.
+func Int64(val string) (int64, error) {
+ return strconv.ParseInt(val, 0, 64)
+}
+
+// Int64Slice converts 'val' where individual integers are separated by
+// 'sep' into a int64 slice.
+func Int64Slice(val, sep string) ([]int64, error) {
+ s := strings.Split(val, sep)
+ values := make([]int64, len(s))
+ for i, v := range s {
+ value, err := Int64(v)
+ if err != nil {
+ return values, err
+ }
+ values[i] = value
+ }
+ return values, nil
+}
+
+// Int32 converts the given string representation of an integer into int32.
+func Int32(val string) (int32, error) {
+ i, err := strconv.ParseInt(val, 0, 32)
+ if err != nil {
+ return 0, err
+ }
+ return int32(i), nil
+}
+
+// Int32Slice converts 'val' where individual integers are separated by
+// 'sep' into a int32 slice.
+func Int32Slice(val, sep string) ([]int32, error) {
+ s := strings.Split(val, sep)
+ values := make([]int32, len(s))
+ for i, v := range s {
+ value, err := Int32(v)
+ if err != nil {
+ return values, err
+ }
+ values[i] = value
+ }
+ return values, nil
+}
+
+// Uint64 converts the given string representation of an integer into uint64.
+func Uint64(val string) (uint64, error) {
+ return strconv.ParseUint(val, 0, 64)
+}
+
+// Uint64Slice converts 'val' where individual integers are separated by
+// 'sep' into a uint64 slice.
+func Uint64Slice(val, sep string) ([]uint64, error) {
+ s := strings.Split(val, sep)
+ values := make([]uint64, len(s))
+ for i, v := range s {
+ value, err := Uint64(v)
+ if err != nil {
+ return values, err
+ }
+ values[i] = value
+ }
+ return values, nil
+}
+
+// Uint32 converts the given string representation of an integer into uint32.
+func Uint32(val string) (uint32, error) {
+ i, err := strconv.ParseUint(val, 0, 32)
+ if err != nil {
+ return 0, err
+ }
+ return uint32(i), nil
+}
+
+// Uint32Slice converts 'val' where individual integers are separated by
+// 'sep' into a uint32 slice.
+func Uint32Slice(val, sep string) ([]uint32, error) {
+ s := strings.Split(val, sep)
+ values := make([]uint32, len(s))
+ for i, v := range s {
+ value, err := Uint32(v)
+ if err != nil {
+ return values, err
+ }
+ values[i] = value
+ }
+ return values, nil
+}
+
+// Bytes converts the given string representation of a byte sequence into a slice of bytes
+// A bytes sequence is encoded in URL-safe base64 without padding
+func Bytes(val string) ([]byte, error) {
+ b, err := base64.StdEncoding.DecodeString(val)
+ if err != nil {
+ b, err = base64.URLEncoding.DecodeString(val)
+ if err != nil {
+ return nil, err
+ }
+ }
+ return b, nil
+}
+
+// BytesSlice converts 'val' where individual bytes sequences, encoded in URL-safe
+// base64 without padding, are separated by 'sep' into a slice of bytes slices slice.
+func BytesSlice(val, sep string) ([][]byte, error) {
+ s := strings.Split(val, sep)
+ values := make([][]byte, len(s))
+ for i, v := range s {
+ value, err := Bytes(v)
+ if err != nil {
+ return values, err
+ }
+ values[i] = value
+ }
+ return values, nil
+}
+
+// Timestamp converts the given RFC3339 formatted string into a timestamp.Timestamp.
+func Timestamp(val string) (*timestamp.Timestamp, error) {
+ var r timestamp.Timestamp
+ err := jsonpb.UnmarshalString(val, &r)
+ if err != nil {
+ return nil, err
+ }
+ return &r, nil
+}
+
+// Duration converts the given string into a timestamp.Duration.
+func Duration(val string) (*duration.Duration, error) {
+ var r duration.Duration
+ err := jsonpb.UnmarshalString(val, &r)
+ if err != nil {
+ return nil, err
+ }
+ return &r, nil
+}
+
+// Enum converts the given string into an int32 that should be type casted into the
+// correct enum proto type.
+func Enum(val string, enumValMap map[string]int32) (int32, error) {
+ e, ok := enumValMap[val]
+ if ok {
+ return e, nil
+ }
+
+ i, err := Int32(val)
+ if err != nil {
+ return 0, fmt.Errorf("%s is not valid", val)
+ }
+ for _, v := range enumValMap {
+ if v == i {
+ return i, nil
+ }
+ }
+ return 0, fmt.Errorf("%s is not valid", val)
+}
+
+// EnumSlice converts 'val' where individual enums are separated by 'sep'
+// into a int32 slice. Each individual int32 should be type casted into the
+// correct enum proto type.
+func EnumSlice(val, sep string, enumValMap map[string]int32) ([]int32, error) {
+ s := strings.Split(val, sep)
+ values := make([]int32, len(s))
+ for i, v := range s {
+ value, err := Enum(v, enumValMap)
+ if err != nil {
+ return values, err
+ }
+ values[i] = value
+ }
+ return values, nil
+}
+
+/*
+ Support fot google.protobuf.wrappers on top of primitive types
+*/
+
+// StringValue well-known type support as wrapper around string type
+func StringValue(val string) (*wrappers.StringValue, error) {
+ return &wrappers.StringValue{Value: val}, nil
+}
+
+// FloatValue well-known type support as wrapper around float32 type
+func FloatValue(val string) (*wrappers.FloatValue, error) {
+ parsedVal, err := Float32(val)
+ return &wrappers.FloatValue{Value: parsedVal}, err
+}
+
+// DoubleValue well-known type support as wrapper around float64 type
+func DoubleValue(val string) (*wrappers.DoubleValue, error) {
+ parsedVal, err := Float64(val)
+ return &wrappers.DoubleValue{Value: parsedVal}, err
+}
+
+// BoolValue well-known type support as wrapper around bool type
+func BoolValue(val string) (*wrappers.BoolValue, error) {
+ parsedVal, err := Bool(val)
+ return &wrappers.BoolValue{Value: parsedVal}, err
+}
+
+// Int32Value well-known type support as wrapper around int32 type
+func Int32Value(val string) (*wrappers.Int32Value, error) {
+ parsedVal, err := Int32(val)
+ return &wrappers.Int32Value{Value: parsedVal}, err
+}
+
+// UInt32Value well-known type support as wrapper around uint32 type
+func UInt32Value(val string) (*wrappers.UInt32Value, error) {
+ parsedVal, err := Uint32(val)
+ return &wrappers.UInt32Value{Value: parsedVal}, err
+}
+
+// Int64Value well-known type support as wrapper around int64 type
+func Int64Value(val string) (*wrappers.Int64Value, error) {
+ parsedVal, err := Int64(val)
+ return &wrappers.Int64Value{Value: parsedVal}, err
+}
+
+// UInt64Value well-known type support as wrapper around uint64 type
+func UInt64Value(val string) (*wrappers.UInt64Value, error) {
+ parsedVal, err := Uint64(val)
+ return &wrappers.UInt64Value{Value: parsedVal}, err
+}
+
+// BytesValue well-known type support as wrapper around bytes[] type
+func BytesValue(val string) (*wrappers.BytesValue, error) {
+ parsedVal, err := Bytes(val)
+ return &wrappers.BytesValue{Value: parsedVal}, err
+}
diff --git a/vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/doc.go b/vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/doc.go
new file mode 100644
index 0000000..b6e5ddf
--- /dev/null
+++ b/vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/doc.go
@@ -0,0 +1,5 @@
+/*
+Package runtime contains runtime helper functions used by
+servers which protoc-gen-grpc-gateway generates.
+*/
+package runtime
diff --git a/vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/errors.go b/vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/errors.go
new file mode 100644
index 0000000..65a5dc6
--- /dev/null
+++ b/vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/errors.go
@@ -0,0 +1,169 @@
+package runtime
+
+import (
+ "context"
+ "io"
+ "net/http"
+
+ "github.com/grpc-ecosystem/grpc-gateway/internal"
+ "google.golang.org/grpc/codes"
+ "google.golang.org/grpc/grpclog"
+ "google.golang.org/grpc/status"
+)
+
+// HTTPStatusFromCode converts a gRPC error code into the corresponding HTTP response status.
+// See: https://github.com/googleapis/googleapis/blob/master/google/rpc/code.proto
+func HTTPStatusFromCode(code codes.Code) int {
+ switch code {
+ case codes.OK:
+ return http.StatusOK
+ case codes.Canceled:
+ return http.StatusRequestTimeout
+ case codes.Unknown:
+ return http.StatusInternalServerError
+ case codes.InvalidArgument:
+ return http.StatusBadRequest
+ case codes.DeadlineExceeded:
+ return http.StatusGatewayTimeout
+ case codes.NotFound:
+ return http.StatusNotFound
+ case codes.AlreadyExists:
+ return http.StatusConflict
+ case codes.PermissionDenied:
+ return http.StatusForbidden
+ case codes.Unauthenticated:
+ return http.StatusUnauthorized
+ case codes.ResourceExhausted:
+ return http.StatusTooManyRequests
+ case codes.FailedPrecondition:
+ // Note, this deliberately doesn't translate to the similarly named '412 Precondition Failed' HTTP response status.
+ return http.StatusBadRequest
+ case codes.Aborted:
+ return http.StatusConflict
+ case codes.OutOfRange:
+ return http.StatusBadRequest
+ case codes.Unimplemented:
+ return http.StatusNotImplemented
+ case codes.Internal:
+ return http.StatusInternalServerError
+ case codes.Unavailable:
+ return http.StatusServiceUnavailable
+ case codes.DataLoss:
+ return http.StatusInternalServerError
+ }
+
+ grpclog.Infof("Unknown gRPC error code: %v", code)
+ return http.StatusInternalServerError
+}
+
+var (
+ // HTTPError replies to the request with an error.
+ //
+ // HTTPError is called:
+ // - From generated per-endpoint gateway handler code, when calling the backend results in an error.
+ // - From gateway runtime code, when forwarding the response message results in an error.
+ //
+ // The default value for HTTPError calls the custom error handler configured on the ServeMux via the
+ // WithProtoErrorHandler serve option if that option was used, calling GlobalHTTPErrorHandler otherwise.
+ //
+ // To customize the error handling of a particular ServeMux instance, use the WithProtoErrorHandler
+ // serve option.
+ //
+ // To customize the error format for all ServeMux instances not using the WithProtoErrorHandler serve
+ // option, set GlobalHTTPErrorHandler to a custom function.
+ //
+ // Setting this variable directly to customize error format is deprecated.
+ HTTPError = MuxOrGlobalHTTPError
+
+ // GlobalHTTPErrorHandler is the HTTPError handler for all ServeMux instances not using the
+ // WithProtoErrorHandler serve option.
+ //
+ // You can set a custom function to this variable to customize error format.
+ GlobalHTTPErrorHandler = DefaultHTTPError
+
+ // OtherErrorHandler handles gateway errors from parsing and routing client requests for all
+ // ServeMux instances not using the WithProtoErrorHandler serve option.
+ //
+ // It returns the following error codes: StatusMethodNotAllowed StatusNotFound StatusBadRequest
+ //
+ // To customize parsing and routing error handling of a particular ServeMux instance, use the
+ // WithProtoErrorHandler serve option.
+ //
+ // To customize parsing and routing error handling of all ServeMux instances not using the
+ // WithProtoErrorHandler serve option, set a custom function to this variable.
+ OtherErrorHandler = DefaultOtherErrorHandler
+)
+
+// MuxOrGlobalHTTPError uses the mux-configured error handler, falling back to GlobalErrorHandler.
+func MuxOrGlobalHTTPError(ctx context.Context, mux *ServeMux, marshaler Marshaler, w http.ResponseWriter, r *http.Request, err error) {
+ if mux.protoErrorHandler != nil {
+ mux.protoErrorHandler(ctx, mux, marshaler, w, r, err)
+ } else {
+ GlobalHTTPErrorHandler(ctx, mux, marshaler, w, r, err)
+ }
+}
+
+// DefaultHTTPError is the default implementation of HTTPError.
+// If "err" is an error from gRPC system, the function replies with the status code mapped by HTTPStatusFromCode.
+// If otherwise, it replies with http.StatusInternalServerError.
+//
+// The response body returned by this function is a JSON object,
+// which contains a member whose key is "error" and whose value is err.Error().
+func DefaultHTTPError(ctx context.Context, mux *ServeMux, marshaler Marshaler, w http.ResponseWriter, _ *http.Request, err error) {
+ const fallback = `{"error": "failed to marshal error message"}`
+
+ s, ok := status.FromError(err)
+ if !ok {
+ s = status.New(codes.Unknown, err.Error())
+ }
+
+ w.Header().Del("Trailer")
+
+ contentType := marshaler.ContentType()
+ // Check marshaler on run time in order to keep backwards compatability
+ // An interface param needs to be added to the ContentType() function on
+ // the Marshal interface to be able to remove this check
+ if typeMarshaler, ok := marshaler.(contentTypeMarshaler); ok {
+ pb := s.Proto()
+ contentType = typeMarshaler.ContentTypeFromMessage(pb)
+ }
+ w.Header().Set("Content-Type", contentType)
+
+ body := &internal.Error{
+ Error: s.Message(),
+ Message: s.Message(),
+ Code: int32(s.Code()),
+ Details: s.Proto().GetDetails(),
+ }
+
+ buf, merr := marshaler.Marshal(body)
+ if merr != nil {
+ grpclog.Infof("Failed to marshal error message %q: %v", body, merr)
+ w.WriteHeader(http.StatusInternalServerError)
+ if _, err := io.WriteString(w, fallback); err != nil {
+ grpclog.Infof("Failed to write response: %v", err)
+ }
+ return
+ }
+
+ md, ok := ServerMetadataFromContext(ctx)
+ if !ok {
+ grpclog.Infof("Failed to extract ServerMetadata from context")
+ }
+
+ handleForwardResponseServerMetadata(w, mux, md)
+ handleForwardResponseTrailerHeader(w, md)
+ st := HTTPStatusFromCode(s.Code())
+ w.WriteHeader(st)
+ if _, err := w.Write(buf); err != nil {
+ grpclog.Infof("Failed to write response: %v", err)
+ }
+
+ handleForwardResponseTrailer(w, md)
+}
+
+// DefaultOtherErrorHandler is the default implementation of OtherErrorHandler.
+// It simply writes a string representation of the given error into "w".
+func DefaultOtherErrorHandler(w http.ResponseWriter, _ *http.Request, msg string, code int) {
+ http.Error(w, msg, code)
+}
diff --git a/vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/fieldmask.go b/vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/fieldmask.go
new file mode 100644
index 0000000..341aad5
--- /dev/null
+++ b/vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/fieldmask.go
@@ -0,0 +1,82 @@
+package runtime
+
+import (
+ "encoding/json"
+ "io"
+ "strings"
+
+ descriptor2 "github.com/golang/protobuf/descriptor"
+ "github.com/golang/protobuf/protoc-gen-go/descriptor"
+ "google.golang.org/genproto/protobuf/field_mask"
+)
+
+func translateName(name string, md *descriptor.DescriptorProto) (string, *descriptor.DescriptorProto) {
+ // TODO - should really gate this with a test that the marshaller has used json names
+ if md != nil {
+ for _, f := range md.Field {
+ if f.JsonName != nil && f.Name != nil && *f.JsonName == name {
+ var subType *descriptor.DescriptorProto
+
+ // If the field has a TypeName then we retrieve the nested type for translating the embedded message names.
+ if f.TypeName != nil {
+ typeSplit := strings.Split(*f.TypeName, ".")
+ typeName := typeSplit[len(typeSplit)-1]
+ for _, t := range md.NestedType {
+ if typeName == *t.Name {
+ subType = t
+ }
+ }
+ }
+ return *f.Name, subType
+ }
+ }
+ }
+ return name, nil
+}
+
+// FieldMaskFromRequestBody creates a FieldMask printing all complete paths from the JSON body.
+func FieldMaskFromRequestBody(r io.Reader, md *descriptor.DescriptorProto) (*field_mask.FieldMask, error) {
+ fm := &field_mask.FieldMask{}
+ var root interface{}
+ if err := json.NewDecoder(r).Decode(&root); err != nil {
+ if err == io.EOF {
+ return fm, nil
+ }
+ return nil, err
+ }
+
+ queue := []fieldMaskPathItem{{node: root, md: md}}
+ for len(queue) > 0 {
+ // dequeue an item
+ item := queue[0]
+ queue = queue[1:]
+
+ if m, ok := item.node.(map[string]interface{}); ok {
+ // if the item is an object, then enqueue all of its children
+ for k, v := range m {
+ protoName, subMd := translateName(k, item.md)
+ if subMsg, ok := v.(descriptor2.Message); ok {
+ _, subMd = descriptor2.ForMessage(subMsg)
+ }
+ queue = append(queue, fieldMaskPathItem{path: append(item.path, protoName), node: v, md: subMd})
+ }
+ } else if len(item.path) > 0 {
+ // otherwise, it's a leaf node so print its path
+ fm.Paths = append(fm.Paths, strings.Join(item.path, "."))
+ }
+ }
+
+ return fm, nil
+}
+
+// fieldMaskPathItem stores a in-progress deconstruction of a path for a fieldmask
+type fieldMaskPathItem struct {
+ // the list of prior fields leading up to node
+ path []string
+
+ // a generic decoded json object the current item to inspect for further path extraction
+ node interface{}
+
+ // descriptor for parent message
+ md *descriptor.DescriptorProto
+}
diff --git a/vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/handler.go b/vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/handler.go
new file mode 100644
index 0000000..b894da8
--- /dev/null
+++ b/vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/handler.go
@@ -0,0 +1,209 @@
+package runtime
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "io"
+ "net/http"
+ "net/textproto"
+
+ "github.com/golang/protobuf/proto"
+ "github.com/grpc-ecosystem/grpc-gateway/internal"
+ "google.golang.org/grpc/grpclog"
+)
+
+var errEmptyResponse = errors.New("empty response")
+
+// ForwardResponseStream forwards the stream from gRPC server to REST client.
+func ForwardResponseStream(ctx context.Context, mux *ServeMux, marshaler Marshaler, w http.ResponseWriter, req *http.Request, recv func() (proto.Message, error), opts ...func(context.Context, http.ResponseWriter, proto.Message) error) {
+ f, ok := w.(http.Flusher)
+ if !ok {
+ grpclog.Infof("Flush not supported in %T", w)
+ http.Error(w, "unexpected type of web server", http.StatusInternalServerError)
+ return
+ }
+
+ md, ok := ServerMetadataFromContext(ctx)
+ if !ok {
+ grpclog.Infof("Failed to extract ServerMetadata from context")
+ http.Error(w, "unexpected error", http.StatusInternalServerError)
+ return
+ }
+ handleForwardResponseServerMetadata(w, mux, md)
+
+ w.Header().Set("Transfer-Encoding", "chunked")
+ w.Header().Set("Content-Type", marshaler.ContentType())
+ if err := handleForwardResponseOptions(ctx, w, nil, opts); err != nil {
+ HTTPError(ctx, mux, marshaler, w, req, err)
+ return
+ }
+
+ var delimiter []byte
+ if d, ok := marshaler.(Delimited); ok {
+ delimiter = d.Delimiter()
+ } else {
+ delimiter = []byte("\n")
+ }
+
+ var wroteHeader bool
+ for {
+ resp, err := recv()
+ if err == io.EOF {
+ return
+ }
+ if err != nil {
+ handleForwardResponseStreamError(ctx, wroteHeader, marshaler, w, req, mux, err)
+ return
+ }
+ if err := handleForwardResponseOptions(ctx, w, resp, opts); err != nil {
+ handleForwardResponseStreamError(ctx, wroteHeader, marshaler, w, req, mux, err)
+ return
+ }
+
+ buf, err := marshaler.Marshal(streamChunk(ctx, resp, mux.streamErrorHandler))
+ if err != nil {
+ grpclog.Infof("Failed to marshal response chunk: %v", err)
+ handleForwardResponseStreamError(ctx, wroteHeader, marshaler, w, req, mux, err)
+ return
+ }
+ if _, err = w.Write(buf); err != nil {
+ grpclog.Infof("Failed to send response chunk: %v", err)
+ return
+ }
+ wroteHeader = true
+ if _, err = w.Write(delimiter); err != nil {
+ grpclog.Infof("Failed to send delimiter chunk: %v", err)
+ return
+ }
+ f.Flush()
+ }
+}
+
+func handleForwardResponseServerMetadata(w http.ResponseWriter, mux *ServeMux, md ServerMetadata) {
+ for k, vs := range md.HeaderMD {
+ if h, ok := mux.outgoingHeaderMatcher(k); ok {
+ for _, v := range vs {
+ w.Header().Add(h, v)
+ }
+ }
+ }
+}
+
+func handleForwardResponseTrailerHeader(w http.ResponseWriter, md ServerMetadata) {
+ for k := range md.TrailerMD {
+ tKey := textproto.CanonicalMIMEHeaderKey(fmt.Sprintf("%s%s", MetadataTrailerPrefix, k))
+ w.Header().Add("Trailer", tKey)
+ }
+}
+
+func handleForwardResponseTrailer(w http.ResponseWriter, md ServerMetadata) {
+ for k, vs := range md.TrailerMD {
+ tKey := fmt.Sprintf("%s%s", MetadataTrailerPrefix, k)
+ for _, v := range vs {
+ w.Header().Add(tKey, v)
+ }
+ }
+}
+
+// responseBody interface contains method for getting field for marshaling to the response body
+// this method is generated for response struct from the value of `response_body` in the `google.api.HttpRule`
+type responseBody interface {
+ XXX_ResponseBody() interface{}
+}
+
+// ForwardResponseMessage forwards the message "resp" from gRPC server to REST client.
+func ForwardResponseMessage(ctx context.Context, mux *ServeMux, marshaler Marshaler, w http.ResponseWriter, req *http.Request, resp proto.Message, opts ...func(context.Context, http.ResponseWriter, proto.Message) error) {
+ md, ok := ServerMetadataFromContext(ctx)
+ if !ok {
+ grpclog.Infof("Failed to extract ServerMetadata from context")
+ }
+
+ handleForwardResponseServerMetadata(w, mux, md)
+ handleForwardResponseTrailerHeader(w, md)
+
+ contentType := marshaler.ContentType()
+ // Check marshaler on run time in order to keep backwards compatability
+ // An interface param needs to be added to the ContentType() function on
+ // the Marshal interface to be able to remove this check
+ if typeMarshaler, ok := marshaler.(contentTypeMarshaler); ok {
+ contentType = typeMarshaler.ContentTypeFromMessage(resp)
+ }
+ w.Header().Set("Content-Type", contentType)
+
+ if err := handleForwardResponseOptions(ctx, w, resp, opts); err != nil {
+ HTTPError(ctx, mux, marshaler, w, req, err)
+ return
+ }
+ var buf []byte
+ var err error
+ if rb, ok := resp.(responseBody); ok {
+ buf, err = marshaler.Marshal(rb.XXX_ResponseBody())
+ } else {
+ buf, err = marshaler.Marshal(resp)
+ }
+ if err != nil {
+ grpclog.Infof("Marshal error: %v", err)
+ HTTPError(ctx, mux, marshaler, w, req, err)
+ return
+ }
+
+ if _, err = w.Write(buf); err != nil {
+ grpclog.Infof("Failed to write response: %v", err)
+ }
+
+ handleForwardResponseTrailer(w, md)
+}
+
+func handleForwardResponseOptions(ctx context.Context, w http.ResponseWriter, resp proto.Message, opts []func(context.Context, http.ResponseWriter, proto.Message) error) error {
+ if len(opts) == 0 {
+ return nil
+ }
+ for _, opt := range opts {
+ if err := opt(ctx, w, resp); err != nil {
+ grpclog.Infof("Error handling ForwardResponseOptions: %v", err)
+ return err
+ }
+ }
+ return nil
+}
+
+func handleForwardResponseStreamError(ctx context.Context, wroteHeader bool, marshaler Marshaler, w http.ResponseWriter, req *http.Request, mux *ServeMux, err error) {
+ serr := streamError(ctx, mux.streamErrorHandler, err)
+ if !wroteHeader {
+ w.WriteHeader(int(serr.HttpCode))
+ }
+ buf, merr := marshaler.Marshal(errorChunk(serr))
+ if merr != nil {
+ grpclog.Infof("Failed to marshal an error: %v", merr)
+ return
+ }
+ if _, werr := w.Write(buf); werr != nil {
+ grpclog.Infof("Failed to notify error to client: %v", werr)
+ return
+ }
+}
+
+// streamChunk returns a chunk in a response stream for the given result. The
+// given errHandler is used to render an error chunk if result is nil.
+func streamChunk(ctx context.Context, result proto.Message, errHandler StreamErrorHandlerFunc) map[string]proto.Message {
+ if result == nil {
+ return errorChunk(streamError(ctx, errHandler, errEmptyResponse))
+ }
+ return map[string]proto.Message{"result": result}
+}
+
+// streamError returns the payload for the final message in a response stream
+// that represents the given err.
+func streamError(ctx context.Context, errHandler StreamErrorHandlerFunc, err error) *StreamError {
+ serr := errHandler(ctx, err)
+ if serr != nil {
+ return serr
+ }
+ // TODO: log about misbehaving stream error handler?
+ return DefaultHTTPStreamErrorHandler(ctx, err)
+}
+
+func errorChunk(err *StreamError) map[string]proto.Message {
+ return map[string]proto.Message{"error": (*internal.StreamError)(err)}
+}
diff --git a/vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/marshal_httpbodyproto.go b/vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/marshal_httpbodyproto.go
new file mode 100644
index 0000000..f55285b
--- /dev/null
+++ b/vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/marshal_httpbodyproto.go
@@ -0,0 +1,43 @@
+package runtime
+
+import (
+ "google.golang.org/genproto/googleapis/api/httpbody"
+)
+
+// SetHTTPBodyMarshaler overwrite the default marshaler with the HTTPBodyMarshaler
+func SetHTTPBodyMarshaler(serveMux *ServeMux) {
+ serveMux.marshalers.mimeMap[MIMEWildcard] = &HTTPBodyMarshaler{
+ Marshaler: &JSONPb{OrigName: true},
+ }
+}
+
+// HTTPBodyMarshaler is a Marshaler which supports marshaling of a
+// google.api.HttpBody message as the full response body if it is
+// the actual message used as the response. If not, then this will
+// simply fallback to the Marshaler specified as its default Marshaler.
+type HTTPBodyMarshaler struct {
+ Marshaler
+}
+
+// ContentType implementation to keep backwards compatability with marshal interface
+func (h *HTTPBodyMarshaler) ContentType() string {
+ return h.ContentTypeFromMessage(nil)
+}
+
+// ContentTypeFromMessage in case v is a google.api.HttpBody message it returns
+// its specified content type otherwise fall back to the default Marshaler.
+func (h *HTTPBodyMarshaler) ContentTypeFromMessage(v interface{}) string {
+ if httpBody, ok := v.(*httpbody.HttpBody); ok {
+ return httpBody.GetContentType()
+ }
+ return h.Marshaler.ContentType()
+}
+
+// Marshal marshals "v" by returning the body bytes if v is a
+// google.api.HttpBody message, otherwise it falls back to the default Marshaler.
+func (h *HTTPBodyMarshaler) Marshal(v interface{}) ([]byte, error) {
+ if httpBody, ok := v.(*httpbody.HttpBody); ok {
+ return httpBody.Data, nil
+ }
+ return h.Marshaler.Marshal(v)
+}
diff --git a/vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/marshal_json.go b/vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/marshal_json.go
new file mode 100644
index 0000000..f9d3a58
--- /dev/null
+++ b/vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/marshal_json.go
@@ -0,0 +1,45 @@
+package runtime
+
+import (
+ "encoding/json"
+ "io"
+)
+
+// JSONBuiltin is a Marshaler which marshals/unmarshals into/from JSON
+// with the standard "encoding/json" package of Golang.
+// Although it is generally faster for simple proto messages than JSONPb,
+// it does not support advanced features of protobuf, e.g. map, oneof, ....
+//
+// The NewEncoder and NewDecoder types return *json.Encoder and
+// *json.Decoder respectively.
+type JSONBuiltin struct{}
+
+// ContentType always Returns "application/json".
+func (*JSONBuiltin) ContentType() string {
+ return "application/json"
+}
+
+// Marshal marshals "v" into JSON
+func (j *JSONBuiltin) Marshal(v interface{}) ([]byte, error) {
+ return json.Marshal(v)
+}
+
+// Unmarshal unmarshals JSON data into "v".
+func (j *JSONBuiltin) Unmarshal(data []byte, v interface{}) error {
+ return json.Unmarshal(data, v)
+}
+
+// NewDecoder returns a Decoder which reads JSON stream from "r".
+func (j *JSONBuiltin) NewDecoder(r io.Reader) Decoder {
+ return json.NewDecoder(r)
+}
+
+// NewEncoder returns an Encoder which writes JSON stream into "w".
+func (j *JSONBuiltin) NewEncoder(w io.Writer) Encoder {
+ return json.NewEncoder(w)
+}
+
+// Delimiter for newline encoded JSON streams.
+func (j *JSONBuiltin) Delimiter() []byte {
+ return []byte("\n")
+}
diff --git a/vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/marshal_jsonpb.go b/vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/marshal_jsonpb.go
new file mode 100644
index 0000000..f0de351
--- /dev/null
+++ b/vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/marshal_jsonpb.go
@@ -0,0 +1,262 @@
+package runtime
+
+import (
+ "bytes"
+ "encoding/json"
+ "fmt"
+ "io"
+ "reflect"
+
+ "github.com/golang/protobuf/jsonpb"
+ "github.com/golang/protobuf/proto"
+)
+
+// JSONPb is a Marshaler which marshals/unmarshals into/from JSON
+// with the "github.com/golang/protobuf/jsonpb".
+// It supports fully functionality of protobuf unlike JSONBuiltin.
+//
+// The NewDecoder method returns a DecoderWrapper, so the underlying
+// *json.Decoder methods can be used.
+type JSONPb jsonpb.Marshaler
+
+// ContentType always returns "application/json".
+func (*JSONPb) ContentType() string {
+ return "application/json"
+}
+
+// Marshal marshals "v" into JSON.
+func (j *JSONPb) Marshal(v interface{}) ([]byte, error) {
+ if _, ok := v.(proto.Message); !ok {
+ return j.marshalNonProtoField(v)
+ }
+
+ var buf bytes.Buffer
+ if err := j.marshalTo(&buf, v); err != nil {
+ return nil, err
+ }
+ return buf.Bytes(), nil
+}
+
+func (j *JSONPb) marshalTo(w io.Writer, v interface{}) error {
+ p, ok := v.(proto.Message)
+ if !ok {
+ buf, err := j.marshalNonProtoField(v)
+ if err != nil {
+ return err
+ }
+ _, err = w.Write(buf)
+ return err
+ }
+ return (*jsonpb.Marshaler)(j).Marshal(w, p)
+}
+
+var (
+ // protoMessageType is stored to prevent constant lookup of the same type at runtime.
+ protoMessageType = reflect.TypeOf((*proto.Message)(nil)).Elem()
+)
+
+// marshalNonProto marshals a non-message field of a protobuf message.
+// This function does not correctly marshals arbitrary data structure into JSON,
+// but it is only capable of marshaling non-message field values of protobuf,
+// i.e. primitive types, enums; pointers to primitives or enums; maps from
+// integer/string types to primitives/enums/pointers to messages.
+func (j *JSONPb) marshalNonProtoField(v interface{}) ([]byte, error) {
+ if v == nil {
+ return []byte("null"), nil
+ }
+ rv := reflect.ValueOf(v)
+ for rv.Kind() == reflect.Ptr {
+ if rv.IsNil() {
+ return []byte("null"), nil
+ }
+ rv = rv.Elem()
+ }
+
+ if rv.Kind() == reflect.Slice {
+ if rv.IsNil() {
+ if j.EmitDefaults {
+ return []byte("[]"), nil
+ }
+ return []byte("null"), nil
+ }
+
+ if rv.Type().Elem().Implements(protoMessageType) {
+ var buf bytes.Buffer
+ err := buf.WriteByte('[')
+ if err != nil {
+ return nil, err
+ }
+ for i := 0; i < rv.Len(); i++ {
+ if i != 0 {
+ err = buf.WriteByte(',')
+ if err != nil {
+ return nil, err
+ }
+ }
+ if err = (*jsonpb.Marshaler)(j).Marshal(&buf, rv.Index(i).Interface().(proto.Message)); err != nil {
+ return nil, err
+ }
+ }
+ err = buf.WriteByte(']')
+ if err != nil {
+ return nil, err
+ }
+
+ return buf.Bytes(), nil
+ }
+ }
+
+ if rv.Kind() == reflect.Map {
+ m := make(map[string]*json.RawMessage)
+ for _, k := range rv.MapKeys() {
+ buf, err := j.Marshal(rv.MapIndex(k).Interface())
+ if err != nil {
+ return nil, err
+ }
+ m[fmt.Sprintf("%v", k.Interface())] = (*json.RawMessage)(&buf)
+ }
+ if j.Indent != "" {
+ return json.MarshalIndent(m, "", j.Indent)
+ }
+ return json.Marshal(m)
+ }
+ if enum, ok := rv.Interface().(protoEnum); ok && !j.EnumsAsInts {
+ return json.Marshal(enum.String())
+ }
+ return json.Marshal(rv.Interface())
+}
+
+// Unmarshal unmarshals JSON "data" into "v"
+func (j *JSONPb) Unmarshal(data []byte, v interface{}) error {
+ return unmarshalJSONPb(data, v)
+}
+
+// NewDecoder returns a Decoder which reads JSON stream from "r".
+func (j *JSONPb) NewDecoder(r io.Reader) Decoder {
+ d := json.NewDecoder(r)
+ return DecoderWrapper{Decoder: d}
+}
+
+// DecoderWrapper is a wrapper around a *json.Decoder that adds
+// support for protos to the Decode method.
+type DecoderWrapper struct {
+ *json.Decoder
+}
+
+// Decode wraps the embedded decoder's Decode method to support
+// protos using a jsonpb.Unmarshaler.
+func (d DecoderWrapper) Decode(v interface{}) error {
+ return decodeJSONPb(d.Decoder, v)
+}
+
+// NewEncoder returns an Encoder which writes JSON stream into "w".
+func (j *JSONPb) NewEncoder(w io.Writer) Encoder {
+ return EncoderFunc(func(v interface{}) error {
+ if err := j.marshalTo(w, v); err != nil {
+ return err
+ }
+ // mimic json.Encoder by adding a newline (makes output
+ // easier to read when it contains multiple encoded items)
+ _, err := w.Write(j.Delimiter())
+ return err
+ })
+}
+
+func unmarshalJSONPb(data []byte, v interface{}) error {
+ d := json.NewDecoder(bytes.NewReader(data))
+ return decodeJSONPb(d, v)
+}
+
+func decodeJSONPb(d *json.Decoder, v interface{}) error {
+ p, ok := v.(proto.Message)
+ if !ok {
+ return decodeNonProtoField(d, v)
+ }
+ unmarshaler := &jsonpb.Unmarshaler{AllowUnknownFields: allowUnknownFields}
+ return unmarshaler.UnmarshalNext(d, p)
+}
+
+func decodeNonProtoField(d *json.Decoder, v interface{}) error {
+ rv := reflect.ValueOf(v)
+ if rv.Kind() != reflect.Ptr {
+ return fmt.Errorf("%T is not a pointer", v)
+ }
+ for rv.Kind() == reflect.Ptr {
+ if rv.IsNil() {
+ rv.Set(reflect.New(rv.Type().Elem()))
+ }
+ if rv.Type().ConvertibleTo(typeProtoMessage) {
+ unmarshaler := &jsonpb.Unmarshaler{AllowUnknownFields: allowUnknownFields}
+ return unmarshaler.UnmarshalNext(d, rv.Interface().(proto.Message))
+ }
+ rv = rv.Elem()
+ }
+ if rv.Kind() == reflect.Map {
+ if rv.IsNil() {
+ rv.Set(reflect.MakeMap(rv.Type()))
+ }
+ conv, ok := convFromType[rv.Type().Key().Kind()]
+ if !ok {
+ return fmt.Errorf("unsupported type of map field key: %v", rv.Type().Key())
+ }
+
+ m := make(map[string]*json.RawMessage)
+ if err := d.Decode(&m); err != nil {
+ return err
+ }
+ for k, v := range m {
+ result := conv.Call([]reflect.Value{reflect.ValueOf(k)})
+ if err := result[1].Interface(); err != nil {
+ return err.(error)
+ }
+ bk := result[0]
+ bv := reflect.New(rv.Type().Elem())
+ if err := unmarshalJSONPb([]byte(*v), bv.Interface()); err != nil {
+ return err
+ }
+ rv.SetMapIndex(bk, bv.Elem())
+ }
+ return nil
+ }
+ if _, ok := rv.Interface().(protoEnum); ok {
+ var repr interface{}
+ if err := d.Decode(&repr); err != nil {
+ return err
+ }
+ switch repr.(type) {
+ case string:
+ // TODO(yugui) Should use proto.StructProperties?
+ return fmt.Errorf("unmarshaling of symbolic enum %q not supported: %T", repr, rv.Interface())
+ case float64:
+ rv.Set(reflect.ValueOf(int32(repr.(float64))).Convert(rv.Type()))
+ return nil
+ default:
+ return fmt.Errorf("cannot assign %#v into Go type %T", repr, rv.Interface())
+ }
+ }
+ return d.Decode(v)
+}
+
+type protoEnum interface {
+ fmt.Stringer
+ EnumDescriptor() ([]byte, []int)
+}
+
+var typeProtoMessage = reflect.TypeOf((*proto.Message)(nil)).Elem()
+
+// Delimiter for newline encoded JSON streams.
+func (j *JSONPb) Delimiter() []byte {
+ return []byte("\n")
+}
+
+// allowUnknownFields helps not to return an error when the destination
+// is a struct and the input contains object keys which do not match any
+// non-ignored, exported fields in the destination.
+var allowUnknownFields = true
+
+// DisallowUnknownFields enables option in decoder (unmarshaller) to
+// return an error when it finds an unknown field. This function must be
+// called before using the JSON marshaller.
+func DisallowUnknownFields() {
+ allowUnknownFields = false
+}
diff --git a/vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/marshal_proto.go b/vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/marshal_proto.go
new file mode 100644
index 0000000..f65d1a2
--- /dev/null
+++ b/vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/marshal_proto.go
@@ -0,0 +1,62 @@
+package runtime
+
+import (
+ "io"
+
+ "errors"
+ "github.com/golang/protobuf/proto"
+ "io/ioutil"
+)
+
+// ProtoMarshaller is a Marshaller which marshals/unmarshals into/from serialize proto bytes
+type ProtoMarshaller struct{}
+
+// ContentType always returns "application/octet-stream".
+func (*ProtoMarshaller) ContentType() string {
+ return "application/octet-stream"
+}
+
+// Marshal marshals "value" into Proto
+func (*ProtoMarshaller) Marshal(value interface{}) ([]byte, error) {
+ message, ok := value.(proto.Message)
+ if !ok {
+ return nil, errors.New("unable to marshal non proto field")
+ }
+ return proto.Marshal(message)
+}
+
+// Unmarshal unmarshals proto "data" into "value"
+func (*ProtoMarshaller) Unmarshal(data []byte, value interface{}) error {
+ message, ok := value.(proto.Message)
+ if !ok {
+ return errors.New("unable to unmarshal non proto field")
+ }
+ return proto.Unmarshal(data, message)
+}
+
+// NewDecoder returns a Decoder which reads proto stream from "reader".
+func (marshaller *ProtoMarshaller) NewDecoder(reader io.Reader) Decoder {
+ return DecoderFunc(func(value interface{}) error {
+ buffer, err := ioutil.ReadAll(reader)
+ if err != nil {
+ return err
+ }
+ return marshaller.Unmarshal(buffer, value)
+ })
+}
+
+// NewEncoder returns an Encoder which writes proto stream into "writer".
+func (marshaller *ProtoMarshaller) NewEncoder(writer io.Writer) Encoder {
+ return EncoderFunc(func(value interface{}) error {
+ buffer, err := marshaller.Marshal(value)
+ if err != nil {
+ return err
+ }
+ _, err = writer.Write(buffer)
+ if err != nil {
+ return err
+ }
+
+ return nil
+ })
+}
diff --git a/vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/marshaler.go b/vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/marshaler.go
new file mode 100644
index 0000000..3fdf9fd
--- /dev/null
+++ b/vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/marshaler.go
@@ -0,0 +1,55 @@
+package runtime
+
+import (
+ "io"
+)
+
+// Marshaler defines a conversion between byte sequence and gRPC payloads / fields.
+type Marshaler interface {
+ // Marshal marshals "v" into byte sequence.
+ Marshal(v interface{}) ([]byte, error)
+ // Unmarshal unmarshals "data" into "v".
+ // "v" must be a pointer value.
+ Unmarshal(data []byte, v interface{}) error
+ // NewDecoder returns a Decoder which reads byte sequence from "r".
+ NewDecoder(r io.Reader) Decoder
+ // NewEncoder returns an Encoder which writes bytes sequence into "w".
+ NewEncoder(w io.Writer) Encoder
+ // ContentType returns the Content-Type which this marshaler is responsible for.
+ ContentType() string
+}
+
+// Marshalers that implement contentTypeMarshaler will have their ContentTypeFromMessage method called
+// to set the Content-Type header on the response
+type contentTypeMarshaler interface {
+ // ContentTypeFromMessage returns the Content-Type this marshaler produces from the provided message
+ ContentTypeFromMessage(v interface{}) string
+}
+
+// Decoder decodes a byte sequence
+type Decoder interface {
+ Decode(v interface{}) error
+}
+
+// Encoder encodes gRPC payloads / fields into byte sequence.
+type Encoder interface {
+ Encode(v interface{}) error
+}
+
+// DecoderFunc adapts an decoder function into Decoder.
+type DecoderFunc func(v interface{}) error
+
+// Decode delegates invocations to the underlying function itself.
+func (f DecoderFunc) Decode(v interface{}) error { return f(v) }
+
+// EncoderFunc adapts an encoder function into Encoder
+type EncoderFunc func(v interface{}) error
+
+// Encode delegates invocations to the underlying function itself.
+func (f EncoderFunc) Encode(v interface{}) error { return f(v) }
+
+// Delimited defines the streaming delimiter.
+type Delimited interface {
+ // Delimiter returns the record seperator for the stream.
+ Delimiter() []byte
+}
diff --git a/vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/marshaler_registry.go b/vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/marshaler_registry.go
new file mode 100644
index 0000000..5cc53ae
--- /dev/null
+++ b/vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/marshaler_registry.go
@@ -0,0 +1,91 @@
+package runtime
+
+import (
+ "errors"
+ "net/http"
+)
+
+// MIMEWildcard is the fallback MIME type used for requests which do not match
+// a registered MIME type.
+const MIMEWildcard = "*"
+
+var (
+ acceptHeader = http.CanonicalHeaderKey("Accept")
+ contentTypeHeader = http.CanonicalHeaderKey("Content-Type")
+
+ defaultMarshaler = &JSONPb{OrigName: true}
+)
+
+// MarshalerForRequest returns the inbound/outbound marshalers for this request.
+// It checks the registry on the ServeMux for the MIME type set by the Content-Type header.
+// If it isn't set (or the request Content-Type is empty), checks for "*".
+// If there are multiple Content-Type headers set, choose the first one that it can
+// exactly match in the registry.
+// Otherwise, it follows the above logic for "*"/InboundMarshaler/OutboundMarshaler.
+func MarshalerForRequest(mux *ServeMux, r *http.Request) (inbound Marshaler, outbound Marshaler) {
+ for _, acceptVal := range r.Header[acceptHeader] {
+ if m, ok := mux.marshalers.mimeMap[acceptVal]; ok {
+ outbound = m
+ break
+ }
+ }
+
+ for _, contentTypeVal := range r.Header[contentTypeHeader] {
+ if m, ok := mux.marshalers.mimeMap[contentTypeVal]; ok {
+ inbound = m
+ break
+ }
+ }
+
+ if inbound == nil {
+ inbound = mux.marshalers.mimeMap[MIMEWildcard]
+ }
+ if outbound == nil {
+ outbound = inbound
+ }
+
+ return inbound, outbound
+}
+
+// marshalerRegistry is a mapping from MIME types to Marshalers.
+type marshalerRegistry struct {
+ mimeMap map[string]Marshaler
+}
+
+// add adds a marshaler for a case-sensitive MIME type string ("*" to match any
+// MIME type).
+func (m marshalerRegistry) add(mime string, marshaler Marshaler) error {
+ if len(mime) == 0 {
+ return errors.New("empty MIME type")
+ }
+
+ m.mimeMap[mime] = marshaler
+
+ return nil
+}
+
+// makeMarshalerMIMERegistry returns a new registry of marshalers.
+// It allows for a mapping of case-sensitive Content-Type MIME type string to runtime.Marshaler interfaces.
+//
+// For example, you could allow the client to specify the use of the runtime.JSONPb marshaler
+// with a "application/jsonpb" Content-Type and the use of the runtime.JSONBuiltin marshaler
+// with a "application/json" Content-Type.
+// "*" can be used to match any Content-Type.
+// This can be attached to a ServerMux with the marshaler option.
+func makeMarshalerMIMERegistry() marshalerRegistry {
+ return marshalerRegistry{
+ mimeMap: map[string]Marshaler{
+ MIMEWildcard: defaultMarshaler,
+ },
+ }
+}
+
+// WithMarshalerOption returns a ServeMuxOption which associates inbound and outbound
+// Marshalers to a MIME type in mux.
+func WithMarshalerOption(mime string, marshaler Marshaler) ServeMuxOption {
+ return func(mux *ServeMux) {
+ if err := mux.marshalers.add(mime, marshaler); err != nil {
+ panic(err)
+ }
+ }
+}
diff --git a/vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/mux.go b/vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/mux.go
new file mode 100644
index 0000000..523a9cb
--- /dev/null
+++ b/vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/mux.go
@@ -0,0 +1,300 @@
+package runtime
+
+import (
+ "context"
+ "fmt"
+ "net/http"
+ "net/textproto"
+ "strings"
+
+ "github.com/golang/protobuf/proto"
+ "google.golang.org/grpc/codes"
+ "google.golang.org/grpc/metadata"
+ "google.golang.org/grpc/status"
+)
+
+// A HandlerFunc handles a specific pair of path pattern and HTTP method.
+type HandlerFunc func(w http.ResponseWriter, r *http.Request, pathParams map[string]string)
+
+// ErrUnknownURI is the error supplied to a custom ProtoErrorHandlerFunc when
+// a request is received with a URI path that does not match any registered
+// service method.
+//
+// Since gRPC servers return an "Unimplemented" code for requests with an
+// unrecognized URI path, this error also has a gRPC "Unimplemented" code.
+var ErrUnknownURI = status.Error(codes.Unimplemented, http.StatusText(http.StatusNotImplemented))
+
+// ServeMux is a request multiplexer for grpc-gateway.
+// It matches http requests to patterns and invokes the corresponding handler.
+type ServeMux struct {
+ // handlers maps HTTP method to a list of handlers.
+ handlers map[string][]handler
+ forwardResponseOptions []func(context.Context, http.ResponseWriter, proto.Message) error
+ marshalers marshalerRegistry
+ incomingHeaderMatcher HeaderMatcherFunc
+ outgoingHeaderMatcher HeaderMatcherFunc
+ metadataAnnotators []func(context.Context, *http.Request) metadata.MD
+ streamErrorHandler StreamErrorHandlerFunc
+ protoErrorHandler ProtoErrorHandlerFunc
+ disablePathLengthFallback bool
+ lastMatchWins bool
+}
+
+// ServeMuxOption is an option that can be given to a ServeMux on construction.
+type ServeMuxOption func(*ServeMux)
+
+// WithForwardResponseOption returns a ServeMuxOption representing the forwardResponseOption.
+//
+// forwardResponseOption is an option that will be called on the relevant context.Context,
+// http.ResponseWriter, and proto.Message before every forwarded response.
+//
+// The message may be nil in the case where just a header is being sent.
+func WithForwardResponseOption(forwardResponseOption func(context.Context, http.ResponseWriter, proto.Message) error) ServeMuxOption {
+ return func(serveMux *ServeMux) {
+ serveMux.forwardResponseOptions = append(serveMux.forwardResponseOptions, forwardResponseOption)
+ }
+}
+
+// SetQueryParameterParser sets the query parameter parser, used to populate message from query parameters.
+// Configuring this will mean the generated swagger output is no longer correct, and it should be
+// done with careful consideration.
+func SetQueryParameterParser(queryParameterParser QueryParameterParser) ServeMuxOption {
+ return func(serveMux *ServeMux) {
+ currentQueryParser = queryParameterParser
+ }
+}
+
+// HeaderMatcherFunc checks whether a header key should be forwarded to/from gRPC context.
+type HeaderMatcherFunc func(string) (string, bool)
+
+// DefaultHeaderMatcher is used to pass http request headers to/from gRPC context. This adds permanent HTTP header
+// keys (as specified by the IANA) to gRPC context with grpcgateway- prefix. HTTP headers that start with
+// 'Grpc-Metadata-' are mapped to gRPC metadata after removing prefix 'Grpc-Metadata-'.
+func DefaultHeaderMatcher(key string) (string, bool) {
+ key = textproto.CanonicalMIMEHeaderKey(key)
+ if isPermanentHTTPHeader(key) {
+ return MetadataPrefix + key, true
+ } else if strings.HasPrefix(key, MetadataHeaderPrefix) {
+ return key[len(MetadataHeaderPrefix):], true
+ }
+ return "", false
+}
+
+// WithIncomingHeaderMatcher returns a ServeMuxOption representing a headerMatcher for incoming request to gateway.
+//
+// This matcher will be called with each header in http.Request. If matcher returns true, that header will be
+// passed to gRPC context. To transform the header before passing to gRPC context, matcher should return modified header.
+func WithIncomingHeaderMatcher(fn HeaderMatcherFunc) ServeMuxOption {
+ return func(mux *ServeMux) {
+ mux.incomingHeaderMatcher = fn
+ }
+}
+
+// WithOutgoingHeaderMatcher returns a ServeMuxOption representing a headerMatcher for outgoing response from gateway.
+//
+// This matcher will be called with each header in response header metadata. If matcher returns true, that header will be
+// passed to http response returned from gateway. To transform the header before passing to response,
+// matcher should return modified header.
+func WithOutgoingHeaderMatcher(fn HeaderMatcherFunc) ServeMuxOption {
+ return func(mux *ServeMux) {
+ mux.outgoingHeaderMatcher = fn
+ }
+}
+
+// WithMetadata returns a ServeMuxOption for passing metadata to a gRPC context.
+//
+// This can be used by services that need to read from http.Request and modify gRPC context. A common use case
+// is reading token from cookie and adding it in gRPC context.
+func WithMetadata(annotator func(context.Context, *http.Request) metadata.MD) ServeMuxOption {
+ return func(serveMux *ServeMux) {
+ serveMux.metadataAnnotators = append(serveMux.metadataAnnotators, annotator)
+ }
+}
+
+// WithProtoErrorHandler returns a ServeMuxOption for configuring a custom error handler.
+//
+// This can be used to handle an error as general proto message defined by gRPC.
+// When this option is used, the mux uses the configured error handler instead of HTTPError and
+// OtherErrorHandler.
+func WithProtoErrorHandler(fn ProtoErrorHandlerFunc) ServeMuxOption {
+ return func(serveMux *ServeMux) {
+ serveMux.protoErrorHandler = fn
+ }
+}
+
+// WithDisablePathLengthFallback returns a ServeMuxOption for disable path length fallback.
+func WithDisablePathLengthFallback() ServeMuxOption {
+ return func(serveMux *ServeMux) {
+ serveMux.disablePathLengthFallback = true
+ }
+}
+
+// WithStreamErrorHandler returns a ServeMuxOption that will use the given custom stream
+// error handler, which allows for customizing the error trailer for server-streaming
+// calls.
+//
+// For stream errors that occur before any response has been written, the mux's
+// ProtoErrorHandler will be invoked. However, once data has been written, the errors must
+// be handled differently: they must be included in the response body. The response body's
+// final message will include the error details returned by the stream error handler.
+func WithStreamErrorHandler(fn StreamErrorHandlerFunc) ServeMuxOption {
+ return func(serveMux *ServeMux) {
+ serveMux.streamErrorHandler = fn
+ }
+}
+
+// WithLastMatchWins returns a ServeMuxOption that will enable "last
+// match wins" behavior, where if multiple path patterns match a
+// request path, the last one defined in the .proto file will be used.
+func WithLastMatchWins() ServeMuxOption {
+ return func(serveMux *ServeMux) {
+ serveMux.lastMatchWins = true
+ }
+}
+
+// NewServeMux returns a new ServeMux whose internal mapping is empty.
+func NewServeMux(opts ...ServeMuxOption) *ServeMux {
+ serveMux := &ServeMux{
+ handlers: make(map[string][]handler),
+ forwardResponseOptions: make([]func(context.Context, http.ResponseWriter, proto.Message) error, 0),
+ marshalers: makeMarshalerMIMERegistry(),
+ streamErrorHandler: DefaultHTTPStreamErrorHandler,
+ }
+
+ for _, opt := range opts {
+ opt(serveMux)
+ }
+
+ if serveMux.incomingHeaderMatcher == nil {
+ serveMux.incomingHeaderMatcher = DefaultHeaderMatcher
+ }
+
+ if serveMux.outgoingHeaderMatcher == nil {
+ serveMux.outgoingHeaderMatcher = func(key string) (string, bool) {
+ return fmt.Sprintf("%s%s", MetadataHeaderPrefix, key), true
+ }
+ }
+
+ return serveMux
+}
+
+// Handle associates "h" to the pair of HTTP method and path pattern.
+func (s *ServeMux) Handle(meth string, pat Pattern, h HandlerFunc) {
+ if s.lastMatchWins {
+ s.handlers[meth] = append([]handler{handler{pat: pat, h: h}}, s.handlers[meth]...)
+ } else {
+ s.handlers[meth] = append(s.handlers[meth], handler{pat: pat, h: h})
+ }
+}
+
+// ServeHTTP dispatches the request to the first handler whose pattern matches to r.Method and r.Path.
+func (s *ServeMux) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+ ctx := r.Context()
+
+ path := r.URL.Path
+ if !strings.HasPrefix(path, "/") {
+ if s.protoErrorHandler != nil {
+ _, outboundMarshaler := MarshalerForRequest(s, r)
+ sterr := status.Error(codes.InvalidArgument, http.StatusText(http.StatusBadRequest))
+ s.protoErrorHandler(ctx, s, outboundMarshaler, w, r, sterr)
+ } else {
+ OtherErrorHandler(w, r, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
+ }
+ return
+ }
+
+ components := strings.Split(path[1:], "/")
+ l := len(components)
+ var verb string
+ if idx := strings.LastIndex(components[l-1], ":"); idx == 0 {
+ if s.protoErrorHandler != nil {
+ _, outboundMarshaler := MarshalerForRequest(s, r)
+ s.protoErrorHandler(ctx, s, outboundMarshaler, w, r, ErrUnknownURI)
+ } else {
+ OtherErrorHandler(w, r, http.StatusText(http.StatusNotFound), http.StatusNotFound)
+ }
+ return
+ } else if idx > 0 {
+ c := components[l-1]
+ components[l-1], verb = c[:idx], c[idx+1:]
+ }
+
+ if override := r.Header.Get("X-HTTP-Method-Override"); override != "" && s.isPathLengthFallback(r) {
+ r.Method = strings.ToUpper(override)
+ if err := r.ParseForm(); err != nil {
+ if s.protoErrorHandler != nil {
+ _, outboundMarshaler := MarshalerForRequest(s, r)
+ sterr := status.Error(codes.InvalidArgument, err.Error())
+ s.protoErrorHandler(ctx, s, outboundMarshaler, w, r, sterr)
+ } else {
+ OtherErrorHandler(w, r, err.Error(), http.StatusBadRequest)
+ }
+ return
+ }
+ }
+ for _, h := range s.handlers[r.Method] {
+ pathParams, err := h.pat.Match(components, verb)
+ if err != nil {
+ continue
+ }
+ h.h(w, r, pathParams)
+ return
+ }
+
+ // lookup other methods to handle fallback from GET to POST and
+ // to determine if it is MethodNotAllowed or NotFound.
+ for m, handlers := range s.handlers {
+ if m == r.Method {
+ continue
+ }
+ for _, h := range handlers {
+ pathParams, err := h.pat.Match(components, verb)
+ if err != nil {
+ continue
+ }
+ // X-HTTP-Method-Override is optional. Always allow fallback to POST.
+ if s.isPathLengthFallback(r) {
+ if err := r.ParseForm(); err != nil {
+ if s.protoErrorHandler != nil {
+ _, outboundMarshaler := MarshalerForRequest(s, r)
+ sterr := status.Error(codes.InvalidArgument, err.Error())
+ s.protoErrorHandler(ctx, s, outboundMarshaler, w, r, sterr)
+ } else {
+ OtherErrorHandler(w, r, err.Error(), http.StatusBadRequest)
+ }
+ return
+ }
+ h.h(w, r, pathParams)
+ return
+ }
+ if s.protoErrorHandler != nil {
+ _, outboundMarshaler := MarshalerForRequest(s, r)
+ s.protoErrorHandler(ctx, s, outboundMarshaler, w, r, ErrUnknownURI)
+ } else {
+ OtherErrorHandler(w, r, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed)
+ }
+ return
+ }
+ }
+
+ if s.protoErrorHandler != nil {
+ _, outboundMarshaler := MarshalerForRequest(s, r)
+ s.protoErrorHandler(ctx, s, outboundMarshaler, w, r, ErrUnknownURI)
+ } else {
+ OtherErrorHandler(w, r, http.StatusText(http.StatusNotFound), http.StatusNotFound)
+ }
+}
+
+// GetForwardResponseOptions returns the ForwardResponseOptions associated with this ServeMux.
+func (s *ServeMux) GetForwardResponseOptions() []func(context.Context, http.ResponseWriter, proto.Message) error {
+ return s.forwardResponseOptions
+}
+
+func (s *ServeMux) isPathLengthFallback(r *http.Request) bool {
+ return !s.disablePathLengthFallback && r.Method == "POST" && r.Header.Get("Content-Type") == "application/x-www-form-urlencoded"
+}
+
+type handler struct {
+ pat Pattern
+ h HandlerFunc
+}
diff --git a/vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/pattern.go b/vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/pattern.go
new file mode 100644
index 0000000..0905369
--- /dev/null
+++ b/vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/pattern.go
@@ -0,0 +1,262 @@
+package runtime
+
+import (
+ "errors"
+ "fmt"
+ "strings"
+
+ "github.com/grpc-ecosystem/grpc-gateway/utilities"
+ "google.golang.org/grpc/grpclog"
+)
+
+var (
+ // ErrNotMatch indicates that the given HTTP request path does not match to the pattern.
+ ErrNotMatch = errors.New("not match to the path pattern")
+ // ErrInvalidPattern indicates that the given definition of Pattern is not valid.
+ ErrInvalidPattern = errors.New("invalid pattern")
+)
+
+type op struct {
+ code utilities.OpCode
+ operand int
+}
+
+// Pattern is a template pattern of http request paths defined in github.com/googleapis/googleapis/google/api/http.proto.
+type Pattern struct {
+ // ops is a list of operations
+ ops []op
+ // pool is a constant pool indexed by the operands or vars.
+ pool []string
+ // vars is a list of variables names to be bound by this pattern
+ vars []string
+ // stacksize is the max depth of the stack
+ stacksize int
+ // tailLen is the length of the fixed-size segments after a deep wildcard
+ tailLen int
+ // verb is the VERB part of the path pattern. It is empty if the pattern does not have VERB part.
+ verb string
+ // assumeColonVerb indicates whether a path suffix after a final
+ // colon may only be interpreted as a verb.
+ assumeColonVerb bool
+}
+
+type patternOptions struct {
+ assumeColonVerb bool
+}
+
+// PatternOpt is an option for creating Patterns.
+type PatternOpt func(*patternOptions)
+
+// NewPattern returns a new Pattern from the given definition values.
+// "ops" is a sequence of op codes. "pool" is a constant pool.
+// "verb" is the verb part of the pattern. It is empty if the pattern does not have the part.
+// "version" must be 1 for now.
+// It returns an error if the given definition is invalid.
+func NewPattern(version int, ops []int, pool []string, verb string, opts ...PatternOpt) (Pattern, error) {
+ options := patternOptions{
+ assumeColonVerb: true,
+ }
+ for _, o := range opts {
+ o(&options)
+ }
+
+ if version != 1 {
+ grpclog.Infof("unsupported version: %d", version)
+ return Pattern{}, ErrInvalidPattern
+ }
+
+ l := len(ops)
+ if l%2 != 0 {
+ grpclog.Infof("odd number of ops codes: %d", l)
+ return Pattern{}, ErrInvalidPattern
+ }
+
+ var (
+ typedOps []op
+ stack, maxstack int
+ tailLen int
+ pushMSeen bool
+ vars []string
+ )
+ for i := 0; i < l; i += 2 {
+ op := op{code: utilities.OpCode(ops[i]), operand: ops[i+1]}
+ switch op.code {
+ case utilities.OpNop:
+ continue
+ case utilities.OpPush:
+ if pushMSeen {
+ tailLen++
+ }
+ stack++
+ case utilities.OpPushM:
+ if pushMSeen {
+ grpclog.Infof("pushM appears twice")
+ return Pattern{}, ErrInvalidPattern
+ }
+ pushMSeen = true
+ stack++
+ case utilities.OpLitPush:
+ if op.operand < 0 || len(pool) <= op.operand {
+ grpclog.Infof("negative literal index: %d", op.operand)
+ return Pattern{}, ErrInvalidPattern
+ }
+ if pushMSeen {
+ tailLen++
+ }
+ stack++
+ case utilities.OpConcatN:
+ if op.operand <= 0 {
+ grpclog.Infof("negative concat size: %d", op.operand)
+ return Pattern{}, ErrInvalidPattern
+ }
+ stack -= op.operand
+ if stack < 0 {
+ grpclog.Print("stack underflow")
+ return Pattern{}, ErrInvalidPattern
+ }
+ stack++
+ case utilities.OpCapture:
+ if op.operand < 0 || len(pool) <= op.operand {
+ grpclog.Infof("variable name index out of bound: %d", op.operand)
+ return Pattern{}, ErrInvalidPattern
+ }
+ v := pool[op.operand]
+ op.operand = len(vars)
+ vars = append(vars, v)
+ stack--
+ if stack < 0 {
+ grpclog.Infof("stack underflow")
+ return Pattern{}, ErrInvalidPattern
+ }
+ default:
+ grpclog.Infof("invalid opcode: %d", op.code)
+ return Pattern{}, ErrInvalidPattern
+ }
+
+ if maxstack < stack {
+ maxstack = stack
+ }
+ typedOps = append(typedOps, op)
+ }
+ return Pattern{
+ ops: typedOps,
+ pool: pool,
+ vars: vars,
+ stacksize: maxstack,
+ tailLen: tailLen,
+ verb: verb,
+ assumeColonVerb: options.assumeColonVerb,
+ }, nil
+}
+
+// MustPattern is a helper function which makes it easier to call NewPattern in variable initialization.
+func MustPattern(p Pattern, err error) Pattern {
+ if err != nil {
+ grpclog.Fatalf("Pattern initialization failed: %v", err)
+ }
+ return p
+}
+
+// Match examines components if it matches to the Pattern.
+// If it matches, the function returns a mapping from field paths to their captured values.
+// If otherwise, the function returns an error.
+func (p Pattern) Match(components []string, verb string) (map[string]string, error) {
+ if p.verb != verb {
+ if p.assumeColonVerb || p.verb != "" {
+ return nil, ErrNotMatch
+ }
+ if len(components) == 0 {
+ components = []string{":" + verb}
+ } else {
+ components = append([]string{}, components...)
+ components[len(components)-1] += ":" + verb
+ }
+ verb = ""
+ }
+
+ var pos int
+ stack := make([]string, 0, p.stacksize)
+ captured := make([]string, len(p.vars))
+ l := len(components)
+ for _, op := range p.ops {
+ switch op.code {
+ case utilities.OpNop:
+ continue
+ case utilities.OpPush, utilities.OpLitPush:
+ if pos >= l {
+ return nil, ErrNotMatch
+ }
+ c := components[pos]
+ if op.code == utilities.OpLitPush {
+ if lit := p.pool[op.operand]; c != lit {
+ return nil, ErrNotMatch
+ }
+ }
+ stack = append(stack, c)
+ pos++
+ case utilities.OpPushM:
+ end := len(components)
+ if end < pos+p.tailLen {
+ return nil, ErrNotMatch
+ }
+ end -= p.tailLen
+ stack = append(stack, strings.Join(components[pos:end], "/"))
+ pos = end
+ case utilities.OpConcatN:
+ n := op.operand
+ l := len(stack) - n
+ stack = append(stack[:l], strings.Join(stack[l:], "/"))
+ case utilities.OpCapture:
+ n := len(stack) - 1
+ captured[op.operand] = stack[n]
+ stack = stack[:n]
+ }
+ }
+ if pos < l {
+ return nil, ErrNotMatch
+ }
+ bindings := make(map[string]string)
+ for i, val := range captured {
+ bindings[p.vars[i]] = val
+ }
+ return bindings, nil
+}
+
+// Verb returns the verb part of the Pattern.
+func (p Pattern) Verb() string { return p.verb }
+
+func (p Pattern) String() string {
+ var stack []string
+ for _, op := range p.ops {
+ switch op.code {
+ case utilities.OpNop:
+ continue
+ case utilities.OpPush:
+ stack = append(stack, "*")
+ case utilities.OpLitPush:
+ stack = append(stack, p.pool[op.operand])
+ case utilities.OpPushM:
+ stack = append(stack, "**")
+ case utilities.OpConcatN:
+ n := op.operand
+ l := len(stack) - n
+ stack = append(stack[:l], strings.Join(stack[l:], "/"))
+ case utilities.OpCapture:
+ n := len(stack) - 1
+ stack[n] = fmt.Sprintf("{%s=%s}", p.vars[op.operand], stack[n])
+ }
+ }
+ segs := strings.Join(stack, "/")
+ if p.verb != "" {
+ return fmt.Sprintf("/%s:%s", segs, p.verb)
+ }
+ return "/" + segs
+}
+
+// AssumeColonVerbOpt indicates whether a path suffix after a final
+// colon may only be interpreted as a verb.
+func AssumeColonVerbOpt(val bool) PatternOpt {
+ return PatternOpt(func(o *patternOptions) {
+ o.assumeColonVerb = val
+ })
+}
diff --git a/vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/proto2_convert.go b/vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/proto2_convert.go
new file mode 100644
index 0000000..a3151e2
--- /dev/null
+++ b/vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/proto2_convert.go
@@ -0,0 +1,80 @@
+package runtime
+
+import (
+ "github.com/golang/protobuf/proto"
+)
+
+// StringP returns a pointer to a string whose pointee is same as the given string value.
+func StringP(val string) (*string, error) {
+ return proto.String(val), nil
+}
+
+// BoolP parses the given string representation of a boolean value,
+// and returns a pointer to a bool whose value is same as the parsed value.
+func BoolP(val string) (*bool, error) {
+ b, err := Bool(val)
+ if err != nil {
+ return nil, err
+ }
+ return proto.Bool(b), nil
+}
+
+// Float64P parses the given string representation of a floating point number,
+// and returns a pointer to a float64 whose value is same as the parsed number.
+func Float64P(val string) (*float64, error) {
+ f, err := Float64(val)
+ if err != nil {
+ return nil, err
+ }
+ return proto.Float64(f), nil
+}
+
+// Float32P parses the given string representation of a floating point number,
+// and returns a pointer to a float32 whose value is same as the parsed number.
+func Float32P(val string) (*float32, error) {
+ f, err := Float32(val)
+ if err != nil {
+ return nil, err
+ }
+ return proto.Float32(f), nil
+}
+
+// Int64P parses the given string representation of an integer
+// and returns a pointer to a int64 whose value is same as the parsed integer.
+func Int64P(val string) (*int64, error) {
+ i, err := Int64(val)
+ if err != nil {
+ return nil, err
+ }
+ return proto.Int64(i), nil
+}
+
+// Int32P parses the given string representation of an integer
+// and returns a pointer to a int32 whose value is same as the parsed integer.
+func Int32P(val string) (*int32, error) {
+ i, err := Int32(val)
+ if err != nil {
+ return nil, err
+ }
+ return proto.Int32(i), err
+}
+
+// Uint64P parses the given string representation of an integer
+// and returns a pointer to a uint64 whose value is same as the parsed integer.
+func Uint64P(val string) (*uint64, error) {
+ i, err := Uint64(val)
+ if err != nil {
+ return nil, err
+ }
+ return proto.Uint64(i), err
+}
+
+// Uint32P parses the given string representation of an integer
+// and returns a pointer to a uint32 whose value is same as the parsed integer.
+func Uint32P(val string) (*uint32, error) {
+ i, err := Uint32(val)
+ if err != nil {
+ return nil, err
+ }
+ return proto.Uint32(i), err
+}
diff --git a/vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/proto_errors.go b/vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/proto_errors.go
new file mode 100644
index 0000000..ea75565
--- /dev/null
+++ b/vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/proto_errors.go
@@ -0,0 +1,106 @@
+package runtime
+
+import (
+ "context"
+ "io"
+ "net/http"
+
+ "github.com/golang/protobuf/ptypes/any"
+ "github.com/grpc-ecosystem/grpc-gateway/internal"
+ "google.golang.org/grpc/codes"
+ "google.golang.org/grpc/grpclog"
+ "google.golang.org/grpc/status"
+)
+
+// StreamErrorHandlerFunc accepts an error as a gRPC error generated via status package and translates it into a
+// a proto struct used to represent error at the end of a stream.
+type StreamErrorHandlerFunc func(context.Context, error) *StreamError
+
+// StreamError is the payload for the final message in a server stream in the event that the server returns an
+// error after a response message has already been sent.
+type StreamError internal.StreamError
+
+// ProtoErrorHandlerFunc handles the error as a gRPC error generated via status package and replies to the request.
+type ProtoErrorHandlerFunc func(context.Context, *ServeMux, Marshaler, http.ResponseWriter, *http.Request, error)
+
+var _ ProtoErrorHandlerFunc = DefaultHTTPProtoErrorHandler
+
+// DefaultHTTPProtoErrorHandler is an implementation of HTTPError.
+// If "err" is an error from gRPC system, the function replies with the status code mapped by HTTPStatusFromCode.
+// If otherwise, it replies with http.StatusInternalServerError.
+//
+// The response body returned by this function is a Status message marshaled by a Marshaler.
+//
+// Do not set this function to HTTPError variable directly, use WithProtoErrorHandler option instead.
+func DefaultHTTPProtoErrorHandler(ctx context.Context, mux *ServeMux, marshaler Marshaler, w http.ResponseWriter, _ *http.Request, err error) {
+ // return Internal when Marshal failed
+ const fallback = `{"code": 13, "message": "failed to marshal error message"}`
+
+ s, ok := status.FromError(err)
+ if !ok {
+ s = status.New(codes.Unknown, err.Error())
+ }
+
+ w.Header().Del("Trailer")
+
+ contentType := marshaler.ContentType()
+ // Check marshaler on run time in order to keep backwards compatability
+ // An interface param needs to be added to the ContentType() function on
+ // the Marshal interface to be able to remove this check
+ if typeMarshaler, ok := marshaler.(contentTypeMarshaler); ok {
+ pb := s.Proto()
+ contentType = typeMarshaler.ContentTypeFromMessage(pb)
+ }
+ w.Header().Set("Content-Type", contentType)
+
+ buf, merr := marshaler.Marshal(s.Proto())
+ if merr != nil {
+ grpclog.Infof("Failed to marshal error message %q: %v", s.Proto(), merr)
+ w.WriteHeader(http.StatusInternalServerError)
+ if _, err := io.WriteString(w, fallback); err != nil {
+ grpclog.Infof("Failed to write response: %v", err)
+ }
+ return
+ }
+
+ md, ok := ServerMetadataFromContext(ctx)
+ if !ok {
+ grpclog.Infof("Failed to extract ServerMetadata from context")
+ }
+
+ handleForwardResponseServerMetadata(w, mux, md)
+ handleForwardResponseTrailerHeader(w, md)
+ st := HTTPStatusFromCode(s.Code())
+ w.WriteHeader(st)
+ if _, err := w.Write(buf); err != nil {
+ grpclog.Infof("Failed to write response: %v", err)
+ }
+
+ handleForwardResponseTrailer(w, md)
+}
+
+// DefaultHTTPStreamErrorHandler converts the given err into a *StreamError via
+// default logic.
+//
+// It extracts the gRPC status from err if possible. The fields of the status are
+// used to populate the returned StreamError, and the HTTP status code is derived
+// from the gRPC code via HTTPStatusFromCode. If the given err does not contain a
+// gRPC status, an "Unknown" gRPC code is used and "Internal Server Error" HTTP code.
+func DefaultHTTPStreamErrorHandler(_ context.Context, err error) *StreamError {
+ grpcCode := codes.Unknown
+ grpcMessage := err.Error()
+ var grpcDetails []*any.Any
+ if s, ok := status.FromError(err); ok {
+ grpcCode = s.Code()
+ grpcMessage = s.Message()
+ grpcDetails = s.Proto().GetDetails()
+ }
+ httpCode := HTTPStatusFromCode(grpcCode)
+ return &StreamError{
+ GrpcCode: int32(grpcCode),
+ HttpCode: int32(httpCode),
+ Message: grpcMessage,
+ HttpStatus: http.StatusText(httpCode),
+ Details: grpcDetails,
+ }
+}
diff --git a/vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/query.go b/vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/query.go
new file mode 100644
index 0000000..ba66842
--- /dev/null
+++ b/vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/query.go
@@ -0,0 +1,406 @@
+package runtime
+
+import (
+ "encoding/base64"
+ "fmt"
+ "net/url"
+ "reflect"
+ "regexp"
+ "strconv"
+ "strings"
+ "time"
+
+ "github.com/golang/protobuf/proto"
+ "github.com/grpc-ecosystem/grpc-gateway/utilities"
+ "google.golang.org/grpc/grpclog"
+)
+
+var valuesKeyRegexp = regexp.MustCompile("^(.*)\\[(.*)\\]$")
+
+var currentQueryParser QueryParameterParser = &defaultQueryParser{}
+
+// QueryParameterParser defines interface for all query parameter parsers
+type QueryParameterParser interface {
+ Parse(msg proto.Message, values url.Values, filter *utilities.DoubleArray) error
+}
+
+// PopulateQueryParameters parses query parameters
+// into "msg" using current query parser
+func PopulateQueryParameters(msg proto.Message, values url.Values, filter *utilities.DoubleArray) error {
+ return currentQueryParser.Parse(msg, values, filter)
+}
+
+type defaultQueryParser struct{}
+
+// Parse populates "values" into "msg".
+// A value is ignored if its key starts with one of the elements in "filter".
+func (*defaultQueryParser) Parse(msg proto.Message, values url.Values, filter *utilities.DoubleArray) error {
+ for key, values := range values {
+ match := valuesKeyRegexp.FindStringSubmatch(key)
+ if len(match) == 3 {
+ key = match[1]
+ values = append([]string{match[2]}, values...)
+ }
+ fieldPath := strings.Split(key, ".")
+ if filter.HasCommonPrefix(fieldPath) {
+ continue
+ }
+ if err := populateFieldValueFromPath(msg, fieldPath, values); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// PopulateFieldFromPath sets a value in a nested Protobuf structure.
+// It instantiates missing protobuf fields as it goes.
+func PopulateFieldFromPath(msg proto.Message, fieldPathString string, value string) error {
+ fieldPath := strings.Split(fieldPathString, ".")
+ return populateFieldValueFromPath(msg, fieldPath, []string{value})
+}
+
+func populateFieldValueFromPath(msg proto.Message, fieldPath []string, values []string) error {
+ m := reflect.ValueOf(msg)
+ if m.Kind() != reflect.Ptr {
+ return fmt.Errorf("unexpected type %T: %v", msg, msg)
+ }
+ var props *proto.Properties
+ m = m.Elem()
+ for i, fieldName := range fieldPath {
+ isLast := i == len(fieldPath)-1
+ if !isLast && m.Kind() != reflect.Struct {
+ return fmt.Errorf("non-aggregate type in the mid of path: %s", strings.Join(fieldPath, "."))
+ }
+ var f reflect.Value
+ var err error
+ f, props, err = fieldByProtoName(m, fieldName)
+ if err != nil {
+ return err
+ } else if !f.IsValid() {
+ grpclog.Infof("field not found in %T: %s", msg, strings.Join(fieldPath, "."))
+ return nil
+ }
+
+ switch f.Kind() {
+ case reflect.Bool, reflect.Float32, reflect.Float64, reflect.Int32, reflect.Int64, reflect.String, reflect.Uint32, reflect.Uint64:
+ if !isLast {
+ return fmt.Errorf("unexpected nested field %s in %s", fieldPath[i+1], strings.Join(fieldPath[:i+1], "."))
+ }
+ m = f
+ case reflect.Slice:
+ if !isLast {
+ return fmt.Errorf("unexpected repeated field in %s", strings.Join(fieldPath, "."))
+ }
+ // Handle []byte
+ if f.Type().Elem().Kind() == reflect.Uint8 {
+ m = f
+ break
+ }
+ return populateRepeatedField(f, values, props)
+ case reflect.Ptr:
+ if f.IsNil() {
+ m = reflect.New(f.Type().Elem())
+ f.Set(m.Convert(f.Type()))
+ }
+ m = f.Elem()
+ continue
+ case reflect.Struct:
+ m = f
+ continue
+ case reflect.Map:
+ if !isLast {
+ return fmt.Errorf("unexpected nested field %s in %s", fieldPath[i+1], strings.Join(fieldPath[:i+1], "."))
+ }
+ return populateMapField(f, values, props)
+ default:
+ return fmt.Errorf("unexpected type %s in %T", f.Type(), msg)
+ }
+ }
+ switch len(values) {
+ case 0:
+ return fmt.Errorf("no value of field: %s", strings.Join(fieldPath, "."))
+ case 1:
+ default:
+ grpclog.Infof("too many field values: %s", strings.Join(fieldPath, "."))
+ }
+ return populateField(m, values[0], props)
+}
+
+// fieldByProtoName looks up a field whose corresponding protobuf field name is "name".
+// "m" must be a struct value. It returns zero reflect.Value if no such field found.
+func fieldByProtoName(m reflect.Value, name string) (reflect.Value, *proto.Properties, error) {
+ props := proto.GetProperties(m.Type())
+
+ // look up field name in oneof map
+ for _, op := range props.OneofTypes {
+ if name == op.Prop.OrigName || name == op.Prop.JSONName {
+ v := reflect.New(op.Type.Elem())
+ field := m.Field(op.Field)
+ if !field.IsNil() {
+ return reflect.Value{}, nil, fmt.Errorf("field already set for %s oneof", props.Prop[op.Field].OrigName)
+ }
+ field.Set(v)
+ return v.Elem().Field(0), op.Prop, nil
+ }
+ }
+
+ for _, p := range props.Prop {
+ if p.OrigName == name {
+ return m.FieldByName(p.Name), p, nil
+ }
+ if p.JSONName == name {
+ return m.FieldByName(p.Name), p, nil
+ }
+ }
+ return reflect.Value{}, nil, nil
+}
+
+func populateMapField(f reflect.Value, values []string, props *proto.Properties) error {
+ if len(values) != 2 {
+ return fmt.Errorf("more than one value provided for key %s in map %s", values[0], props.Name)
+ }
+
+ key, value := values[0], values[1]
+ keyType := f.Type().Key()
+ valueType := f.Type().Elem()
+ if f.IsNil() {
+ f.Set(reflect.MakeMap(f.Type()))
+ }
+
+ keyConv, ok := convFromType[keyType.Kind()]
+ if !ok {
+ return fmt.Errorf("unsupported key type %s in map %s", keyType, props.Name)
+ }
+ valueConv, ok := convFromType[valueType.Kind()]
+ if !ok {
+ return fmt.Errorf("unsupported value type %s in map %s", valueType, props.Name)
+ }
+
+ keyV := keyConv.Call([]reflect.Value{reflect.ValueOf(key)})
+ if err := keyV[1].Interface(); err != nil {
+ return err.(error)
+ }
+ valueV := valueConv.Call([]reflect.Value{reflect.ValueOf(value)})
+ if err := valueV[1].Interface(); err != nil {
+ return err.(error)
+ }
+
+ f.SetMapIndex(keyV[0].Convert(keyType), valueV[0].Convert(valueType))
+
+ return nil
+}
+
+func populateRepeatedField(f reflect.Value, values []string, props *proto.Properties) error {
+ elemType := f.Type().Elem()
+
+ // is the destination field a slice of an enumeration type?
+ if enumValMap := proto.EnumValueMap(props.Enum); enumValMap != nil {
+ return populateFieldEnumRepeated(f, values, enumValMap)
+ }
+
+ conv, ok := convFromType[elemType.Kind()]
+ if !ok {
+ return fmt.Errorf("unsupported field type %s", elemType)
+ }
+ f.Set(reflect.MakeSlice(f.Type(), len(values), len(values)).Convert(f.Type()))
+ for i, v := range values {
+ result := conv.Call([]reflect.Value{reflect.ValueOf(v)})
+ if err := result[1].Interface(); err != nil {
+ return err.(error)
+ }
+ f.Index(i).Set(result[0].Convert(f.Index(i).Type()))
+ }
+ return nil
+}
+
+func populateField(f reflect.Value, value string, props *proto.Properties) error {
+ i := f.Addr().Interface()
+
+ // Handle protobuf well known types
+ var name string
+ switch m := i.(type) {
+ case interface{ XXX_WellKnownType() string }:
+ name = m.XXX_WellKnownType()
+ case proto.Message:
+ const wktPrefix = "google.protobuf."
+ if fullName := proto.MessageName(m); strings.HasPrefix(fullName, wktPrefix) {
+ name = fullName[len(wktPrefix):]
+ }
+ }
+ switch name {
+ case "Timestamp":
+ if value == "null" {
+ f.FieldByName("Seconds").SetInt(0)
+ f.FieldByName("Nanos").SetInt(0)
+ return nil
+ }
+
+ t, err := time.Parse(time.RFC3339Nano, value)
+ if err != nil {
+ return fmt.Errorf("bad Timestamp: %v", err)
+ }
+ f.FieldByName("Seconds").SetInt(int64(t.Unix()))
+ f.FieldByName("Nanos").SetInt(int64(t.Nanosecond()))
+ return nil
+ case "Duration":
+ if value == "null" {
+ f.FieldByName("Seconds").SetInt(0)
+ f.FieldByName("Nanos").SetInt(0)
+ return nil
+ }
+ d, err := time.ParseDuration(value)
+ if err != nil {
+ return fmt.Errorf("bad Duration: %v", err)
+ }
+
+ ns := d.Nanoseconds()
+ s := ns / 1e9
+ ns %= 1e9
+ f.FieldByName("Seconds").SetInt(s)
+ f.FieldByName("Nanos").SetInt(ns)
+ return nil
+ case "DoubleValue":
+ fallthrough
+ case "FloatValue":
+ float64Val, err := strconv.ParseFloat(value, 64)
+ if err != nil {
+ return fmt.Errorf("bad DoubleValue: %s", value)
+ }
+ f.FieldByName("Value").SetFloat(float64Val)
+ return nil
+ case "Int64Value":
+ fallthrough
+ case "Int32Value":
+ int64Val, err := strconv.ParseInt(value, 10, 64)
+ if err != nil {
+ return fmt.Errorf("bad DoubleValue: %s", value)
+ }
+ f.FieldByName("Value").SetInt(int64Val)
+ return nil
+ case "UInt64Value":
+ fallthrough
+ case "UInt32Value":
+ uint64Val, err := strconv.ParseUint(value, 10, 64)
+ if err != nil {
+ return fmt.Errorf("bad DoubleValue: %s", value)
+ }
+ f.FieldByName("Value").SetUint(uint64Val)
+ return nil
+ case "BoolValue":
+ if value == "true" {
+ f.FieldByName("Value").SetBool(true)
+ } else if value == "false" {
+ f.FieldByName("Value").SetBool(false)
+ } else {
+ return fmt.Errorf("bad BoolValue: %s", value)
+ }
+ return nil
+ case "StringValue":
+ f.FieldByName("Value").SetString(value)
+ return nil
+ case "BytesValue":
+ bytesVal, err := base64.StdEncoding.DecodeString(value)
+ if err != nil {
+ return fmt.Errorf("bad BytesValue: %s", value)
+ }
+ f.FieldByName("Value").SetBytes(bytesVal)
+ return nil
+ case "FieldMask":
+ p := f.FieldByName("Paths")
+ for _, v := range strings.Split(value, ",") {
+ if v != "" {
+ p.Set(reflect.Append(p, reflect.ValueOf(v)))
+ }
+ }
+ return nil
+ }
+
+ // Handle Time and Duration stdlib types
+ switch t := i.(type) {
+ case *time.Time:
+ pt, err := time.Parse(time.RFC3339Nano, value)
+ if err != nil {
+ return fmt.Errorf("bad Timestamp: %v", err)
+ }
+ *t = pt
+ return nil
+ case *time.Duration:
+ d, err := time.ParseDuration(value)
+ if err != nil {
+ return fmt.Errorf("bad Duration: %v", err)
+ }
+ *t = d
+ return nil
+ }
+
+ // is the destination field an enumeration type?
+ if enumValMap := proto.EnumValueMap(props.Enum); enumValMap != nil {
+ return populateFieldEnum(f, value, enumValMap)
+ }
+
+ conv, ok := convFromType[f.Kind()]
+ if !ok {
+ return fmt.Errorf("field type %T is not supported in query parameters", i)
+ }
+ result := conv.Call([]reflect.Value{reflect.ValueOf(value)})
+ if err := result[1].Interface(); err != nil {
+ return err.(error)
+ }
+ f.Set(result[0].Convert(f.Type()))
+ return nil
+}
+
+func convertEnum(value string, t reflect.Type, enumValMap map[string]int32) (reflect.Value, error) {
+ // see if it's an enumeration string
+ if enumVal, ok := enumValMap[value]; ok {
+ return reflect.ValueOf(enumVal).Convert(t), nil
+ }
+
+ // check for an integer that matches an enumeration value
+ eVal, err := strconv.Atoi(value)
+ if err != nil {
+ return reflect.Value{}, fmt.Errorf("%s is not a valid %s", value, t)
+ }
+ for _, v := range enumValMap {
+ if v == int32(eVal) {
+ return reflect.ValueOf(eVal).Convert(t), nil
+ }
+ }
+ return reflect.Value{}, fmt.Errorf("%s is not a valid %s", value, t)
+}
+
+func populateFieldEnum(f reflect.Value, value string, enumValMap map[string]int32) error {
+ cval, err := convertEnum(value, f.Type(), enumValMap)
+ if err != nil {
+ return err
+ }
+ f.Set(cval)
+ return nil
+}
+
+func populateFieldEnumRepeated(f reflect.Value, values []string, enumValMap map[string]int32) error {
+ elemType := f.Type().Elem()
+ f.Set(reflect.MakeSlice(f.Type(), len(values), len(values)).Convert(f.Type()))
+ for i, v := range values {
+ result, err := convertEnum(v, elemType, enumValMap)
+ if err != nil {
+ return err
+ }
+ f.Index(i).Set(result)
+ }
+ return nil
+}
+
+var (
+ convFromType = map[reflect.Kind]reflect.Value{
+ reflect.String: reflect.ValueOf(String),
+ reflect.Bool: reflect.ValueOf(Bool),
+ reflect.Float64: reflect.ValueOf(Float64),
+ reflect.Float32: reflect.ValueOf(Float32),
+ reflect.Int64: reflect.ValueOf(Int64),
+ reflect.Int32: reflect.ValueOf(Int32),
+ reflect.Uint64: reflect.ValueOf(Uint64),
+ reflect.Uint32: reflect.ValueOf(Uint32),
+ reflect.Slice: reflect.ValueOf(Bytes),
+ }
+)
diff --git a/vendor/github.com/grpc-ecosystem/grpc-gateway/utilities/BUILD.bazel b/vendor/github.com/grpc-ecosystem/grpc-gateway/utilities/BUILD.bazel
new file mode 100644
index 0000000..7109d79
--- /dev/null
+++ b/vendor/github.com/grpc-ecosystem/grpc-gateway/utilities/BUILD.bazel
@@ -0,0 +1,21 @@
+load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
+
+package(default_visibility = ["//visibility:public"])
+
+go_library(
+ name = "go_default_library",
+ srcs = [
+ "doc.go",
+ "pattern.go",
+ "readerfactory.go",
+ "trie.go",
+ ],
+ importpath = "github.com/grpc-ecosystem/grpc-gateway/utilities",
+)
+
+go_test(
+ name = "go_default_test",
+ size = "small",
+ srcs = ["trie_test.go"],
+ embed = [":go_default_library"],
+)
diff --git a/vendor/github.com/grpc-ecosystem/grpc-gateway/utilities/doc.go b/vendor/github.com/grpc-ecosystem/grpc-gateway/utilities/doc.go
new file mode 100644
index 0000000..cf79a4d
--- /dev/null
+++ b/vendor/github.com/grpc-ecosystem/grpc-gateway/utilities/doc.go
@@ -0,0 +1,2 @@
+// Package utilities provides members for internal use in grpc-gateway.
+package utilities
diff --git a/vendor/github.com/grpc-ecosystem/grpc-gateway/utilities/pattern.go b/vendor/github.com/grpc-ecosystem/grpc-gateway/utilities/pattern.go
new file mode 100644
index 0000000..dfe7de4
--- /dev/null
+++ b/vendor/github.com/grpc-ecosystem/grpc-gateway/utilities/pattern.go
@@ -0,0 +1,22 @@
+package utilities
+
+// An OpCode is a opcode of compiled path patterns.
+type OpCode int
+
+// These constants are the valid values of OpCode.
+const (
+ // OpNop does nothing
+ OpNop = OpCode(iota)
+ // OpPush pushes a component to stack
+ OpPush
+ // OpLitPush pushes a component to stack if it matches to the literal
+ OpLitPush
+ // OpPushM concatenates the remaining components and pushes it to stack
+ OpPushM
+ // OpConcatN pops N items from stack, concatenates them and pushes it back to stack
+ OpConcatN
+ // OpCapture pops an item and binds it to the variable
+ OpCapture
+ // OpEnd is the least positive invalid opcode.
+ OpEnd
+)
diff --git a/vendor/github.com/grpc-ecosystem/grpc-gateway/utilities/readerfactory.go b/vendor/github.com/grpc-ecosystem/grpc-gateway/utilities/readerfactory.go
new file mode 100644
index 0000000..6dd3854
--- /dev/null
+++ b/vendor/github.com/grpc-ecosystem/grpc-gateway/utilities/readerfactory.go
@@ -0,0 +1,20 @@
+package utilities
+
+import (
+ "bytes"
+ "io"
+ "io/ioutil"
+)
+
+// IOReaderFactory takes in an io.Reader and returns a function that will allow you to create a new reader that begins
+// at the start of the stream
+func IOReaderFactory(r io.Reader) (func() io.Reader, error) {
+ b, err := ioutil.ReadAll(r)
+ if err != nil {
+ return nil, err
+ }
+
+ return func() io.Reader {
+ return bytes.NewReader(b)
+ }, nil
+}
diff --git a/vendor/github.com/grpc-ecosystem/grpc-gateway/utilities/trie.go b/vendor/github.com/grpc-ecosystem/grpc-gateway/utilities/trie.go
new file mode 100644
index 0000000..c2b7b30
--- /dev/null
+++ b/vendor/github.com/grpc-ecosystem/grpc-gateway/utilities/trie.go
@@ -0,0 +1,177 @@
+package utilities
+
+import (
+ "sort"
+)
+
+// DoubleArray is a Double Array implementation of trie on sequences of strings.
+type DoubleArray struct {
+ // Encoding keeps an encoding from string to int
+ Encoding map[string]int
+ // Base is the base array of Double Array
+ Base []int
+ // Check is the check array of Double Array
+ Check []int
+}
+
+// NewDoubleArray builds a DoubleArray from a set of sequences of strings.
+func NewDoubleArray(seqs [][]string) *DoubleArray {
+ da := &DoubleArray{Encoding: make(map[string]int)}
+ if len(seqs) == 0 {
+ return da
+ }
+
+ encoded := registerTokens(da, seqs)
+ sort.Sort(byLex(encoded))
+
+ root := node{row: -1, col: -1, left: 0, right: len(encoded)}
+ addSeqs(da, encoded, 0, root)
+
+ for i := len(da.Base); i > 0; i-- {
+ if da.Check[i-1] != 0 {
+ da.Base = da.Base[:i]
+ da.Check = da.Check[:i]
+ break
+ }
+ }
+ return da
+}
+
+func registerTokens(da *DoubleArray, seqs [][]string) [][]int {
+ var result [][]int
+ for _, seq := range seqs {
+ var encoded []int
+ for _, token := range seq {
+ if _, ok := da.Encoding[token]; !ok {
+ da.Encoding[token] = len(da.Encoding)
+ }
+ encoded = append(encoded, da.Encoding[token])
+ }
+ result = append(result, encoded)
+ }
+ for i := range result {
+ result[i] = append(result[i], len(da.Encoding))
+ }
+ return result
+}
+
+type node struct {
+ row, col int
+ left, right int
+}
+
+func (n node) value(seqs [][]int) int {
+ return seqs[n.row][n.col]
+}
+
+func (n node) children(seqs [][]int) []*node {
+ var result []*node
+ lastVal := int(-1)
+ last := new(node)
+ for i := n.left; i < n.right; i++ {
+ if lastVal == seqs[i][n.col+1] {
+ continue
+ }
+ last.right = i
+ last = &node{
+ row: i,
+ col: n.col + 1,
+ left: i,
+ }
+ result = append(result, last)
+ }
+ last.right = n.right
+ return result
+}
+
+func addSeqs(da *DoubleArray, seqs [][]int, pos int, n node) {
+ ensureSize(da, pos)
+
+ children := n.children(seqs)
+ var i int
+ for i = 1; ; i++ {
+ ok := func() bool {
+ for _, child := range children {
+ code := child.value(seqs)
+ j := i + code
+ ensureSize(da, j)
+ if da.Check[j] != 0 {
+ return false
+ }
+ }
+ return true
+ }()
+ if ok {
+ break
+ }
+ }
+ da.Base[pos] = i
+ for _, child := range children {
+ code := child.value(seqs)
+ j := i + code
+ da.Check[j] = pos + 1
+ }
+ terminator := len(da.Encoding)
+ for _, child := range children {
+ code := child.value(seqs)
+ if code == terminator {
+ continue
+ }
+ j := i + code
+ addSeqs(da, seqs, j, *child)
+ }
+}
+
+func ensureSize(da *DoubleArray, i int) {
+ for i >= len(da.Base) {
+ da.Base = append(da.Base, make([]int, len(da.Base)+1)...)
+ da.Check = append(da.Check, make([]int, len(da.Check)+1)...)
+ }
+}
+
+type byLex [][]int
+
+func (l byLex) Len() int { return len(l) }
+func (l byLex) Swap(i, j int) { l[i], l[j] = l[j], l[i] }
+func (l byLex) Less(i, j int) bool {
+ si := l[i]
+ sj := l[j]
+ var k int
+ for k = 0; k < len(si) && k < len(sj); k++ {
+ if si[k] < sj[k] {
+ return true
+ }
+ if si[k] > sj[k] {
+ return false
+ }
+ }
+ if k < len(sj) {
+ return true
+ }
+ return false
+}
+
+// HasCommonPrefix determines if any sequence in the DoubleArray is a prefix of the given sequence.
+func (da *DoubleArray) HasCommonPrefix(seq []string) bool {
+ if len(da.Base) == 0 {
+ return false
+ }
+
+ var i int
+ for _, t := range seq {
+ code, ok := da.Encoding[t]
+ if !ok {
+ break
+ }
+ j := da.Base[i] + code
+ if len(da.Check) <= j || da.Check[j] != i+1 {
+ break
+ }
+ i = j
+ }
+ j := da.Base[i] + len(da.Encoding)
+ if len(da.Check) <= j || da.Check[j] != i+1 {
+ return false
+ }
+ return true
+}
diff --git a/vendor/github.com/jaegertracing/jaeger/LICENSE b/vendor/github.com/jaegertracing/jaeger/LICENSE
new file mode 100644
index 0000000..261eeb9
--- /dev/null
+++ b/vendor/github.com/jaegertracing/jaeger/LICENSE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/vendor/github.com/jaegertracing/jaeger/NOTICE b/vendor/github.com/jaegertracing/jaeger/NOTICE
new file mode 100644
index 0000000..31e7311
--- /dev/null
+++ b/vendor/github.com/jaegertracing/jaeger/NOTICE
@@ -0,0 +1,7 @@
+Jaeger, Distributed Tracing Platform.
+
+Copyright 2015-2019 The Jaeger Project Authors
+
+Licensed under Apache License 2.0. See LICENSE for terms.
+
+Includes software developed at Uber Technologies, Inc. (https://eng.uber.com/).
diff --git a/vendor/github.com/jaegertracing/jaeger/model/dependencies.go b/vendor/github.com/jaegertracing/jaeger/model/dependencies.go
new file mode 100644
index 0000000..d1a86ba
--- /dev/null
+++ b/vendor/github.com/jaegertracing/jaeger/model/dependencies.go
@@ -0,0 +1,29 @@
+// Copyright (c) 2019 The Jaeger Authors.
+// Copyright (c) 2017 Uber Technologies, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package model
+
+const (
+ // JaegerDependencyLinkSource describes a dependency diagram that was generated from Jaeger traces.
+ JaegerDependencyLinkSource = "jaeger"
+)
+
+// ApplyDefaults applies defaults to the DependencyLink.
+func (d DependencyLink) ApplyDefaults() DependencyLink {
+ if d.Source == "" {
+ d.Source = JaegerDependencyLinkSource
+ }
+ return d
+}
diff --git a/vendor/github.com/jaegertracing/jaeger/model/doc.go b/vendor/github.com/jaegertracing/jaeger/model/doc.go
new file mode 100644
index 0000000..b44aea6
--- /dev/null
+++ b/vendor/github.com/jaegertracing/jaeger/model/doc.go
@@ -0,0 +1,17 @@
+// Copyright (c) 2019 The Jaeger Authors.
+// Copyright (c) 2017 Uber Technologies, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Package model describes the internal data model for Trace and Span
+package model
diff --git a/vendor/github.com/jaegertracing/jaeger/model/hash.go b/vendor/github.com/jaegertracing/jaeger/model/hash.go
new file mode 100644
index 0000000..a37ea65
--- /dev/null
+++ b/vendor/github.com/jaegertracing/jaeger/model/hash.go
@@ -0,0 +1,37 @@
+// Copyright (c) 2019 The Jaeger Authors.
+// Copyright (c) 2017 Uber Technologies, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package model
+
+import (
+ "hash/fnv"
+ "io"
+)
+
+// Hashable interface is for type that can participate in a hash computation
+// by writing their data into io.Writer, which is usually an instance of hash.Hash.
+//
+type Hashable interface {
+ Hash(w io.Writer) error
+}
+
+// HashCode calculates a FNV-1a hash code for a Hashable object.
+func HashCode(o Hashable) (uint64, error) {
+ h := fnv.New64a()
+ if err := o.Hash(h); err != nil {
+ return 0, err
+ }
+ return h.Sum64(), nil
+}
diff --git a/vendor/github.com/jaegertracing/jaeger/model/ids.go b/vendor/github.com/jaegertracing/jaeger/model/ids.go
new file mode 100644
index 0000000..8b34f7c
--- /dev/null
+++ b/vendor/github.com/jaegertracing/jaeger/model/ids.go
@@ -0,0 +1,254 @@
+// Copyright (c) 2019 The Jaeger Authors.
+// Copyright (c) 2018 Uber Technologies, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package model
+
+import (
+ "encoding/base64"
+ "encoding/binary"
+ "fmt"
+ "strconv"
+
+ "github.com/gogo/protobuf/jsonpb"
+)
+
+const (
+ // traceIDShortBytesLen indicates length of 64bit traceID when represented as list of bytes
+ traceIDShortBytesLen = 8
+ // traceIDLongBytesLen indicates length of 128bit traceID when represented as list of bytes
+ traceIDLongBytesLen = 16
+)
+
+// TraceID is a random 128bit identifier for a trace
+type TraceID struct {
+ Low uint64 `json:"lo"`
+ High uint64 `json:"hi"`
+}
+
+// SpanID is a random 64bit identifier for a span
+type SpanID uint64
+
+// ------- TraceID -------
+
+// NewTraceID creates a new TraceID from two 64bit unsigned ints.
+func NewTraceID(high, low uint64) TraceID {
+ return TraceID{High: high, Low: low}
+}
+
+func (t TraceID) String() string {
+ if t.High == 0 {
+ return fmt.Sprintf("%x", t.Low)
+ }
+ return fmt.Sprintf("%x%016x", t.High, t.Low)
+}
+
+// TraceIDFromString creates a TraceID from a hexadecimal string
+func TraceIDFromString(s string) (TraceID, error) {
+ var hi, lo uint64
+ var err error
+ switch {
+ case len(s) > 32:
+ return TraceID{}, fmt.Errorf("TraceID cannot be longer than 32 hex characters: %s", s)
+ case len(s) > 16:
+ hiLen := len(s) - 16
+ if hi, err = strconv.ParseUint(s[0:hiLen], 16, 64); err != nil {
+ return TraceID{}, err
+ }
+ if lo, err = strconv.ParseUint(s[hiLen:], 16, 64); err != nil {
+ return TraceID{}, err
+ }
+ default:
+ if lo, err = strconv.ParseUint(s, 16, 64); err != nil {
+ return TraceID{}, err
+ }
+ }
+ return TraceID{High: hi, Low: lo}, nil
+}
+
+// TraceIDFromBytes creates a TraceID from list of bytes
+func TraceIDFromBytes(data []byte) (TraceID, error) {
+ var t TraceID
+ switch {
+ case len(data) == traceIDLongBytesLen:
+ t.High = binary.BigEndian.Uint64(data[:traceIDShortBytesLen])
+ t.Low = binary.BigEndian.Uint64(data[traceIDShortBytesLen:])
+ case len(data) == traceIDShortBytesLen:
+ t.Low = binary.BigEndian.Uint64(data)
+ default:
+ return TraceID{}, fmt.Errorf("invalid length for TraceID")
+ }
+ return t, nil
+}
+
+// MarshalText is called by encoding/json, which we do not want people to use.
+func (t TraceID) MarshalText() ([]byte, error) {
+ return nil, fmt.Errorf("unsupported method TraceID.MarshalText; please use github.com/gogo/protobuf/jsonpb for marshalling")
+}
+
+// UnmarshalText is called by encoding/json, which we do not want people to use.
+func (t *TraceID) UnmarshalText(text []byte) error {
+ return fmt.Errorf("unsupported method TraceID.UnmarshalText; please use github.com/gogo/protobuf/jsonpb for marshalling")
+}
+
+// Size returns the size of this datum in protobuf. It is always 16 bytes.
+func (t *TraceID) Size() int {
+ return 16
+}
+
+// MarshalTo converts trace ID into a binary representation. Called by protobuf serialization.
+func (t *TraceID) MarshalTo(data []byte) (n int, err error) {
+ var b [16]byte
+ binary.BigEndian.PutUint64(b[:8], uint64(t.High))
+ binary.BigEndian.PutUint64(b[8:], uint64(t.Low))
+ return marshalBytes(data, b[:])
+}
+
+// Unmarshal inflates this trace ID from binary representation. Called by protobuf serialization.
+func (t *TraceID) Unmarshal(data []byte) error {
+ var err error
+ *t, err = TraceIDFromBytes(data)
+ return err
+}
+
+func marshalBytes(dst []byte, src []byte) (n int, err error) {
+ if len(dst) < len(src) {
+ return 0, fmt.Errorf("buffer is too short")
+ }
+ return copy(dst, src), nil
+}
+
+// MarshalJSON converts trace id into a base64 string enclosed in quotes.
+// Used by protobuf JSON serialization.
+// Example: {high:2, low:1} => "AAAAAAAAAAIAAAAAAAAAAQ==".
+func (t TraceID) MarshalJSON() ([]byte, error) {
+ var b [16]byte
+ t.MarshalTo(b[:]) // can only error on incorrect buffer size
+ s := make([]byte, 24+2)
+ base64.StdEncoding.Encode(s[1:25], b[:])
+ s[0], s[25] = '"', '"'
+ return s, nil
+}
+
+// UnmarshalJSON inflates trace id from base64 string, possibly enclosed in quotes.
+// User by protobuf JSON serialization.
+func (t *TraceID) UnmarshalJSON(data []byte) error {
+ s := string(data)
+ if l := len(s); l > 2 && s[0] == '"' && s[l-1] == '"' {
+ s = s[1 : l-1]
+ }
+ b, err := base64.StdEncoding.DecodeString(s)
+ if err != nil {
+ return fmt.Errorf("cannot unmarshal TraceID from string '%s': %v", string(data), err)
+ }
+ return t.Unmarshal(b)
+}
+
+// ------- SpanID -------
+
+// NewSpanID creates a new SpanID from a 64bit unsigned int.
+func NewSpanID(v uint64) SpanID {
+ return SpanID(v)
+}
+
+func (s SpanID) String() string {
+ return fmt.Sprintf("%x", uint64(s))
+}
+
+// SpanIDFromString creates a SpanID from a hexadecimal string
+func SpanIDFromString(s string) (SpanID, error) {
+ if len(s) > 16 {
+ return SpanID(0), fmt.Errorf("SpanID cannot be longer than 16 hex characters: %s", s)
+ }
+ id, err := strconv.ParseUint(s, 16, 64)
+ if err != nil {
+ return SpanID(0), err
+ }
+ return SpanID(id), nil
+}
+
+// SpanIDFromBytes creates a SpandID from list of bytes
+func SpanIDFromBytes(data []byte) (SpanID, error) {
+ if len(data) != traceIDShortBytesLen {
+ return SpanID(0), fmt.Errorf("invalid length for SpanID")
+ }
+ return NewSpanID(binary.BigEndian.Uint64(data)), nil
+}
+
+// MarshalText is called by encoding/json, which we do not want people to use.
+func (s SpanID) MarshalText() ([]byte, error) {
+ return nil, fmt.Errorf("unsupported method SpanID.MarshalText; please use github.com/gogo/protobuf/jsonpb for marshalling")
+}
+
+// UnmarshalText is called by encoding/json, which we do not want people to use.
+func (s *SpanID) UnmarshalText(text []byte) error {
+ return fmt.Errorf("unsupported method SpanID.UnmarshalText; please use github.com/gogo/protobuf/jsonpb for marshalling")
+}
+
+// Size returns the size of this datum in protobuf. It is always 8 bytes.
+func (s *SpanID) Size() int {
+ return 8
+}
+
+// MarshalTo converts span ID into a binary representation. Called by protobuf serialization.
+func (s *SpanID) MarshalTo(data []byte) (n int, err error) {
+ var b [8]byte
+ binary.BigEndian.PutUint64(b[:], uint64(*s))
+ return marshalBytes(data, b[:])
+}
+
+// Unmarshal inflates span ID from a binary representation. Called by protobuf serialization.
+func (s *SpanID) Unmarshal(data []byte) error {
+ var err error
+ *s, err = SpanIDFromBytes(data)
+ return err
+}
+
+// MarshalJSON converts span id into a base64 string enclosed in quotes.
+// Used by protobuf JSON serialization.
+// Example: {1} => "AAAAAAAAAAE=".
+func (s SpanID) MarshalJSON() ([]byte, error) {
+ var b [8]byte
+ s.MarshalTo(b[:]) // can only error on incorrect buffer size
+ v := make([]byte, 12+2)
+ base64.StdEncoding.Encode(v[1:13], b[:])
+ v[0], v[13] = '"', '"'
+ return v, nil
+}
+
+// UnmarshalJSON inflates span id from base64 string, possibly enclosed in quotes.
+// User by protobuf JSON serialization.
+//
+// There appears to be a bug in gogoproto, as this function is only called for numeric values.
+// https://github.com/gogo/protobuf/issues/411#issuecomment-393856837
+func (s *SpanID) UnmarshalJSON(data []byte) error {
+ str := string(data)
+ if l := len(str); l > 2 && str[0] == '"' && str[l-1] == '"' {
+ str = str[1 : l-1]
+ }
+ b, err := base64.StdEncoding.DecodeString(str)
+ if err != nil {
+ return fmt.Errorf("cannot unmarshal SpanID from string '%s': %v", string(data), err)
+ }
+ return s.Unmarshal(b)
+}
+
+// UnmarshalJSONPB inflates span id from base64 string, possibly enclosed in quotes.
+// User by protobuf JSON serialization.
+//
+// TODO: can be removed once this ticket is fixed:
+// https://github.com/gogo/protobuf/issues/411#issuecomment-393856837
+func (s *SpanID) UnmarshalJSONPB(_ *jsonpb.Unmarshaler, b []byte) error {
+ return s.UnmarshalJSON(b)
+}
diff --git a/vendor/github.com/jaegertracing/jaeger/model/keyvalue.go b/vendor/github.com/jaegertracing/jaeger/model/keyvalue.go
new file mode 100644
index 0000000..09fae48
--- /dev/null
+++ b/vendor/github.com/jaegertracing/jaeger/model/keyvalue.go
@@ -0,0 +1,223 @@
+// Copyright (c) 2019 The Jaeger Authors.
+// Copyright (c) 2017 Uber Technologies, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package model
+
+import (
+ "encoding/binary"
+ "encoding/hex"
+ "fmt"
+ "io"
+ "sort"
+ "strconv"
+)
+
+// These constants are kept mostly for backwards compatibility.
+const (
+ // StringType indicates the value is a unicode string
+ StringType = ValueType_STRING
+ // BoolType indicates the value is a Boolean encoded as int64 number 0 or 1
+ BoolType = ValueType_BOOL
+ // Int64Type indicates the value is an int64 number
+ Int64Type = ValueType_INT64
+ // Float64Type indicates the value is a float64 number stored as int64
+ Float64Type = ValueType_FLOAT64
+ // BinaryType indicates the value is binary blob stored as a byte array
+ BinaryType = ValueType_BINARY
+)
+
+// KeyValues is a type alias that exposes convenience functions like Sort, FindByKey.
+type KeyValues []KeyValue
+
+// String creates a String-typed KeyValue
+func String(key string, value string) KeyValue {
+ return KeyValue{Key: key, VType: StringType, VStr: value}
+}
+
+// Bool creates a Bool-typed KeyValue
+func Bool(key string, value bool) KeyValue {
+ return KeyValue{Key: key, VType: BoolType, VBool: value}
+}
+
+// Int64 creates a Int64-typed KeyValue
+func Int64(key string, value int64) KeyValue {
+ return KeyValue{Key: key, VType: Int64Type, VInt64: value}
+}
+
+// Float64 creates a Float64-typed KeyValue
+func Float64(key string, value float64) KeyValue {
+ return KeyValue{Key: key, VType: Float64Type, VFloat64: value}
+}
+
+// Binary creates a Binary-typed KeyValue
+func Binary(key string, value []byte) KeyValue {
+ return KeyValue{Key: key, VType: BinaryType, VBinary: value}
+}
+
+// Bool returns the Boolean value stored in this KeyValue or false if it stores a different type.
+// The caller must check VType before using this method.
+func (kv *KeyValue) Bool() bool {
+ if kv.VType == BoolType {
+ return kv.VBool
+ }
+ return false
+}
+
+// Int64 returns the Int64 value stored in this KeyValue or 0 if it stores a different type.
+// The caller must check VType before using this method.
+func (kv *KeyValue) Int64() int64 {
+ if kv.VType == Int64Type {
+ return kv.VInt64
+ }
+ return 0
+}
+
+// Float64 returns the Float64 value stored in this KeyValue or 0 if it stores a different type.
+// The caller must check VType before using this method.
+func (kv *KeyValue) Float64() float64 {
+ if kv.VType == Float64Type {
+ return kv.VFloat64
+ }
+ return 0
+}
+
+// Binary returns the blob ([]byte) value stored in this KeyValue or nil if it stores a different type.
+// The caller must check VType before using this method.
+func (kv *KeyValue) Binary() []byte {
+ if kv.VType == BinaryType {
+ return kv.VBinary
+ }
+ return nil
+}
+
+// Value returns typed values stored in KeyValue as interface{}.
+func (kv *KeyValue) Value() interface{} {
+ switch kv.VType {
+ case StringType:
+ return kv.VStr
+ case BoolType:
+ return kv.VBool
+ case Int64Type:
+ return kv.VInt64
+ case Float64Type:
+ return kv.VFloat64
+ case BinaryType:
+ return kv.VBinary
+ default:
+ return fmt.Errorf("unknown type %d", kv.VType)
+ }
+}
+
+// AsString returns a potentially lossy string representation of the value.
+func (kv *KeyValue) AsString() string {
+ switch kv.VType {
+ case StringType:
+ return kv.VStr
+ case BoolType:
+ if kv.Bool() {
+ return "true"
+ }
+ return "false"
+ case Int64Type:
+ return strconv.FormatInt(kv.Int64(), 10)
+ case Float64Type:
+ return strconv.FormatFloat(kv.Float64(), 'g', 10, 64)
+ case BinaryType:
+ if len(kv.VBinary) > 256 {
+ return hex.EncodeToString(kv.VBinary[0:256]) + "..."
+ }
+ return hex.EncodeToString(kv.VBinary)
+ default:
+ return fmt.Sprintf("unknown type %d", kv.VType)
+ }
+}
+
+// IsLess compares KeyValue object with another KeyValue.
+// The order is based first on the keys, then on type, and finally on the value.
+func (kv *KeyValue) IsLess(two *KeyValue) bool {
+ return kv.Compare(two) < 0
+}
+
+func (kvs KeyValues) Len() int { return len(kvs) }
+func (kvs KeyValues) Swap(i, j int) { kvs[i], kvs[j] = kvs[j], kvs[i] }
+func (kvs KeyValues) Less(i, j int) bool {
+ return kvs[i].IsLess(&kvs[j])
+}
+
+// Sort does in-place sorting of KeyValues, then by value type, then by value.
+func (kvs KeyValues) Sort() {
+ sort.Sort(kvs)
+}
+
+// FindByKey scans the list of key-values searching for the first one with the given key.
+// Returns found tag and a boolean flag indicating if the search was successful.
+func (kvs KeyValues) FindByKey(key string) (KeyValue, bool) {
+ for _, kv := range kvs {
+ if kv.Key == key {
+ return kv, true
+ }
+ }
+ return KeyValue{}, false
+}
+
+// Equal compares KeyValues with another list. Both lists must be already sorted.
+func (kvs KeyValues) Equal(other KeyValues) bool {
+ l1, l2 := len(kvs), len(other)
+ if l1 != l2 {
+ return false
+ }
+ for i := 0; i < l1; i++ {
+ if !kvs[i].Equal(&other[i]) {
+ return false
+ }
+ }
+ return true
+}
+
+// Hash implements Hash from Hashable.
+func (kvs KeyValues) Hash(w io.Writer) error {
+ for i := range kvs {
+ if err := kvs[i].Hash(w); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// Hash implements Hash from Hashable.
+func (kv KeyValue) Hash(w io.Writer) error {
+ if _, err := w.Write([]byte(kv.Key)); err != nil {
+ return err
+ }
+ if err := binary.Write(w, binary.BigEndian, uint16(kv.VType)); err != nil {
+ return err
+ }
+ var err error
+ switch kv.VType {
+ case StringType:
+ _, err = w.Write([]byte(kv.VStr))
+ case BoolType:
+ err = binary.Write(w, binary.BigEndian, kv.VBool)
+ case Int64Type:
+ err = binary.Write(w, binary.BigEndian, kv.VInt64)
+ case Float64Type:
+ err = binary.Write(w, binary.BigEndian, kv.VFloat64)
+ case BinaryType:
+ _, err = w.Write(kv.VBinary)
+ default:
+ err = fmt.Errorf("unknown type %d", kv.VType)
+ }
+ return err
+}
diff --git a/vendor/github.com/jaegertracing/jaeger/model/model.pb.go b/vendor/github.com/jaegertracing/jaeger/model/model.pb.go
new file mode 100644
index 0000000..ca5bf99
--- /dev/null
+++ b/vendor/github.com/jaegertracing/jaeger/model/model.pb.go
@@ -0,0 +1,3402 @@
+// Code generated by protoc-gen-gogo. DO NOT EDIT.
+// source: model.proto
+
+package model
+
+import (
+ bytes "bytes"
+ encoding_binary "encoding/binary"
+ fmt "fmt"
+ _ "github.com/gogo/googleapis/google/api"
+ _ "github.com/gogo/protobuf/gogoproto"
+ proto "github.com/gogo/protobuf/proto"
+ _ "github.com/gogo/protobuf/types"
+ github_com_gogo_protobuf_types "github.com/gogo/protobuf/types"
+ golang_proto "github.com/golang/protobuf/proto"
+ io "io"
+ math "math"
+ time "time"
+)
+
+// Reference imports to suppress errors if they are not otherwise used.
+var _ = proto.Marshal
+var _ = golang_proto.Marshal
+var _ = fmt.Errorf
+var _ = math.Inf
+var _ = time.Kitchen
+
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the proto package it is being compiled against.
+// A compilation error at this line likely means your copy of the
+// proto package needs to be updated.
+const _ = proto.GoGoProtoPackageIsVersion2 // please upgrade the proto package
+
+type ValueType int32
+
+const (
+ ValueType_STRING ValueType = 0
+ ValueType_BOOL ValueType = 1
+ ValueType_INT64 ValueType = 2
+ ValueType_FLOAT64 ValueType = 3
+ ValueType_BINARY ValueType = 4
+)
+
+var ValueType_name = map[int32]string{
+ 0: "STRING",
+ 1: "BOOL",
+ 2: "INT64",
+ 3: "FLOAT64",
+ 4: "BINARY",
+}
+
+var ValueType_value = map[string]int32{
+ "STRING": 0,
+ "BOOL": 1,
+ "INT64": 2,
+ "FLOAT64": 3,
+ "BINARY": 4,
+}
+
+func (x ValueType) String() string {
+ return proto.EnumName(ValueType_name, int32(x))
+}
+
+func (ValueType) EnumDescriptor() ([]byte, []int) {
+ return fileDescriptor_4c16552f9fdb66d8, []int{0}
+}
+
+type SpanRefType int32
+
+const (
+ SpanRefType_CHILD_OF SpanRefType = 0
+ SpanRefType_FOLLOWS_FROM SpanRefType = 1
+)
+
+var SpanRefType_name = map[int32]string{
+ 0: "CHILD_OF",
+ 1: "FOLLOWS_FROM",
+}
+
+var SpanRefType_value = map[string]int32{
+ "CHILD_OF": 0,
+ "FOLLOWS_FROM": 1,
+}
+
+func (x SpanRefType) String() string {
+ return proto.EnumName(SpanRefType_name, int32(x))
+}
+
+func (SpanRefType) EnumDescriptor() ([]byte, []int) {
+ return fileDescriptor_4c16552f9fdb66d8, []int{1}
+}
+
+type KeyValue struct {
+ Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
+ VType ValueType `protobuf:"varint,2,opt,name=v_type,json=vType,proto3,enum=jaeger.api_v2.ValueType" json:"v_type,omitempty"`
+ VStr string `protobuf:"bytes,3,opt,name=v_str,json=vStr,proto3" json:"v_str,omitempty"`
+ VBool bool `protobuf:"varint,4,opt,name=v_bool,json=vBool,proto3" json:"v_bool,omitempty"`
+ VInt64 int64 `protobuf:"varint,5,opt,name=v_int64,json=vInt64,proto3" json:"v_int64,omitempty"`
+ VFloat64 float64 `protobuf:"fixed64,6,opt,name=v_float64,json=vFloat64,proto3" json:"v_float64,omitempty"`
+ VBinary []byte `protobuf:"bytes,7,opt,name=v_binary,json=vBinary,proto3" json:"v_binary,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *KeyValue) Reset() { *m = KeyValue{} }
+func (m *KeyValue) String() string { return proto.CompactTextString(m) }
+func (*KeyValue) ProtoMessage() {}
+func (*KeyValue) Descriptor() ([]byte, []int) {
+ return fileDescriptor_4c16552f9fdb66d8, []int{0}
+}
+func (m *KeyValue) XXX_Unmarshal(b []byte) error {
+ return m.Unmarshal(b)
+}
+func (m *KeyValue) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ if deterministic {
+ return xxx_messageInfo_KeyValue.Marshal(b, m, deterministic)
+ } else {
+ b = b[:cap(b)]
+ n, err := m.MarshalTo(b)
+ if err != nil {
+ return nil, err
+ }
+ return b[:n], nil
+ }
+}
+func (m *KeyValue) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_KeyValue.Merge(m, src)
+}
+func (m *KeyValue) XXX_Size() int {
+ return m.Size()
+}
+func (m *KeyValue) XXX_DiscardUnknown() {
+ xxx_messageInfo_KeyValue.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_KeyValue proto.InternalMessageInfo
+
+func (m *KeyValue) GetKey() string {
+ if m != nil {
+ return m.Key
+ }
+ return ""
+}
+
+func (m *KeyValue) GetVType() ValueType {
+ if m != nil {
+ return m.VType
+ }
+ return ValueType_STRING
+}
+
+func (m *KeyValue) GetVStr() string {
+ if m != nil {
+ return m.VStr
+ }
+ return ""
+}
+
+func (m *KeyValue) GetVBool() bool {
+ if m != nil {
+ return m.VBool
+ }
+ return false
+}
+
+func (m *KeyValue) GetVInt64() int64 {
+ if m != nil {
+ return m.VInt64
+ }
+ return 0
+}
+
+func (m *KeyValue) GetVFloat64() float64 {
+ if m != nil {
+ return m.VFloat64
+ }
+ return 0
+}
+
+func (m *KeyValue) GetVBinary() []byte {
+ if m != nil {
+ return m.VBinary
+ }
+ return nil
+}
+
+type Log struct {
+ Timestamp time.Time `protobuf:"bytes,1,opt,name=timestamp,proto3,stdtime" json:"timestamp"`
+ Fields []KeyValue `protobuf:"bytes,2,rep,name=fields,proto3" json:"fields"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *Log) Reset() { *m = Log{} }
+func (m *Log) String() string { return proto.CompactTextString(m) }
+func (*Log) ProtoMessage() {}
+func (*Log) Descriptor() ([]byte, []int) {
+ return fileDescriptor_4c16552f9fdb66d8, []int{1}
+}
+func (m *Log) XXX_Unmarshal(b []byte) error {
+ return m.Unmarshal(b)
+}
+func (m *Log) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ if deterministic {
+ return xxx_messageInfo_Log.Marshal(b, m, deterministic)
+ } else {
+ b = b[:cap(b)]
+ n, err := m.MarshalTo(b)
+ if err != nil {
+ return nil, err
+ }
+ return b[:n], nil
+ }
+}
+func (m *Log) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_Log.Merge(m, src)
+}
+func (m *Log) XXX_Size() int {
+ return m.Size()
+}
+func (m *Log) XXX_DiscardUnknown() {
+ xxx_messageInfo_Log.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_Log proto.InternalMessageInfo
+
+func (m *Log) GetTimestamp() time.Time {
+ if m != nil {
+ return m.Timestamp
+ }
+ return time.Time{}
+}
+
+func (m *Log) GetFields() []KeyValue {
+ if m != nil {
+ return m.Fields
+ }
+ return nil
+}
+
+type SpanRef struct {
+ TraceID TraceID `protobuf:"bytes,1,opt,name=trace_id,json=traceId,proto3,customtype=TraceID" json:"trace_id"`
+ SpanID SpanID `protobuf:"bytes,2,opt,name=span_id,json=spanId,proto3,customtype=SpanID" json:"span_id"`
+ RefType SpanRefType `protobuf:"varint,3,opt,name=ref_type,json=refType,proto3,enum=jaeger.api_v2.SpanRefType" json:"ref_type,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *SpanRef) Reset() { *m = SpanRef{} }
+func (m *SpanRef) String() string { return proto.CompactTextString(m) }
+func (*SpanRef) ProtoMessage() {}
+func (*SpanRef) Descriptor() ([]byte, []int) {
+ return fileDescriptor_4c16552f9fdb66d8, []int{2}
+}
+func (m *SpanRef) XXX_Unmarshal(b []byte) error {
+ return m.Unmarshal(b)
+}
+func (m *SpanRef) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ if deterministic {
+ return xxx_messageInfo_SpanRef.Marshal(b, m, deterministic)
+ } else {
+ b = b[:cap(b)]
+ n, err := m.MarshalTo(b)
+ if err != nil {
+ return nil, err
+ }
+ return b[:n], nil
+ }
+}
+func (m *SpanRef) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_SpanRef.Merge(m, src)
+}
+func (m *SpanRef) XXX_Size() int {
+ return m.Size()
+}
+func (m *SpanRef) XXX_DiscardUnknown() {
+ xxx_messageInfo_SpanRef.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_SpanRef proto.InternalMessageInfo
+
+func (m *SpanRef) GetRefType() SpanRefType {
+ if m != nil {
+ return m.RefType
+ }
+ return SpanRefType_CHILD_OF
+}
+
+type Process struct {
+ ServiceName string `protobuf:"bytes,1,opt,name=service_name,json=serviceName,proto3" json:"service_name,omitempty"`
+ Tags []KeyValue `protobuf:"bytes,2,rep,name=tags,proto3" json:"tags"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *Process) Reset() { *m = Process{} }
+func (m *Process) String() string { return proto.CompactTextString(m) }
+func (*Process) ProtoMessage() {}
+func (*Process) Descriptor() ([]byte, []int) {
+ return fileDescriptor_4c16552f9fdb66d8, []int{3}
+}
+func (m *Process) XXX_Unmarshal(b []byte) error {
+ return m.Unmarshal(b)
+}
+func (m *Process) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ if deterministic {
+ return xxx_messageInfo_Process.Marshal(b, m, deterministic)
+ } else {
+ b = b[:cap(b)]
+ n, err := m.MarshalTo(b)
+ if err != nil {
+ return nil, err
+ }
+ return b[:n], nil
+ }
+}
+func (m *Process) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_Process.Merge(m, src)
+}
+func (m *Process) XXX_Size() int {
+ return m.Size()
+}
+func (m *Process) XXX_DiscardUnknown() {
+ xxx_messageInfo_Process.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_Process proto.InternalMessageInfo
+
+func (m *Process) GetServiceName() string {
+ if m != nil {
+ return m.ServiceName
+ }
+ return ""
+}
+
+func (m *Process) GetTags() []KeyValue {
+ if m != nil {
+ return m.Tags
+ }
+ return nil
+}
+
+type Span struct {
+ TraceID TraceID `protobuf:"bytes,1,opt,name=trace_id,json=traceId,proto3,customtype=TraceID" json:"trace_id"`
+ SpanID SpanID `protobuf:"bytes,2,opt,name=span_id,json=spanId,proto3,customtype=SpanID" json:"span_id"`
+ OperationName string `protobuf:"bytes,3,opt,name=operation_name,json=operationName,proto3" json:"operation_name,omitempty"`
+ References []SpanRef `protobuf:"bytes,4,rep,name=references,proto3" json:"references"`
+ Flags Flags `protobuf:"varint,5,opt,name=flags,proto3,customtype=Flags" json:"flags"`
+ StartTime time.Time `protobuf:"bytes,6,opt,name=start_time,json=startTime,proto3,stdtime" json:"start_time"`
+ Duration time.Duration `protobuf:"bytes,7,opt,name=duration,proto3,stdduration" json:"duration"`
+ Tags []KeyValue `protobuf:"bytes,8,rep,name=tags,proto3" json:"tags"`
+ Logs []Log `protobuf:"bytes,9,rep,name=logs,proto3" json:"logs"`
+ Process *Process `protobuf:"bytes,10,opt,name=process,proto3" json:"process,omitempty"`
+ ProcessID string `protobuf:"bytes,11,opt,name=process_id,json=processId,proto3" json:"process_id,omitempty"`
+ Warnings []string `protobuf:"bytes,12,rep,name=warnings,proto3" json:"warnings,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *Span) Reset() { *m = Span{} }
+func (m *Span) String() string { return proto.CompactTextString(m) }
+func (*Span) ProtoMessage() {}
+func (*Span) Descriptor() ([]byte, []int) {
+ return fileDescriptor_4c16552f9fdb66d8, []int{4}
+}
+func (m *Span) XXX_Unmarshal(b []byte) error {
+ return m.Unmarshal(b)
+}
+func (m *Span) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ if deterministic {
+ return xxx_messageInfo_Span.Marshal(b, m, deterministic)
+ } else {
+ b = b[:cap(b)]
+ n, err := m.MarshalTo(b)
+ if err != nil {
+ return nil, err
+ }
+ return b[:n], nil
+ }
+}
+func (m *Span) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_Span.Merge(m, src)
+}
+func (m *Span) XXX_Size() int {
+ return m.Size()
+}
+func (m *Span) XXX_DiscardUnknown() {
+ xxx_messageInfo_Span.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_Span proto.InternalMessageInfo
+
+func (m *Span) GetOperationName() string {
+ if m != nil {
+ return m.OperationName
+ }
+ return ""
+}
+
+func (m *Span) GetReferences() []SpanRef {
+ if m != nil {
+ return m.References
+ }
+ return nil
+}
+
+func (m *Span) GetStartTime() time.Time {
+ if m != nil {
+ return m.StartTime
+ }
+ return time.Time{}
+}
+
+func (m *Span) GetDuration() time.Duration {
+ if m != nil {
+ return m.Duration
+ }
+ return 0
+}
+
+func (m *Span) GetTags() []KeyValue {
+ if m != nil {
+ return m.Tags
+ }
+ return nil
+}
+
+func (m *Span) GetLogs() []Log {
+ if m != nil {
+ return m.Logs
+ }
+ return nil
+}
+
+func (m *Span) GetProcess() *Process {
+ if m != nil {
+ return m.Process
+ }
+ return nil
+}
+
+func (m *Span) GetProcessID() string {
+ if m != nil {
+ return m.ProcessID
+ }
+ return ""
+}
+
+func (m *Span) GetWarnings() []string {
+ if m != nil {
+ return m.Warnings
+ }
+ return nil
+}
+
+type Trace struct {
+ Spans []*Span `protobuf:"bytes,1,rep,name=spans,proto3" json:"spans,omitempty"`
+ ProcessMap []Trace_ProcessMapping `protobuf:"bytes,2,rep,name=process_map,json=processMap,proto3" json:"process_map"`
+ Warnings []string `protobuf:"bytes,3,rep,name=warnings,proto3" json:"warnings,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *Trace) Reset() { *m = Trace{} }
+func (m *Trace) String() string { return proto.CompactTextString(m) }
+func (*Trace) ProtoMessage() {}
+func (*Trace) Descriptor() ([]byte, []int) {
+ return fileDescriptor_4c16552f9fdb66d8, []int{5}
+}
+func (m *Trace) XXX_Unmarshal(b []byte) error {
+ return m.Unmarshal(b)
+}
+func (m *Trace) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ if deterministic {
+ return xxx_messageInfo_Trace.Marshal(b, m, deterministic)
+ } else {
+ b = b[:cap(b)]
+ n, err := m.MarshalTo(b)
+ if err != nil {
+ return nil, err
+ }
+ return b[:n], nil
+ }
+}
+func (m *Trace) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_Trace.Merge(m, src)
+}
+func (m *Trace) XXX_Size() int {
+ return m.Size()
+}
+func (m *Trace) XXX_DiscardUnknown() {
+ xxx_messageInfo_Trace.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_Trace proto.InternalMessageInfo
+
+func (m *Trace) GetSpans() []*Span {
+ if m != nil {
+ return m.Spans
+ }
+ return nil
+}
+
+func (m *Trace) GetProcessMap() []Trace_ProcessMapping {
+ if m != nil {
+ return m.ProcessMap
+ }
+ return nil
+}
+
+func (m *Trace) GetWarnings() []string {
+ if m != nil {
+ return m.Warnings
+ }
+ return nil
+}
+
+type Trace_ProcessMapping struct {
+ ProcessID string `protobuf:"bytes,1,opt,name=process_id,json=processId,proto3" json:"process_id,omitempty"`
+ Process Process `protobuf:"bytes,2,opt,name=process,proto3" json:"process"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *Trace_ProcessMapping) Reset() { *m = Trace_ProcessMapping{} }
+func (m *Trace_ProcessMapping) String() string { return proto.CompactTextString(m) }
+func (*Trace_ProcessMapping) ProtoMessage() {}
+func (*Trace_ProcessMapping) Descriptor() ([]byte, []int) {
+ return fileDescriptor_4c16552f9fdb66d8, []int{5, 0}
+}
+func (m *Trace_ProcessMapping) XXX_Unmarshal(b []byte) error {
+ return m.Unmarshal(b)
+}
+func (m *Trace_ProcessMapping) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ if deterministic {
+ return xxx_messageInfo_Trace_ProcessMapping.Marshal(b, m, deterministic)
+ } else {
+ b = b[:cap(b)]
+ n, err := m.MarshalTo(b)
+ if err != nil {
+ return nil, err
+ }
+ return b[:n], nil
+ }
+}
+func (m *Trace_ProcessMapping) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_Trace_ProcessMapping.Merge(m, src)
+}
+func (m *Trace_ProcessMapping) XXX_Size() int {
+ return m.Size()
+}
+func (m *Trace_ProcessMapping) XXX_DiscardUnknown() {
+ xxx_messageInfo_Trace_ProcessMapping.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_Trace_ProcessMapping proto.InternalMessageInfo
+
+func (m *Trace_ProcessMapping) GetProcessID() string {
+ if m != nil {
+ return m.ProcessID
+ }
+ return ""
+}
+
+func (m *Trace_ProcessMapping) GetProcess() Process {
+ if m != nil {
+ return m.Process
+ }
+ return Process{}
+}
+
+type Batch struct {
+ Spans []*Span `protobuf:"bytes,1,rep,name=spans,proto3" json:"spans,omitempty"`
+ Process *Process `protobuf:"bytes,2,opt,name=process,proto3" json:"process,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *Batch) Reset() { *m = Batch{} }
+func (m *Batch) String() string { return proto.CompactTextString(m) }
+func (*Batch) ProtoMessage() {}
+func (*Batch) Descriptor() ([]byte, []int) {
+ return fileDescriptor_4c16552f9fdb66d8, []int{6}
+}
+func (m *Batch) XXX_Unmarshal(b []byte) error {
+ return m.Unmarshal(b)
+}
+func (m *Batch) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ if deterministic {
+ return xxx_messageInfo_Batch.Marshal(b, m, deterministic)
+ } else {
+ b = b[:cap(b)]
+ n, err := m.MarshalTo(b)
+ if err != nil {
+ return nil, err
+ }
+ return b[:n], nil
+ }
+}
+func (m *Batch) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_Batch.Merge(m, src)
+}
+func (m *Batch) XXX_Size() int {
+ return m.Size()
+}
+func (m *Batch) XXX_DiscardUnknown() {
+ xxx_messageInfo_Batch.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_Batch proto.InternalMessageInfo
+
+func (m *Batch) GetSpans() []*Span {
+ if m != nil {
+ return m.Spans
+ }
+ return nil
+}
+
+func (m *Batch) GetProcess() *Process {
+ if m != nil {
+ return m.Process
+ }
+ return nil
+}
+
+type DependencyLink struct {
+ Parent string `protobuf:"bytes,1,opt,name=parent,proto3" json:"parent,omitempty"`
+ Child string `protobuf:"bytes,2,opt,name=child,proto3" json:"child,omitempty"`
+ CallCount uint64 `protobuf:"varint,3,opt,name=call_count,json=callCount,proto3" json:"call_count,omitempty"`
+ Source string `protobuf:"bytes,4,opt,name=source,proto3" json:"source,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *DependencyLink) Reset() { *m = DependencyLink{} }
+func (m *DependencyLink) String() string { return proto.CompactTextString(m) }
+func (*DependencyLink) ProtoMessage() {}
+func (*DependencyLink) Descriptor() ([]byte, []int) {
+ return fileDescriptor_4c16552f9fdb66d8, []int{7}
+}
+func (m *DependencyLink) XXX_Unmarshal(b []byte) error {
+ return m.Unmarshal(b)
+}
+func (m *DependencyLink) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ if deterministic {
+ return xxx_messageInfo_DependencyLink.Marshal(b, m, deterministic)
+ } else {
+ b = b[:cap(b)]
+ n, err := m.MarshalTo(b)
+ if err != nil {
+ return nil, err
+ }
+ return b[:n], nil
+ }
+}
+func (m *DependencyLink) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_DependencyLink.Merge(m, src)
+}
+func (m *DependencyLink) XXX_Size() int {
+ return m.Size()
+}
+func (m *DependencyLink) XXX_DiscardUnknown() {
+ xxx_messageInfo_DependencyLink.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_DependencyLink proto.InternalMessageInfo
+
+func (m *DependencyLink) GetParent() string {
+ if m != nil {
+ return m.Parent
+ }
+ return ""
+}
+
+func (m *DependencyLink) GetChild() string {
+ if m != nil {
+ return m.Child
+ }
+ return ""
+}
+
+func (m *DependencyLink) GetCallCount() uint64 {
+ if m != nil {
+ return m.CallCount
+ }
+ return 0
+}
+
+func (m *DependencyLink) GetSource() string {
+ if m != nil {
+ return m.Source
+ }
+ return ""
+}
+
+func init() {
+ proto.RegisterEnum("jaeger.api_v2.ValueType", ValueType_name, ValueType_value)
+ golang_proto.RegisterEnum("jaeger.api_v2.ValueType", ValueType_name, ValueType_value)
+ proto.RegisterEnum("jaeger.api_v2.SpanRefType", SpanRefType_name, SpanRefType_value)
+ golang_proto.RegisterEnum("jaeger.api_v2.SpanRefType", SpanRefType_name, SpanRefType_value)
+ proto.RegisterType((*KeyValue)(nil), "jaeger.api_v2.KeyValue")
+ golang_proto.RegisterType((*KeyValue)(nil), "jaeger.api_v2.KeyValue")
+ proto.RegisterType((*Log)(nil), "jaeger.api_v2.Log")
+ golang_proto.RegisterType((*Log)(nil), "jaeger.api_v2.Log")
+ proto.RegisterType((*SpanRef)(nil), "jaeger.api_v2.SpanRef")
+ golang_proto.RegisterType((*SpanRef)(nil), "jaeger.api_v2.SpanRef")
+ proto.RegisterType((*Process)(nil), "jaeger.api_v2.Process")
+ golang_proto.RegisterType((*Process)(nil), "jaeger.api_v2.Process")
+ proto.RegisterType((*Span)(nil), "jaeger.api_v2.Span")
+ golang_proto.RegisterType((*Span)(nil), "jaeger.api_v2.Span")
+ proto.RegisterType((*Trace)(nil), "jaeger.api_v2.Trace")
+ golang_proto.RegisterType((*Trace)(nil), "jaeger.api_v2.Trace")
+ proto.RegisterType((*Trace_ProcessMapping)(nil), "jaeger.api_v2.Trace.ProcessMapping")
+ golang_proto.RegisterType((*Trace_ProcessMapping)(nil), "jaeger.api_v2.Trace.ProcessMapping")
+ proto.RegisterType((*Batch)(nil), "jaeger.api_v2.Batch")
+ golang_proto.RegisterType((*Batch)(nil), "jaeger.api_v2.Batch")
+ proto.RegisterType((*DependencyLink)(nil), "jaeger.api_v2.DependencyLink")
+ golang_proto.RegisterType((*DependencyLink)(nil), "jaeger.api_v2.DependencyLink")
+}
+
+func init() { proto.RegisterFile("model.proto", fileDescriptor_4c16552f9fdb66d8) }
+func init() { golang_proto.RegisterFile("model.proto", fileDescriptor_4c16552f9fdb66d8) }
+
+var fileDescriptor_4c16552f9fdb66d8 = []byte{
+ // 975 bytes of a gzipped FileDescriptorProto
+ 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x55, 0x41, 0x8f, 0xdb, 0x44,
+ 0x14, 0xde, 0x49, 0xec, 0xd8, 0x7e, 0xc9, 0xae, 0xa2, 0x69, 0xe9, 0xba, 0x01, 0x36, 0x21, 0x15,
+ 0x52, 0xa8, 0x4a, 0xb6, 0x5d, 0xda, 0x3d, 0x20, 0x24, 0x54, 0xef, 0x12, 0x08, 0x64, 0x37, 0x68,
+ 0x76, 0x05, 0x82, 0x8b, 0x35, 0xeb, 0x4c, 0x5c, 0xb7, 0x8e, 0xc7, 0xb2, 0x1d, 0xa3, 0xdc, 0xf8,
+ 0x09, 0x88, 0x13, 0x47, 0xb8, 0xf2, 0x2b, 0x38, 0xf6, 0xc8, 0x81, 0x13, 0x12, 0x0b, 0x0a, 0x97,
+ 0xfe, 0x0c, 0x34, 0xe3, 0x71, 0xb6, 0x1b, 0x2a, 0xd8, 0x5e, 0x7a, 0xf2, 0xbc, 0x79, 0xdf, 0x7b,
+ 0xf3, 0xde, 0xf7, 0xbe, 0xf1, 0x40, 0x7d, 0xc6, 0x27, 0x2c, 0xec, 0xc7, 0x09, 0xcf, 0x38, 0xde,
+ 0x7c, 0x4c, 0x99, 0xcf, 0x92, 0x3e, 0x8d, 0x03, 0x37, 0xdf, 0x6b, 0x5d, 0xf7, 0xb9, 0xcf, 0xa5,
+ 0x67, 0x57, 0xac, 0x0a, 0x50, 0xeb, 0x0d, 0x9f, 0x73, 0x3f, 0x64, 0xbb, 0x34, 0x0e, 0x76, 0x69,
+ 0x14, 0xf1, 0x8c, 0x66, 0x01, 0x8f, 0x52, 0xe5, 0x6d, 0x2b, 0xaf, 0xb4, 0xce, 0xe6, 0xd3, 0xdd,
+ 0x2c, 0x98, 0xb1, 0x34, 0xa3, 0xb3, 0x58, 0x01, 0x76, 0xd6, 0x01, 0x93, 0x79, 0x22, 0x33, 0x14,
+ 0xfe, 0xee, 0x6f, 0x08, 0xcc, 0xcf, 0xd8, 0xe2, 0x0b, 0x1a, 0xce, 0x19, 0x6e, 0x42, 0xf5, 0x09,
+ 0x5b, 0xd8, 0xa8, 0x83, 0x7a, 0x16, 0x11, 0x4b, 0xbc, 0x0b, 0xb5, 0xdc, 0xcd, 0x16, 0x31, 0xb3,
+ 0x2b, 0x1d, 0xd4, 0xdb, 0xda, 0xb3, 0xfb, 0x97, 0x6a, 0xee, 0xcb, 0xb8, 0xd3, 0x45, 0xcc, 0x88,
+ 0x9e, 0x8b, 0x0f, 0xbe, 0x06, 0x7a, 0xee, 0xa6, 0x59, 0x62, 0x57, 0x65, 0x12, 0x2d, 0x3f, 0xc9,
+ 0x12, 0xfc, 0x9a, 0xc8, 0x72, 0xc6, 0x79, 0x68, 0x6b, 0x1d, 0xd4, 0x33, 0x89, 0x9e, 0x3b, 0x9c,
+ 0x87, 0x78, 0x1b, 0x8c, 0xdc, 0x0d, 0xa2, 0x6c, 0xff, 0xbe, 0xad, 0x77, 0x50, 0xaf, 0x4a, 0x6a,
+ 0xf9, 0x50, 0x58, 0xf8, 0x75, 0xb0, 0x72, 0x77, 0x1a, 0x72, 0x2a, 0x5c, 0xb5, 0x0e, 0xea, 0x21,
+ 0x62, 0xe6, 0x83, 0xc2, 0xc6, 0x37, 0xc1, 0xcc, 0xdd, 0xb3, 0x20, 0xa2, 0xc9, 0xc2, 0x36, 0x3a,
+ 0xa8, 0xd7, 0x20, 0x46, 0xee, 0x48, 0xf3, 0x7d, 0xf3, 0xd9, 0x8f, 0x6d, 0xf4, 0xec, 0xa7, 0x36,
+ 0xea, 0x7e, 0x8b, 0xa0, 0x3a, 0xe2, 0x3e, 0x76, 0xc0, 0x5a, 0x31, 0x22, 0xfb, 0xaa, 0xef, 0xb5,
+ 0xfa, 0x05, 0x25, 0xfd, 0x92, 0x92, 0xfe, 0x69, 0x89, 0x70, 0xcc, 0xa7, 0xe7, 0xed, 0x8d, 0xef,
+ 0xfe, 0x6c, 0x23, 0x72, 0x11, 0x86, 0x1f, 0x40, 0x6d, 0x1a, 0xb0, 0x70, 0x92, 0xda, 0x95, 0x4e,
+ 0xb5, 0x57, 0xdf, 0xdb, 0x5e, 0xe3, 0xa0, 0xa4, 0xcf, 0xd1, 0x44, 0x34, 0x51, 0xe0, 0xee, 0xcf,
+ 0x08, 0x8c, 0x93, 0x98, 0x46, 0x84, 0x4d, 0xf1, 0x03, 0x30, 0xb3, 0x84, 0x7a, 0xcc, 0x0d, 0x26,
+ 0xb2, 0x8a, 0x86, 0xd3, 0x12, 0xd8, 0xdf, 0xcf, 0xdb, 0xc6, 0xa9, 0xd8, 0x1f, 0x1e, 0x2e, 0x2f,
+ 0x96, 0xc4, 0x90, 0xd8, 0xe1, 0x04, 0xdf, 0x03, 0x23, 0x8d, 0x69, 0x24, 0xa2, 0x2a, 0x32, 0xca,
+ 0x56, 0x51, 0x35, 0x91, 0x58, 0x06, 0xa9, 0x15, 0xa9, 0x09, 0xe0, 0x70, 0x22, 0x4e, 0x4a, 0xd8,
+ 0xb4, 0x18, 0x59, 0x55, 0x8e, 0xac, 0xb5, 0x56, 0xae, 0xaa, 0x49, 0x0e, 0xcd, 0x48, 0x8a, 0x45,
+ 0xd7, 0x05, 0xe3, 0xf3, 0x84, 0x7b, 0x2c, 0x4d, 0xf1, 0x5b, 0xd0, 0x48, 0x59, 0x92, 0x07, 0x1e,
+ 0x73, 0x23, 0x3a, 0x63, 0x4a, 0x0d, 0x75, 0xb5, 0x77, 0x4c, 0x67, 0x0c, 0xdf, 0x03, 0x2d, 0xa3,
+ 0xfe, 0x15, 0xf9, 0x90, 0xd0, 0xee, 0x1f, 0x1a, 0x68, 0xe2, 0xe4, 0x57, 0x48, 0xc5, 0xdb, 0xb0,
+ 0xc5, 0x63, 0x56, 0xa8, 0xbd, 0x68, 0xa5, 0xd0, 0xe4, 0xe6, 0x6a, 0x57, 0x36, 0xf3, 0x01, 0x40,
+ 0xc2, 0xa6, 0x2c, 0x61, 0x91, 0xc7, 0x52, 0x5b, 0x93, 0x2d, 0xdd, 0x78, 0x31, 0x67, 0xaa, 0xa3,
+ 0xe7, 0xf0, 0xf8, 0x16, 0xe8, 0xd3, 0x50, 0x70, 0x21, 0x14, 0xbc, 0xe9, 0x6c, 0xaa, 0xaa, 0xf4,
+ 0x81, 0xd8, 0x24, 0x85, 0x0f, 0x1f, 0x00, 0xa4, 0x19, 0x4d, 0x32, 0x57, 0x88, 0x4a, 0x0a, 0xfa,
+ 0xca, 0x32, 0x94, 0x71, 0xc2, 0x83, 0x3f, 0x04, 0xb3, 0xbc, 0xbb, 0x52, 0xf7, 0xf5, 0xbd, 0x9b,
+ 0xff, 0x4a, 0x71, 0xa8, 0x00, 0x45, 0x86, 0x1f, 0x44, 0x86, 0x55, 0xd0, 0x6a, 0x6a, 0xe6, 0x95,
+ 0xa7, 0x86, 0xef, 0x80, 0x16, 0x72, 0x3f, 0xb5, 0x2d, 0x19, 0x82, 0xd7, 0x42, 0x46, 0xdc, 0x2f,
+ 0xd1, 0x02, 0x85, 0xef, 0x82, 0x11, 0x17, 0x22, 0xb2, 0x41, 0x16, 0xb8, 0x4e, 0xa3, 0x92, 0x18,
+ 0x29, 0x61, 0xf8, 0x0e, 0x80, 0x5a, 0x8a, 0xc1, 0xd6, 0xc5, 0x78, 0x9c, 0xcd, 0xe5, 0x79, 0xdb,
+ 0x52, 0xc8, 0xe1, 0x21, 0xb1, 0x14, 0x60, 0x38, 0xc1, 0x2d, 0x30, 0xbf, 0xa1, 0x49, 0x14, 0x44,
+ 0x7e, 0x6a, 0x37, 0x3a, 0xd5, 0x9e, 0x45, 0x56, 0x76, 0xf7, 0xfb, 0x0a, 0xe8, 0x52, 0x34, 0xf8,
+ 0x1d, 0xd0, 0x85, 0x00, 0x52, 0x1b, 0xc9, 0xa2, 0xaf, 0xbd, 0x68, 0x94, 0x05, 0x02, 0x7f, 0x0a,
+ 0xf5, 0xf2, 0xf8, 0x19, 0x8d, 0x95, 0x9c, 0x6f, 0xad, 0x05, 0xc8, 0xac, 0x65, 0xe9, 0x47, 0x34,
+ 0x8e, 0x83, 0xa8, 0x6c, 0xbb, 0x2c, 0xfe, 0x88, 0xc6, 0x97, 0x8a, 0xab, 0x5e, 0x2e, 0xae, 0x95,
+ 0xc3, 0xd6, 0xe5, 0xf8, 0xb5, 0xc6, 0xd1, 0xff, 0x34, 0xbe, 0x7f, 0x41, 0x6c, 0xe5, 0xbf, 0x88,
+ 0x55, 0x65, 0x95, 0xe0, 0xee, 0x63, 0xd0, 0x1d, 0x9a, 0x79, 0x8f, 0x5e, 0x86, 0x93, 0x97, 0x3a,
+ 0x0b, 0x5d, 0x9c, 0x35, 0x87, 0xad, 0x43, 0x16, 0xb3, 0x68, 0xc2, 0x22, 0x6f, 0x31, 0x0a, 0xa2,
+ 0x27, 0xf8, 0x06, 0xd4, 0x62, 0x9a, 0xb0, 0x28, 0x53, 0xbf, 0x10, 0x65, 0xe1, 0xeb, 0xa0, 0x7b,
+ 0x8f, 0x82, 0xb0, 0xb8, 0xc8, 0x16, 0x29, 0x0c, 0xfc, 0x26, 0x80, 0x47, 0xc3, 0xd0, 0xf5, 0xf8,
+ 0x3c, 0xca, 0xe4, 0x4d, 0xd5, 0x88, 0x25, 0x76, 0x0e, 0xc4, 0x86, 0x48, 0x96, 0xf2, 0x79, 0xe2,
+ 0x31, 0xf9, 0x84, 0x58, 0x44, 0x59, 0xb7, 0x3f, 0x02, 0x6b, 0xf5, 0x06, 0x61, 0x80, 0xda, 0xc9,
+ 0x29, 0x19, 0x1e, 0x7f, 0xdc, 0xdc, 0xc0, 0x26, 0x68, 0xce, 0x78, 0x3c, 0x6a, 0x22, 0x6c, 0x81,
+ 0x3e, 0x3c, 0x3e, 0xdd, 0xbf, 0xdf, 0xac, 0xe0, 0x3a, 0x18, 0x83, 0xd1, 0xf8, 0xa1, 0x30, 0xaa,
+ 0x02, 0xed, 0x0c, 0x8f, 0x1f, 0x92, 0xaf, 0x9a, 0xda, 0xed, 0x77, 0xa1, 0xfe, 0xdc, 0x7f, 0x11,
+ 0x37, 0xc0, 0x3c, 0xf8, 0x64, 0x38, 0x3a, 0x74, 0xc7, 0x83, 0xe6, 0x06, 0x6e, 0x42, 0x63, 0x30,
+ 0x1e, 0x8d, 0xc6, 0x5f, 0x9e, 0xb8, 0x03, 0x32, 0x3e, 0x6a, 0x22, 0xe7, 0xee, 0xd3, 0xe5, 0x0e,
+ 0xfa, 0x75, 0xb9, 0x83, 0xfe, 0x5a, 0xee, 0xa0, 0x5f, 0xfe, 0xde, 0x41, 0xb0, 0x1d, 0x70, 0xc5,
+ 0x93, 0xf8, 0x63, 0x05, 0x91, 0xaf, 0xe8, 0xfa, 0x5a, 0x97, 0x2f, 0xfe, 0x59, 0x4d, 0xde, 0xd1,
+ 0xf7, 0xfe, 0x09, 0x00, 0x00, 0xff, 0xff, 0xff, 0xb8, 0x61, 0xb8, 0x01, 0x08, 0x00, 0x00,
+}
+
+func (this *KeyValue) Compare(that interface{}) int {
+ if that == nil {
+ if this == nil {
+ return 0
+ }
+ return 1
+ }
+
+ that1, ok := that.(*KeyValue)
+ if !ok {
+ that2, ok := that.(KeyValue)
+ if ok {
+ that1 = &that2
+ } else {
+ return 1
+ }
+ }
+ if that1 == nil {
+ if this == nil {
+ return 0
+ }
+ return 1
+ } else if this == nil {
+ return -1
+ }
+ if this.Key != that1.Key {
+ if this.Key < that1.Key {
+ return -1
+ }
+ return 1
+ }
+ if this.VType != that1.VType {
+ if this.VType < that1.VType {
+ return -1
+ }
+ return 1
+ }
+ if this.VStr != that1.VStr {
+ if this.VStr < that1.VStr {
+ return -1
+ }
+ return 1
+ }
+ if this.VBool != that1.VBool {
+ if !this.VBool {
+ return -1
+ }
+ return 1
+ }
+ if this.VInt64 != that1.VInt64 {
+ if this.VInt64 < that1.VInt64 {
+ return -1
+ }
+ return 1
+ }
+ if this.VFloat64 != that1.VFloat64 {
+ if this.VFloat64 < that1.VFloat64 {
+ return -1
+ }
+ return 1
+ }
+ if c := bytes.Compare(this.VBinary, that1.VBinary); c != 0 {
+ return c
+ }
+ if c := bytes.Compare(this.XXX_unrecognized, that1.XXX_unrecognized); c != 0 {
+ return c
+ }
+ return 0
+}
+func (this *KeyValue) Equal(that interface{}) bool {
+ if that == nil {
+ return this == nil
+ }
+
+ that1, ok := that.(*KeyValue)
+ if !ok {
+ that2, ok := that.(KeyValue)
+ if ok {
+ that1 = &that2
+ } else {
+ return false
+ }
+ }
+ if that1 == nil {
+ return this == nil
+ } else if this == nil {
+ return false
+ }
+ if this.Key != that1.Key {
+ return false
+ }
+ if this.VType != that1.VType {
+ return false
+ }
+ if this.VStr != that1.VStr {
+ return false
+ }
+ if this.VBool != that1.VBool {
+ return false
+ }
+ if this.VInt64 != that1.VInt64 {
+ return false
+ }
+ if this.VFloat64 != that1.VFloat64 {
+ return false
+ }
+ if !bytes.Equal(this.VBinary, that1.VBinary) {
+ return false
+ }
+ if !bytes.Equal(this.XXX_unrecognized, that1.XXX_unrecognized) {
+ return false
+ }
+ return true
+}
+func (m *KeyValue) Marshal() (dAtA []byte, err error) {
+ size := m.Size()
+ dAtA = make([]byte, size)
+ n, err := m.MarshalTo(dAtA)
+ if err != nil {
+ return nil, err
+ }
+ return dAtA[:n], nil
+}
+
+func (m *KeyValue) MarshalTo(dAtA []byte) (int, error) {
+ var i int
+ _ = i
+ var l int
+ _ = l
+ if len(m.Key) > 0 {
+ dAtA[i] = 0xa
+ i++
+ i = encodeVarintModel(dAtA, i, uint64(len(m.Key)))
+ i += copy(dAtA[i:], m.Key)
+ }
+ if m.VType != 0 {
+ dAtA[i] = 0x10
+ i++
+ i = encodeVarintModel(dAtA, i, uint64(m.VType))
+ }
+ if len(m.VStr) > 0 {
+ dAtA[i] = 0x1a
+ i++
+ i = encodeVarintModel(dAtA, i, uint64(len(m.VStr)))
+ i += copy(dAtA[i:], m.VStr)
+ }
+ if m.VBool {
+ dAtA[i] = 0x20
+ i++
+ if m.VBool {
+ dAtA[i] = 1
+ } else {
+ dAtA[i] = 0
+ }
+ i++
+ }
+ if m.VInt64 != 0 {
+ dAtA[i] = 0x28
+ i++
+ i = encodeVarintModel(dAtA, i, uint64(m.VInt64))
+ }
+ if m.VFloat64 != 0 {
+ dAtA[i] = 0x31
+ i++
+ encoding_binary.LittleEndian.PutUint64(dAtA[i:], uint64(math.Float64bits(float64(m.VFloat64))))
+ i += 8
+ }
+ if len(m.VBinary) > 0 {
+ dAtA[i] = 0x3a
+ i++
+ i = encodeVarintModel(dAtA, i, uint64(len(m.VBinary)))
+ i += copy(dAtA[i:], m.VBinary)
+ }
+ if m.XXX_unrecognized != nil {
+ i += copy(dAtA[i:], m.XXX_unrecognized)
+ }
+ return i, nil
+}
+
+func (m *Log) Marshal() (dAtA []byte, err error) {
+ size := m.Size()
+ dAtA = make([]byte, size)
+ n, err := m.MarshalTo(dAtA)
+ if err != nil {
+ return nil, err
+ }
+ return dAtA[:n], nil
+}
+
+func (m *Log) MarshalTo(dAtA []byte) (int, error) {
+ var i int
+ _ = i
+ var l int
+ _ = l
+ dAtA[i] = 0xa
+ i++
+ i = encodeVarintModel(dAtA, i, uint64(github_com_gogo_protobuf_types.SizeOfStdTime(m.Timestamp)))
+ n1, err := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.Timestamp, dAtA[i:])
+ if err != nil {
+ return 0, err
+ }
+ i += n1
+ if len(m.Fields) > 0 {
+ for _, msg := range m.Fields {
+ dAtA[i] = 0x12
+ i++
+ i = encodeVarintModel(dAtA, i, uint64(msg.Size()))
+ n, err := msg.MarshalTo(dAtA[i:])
+ if err != nil {
+ return 0, err
+ }
+ i += n
+ }
+ }
+ if m.XXX_unrecognized != nil {
+ i += copy(dAtA[i:], m.XXX_unrecognized)
+ }
+ return i, nil
+}
+
+func (m *SpanRef) Marshal() (dAtA []byte, err error) {
+ size := m.Size()
+ dAtA = make([]byte, size)
+ n, err := m.MarshalTo(dAtA)
+ if err != nil {
+ return nil, err
+ }
+ return dAtA[:n], nil
+}
+
+func (m *SpanRef) MarshalTo(dAtA []byte) (int, error) {
+ var i int
+ _ = i
+ var l int
+ _ = l
+ dAtA[i] = 0xa
+ i++
+ i = encodeVarintModel(dAtA, i, uint64(m.TraceID.Size()))
+ n2, err := m.TraceID.MarshalTo(dAtA[i:])
+ if err != nil {
+ return 0, err
+ }
+ i += n2
+ dAtA[i] = 0x12
+ i++
+ i = encodeVarintModel(dAtA, i, uint64(m.SpanID.Size()))
+ n3, err := m.SpanID.MarshalTo(dAtA[i:])
+ if err != nil {
+ return 0, err
+ }
+ i += n3
+ if m.RefType != 0 {
+ dAtA[i] = 0x18
+ i++
+ i = encodeVarintModel(dAtA, i, uint64(m.RefType))
+ }
+ if m.XXX_unrecognized != nil {
+ i += copy(dAtA[i:], m.XXX_unrecognized)
+ }
+ return i, nil
+}
+
+func (m *Process) Marshal() (dAtA []byte, err error) {
+ size := m.Size()
+ dAtA = make([]byte, size)
+ n, err := m.MarshalTo(dAtA)
+ if err != nil {
+ return nil, err
+ }
+ return dAtA[:n], nil
+}
+
+func (m *Process) MarshalTo(dAtA []byte) (int, error) {
+ var i int
+ _ = i
+ var l int
+ _ = l
+ if len(m.ServiceName) > 0 {
+ dAtA[i] = 0xa
+ i++
+ i = encodeVarintModel(dAtA, i, uint64(len(m.ServiceName)))
+ i += copy(dAtA[i:], m.ServiceName)
+ }
+ if len(m.Tags) > 0 {
+ for _, msg := range m.Tags {
+ dAtA[i] = 0x12
+ i++
+ i = encodeVarintModel(dAtA, i, uint64(msg.Size()))
+ n, err := msg.MarshalTo(dAtA[i:])
+ if err != nil {
+ return 0, err
+ }
+ i += n
+ }
+ }
+ if m.XXX_unrecognized != nil {
+ i += copy(dAtA[i:], m.XXX_unrecognized)
+ }
+ return i, nil
+}
+
+func (m *Span) Marshal() (dAtA []byte, err error) {
+ size := m.Size()
+ dAtA = make([]byte, size)
+ n, err := m.MarshalTo(dAtA)
+ if err != nil {
+ return nil, err
+ }
+ return dAtA[:n], nil
+}
+
+func (m *Span) MarshalTo(dAtA []byte) (int, error) {
+ var i int
+ _ = i
+ var l int
+ _ = l
+ dAtA[i] = 0xa
+ i++
+ i = encodeVarintModel(dAtA, i, uint64(m.TraceID.Size()))
+ n4, err := m.TraceID.MarshalTo(dAtA[i:])
+ if err != nil {
+ return 0, err
+ }
+ i += n4
+ dAtA[i] = 0x12
+ i++
+ i = encodeVarintModel(dAtA, i, uint64(m.SpanID.Size()))
+ n5, err := m.SpanID.MarshalTo(dAtA[i:])
+ if err != nil {
+ return 0, err
+ }
+ i += n5
+ if len(m.OperationName) > 0 {
+ dAtA[i] = 0x1a
+ i++
+ i = encodeVarintModel(dAtA, i, uint64(len(m.OperationName)))
+ i += copy(dAtA[i:], m.OperationName)
+ }
+ if len(m.References) > 0 {
+ for _, msg := range m.References {
+ dAtA[i] = 0x22
+ i++
+ i = encodeVarintModel(dAtA, i, uint64(msg.Size()))
+ n, err := msg.MarshalTo(dAtA[i:])
+ if err != nil {
+ return 0, err
+ }
+ i += n
+ }
+ }
+ if m.Flags != 0 {
+ dAtA[i] = 0x28
+ i++
+ i = encodeVarintModel(dAtA, i, uint64(m.Flags))
+ }
+ dAtA[i] = 0x32
+ i++
+ i = encodeVarintModel(dAtA, i, uint64(github_com_gogo_protobuf_types.SizeOfStdTime(m.StartTime)))
+ n6, err := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.StartTime, dAtA[i:])
+ if err != nil {
+ return 0, err
+ }
+ i += n6
+ dAtA[i] = 0x3a
+ i++
+ i = encodeVarintModel(dAtA, i, uint64(github_com_gogo_protobuf_types.SizeOfStdDuration(m.Duration)))
+ n7, err := github_com_gogo_protobuf_types.StdDurationMarshalTo(m.Duration, dAtA[i:])
+ if err != nil {
+ return 0, err
+ }
+ i += n7
+ if len(m.Tags) > 0 {
+ for _, msg := range m.Tags {
+ dAtA[i] = 0x42
+ i++
+ i = encodeVarintModel(dAtA, i, uint64(msg.Size()))
+ n, err := msg.MarshalTo(dAtA[i:])
+ if err != nil {
+ return 0, err
+ }
+ i += n
+ }
+ }
+ if len(m.Logs) > 0 {
+ for _, msg := range m.Logs {
+ dAtA[i] = 0x4a
+ i++
+ i = encodeVarintModel(dAtA, i, uint64(msg.Size()))
+ n, err := msg.MarshalTo(dAtA[i:])
+ if err != nil {
+ return 0, err
+ }
+ i += n
+ }
+ }
+ if m.Process != nil {
+ dAtA[i] = 0x52
+ i++
+ i = encodeVarintModel(dAtA, i, uint64(m.Process.Size()))
+ n8, err := m.Process.MarshalTo(dAtA[i:])
+ if err != nil {
+ return 0, err
+ }
+ i += n8
+ }
+ if len(m.ProcessID) > 0 {
+ dAtA[i] = 0x5a
+ i++
+ i = encodeVarintModel(dAtA, i, uint64(len(m.ProcessID)))
+ i += copy(dAtA[i:], m.ProcessID)
+ }
+ if len(m.Warnings) > 0 {
+ for _, s := range m.Warnings {
+ dAtA[i] = 0x62
+ i++
+ l = len(s)
+ for l >= 1<<7 {
+ dAtA[i] = uint8(uint64(l)&0x7f | 0x80)
+ l >>= 7
+ i++
+ }
+ dAtA[i] = uint8(l)
+ i++
+ i += copy(dAtA[i:], s)
+ }
+ }
+ if m.XXX_unrecognized != nil {
+ i += copy(dAtA[i:], m.XXX_unrecognized)
+ }
+ return i, nil
+}
+
+func (m *Trace) Marshal() (dAtA []byte, err error) {
+ size := m.Size()
+ dAtA = make([]byte, size)
+ n, err := m.MarshalTo(dAtA)
+ if err != nil {
+ return nil, err
+ }
+ return dAtA[:n], nil
+}
+
+func (m *Trace) MarshalTo(dAtA []byte) (int, error) {
+ var i int
+ _ = i
+ var l int
+ _ = l
+ if len(m.Spans) > 0 {
+ for _, msg := range m.Spans {
+ dAtA[i] = 0xa
+ i++
+ i = encodeVarintModel(dAtA, i, uint64(msg.Size()))
+ n, err := msg.MarshalTo(dAtA[i:])
+ if err != nil {
+ return 0, err
+ }
+ i += n
+ }
+ }
+ if len(m.ProcessMap) > 0 {
+ for _, msg := range m.ProcessMap {
+ dAtA[i] = 0x12
+ i++
+ i = encodeVarintModel(dAtA, i, uint64(msg.Size()))
+ n, err := msg.MarshalTo(dAtA[i:])
+ if err != nil {
+ return 0, err
+ }
+ i += n
+ }
+ }
+ if len(m.Warnings) > 0 {
+ for _, s := range m.Warnings {
+ dAtA[i] = 0x1a
+ i++
+ l = len(s)
+ for l >= 1<<7 {
+ dAtA[i] = uint8(uint64(l)&0x7f | 0x80)
+ l >>= 7
+ i++
+ }
+ dAtA[i] = uint8(l)
+ i++
+ i += copy(dAtA[i:], s)
+ }
+ }
+ if m.XXX_unrecognized != nil {
+ i += copy(dAtA[i:], m.XXX_unrecognized)
+ }
+ return i, nil
+}
+
+func (m *Trace_ProcessMapping) Marshal() (dAtA []byte, err error) {
+ size := m.Size()
+ dAtA = make([]byte, size)
+ n, err := m.MarshalTo(dAtA)
+ if err != nil {
+ return nil, err
+ }
+ return dAtA[:n], nil
+}
+
+func (m *Trace_ProcessMapping) MarshalTo(dAtA []byte) (int, error) {
+ var i int
+ _ = i
+ var l int
+ _ = l
+ if len(m.ProcessID) > 0 {
+ dAtA[i] = 0xa
+ i++
+ i = encodeVarintModel(dAtA, i, uint64(len(m.ProcessID)))
+ i += copy(dAtA[i:], m.ProcessID)
+ }
+ dAtA[i] = 0x12
+ i++
+ i = encodeVarintModel(dAtA, i, uint64(m.Process.Size()))
+ n9, err := m.Process.MarshalTo(dAtA[i:])
+ if err != nil {
+ return 0, err
+ }
+ i += n9
+ if m.XXX_unrecognized != nil {
+ i += copy(dAtA[i:], m.XXX_unrecognized)
+ }
+ return i, nil
+}
+
+func (m *Batch) Marshal() (dAtA []byte, err error) {
+ size := m.Size()
+ dAtA = make([]byte, size)
+ n, err := m.MarshalTo(dAtA)
+ if err != nil {
+ return nil, err
+ }
+ return dAtA[:n], nil
+}
+
+func (m *Batch) MarshalTo(dAtA []byte) (int, error) {
+ var i int
+ _ = i
+ var l int
+ _ = l
+ if len(m.Spans) > 0 {
+ for _, msg := range m.Spans {
+ dAtA[i] = 0xa
+ i++
+ i = encodeVarintModel(dAtA, i, uint64(msg.Size()))
+ n, err := msg.MarshalTo(dAtA[i:])
+ if err != nil {
+ return 0, err
+ }
+ i += n
+ }
+ }
+ if m.Process != nil {
+ dAtA[i] = 0x12
+ i++
+ i = encodeVarintModel(dAtA, i, uint64(m.Process.Size()))
+ n10, err := m.Process.MarshalTo(dAtA[i:])
+ if err != nil {
+ return 0, err
+ }
+ i += n10
+ }
+ if m.XXX_unrecognized != nil {
+ i += copy(dAtA[i:], m.XXX_unrecognized)
+ }
+ return i, nil
+}
+
+func (m *DependencyLink) Marshal() (dAtA []byte, err error) {
+ size := m.Size()
+ dAtA = make([]byte, size)
+ n, err := m.MarshalTo(dAtA)
+ if err != nil {
+ return nil, err
+ }
+ return dAtA[:n], nil
+}
+
+func (m *DependencyLink) MarshalTo(dAtA []byte) (int, error) {
+ var i int
+ _ = i
+ var l int
+ _ = l
+ if len(m.Parent) > 0 {
+ dAtA[i] = 0xa
+ i++
+ i = encodeVarintModel(dAtA, i, uint64(len(m.Parent)))
+ i += copy(dAtA[i:], m.Parent)
+ }
+ if len(m.Child) > 0 {
+ dAtA[i] = 0x12
+ i++
+ i = encodeVarintModel(dAtA, i, uint64(len(m.Child)))
+ i += copy(dAtA[i:], m.Child)
+ }
+ if m.CallCount != 0 {
+ dAtA[i] = 0x18
+ i++
+ i = encodeVarintModel(dAtA, i, uint64(m.CallCount))
+ }
+ if len(m.Source) > 0 {
+ dAtA[i] = 0x22
+ i++
+ i = encodeVarintModel(dAtA, i, uint64(len(m.Source)))
+ i += copy(dAtA[i:], m.Source)
+ }
+ if m.XXX_unrecognized != nil {
+ i += copy(dAtA[i:], m.XXX_unrecognized)
+ }
+ return i, nil
+}
+
+func encodeVarintModel(dAtA []byte, offset int, v uint64) int {
+ for v >= 1<<7 {
+ dAtA[offset] = uint8(v&0x7f | 0x80)
+ v >>= 7
+ offset++
+ }
+ dAtA[offset] = uint8(v)
+ return offset + 1
+}
+func (m *KeyValue) Size() (n int) {
+ if m == nil {
+ return 0
+ }
+ var l int
+ _ = l
+ l = len(m.Key)
+ if l > 0 {
+ n += 1 + l + sovModel(uint64(l))
+ }
+ if m.VType != 0 {
+ n += 1 + sovModel(uint64(m.VType))
+ }
+ l = len(m.VStr)
+ if l > 0 {
+ n += 1 + l + sovModel(uint64(l))
+ }
+ if m.VBool {
+ n += 2
+ }
+ if m.VInt64 != 0 {
+ n += 1 + sovModel(uint64(m.VInt64))
+ }
+ if m.VFloat64 != 0 {
+ n += 9
+ }
+ l = len(m.VBinary)
+ if l > 0 {
+ n += 1 + l + sovModel(uint64(l))
+ }
+ if m.XXX_unrecognized != nil {
+ n += len(m.XXX_unrecognized)
+ }
+ return n
+}
+
+func (m *Log) Size() (n int) {
+ if m == nil {
+ return 0
+ }
+ var l int
+ _ = l
+ l = github_com_gogo_protobuf_types.SizeOfStdTime(m.Timestamp)
+ n += 1 + l + sovModel(uint64(l))
+ if len(m.Fields) > 0 {
+ for _, e := range m.Fields {
+ l = e.Size()
+ n += 1 + l + sovModel(uint64(l))
+ }
+ }
+ if m.XXX_unrecognized != nil {
+ n += len(m.XXX_unrecognized)
+ }
+ return n
+}
+
+func (m *SpanRef) Size() (n int) {
+ if m == nil {
+ return 0
+ }
+ var l int
+ _ = l
+ l = m.TraceID.Size()
+ n += 1 + l + sovModel(uint64(l))
+ l = m.SpanID.Size()
+ n += 1 + l + sovModel(uint64(l))
+ if m.RefType != 0 {
+ n += 1 + sovModel(uint64(m.RefType))
+ }
+ if m.XXX_unrecognized != nil {
+ n += len(m.XXX_unrecognized)
+ }
+ return n
+}
+
+func (m *Process) Size() (n int) {
+ if m == nil {
+ return 0
+ }
+ var l int
+ _ = l
+ l = len(m.ServiceName)
+ if l > 0 {
+ n += 1 + l + sovModel(uint64(l))
+ }
+ if len(m.Tags) > 0 {
+ for _, e := range m.Tags {
+ l = e.Size()
+ n += 1 + l + sovModel(uint64(l))
+ }
+ }
+ if m.XXX_unrecognized != nil {
+ n += len(m.XXX_unrecognized)
+ }
+ return n
+}
+
+func (m *Span) Size() (n int) {
+ if m == nil {
+ return 0
+ }
+ var l int
+ _ = l
+ l = m.TraceID.Size()
+ n += 1 + l + sovModel(uint64(l))
+ l = m.SpanID.Size()
+ n += 1 + l + sovModel(uint64(l))
+ l = len(m.OperationName)
+ if l > 0 {
+ n += 1 + l + sovModel(uint64(l))
+ }
+ if len(m.References) > 0 {
+ for _, e := range m.References {
+ l = e.Size()
+ n += 1 + l + sovModel(uint64(l))
+ }
+ }
+ if m.Flags != 0 {
+ n += 1 + sovModel(uint64(m.Flags))
+ }
+ l = github_com_gogo_protobuf_types.SizeOfStdTime(m.StartTime)
+ n += 1 + l + sovModel(uint64(l))
+ l = github_com_gogo_protobuf_types.SizeOfStdDuration(m.Duration)
+ n += 1 + l + sovModel(uint64(l))
+ if len(m.Tags) > 0 {
+ for _, e := range m.Tags {
+ l = e.Size()
+ n += 1 + l + sovModel(uint64(l))
+ }
+ }
+ if len(m.Logs) > 0 {
+ for _, e := range m.Logs {
+ l = e.Size()
+ n += 1 + l + sovModel(uint64(l))
+ }
+ }
+ if m.Process != nil {
+ l = m.Process.Size()
+ n += 1 + l + sovModel(uint64(l))
+ }
+ l = len(m.ProcessID)
+ if l > 0 {
+ n += 1 + l + sovModel(uint64(l))
+ }
+ if len(m.Warnings) > 0 {
+ for _, s := range m.Warnings {
+ l = len(s)
+ n += 1 + l + sovModel(uint64(l))
+ }
+ }
+ if m.XXX_unrecognized != nil {
+ n += len(m.XXX_unrecognized)
+ }
+ return n
+}
+
+func (m *Trace) Size() (n int) {
+ if m == nil {
+ return 0
+ }
+ var l int
+ _ = l
+ if len(m.Spans) > 0 {
+ for _, e := range m.Spans {
+ l = e.Size()
+ n += 1 + l + sovModel(uint64(l))
+ }
+ }
+ if len(m.ProcessMap) > 0 {
+ for _, e := range m.ProcessMap {
+ l = e.Size()
+ n += 1 + l + sovModel(uint64(l))
+ }
+ }
+ if len(m.Warnings) > 0 {
+ for _, s := range m.Warnings {
+ l = len(s)
+ n += 1 + l + sovModel(uint64(l))
+ }
+ }
+ if m.XXX_unrecognized != nil {
+ n += len(m.XXX_unrecognized)
+ }
+ return n
+}
+
+func (m *Trace_ProcessMapping) Size() (n int) {
+ if m == nil {
+ return 0
+ }
+ var l int
+ _ = l
+ l = len(m.ProcessID)
+ if l > 0 {
+ n += 1 + l + sovModel(uint64(l))
+ }
+ l = m.Process.Size()
+ n += 1 + l + sovModel(uint64(l))
+ if m.XXX_unrecognized != nil {
+ n += len(m.XXX_unrecognized)
+ }
+ return n
+}
+
+func (m *Batch) Size() (n int) {
+ if m == nil {
+ return 0
+ }
+ var l int
+ _ = l
+ if len(m.Spans) > 0 {
+ for _, e := range m.Spans {
+ l = e.Size()
+ n += 1 + l + sovModel(uint64(l))
+ }
+ }
+ if m.Process != nil {
+ l = m.Process.Size()
+ n += 1 + l + sovModel(uint64(l))
+ }
+ if m.XXX_unrecognized != nil {
+ n += len(m.XXX_unrecognized)
+ }
+ return n
+}
+
+func (m *DependencyLink) Size() (n int) {
+ if m == nil {
+ return 0
+ }
+ var l int
+ _ = l
+ l = len(m.Parent)
+ if l > 0 {
+ n += 1 + l + sovModel(uint64(l))
+ }
+ l = len(m.Child)
+ if l > 0 {
+ n += 1 + l + sovModel(uint64(l))
+ }
+ if m.CallCount != 0 {
+ n += 1 + sovModel(uint64(m.CallCount))
+ }
+ l = len(m.Source)
+ if l > 0 {
+ n += 1 + l + sovModel(uint64(l))
+ }
+ if m.XXX_unrecognized != nil {
+ n += len(m.XXX_unrecognized)
+ }
+ return n
+}
+
+func sovModel(x uint64) (n int) {
+ for {
+ n++
+ x >>= 7
+ if x == 0 {
+ break
+ }
+ }
+ return n
+}
+func sozModel(x uint64) (n int) {
+ return sovModel(uint64((x << 1) ^ uint64((int64(x) >> 63))))
+}
+func (m *KeyValue) Unmarshal(dAtA []byte) error {
+ l := len(dAtA)
+ iNdEx := 0
+ for iNdEx < l {
+ preIndex := iNdEx
+ var wire uint64
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowModel
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ wire |= uint64(b&0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ fieldNum := int32(wire >> 3)
+ wireType := int(wire & 0x7)
+ if wireType == 4 {
+ return fmt.Errorf("proto: KeyValue: wiretype end group for non-group")
+ }
+ if fieldNum <= 0 {
+ return fmt.Errorf("proto: KeyValue: illegal tag %d (wire type %d)", fieldNum, wire)
+ }
+ switch fieldNum {
+ case 1:
+ if wireType != 2 {
+ return fmt.Errorf("proto: wrong wireType = %d for field Key", wireType)
+ }
+ var stringLen uint64
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowModel
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ stringLen |= uint64(b&0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ intStringLen := int(stringLen)
+ if intStringLen < 0 {
+ return ErrInvalidLengthModel
+ }
+ postIndex := iNdEx + intStringLen
+ if postIndex < 0 {
+ return ErrInvalidLengthModel
+ }
+ if postIndex > l {
+ return io.ErrUnexpectedEOF
+ }
+ m.Key = string(dAtA[iNdEx:postIndex])
+ iNdEx = postIndex
+ case 2:
+ if wireType != 0 {
+ return fmt.Errorf("proto: wrong wireType = %d for field VType", wireType)
+ }
+ m.VType = 0
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowModel
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ m.VType |= ValueType(b&0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ case 3:
+ if wireType != 2 {
+ return fmt.Errorf("proto: wrong wireType = %d for field VStr", wireType)
+ }
+ var stringLen uint64
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowModel
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ stringLen |= uint64(b&0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ intStringLen := int(stringLen)
+ if intStringLen < 0 {
+ return ErrInvalidLengthModel
+ }
+ postIndex := iNdEx + intStringLen
+ if postIndex < 0 {
+ return ErrInvalidLengthModel
+ }
+ if postIndex > l {
+ return io.ErrUnexpectedEOF
+ }
+ m.VStr = string(dAtA[iNdEx:postIndex])
+ iNdEx = postIndex
+ case 4:
+ if wireType != 0 {
+ return fmt.Errorf("proto: wrong wireType = %d for field VBool", wireType)
+ }
+ var v int
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowModel
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ v |= int(b&0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ m.VBool = bool(v != 0)
+ case 5:
+ if wireType != 0 {
+ return fmt.Errorf("proto: wrong wireType = %d for field VInt64", wireType)
+ }
+ m.VInt64 = 0
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowModel
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ m.VInt64 |= int64(b&0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ case 6:
+ if wireType != 1 {
+ return fmt.Errorf("proto: wrong wireType = %d for field VFloat64", wireType)
+ }
+ var v uint64
+ if (iNdEx + 8) > l {
+ return io.ErrUnexpectedEOF
+ }
+ v = uint64(encoding_binary.LittleEndian.Uint64(dAtA[iNdEx:]))
+ iNdEx += 8
+ m.VFloat64 = float64(math.Float64frombits(v))
+ case 7:
+ if wireType != 2 {
+ return fmt.Errorf("proto: wrong wireType = %d for field VBinary", wireType)
+ }
+ var byteLen int
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowModel
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ byteLen |= int(b&0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ if byteLen < 0 {
+ return ErrInvalidLengthModel
+ }
+ postIndex := iNdEx + byteLen
+ if postIndex < 0 {
+ return ErrInvalidLengthModel
+ }
+ if postIndex > l {
+ return io.ErrUnexpectedEOF
+ }
+ m.VBinary = append(m.VBinary[:0], dAtA[iNdEx:postIndex]...)
+ if m.VBinary == nil {
+ m.VBinary = []byte{}
+ }
+ iNdEx = postIndex
+ default:
+ iNdEx = preIndex
+ skippy, err := skipModel(dAtA[iNdEx:])
+ if err != nil {
+ return err
+ }
+ if skippy < 0 {
+ return ErrInvalidLengthModel
+ }
+ if (iNdEx + skippy) < 0 {
+ return ErrInvalidLengthModel
+ }
+ if (iNdEx + skippy) > l {
+ return io.ErrUnexpectedEOF
+ }
+ m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)
+ iNdEx += skippy
+ }
+ }
+
+ if iNdEx > l {
+ return io.ErrUnexpectedEOF
+ }
+ return nil
+}
+func (m *Log) Unmarshal(dAtA []byte) error {
+ l := len(dAtA)
+ iNdEx := 0
+ for iNdEx < l {
+ preIndex := iNdEx
+ var wire uint64
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowModel
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ wire |= uint64(b&0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ fieldNum := int32(wire >> 3)
+ wireType := int(wire & 0x7)
+ if wireType == 4 {
+ return fmt.Errorf("proto: Log: wiretype end group for non-group")
+ }
+ if fieldNum <= 0 {
+ return fmt.Errorf("proto: Log: illegal tag %d (wire type %d)", fieldNum, wire)
+ }
+ switch fieldNum {
+ case 1:
+ if wireType != 2 {
+ return fmt.Errorf("proto: wrong wireType = %d for field Timestamp", wireType)
+ }
+ var msglen int
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowModel
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ msglen |= int(b&0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ if msglen < 0 {
+ return ErrInvalidLengthModel
+ }
+ postIndex := iNdEx + msglen
+ if postIndex < 0 {
+ return ErrInvalidLengthModel
+ }
+ if postIndex > l {
+ return io.ErrUnexpectedEOF
+ }
+ if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.Timestamp, dAtA[iNdEx:postIndex]); err != nil {
+ return err
+ }
+ iNdEx = postIndex
+ case 2:
+ if wireType != 2 {
+ return fmt.Errorf("proto: wrong wireType = %d for field Fields", wireType)
+ }
+ var msglen int
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowModel
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ msglen |= int(b&0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ if msglen < 0 {
+ return ErrInvalidLengthModel
+ }
+ postIndex := iNdEx + msglen
+ if postIndex < 0 {
+ return ErrInvalidLengthModel
+ }
+ if postIndex > l {
+ return io.ErrUnexpectedEOF
+ }
+ m.Fields = append(m.Fields, KeyValue{})
+ if err := m.Fields[len(m.Fields)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
+ return err
+ }
+ iNdEx = postIndex
+ default:
+ iNdEx = preIndex
+ skippy, err := skipModel(dAtA[iNdEx:])
+ if err != nil {
+ return err
+ }
+ if skippy < 0 {
+ return ErrInvalidLengthModel
+ }
+ if (iNdEx + skippy) < 0 {
+ return ErrInvalidLengthModel
+ }
+ if (iNdEx + skippy) > l {
+ return io.ErrUnexpectedEOF
+ }
+ m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)
+ iNdEx += skippy
+ }
+ }
+
+ if iNdEx > l {
+ return io.ErrUnexpectedEOF
+ }
+ return nil
+}
+func (m *SpanRef) Unmarshal(dAtA []byte) error {
+ l := len(dAtA)
+ iNdEx := 0
+ for iNdEx < l {
+ preIndex := iNdEx
+ var wire uint64
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowModel
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ wire |= uint64(b&0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ fieldNum := int32(wire >> 3)
+ wireType := int(wire & 0x7)
+ if wireType == 4 {
+ return fmt.Errorf("proto: SpanRef: wiretype end group for non-group")
+ }
+ if fieldNum <= 0 {
+ return fmt.Errorf("proto: SpanRef: illegal tag %d (wire type %d)", fieldNum, wire)
+ }
+ switch fieldNum {
+ case 1:
+ if wireType != 2 {
+ return fmt.Errorf("proto: wrong wireType = %d for field TraceID", wireType)
+ }
+ var byteLen int
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowModel
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ byteLen |= int(b&0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ if byteLen < 0 {
+ return ErrInvalidLengthModel
+ }
+ postIndex := iNdEx + byteLen
+ if postIndex < 0 {
+ return ErrInvalidLengthModel
+ }
+ if postIndex > l {
+ return io.ErrUnexpectedEOF
+ }
+ if err := m.TraceID.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
+ return err
+ }
+ iNdEx = postIndex
+ case 2:
+ if wireType != 2 {
+ return fmt.Errorf("proto: wrong wireType = %d for field SpanID", wireType)
+ }
+ var byteLen int
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowModel
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ byteLen |= int(b&0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ if byteLen < 0 {
+ return ErrInvalidLengthModel
+ }
+ postIndex := iNdEx + byteLen
+ if postIndex < 0 {
+ return ErrInvalidLengthModel
+ }
+ if postIndex > l {
+ return io.ErrUnexpectedEOF
+ }
+ if err := m.SpanID.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
+ return err
+ }
+ iNdEx = postIndex
+ case 3:
+ if wireType != 0 {
+ return fmt.Errorf("proto: wrong wireType = %d for field RefType", wireType)
+ }
+ m.RefType = 0
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowModel
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ m.RefType |= SpanRefType(b&0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ default:
+ iNdEx = preIndex
+ skippy, err := skipModel(dAtA[iNdEx:])
+ if err != nil {
+ return err
+ }
+ if skippy < 0 {
+ return ErrInvalidLengthModel
+ }
+ if (iNdEx + skippy) < 0 {
+ return ErrInvalidLengthModel
+ }
+ if (iNdEx + skippy) > l {
+ return io.ErrUnexpectedEOF
+ }
+ m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)
+ iNdEx += skippy
+ }
+ }
+
+ if iNdEx > l {
+ return io.ErrUnexpectedEOF
+ }
+ return nil
+}
+func (m *Process) Unmarshal(dAtA []byte) error {
+ l := len(dAtA)
+ iNdEx := 0
+ for iNdEx < l {
+ preIndex := iNdEx
+ var wire uint64
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowModel
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ wire |= uint64(b&0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ fieldNum := int32(wire >> 3)
+ wireType := int(wire & 0x7)
+ if wireType == 4 {
+ return fmt.Errorf("proto: Process: wiretype end group for non-group")
+ }
+ if fieldNum <= 0 {
+ return fmt.Errorf("proto: Process: illegal tag %d (wire type %d)", fieldNum, wire)
+ }
+ switch fieldNum {
+ case 1:
+ if wireType != 2 {
+ return fmt.Errorf("proto: wrong wireType = %d for field ServiceName", wireType)
+ }
+ var stringLen uint64
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowModel
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ stringLen |= uint64(b&0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ intStringLen := int(stringLen)
+ if intStringLen < 0 {
+ return ErrInvalidLengthModel
+ }
+ postIndex := iNdEx + intStringLen
+ if postIndex < 0 {
+ return ErrInvalidLengthModel
+ }
+ if postIndex > l {
+ return io.ErrUnexpectedEOF
+ }
+ m.ServiceName = string(dAtA[iNdEx:postIndex])
+ iNdEx = postIndex
+ case 2:
+ if wireType != 2 {
+ return fmt.Errorf("proto: wrong wireType = %d for field Tags", wireType)
+ }
+ var msglen int
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowModel
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ msglen |= int(b&0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ if msglen < 0 {
+ return ErrInvalidLengthModel
+ }
+ postIndex := iNdEx + msglen
+ if postIndex < 0 {
+ return ErrInvalidLengthModel
+ }
+ if postIndex > l {
+ return io.ErrUnexpectedEOF
+ }
+ m.Tags = append(m.Tags, KeyValue{})
+ if err := m.Tags[len(m.Tags)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
+ return err
+ }
+ iNdEx = postIndex
+ default:
+ iNdEx = preIndex
+ skippy, err := skipModel(dAtA[iNdEx:])
+ if err != nil {
+ return err
+ }
+ if skippy < 0 {
+ return ErrInvalidLengthModel
+ }
+ if (iNdEx + skippy) < 0 {
+ return ErrInvalidLengthModel
+ }
+ if (iNdEx + skippy) > l {
+ return io.ErrUnexpectedEOF
+ }
+ m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)
+ iNdEx += skippy
+ }
+ }
+
+ if iNdEx > l {
+ return io.ErrUnexpectedEOF
+ }
+ return nil
+}
+func (m *Span) Unmarshal(dAtA []byte) error {
+ l := len(dAtA)
+ iNdEx := 0
+ for iNdEx < l {
+ preIndex := iNdEx
+ var wire uint64
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowModel
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ wire |= uint64(b&0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ fieldNum := int32(wire >> 3)
+ wireType := int(wire & 0x7)
+ if wireType == 4 {
+ return fmt.Errorf("proto: Span: wiretype end group for non-group")
+ }
+ if fieldNum <= 0 {
+ return fmt.Errorf("proto: Span: illegal tag %d (wire type %d)", fieldNum, wire)
+ }
+ switch fieldNum {
+ case 1:
+ if wireType != 2 {
+ return fmt.Errorf("proto: wrong wireType = %d for field TraceID", wireType)
+ }
+ var byteLen int
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowModel
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ byteLen |= int(b&0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ if byteLen < 0 {
+ return ErrInvalidLengthModel
+ }
+ postIndex := iNdEx + byteLen
+ if postIndex < 0 {
+ return ErrInvalidLengthModel
+ }
+ if postIndex > l {
+ return io.ErrUnexpectedEOF
+ }
+ if err := m.TraceID.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
+ return err
+ }
+ iNdEx = postIndex
+ case 2:
+ if wireType != 2 {
+ return fmt.Errorf("proto: wrong wireType = %d for field SpanID", wireType)
+ }
+ var byteLen int
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowModel
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ byteLen |= int(b&0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ if byteLen < 0 {
+ return ErrInvalidLengthModel
+ }
+ postIndex := iNdEx + byteLen
+ if postIndex < 0 {
+ return ErrInvalidLengthModel
+ }
+ if postIndex > l {
+ return io.ErrUnexpectedEOF
+ }
+ if err := m.SpanID.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
+ return err
+ }
+ iNdEx = postIndex
+ case 3:
+ if wireType != 2 {
+ return fmt.Errorf("proto: wrong wireType = %d for field OperationName", wireType)
+ }
+ var stringLen uint64
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowModel
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ stringLen |= uint64(b&0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ intStringLen := int(stringLen)
+ if intStringLen < 0 {
+ return ErrInvalidLengthModel
+ }
+ postIndex := iNdEx + intStringLen
+ if postIndex < 0 {
+ return ErrInvalidLengthModel
+ }
+ if postIndex > l {
+ return io.ErrUnexpectedEOF
+ }
+ m.OperationName = string(dAtA[iNdEx:postIndex])
+ iNdEx = postIndex
+ case 4:
+ if wireType != 2 {
+ return fmt.Errorf("proto: wrong wireType = %d for field References", wireType)
+ }
+ var msglen int
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowModel
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ msglen |= int(b&0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ if msglen < 0 {
+ return ErrInvalidLengthModel
+ }
+ postIndex := iNdEx + msglen
+ if postIndex < 0 {
+ return ErrInvalidLengthModel
+ }
+ if postIndex > l {
+ return io.ErrUnexpectedEOF
+ }
+ m.References = append(m.References, SpanRef{})
+ if err := m.References[len(m.References)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
+ return err
+ }
+ iNdEx = postIndex
+ case 5:
+ if wireType != 0 {
+ return fmt.Errorf("proto: wrong wireType = %d for field Flags", wireType)
+ }
+ m.Flags = 0
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowModel
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ m.Flags |= Flags(b&0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ case 6:
+ if wireType != 2 {
+ return fmt.Errorf("proto: wrong wireType = %d for field StartTime", wireType)
+ }
+ var msglen int
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowModel
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ msglen |= int(b&0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ if msglen < 0 {
+ return ErrInvalidLengthModel
+ }
+ postIndex := iNdEx + msglen
+ if postIndex < 0 {
+ return ErrInvalidLengthModel
+ }
+ if postIndex > l {
+ return io.ErrUnexpectedEOF
+ }
+ if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.StartTime, dAtA[iNdEx:postIndex]); err != nil {
+ return err
+ }
+ iNdEx = postIndex
+ case 7:
+ if wireType != 2 {
+ return fmt.Errorf("proto: wrong wireType = %d for field Duration", wireType)
+ }
+ var msglen int
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowModel
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ msglen |= int(b&0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ if msglen < 0 {
+ return ErrInvalidLengthModel
+ }
+ postIndex := iNdEx + msglen
+ if postIndex < 0 {
+ return ErrInvalidLengthModel
+ }
+ if postIndex > l {
+ return io.ErrUnexpectedEOF
+ }
+ if err := github_com_gogo_protobuf_types.StdDurationUnmarshal(&m.Duration, dAtA[iNdEx:postIndex]); err != nil {
+ return err
+ }
+ iNdEx = postIndex
+ case 8:
+ if wireType != 2 {
+ return fmt.Errorf("proto: wrong wireType = %d for field Tags", wireType)
+ }
+ var msglen int
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowModel
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ msglen |= int(b&0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ if msglen < 0 {
+ return ErrInvalidLengthModel
+ }
+ postIndex := iNdEx + msglen
+ if postIndex < 0 {
+ return ErrInvalidLengthModel
+ }
+ if postIndex > l {
+ return io.ErrUnexpectedEOF
+ }
+ m.Tags = append(m.Tags, KeyValue{})
+ if err := m.Tags[len(m.Tags)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
+ return err
+ }
+ iNdEx = postIndex
+ case 9:
+ if wireType != 2 {
+ return fmt.Errorf("proto: wrong wireType = %d for field Logs", wireType)
+ }
+ var msglen int
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowModel
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ msglen |= int(b&0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ if msglen < 0 {
+ return ErrInvalidLengthModel
+ }
+ postIndex := iNdEx + msglen
+ if postIndex < 0 {
+ return ErrInvalidLengthModel
+ }
+ if postIndex > l {
+ return io.ErrUnexpectedEOF
+ }
+ m.Logs = append(m.Logs, Log{})
+ if err := m.Logs[len(m.Logs)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
+ return err
+ }
+ iNdEx = postIndex
+ case 10:
+ if wireType != 2 {
+ return fmt.Errorf("proto: wrong wireType = %d for field Process", wireType)
+ }
+ var msglen int
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowModel
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ msglen |= int(b&0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ if msglen < 0 {
+ return ErrInvalidLengthModel
+ }
+ postIndex := iNdEx + msglen
+ if postIndex < 0 {
+ return ErrInvalidLengthModel
+ }
+ if postIndex > l {
+ return io.ErrUnexpectedEOF
+ }
+ if m.Process == nil {
+ m.Process = &Process{}
+ }
+ if err := m.Process.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
+ return err
+ }
+ iNdEx = postIndex
+ case 11:
+ if wireType != 2 {
+ return fmt.Errorf("proto: wrong wireType = %d for field ProcessID", wireType)
+ }
+ var stringLen uint64
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowModel
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ stringLen |= uint64(b&0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ intStringLen := int(stringLen)
+ if intStringLen < 0 {
+ return ErrInvalidLengthModel
+ }
+ postIndex := iNdEx + intStringLen
+ if postIndex < 0 {
+ return ErrInvalidLengthModel
+ }
+ if postIndex > l {
+ return io.ErrUnexpectedEOF
+ }
+ m.ProcessID = string(dAtA[iNdEx:postIndex])
+ iNdEx = postIndex
+ case 12:
+ if wireType != 2 {
+ return fmt.Errorf("proto: wrong wireType = %d for field Warnings", wireType)
+ }
+ var stringLen uint64
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowModel
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ stringLen |= uint64(b&0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ intStringLen := int(stringLen)
+ if intStringLen < 0 {
+ return ErrInvalidLengthModel
+ }
+ postIndex := iNdEx + intStringLen
+ if postIndex < 0 {
+ return ErrInvalidLengthModel
+ }
+ if postIndex > l {
+ return io.ErrUnexpectedEOF
+ }
+ m.Warnings = append(m.Warnings, string(dAtA[iNdEx:postIndex]))
+ iNdEx = postIndex
+ default:
+ iNdEx = preIndex
+ skippy, err := skipModel(dAtA[iNdEx:])
+ if err != nil {
+ return err
+ }
+ if skippy < 0 {
+ return ErrInvalidLengthModel
+ }
+ if (iNdEx + skippy) < 0 {
+ return ErrInvalidLengthModel
+ }
+ if (iNdEx + skippy) > l {
+ return io.ErrUnexpectedEOF
+ }
+ m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)
+ iNdEx += skippy
+ }
+ }
+
+ if iNdEx > l {
+ return io.ErrUnexpectedEOF
+ }
+ return nil
+}
+func (m *Trace) Unmarshal(dAtA []byte) error {
+ l := len(dAtA)
+ iNdEx := 0
+ for iNdEx < l {
+ preIndex := iNdEx
+ var wire uint64
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowModel
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ wire |= uint64(b&0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ fieldNum := int32(wire >> 3)
+ wireType := int(wire & 0x7)
+ if wireType == 4 {
+ return fmt.Errorf("proto: Trace: wiretype end group for non-group")
+ }
+ if fieldNum <= 0 {
+ return fmt.Errorf("proto: Trace: illegal tag %d (wire type %d)", fieldNum, wire)
+ }
+ switch fieldNum {
+ case 1:
+ if wireType != 2 {
+ return fmt.Errorf("proto: wrong wireType = %d for field Spans", wireType)
+ }
+ var msglen int
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowModel
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ msglen |= int(b&0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ if msglen < 0 {
+ return ErrInvalidLengthModel
+ }
+ postIndex := iNdEx + msglen
+ if postIndex < 0 {
+ return ErrInvalidLengthModel
+ }
+ if postIndex > l {
+ return io.ErrUnexpectedEOF
+ }
+ m.Spans = append(m.Spans, &Span{})
+ if err := m.Spans[len(m.Spans)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
+ return err
+ }
+ iNdEx = postIndex
+ case 2:
+ if wireType != 2 {
+ return fmt.Errorf("proto: wrong wireType = %d for field ProcessMap", wireType)
+ }
+ var msglen int
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowModel
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ msglen |= int(b&0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ if msglen < 0 {
+ return ErrInvalidLengthModel
+ }
+ postIndex := iNdEx + msglen
+ if postIndex < 0 {
+ return ErrInvalidLengthModel
+ }
+ if postIndex > l {
+ return io.ErrUnexpectedEOF
+ }
+ m.ProcessMap = append(m.ProcessMap, Trace_ProcessMapping{})
+ if err := m.ProcessMap[len(m.ProcessMap)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
+ return err
+ }
+ iNdEx = postIndex
+ case 3:
+ if wireType != 2 {
+ return fmt.Errorf("proto: wrong wireType = %d for field Warnings", wireType)
+ }
+ var stringLen uint64
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowModel
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ stringLen |= uint64(b&0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ intStringLen := int(stringLen)
+ if intStringLen < 0 {
+ return ErrInvalidLengthModel
+ }
+ postIndex := iNdEx + intStringLen
+ if postIndex < 0 {
+ return ErrInvalidLengthModel
+ }
+ if postIndex > l {
+ return io.ErrUnexpectedEOF
+ }
+ m.Warnings = append(m.Warnings, string(dAtA[iNdEx:postIndex]))
+ iNdEx = postIndex
+ default:
+ iNdEx = preIndex
+ skippy, err := skipModel(dAtA[iNdEx:])
+ if err != nil {
+ return err
+ }
+ if skippy < 0 {
+ return ErrInvalidLengthModel
+ }
+ if (iNdEx + skippy) < 0 {
+ return ErrInvalidLengthModel
+ }
+ if (iNdEx + skippy) > l {
+ return io.ErrUnexpectedEOF
+ }
+ m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)
+ iNdEx += skippy
+ }
+ }
+
+ if iNdEx > l {
+ return io.ErrUnexpectedEOF
+ }
+ return nil
+}
+func (m *Trace_ProcessMapping) Unmarshal(dAtA []byte) error {
+ l := len(dAtA)
+ iNdEx := 0
+ for iNdEx < l {
+ preIndex := iNdEx
+ var wire uint64
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowModel
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ wire |= uint64(b&0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ fieldNum := int32(wire >> 3)
+ wireType := int(wire & 0x7)
+ if wireType == 4 {
+ return fmt.Errorf("proto: ProcessMapping: wiretype end group for non-group")
+ }
+ if fieldNum <= 0 {
+ return fmt.Errorf("proto: ProcessMapping: illegal tag %d (wire type %d)", fieldNum, wire)
+ }
+ switch fieldNum {
+ case 1:
+ if wireType != 2 {
+ return fmt.Errorf("proto: wrong wireType = %d for field ProcessID", wireType)
+ }
+ var stringLen uint64
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowModel
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ stringLen |= uint64(b&0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ intStringLen := int(stringLen)
+ if intStringLen < 0 {
+ return ErrInvalidLengthModel
+ }
+ postIndex := iNdEx + intStringLen
+ if postIndex < 0 {
+ return ErrInvalidLengthModel
+ }
+ if postIndex > l {
+ return io.ErrUnexpectedEOF
+ }
+ m.ProcessID = string(dAtA[iNdEx:postIndex])
+ iNdEx = postIndex
+ case 2:
+ if wireType != 2 {
+ return fmt.Errorf("proto: wrong wireType = %d for field Process", wireType)
+ }
+ var msglen int
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowModel
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ msglen |= int(b&0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ if msglen < 0 {
+ return ErrInvalidLengthModel
+ }
+ postIndex := iNdEx + msglen
+ if postIndex < 0 {
+ return ErrInvalidLengthModel
+ }
+ if postIndex > l {
+ return io.ErrUnexpectedEOF
+ }
+ if err := m.Process.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
+ return err
+ }
+ iNdEx = postIndex
+ default:
+ iNdEx = preIndex
+ skippy, err := skipModel(dAtA[iNdEx:])
+ if err != nil {
+ return err
+ }
+ if skippy < 0 {
+ return ErrInvalidLengthModel
+ }
+ if (iNdEx + skippy) < 0 {
+ return ErrInvalidLengthModel
+ }
+ if (iNdEx + skippy) > l {
+ return io.ErrUnexpectedEOF
+ }
+ m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)
+ iNdEx += skippy
+ }
+ }
+
+ if iNdEx > l {
+ return io.ErrUnexpectedEOF
+ }
+ return nil
+}
+func (m *Batch) Unmarshal(dAtA []byte) error {
+ l := len(dAtA)
+ iNdEx := 0
+ for iNdEx < l {
+ preIndex := iNdEx
+ var wire uint64
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowModel
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ wire |= uint64(b&0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ fieldNum := int32(wire >> 3)
+ wireType := int(wire & 0x7)
+ if wireType == 4 {
+ return fmt.Errorf("proto: Batch: wiretype end group for non-group")
+ }
+ if fieldNum <= 0 {
+ return fmt.Errorf("proto: Batch: illegal tag %d (wire type %d)", fieldNum, wire)
+ }
+ switch fieldNum {
+ case 1:
+ if wireType != 2 {
+ return fmt.Errorf("proto: wrong wireType = %d for field Spans", wireType)
+ }
+ var msglen int
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowModel
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ msglen |= int(b&0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ if msglen < 0 {
+ return ErrInvalidLengthModel
+ }
+ postIndex := iNdEx + msglen
+ if postIndex < 0 {
+ return ErrInvalidLengthModel
+ }
+ if postIndex > l {
+ return io.ErrUnexpectedEOF
+ }
+ m.Spans = append(m.Spans, &Span{})
+ if err := m.Spans[len(m.Spans)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
+ return err
+ }
+ iNdEx = postIndex
+ case 2:
+ if wireType != 2 {
+ return fmt.Errorf("proto: wrong wireType = %d for field Process", wireType)
+ }
+ var msglen int
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowModel
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ msglen |= int(b&0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ if msglen < 0 {
+ return ErrInvalidLengthModel
+ }
+ postIndex := iNdEx + msglen
+ if postIndex < 0 {
+ return ErrInvalidLengthModel
+ }
+ if postIndex > l {
+ return io.ErrUnexpectedEOF
+ }
+ if m.Process == nil {
+ m.Process = &Process{}
+ }
+ if err := m.Process.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
+ return err
+ }
+ iNdEx = postIndex
+ default:
+ iNdEx = preIndex
+ skippy, err := skipModel(dAtA[iNdEx:])
+ if err != nil {
+ return err
+ }
+ if skippy < 0 {
+ return ErrInvalidLengthModel
+ }
+ if (iNdEx + skippy) < 0 {
+ return ErrInvalidLengthModel
+ }
+ if (iNdEx + skippy) > l {
+ return io.ErrUnexpectedEOF
+ }
+ m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)
+ iNdEx += skippy
+ }
+ }
+
+ if iNdEx > l {
+ return io.ErrUnexpectedEOF
+ }
+ return nil
+}
+func (m *DependencyLink) Unmarshal(dAtA []byte) error {
+ l := len(dAtA)
+ iNdEx := 0
+ for iNdEx < l {
+ preIndex := iNdEx
+ var wire uint64
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowModel
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ wire |= uint64(b&0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ fieldNum := int32(wire >> 3)
+ wireType := int(wire & 0x7)
+ if wireType == 4 {
+ return fmt.Errorf("proto: DependencyLink: wiretype end group for non-group")
+ }
+ if fieldNum <= 0 {
+ return fmt.Errorf("proto: DependencyLink: illegal tag %d (wire type %d)", fieldNum, wire)
+ }
+ switch fieldNum {
+ case 1:
+ if wireType != 2 {
+ return fmt.Errorf("proto: wrong wireType = %d for field Parent", wireType)
+ }
+ var stringLen uint64
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowModel
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ stringLen |= uint64(b&0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ intStringLen := int(stringLen)
+ if intStringLen < 0 {
+ return ErrInvalidLengthModel
+ }
+ postIndex := iNdEx + intStringLen
+ if postIndex < 0 {
+ return ErrInvalidLengthModel
+ }
+ if postIndex > l {
+ return io.ErrUnexpectedEOF
+ }
+ m.Parent = string(dAtA[iNdEx:postIndex])
+ iNdEx = postIndex
+ case 2:
+ if wireType != 2 {
+ return fmt.Errorf("proto: wrong wireType = %d for field Child", wireType)
+ }
+ var stringLen uint64
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowModel
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ stringLen |= uint64(b&0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ intStringLen := int(stringLen)
+ if intStringLen < 0 {
+ return ErrInvalidLengthModel
+ }
+ postIndex := iNdEx + intStringLen
+ if postIndex < 0 {
+ return ErrInvalidLengthModel
+ }
+ if postIndex > l {
+ return io.ErrUnexpectedEOF
+ }
+ m.Child = string(dAtA[iNdEx:postIndex])
+ iNdEx = postIndex
+ case 3:
+ if wireType != 0 {
+ return fmt.Errorf("proto: wrong wireType = %d for field CallCount", wireType)
+ }
+ m.CallCount = 0
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowModel
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ m.CallCount |= uint64(b&0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ case 4:
+ if wireType != 2 {
+ return fmt.Errorf("proto: wrong wireType = %d for field Source", wireType)
+ }
+ var stringLen uint64
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowModel
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ stringLen |= uint64(b&0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ intStringLen := int(stringLen)
+ if intStringLen < 0 {
+ return ErrInvalidLengthModel
+ }
+ postIndex := iNdEx + intStringLen
+ if postIndex < 0 {
+ return ErrInvalidLengthModel
+ }
+ if postIndex > l {
+ return io.ErrUnexpectedEOF
+ }
+ m.Source = string(dAtA[iNdEx:postIndex])
+ iNdEx = postIndex
+ default:
+ iNdEx = preIndex
+ skippy, err := skipModel(dAtA[iNdEx:])
+ if err != nil {
+ return err
+ }
+ if skippy < 0 {
+ return ErrInvalidLengthModel
+ }
+ if (iNdEx + skippy) < 0 {
+ return ErrInvalidLengthModel
+ }
+ if (iNdEx + skippy) > l {
+ return io.ErrUnexpectedEOF
+ }
+ m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)
+ iNdEx += skippy
+ }
+ }
+
+ if iNdEx > l {
+ return io.ErrUnexpectedEOF
+ }
+ return nil
+}
+func skipModel(dAtA []byte) (n int, err error) {
+ l := len(dAtA)
+ iNdEx := 0
+ for iNdEx < l {
+ var wire uint64
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return 0, ErrIntOverflowModel
+ }
+ if iNdEx >= l {
+ return 0, io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ wire |= (uint64(b) & 0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ wireType := int(wire & 0x7)
+ switch wireType {
+ case 0:
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return 0, ErrIntOverflowModel
+ }
+ if iNdEx >= l {
+ return 0, io.ErrUnexpectedEOF
+ }
+ iNdEx++
+ if dAtA[iNdEx-1] < 0x80 {
+ break
+ }
+ }
+ return iNdEx, nil
+ case 1:
+ iNdEx += 8
+ return iNdEx, nil
+ case 2:
+ var length int
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return 0, ErrIntOverflowModel
+ }
+ if iNdEx >= l {
+ return 0, io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ length |= (int(b) & 0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ if length < 0 {
+ return 0, ErrInvalidLengthModel
+ }
+ iNdEx += length
+ if iNdEx < 0 {
+ return 0, ErrInvalidLengthModel
+ }
+ return iNdEx, nil
+ case 3:
+ for {
+ var innerWire uint64
+ var start int = iNdEx
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return 0, ErrIntOverflowModel
+ }
+ if iNdEx >= l {
+ return 0, io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ innerWire |= (uint64(b) & 0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ innerWireType := int(innerWire & 0x7)
+ if innerWireType == 4 {
+ break
+ }
+ next, err := skipModel(dAtA[start:])
+ if err != nil {
+ return 0, err
+ }
+ iNdEx = start + next
+ if iNdEx < 0 {
+ return 0, ErrInvalidLengthModel
+ }
+ }
+ return iNdEx, nil
+ case 4:
+ return iNdEx, nil
+ case 5:
+ iNdEx += 4
+ return iNdEx, nil
+ default:
+ return 0, fmt.Errorf("proto: illegal wireType %d", wireType)
+ }
+ }
+ panic("unreachable")
+}
+
+var (
+ ErrInvalidLengthModel = fmt.Errorf("proto: negative length found during unmarshaling")
+ ErrIntOverflowModel = fmt.Errorf("proto: integer overflow")
+)
diff --git a/vendor/github.com/jaegertracing/jaeger/model/process.go b/vendor/github.com/jaegertracing/jaeger/model/process.go
new file mode 100644
index 0000000..1babaeb
--- /dev/null
+++ b/vendor/github.com/jaegertracing/jaeger/model/process.go
@@ -0,0 +1,46 @@
+// Copyright (c) 2019 The Jaeger Authors.
+// Copyright (c) 2017 Uber Technologies, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package model
+
+import (
+ "io"
+)
+
+// NewProcess creates a new Process for given serviceName and tags.
+// The tags are sorted in place and kept in the same array/slice,
+// in order to store the Process in a canonical form that is relied
+// upon by the Equal and Hash functions.
+func NewProcess(serviceName string, tags []KeyValue) *Process {
+ typedTags := KeyValues(tags)
+ typedTags.Sort()
+ return &Process{ServiceName: serviceName, Tags: typedTags}
+}
+
+// Equal compares Process object with another Process.
+func (p *Process) Equal(other *Process) bool {
+ if p.ServiceName != other.ServiceName {
+ return false
+ }
+ return KeyValues(p.Tags).Equal(other.Tags)
+}
+
+// Hash implements Hash from Hashable.
+func (p *Process) Hash(w io.Writer) (err error) {
+ if _, err := w.Write([]byte(p.ServiceName)); err != nil {
+ return err
+ }
+ return KeyValues(p.Tags).Hash(w)
+}
diff --git a/vendor/github.com/jaegertracing/jaeger/model/sort.go b/vendor/github.com/jaegertracing/jaeger/model/sort.go
new file mode 100644
index 0000000..b2556d8
--- /dev/null
+++ b/vendor/github.com/jaegertracing/jaeger/model/sort.go
@@ -0,0 +1,112 @@
+// Copyright (c) 2019 The Jaeger Authors.
+// Copyright (c) 2017 Uber Technologies, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package model
+
+import (
+ "sort"
+)
+
+type byTraceID []*TraceID
+
+func (s byTraceID) Len() int { return len(s) }
+func (s byTraceID) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
+func (s byTraceID) Less(i, j int) bool {
+ if s[i].High < s[j].High {
+ return true
+ } else if s[i].High > s[j].High {
+ return false
+ }
+ return s[i].Low < s[j].Low
+}
+
+// SortTraceIDs sorts a list of TraceIDs
+func SortTraceIDs(traceIDs []*TraceID) {
+ sort.Sort(byTraceID(traceIDs))
+}
+
+type traceByTraceID []*Trace
+
+func (s traceByTraceID) Len() int { return len(s) }
+func (s traceByTraceID) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
+func (s traceByTraceID) Less(i, j int) bool {
+ switch {
+ case len(s[i].Spans) == 0:
+ return true
+ case len(s[j].Spans) == 0:
+ return false
+ default:
+ return s[i].Spans[0].TraceID.Low < s[j].Spans[0].TraceID.Low
+ }
+}
+
+// SortTraces deep sorts a list of traces by TraceID.
+func SortTraces(traces []*Trace) {
+ sort.Sort(traceByTraceID(traces))
+ for _, trace := range traces {
+ SortTrace(trace)
+ }
+}
+
+type spanBySpanID []*Span
+
+func (s spanBySpanID) Len() int { return len(s) }
+func (s spanBySpanID) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
+func (s spanBySpanID) Less(i, j int) bool { return s[i].SpanID < s[j].SpanID }
+
+// SortTrace deep sorts a trace's spans by SpanID.
+func SortTrace(trace *Trace) {
+ sort.Sort(spanBySpanID(trace.Spans))
+ for _, span := range trace.Spans {
+ SortSpan(span)
+ }
+}
+
+// SortSpan deep sorts a span: this sorts its tags, logs by timestamp, tags in logs, and tags in process.
+func SortSpan(span *Span) {
+ span.NormalizeTimestamps()
+ sortTags(span.Tags)
+ sortLogs(span.Logs)
+ sortProcess(span.Process)
+}
+
+type tagByKey []KeyValue
+
+func (t tagByKey) Len() int { return len(t) }
+func (t tagByKey) Swap(i, j int) { t[i], t[j] = t[j], t[i] }
+func (t tagByKey) Less(i, j int) bool { return t[i].Key < t[j].Key }
+
+func sortTags(tags []KeyValue) {
+ sort.Sort(tagByKey(tags))
+}
+
+type logByTimestamp []Log
+
+func (t logByTimestamp) Len() int { return len(t) }
+func (t logByTimestamp) Swap(i, j int) { t[i], t[j] = t[j], t[i] }
+func (t logByTimestamp) Less(i, j int) bool { return t[i].Timestamp.Before(t[j].Timestamp) }
+
+func sortLogs(logs []Log) {
+ sort.Sort(logByTimestamp(logs))
+ for _, log := range logs {
+ sortTags(log.Fields)
+ }
+}
+
+func sortProcess(process *Process) {
+ if process != nil {
+ sortTags(process.Tags)
+ }
+}
diff --git a/vendor/github.com/jaegertracing/jaeger/model/span.go b/vendor/github.com/jaegertracing/jaeger/model/span.go
new file mode 100644
index 0000000..0fbd0ed
--- /dev/null
+++ b/vendor/github.com/jaegertracing/jaeger/model/span.go
@@ -0,0 +1,153 @@
+// Copyright (c) 2019 The Jaeger Authors.
+// Copyright (c) 2017 Uber Technologies, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package model
+
+import (
+ "encoding/gob"
+ "io"
+
+ "github.com/opentracing/opentracing-go/ext"
+)
+
+const (
+ // SampledFlag is the bit set in Flags in order to define a span as a sampled span
+ SampledFlag = Flags(1)
+ // DebugFlag is the bit set in Flags in order to define a span as a debug span
+ DebugFlag = Flags(2)
+ //FirehoseFlag is the bit in Flags in order to define a span as a firehose span
+ FirehoseFlag = Flags(8)
+
+ samplerType = "sampler.type"
+ samplerTypeUnknown = "unknown"
+)
+
+// Flags is a bit map of flags for a span
+type Flags uint32
+
+// Hash implements Hash from Hashable.
+func (s *Span) Hash(w io.Writer) (err error) {
+ // gob is not the most efficient way, but it ensures we don't miss any fields.
+ // See BenchmarkSpanHash in span_test.go
+ enc := gob.NewEncoder(w)
+ return enc.Encode(s)
+}
+
+// HasSpanKind returns true if the span has a `span.kind` tag set to `kind`.
+func (s *Span) HasSpanKind(kind ext.SpanKindEnum) bool {
+ if tag, ok := KeyValues(s.Tags).FindByKey(string(ext.SpanKind)); ok {
+ return tag.AsString() == string(kind)
+ }
+ return false
+}
+
+// GetSamplerType returns the sampler type for span
+func (s *Span) GetSamplerType() string {
+ // There's no corresponding opentracing-go tag label corresponding to sampler.type
+ if tag, ok := KeyValues(s.Tags).FindByKey(samplerType); ok {
+ if tag.VStr == "" {
+ return samplerTypeUnknown
+ }
+ return tag.VStr
+ }
+ return samplerTypeUnknown
+}
+
+// IsRPCClient returns true if the span represents a client side of an RPC,
+// as indicated by the `span.kind` tag set to `client`.
+func (s *Span) IsRPCClient() bool {
+ return s.HasSpanKind(ext.SpanKindRPCClientEnum)
+}
+
+// IsRPCServer returns true if the span represents a server side of an RPC,
+// as indicated by the `span.kind` tag set to `server`.
+func (s *Span) IsRPCServer() bool {
+ return s.HasSpanKind(ext.SpanKindRPCServerEnum)
+}
+
+// NormalizeTimestamps changes all timestamps in this span to UTC.
+func (s *Span) NormalizeTimestamps() {
+ s.StartTime = s.StartTime.UTC()
+ for i := range s.Logs {
+ s.Logs[i].Timestamp = s.Logs[i].Timestamp.UTC()
+ }
+}
+
+// ParentSpanID returns ID of a parent span if it exists.
+// It searches for the first child-of reference pointing to the same trace ID.
+func (s *Span) ParentSpanID() SpanID {
+ for i := range s.References {
+ ref := &s.References[i]
+ if ref.TraceID == s.TraceID && ref.RefType == ChildOf {
+ return ref.SpanID
+ }
+ }
+ return SpanID(0)
+}
+
+// ReplaceParentID replaces span ID in the parent span reference.
+// See also ParentSpanID.
+func (s *Span) ReplaceParentID(newParentID SpanID) {
+ oldParentID := s.ParentSpanID()
+ for i := range s.References {
+ if s.References[i].SpanID == oldParentID && s.References[i].TraceID == s.TraceID {
+ s.References[i].SpanID = newParentID
+ return
+ }
+ }
+ s.References = MaybeAddParentSpanID(s.TraceID, newParentID, s.References)
+}
+
+// ------- Flags -------
+
+// SetSampled sets the Flags as sampled
+func (f *Flags) SetSampled() {
+ f.setFlags(SampledFlag)
+}
+
+// SetDebug set the Flags as sampled
+func (f *Flags) SetDebug() {
+ f.setFlags(DebugFlag)
+}
+
+// SetFirehose set the Flags as firehose enabled
+func (f *Flags) SetFirehose() {
+ f.setFlags(FirehoseFlag)
+}
+
+func (f *Flags) setFlags(bit Flags) {
+ *f = *f | bit
+}
+
+// IsSampled returns true if the Flags denote sampling
+func (f Flags) IsSampled() bool {
+ return f.checkFlags(SampledFlag)
+}
+
+// IsDebug returns true if the Flags denote debugging
+// Debugging can be useful in testing tracing availability or correctness
+func (f Flags) IsDebug() bool {
+ return f.checkFlags(DebugFlag)
+}
+
+// IsFirehoseEnabled returns true if firehose is enabled
+// Firehose is used to decide whether to index a span or not
+func (f Flags) IsFirehoseEnabled() bool {
+ return f.checkFlags(FirehoseFlag)
+}
+
+func (f Flags) checkFlags(bit Flags) bool {
+ return f&bit == bit
+}
diff --git a/vendor/github.com/jaegertracing/jaeger/model/spanref.go b/vendor/github.com/jaegertracing/jaeger/model/spanref.go
new file mode 100644
index 0000000..92acc21
--- /dev/null
+++ b/vendor/github.com/jaegertracing/jaeger/model/spanref.go
@@ -0,0 +1,72 @@
+// Copyright (c) 2019 The Jaeger Authors.
+// Copyright (c) 2017 Uber Technologies, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package model
+
+const (
+ // ChildOf span reference type describes a reference to a parent span
+ // that depends on the response from the current (child) span
+ ChildOf = SpanRefType_CHILD_OF
+
+ // FollowsFrom span reference type describes a reference to a "parent" span
+ // that does not depend on the response from the current (child) span
+ FollowsFrom = SpanRefType_FOLLOWS_FROM
+)
+
+// MaybeAddParentSpanID adds non-zero parentSpanID to refs as a child-of reference.
+// We no longer store ParentSpanID in the domain model, but the data in the database
+// or other formats might still have these IDs without representing them in the References,
+// so this converts parent IDs to canonical reference format.
+func MaybeAddParentSpanID(traceID TraceID, parentSpanID SpanID, refs []SpanRef) []SpanRef {
+ if parentSpanID == 0 {
+ return refs
+ }
+ for i := range refs {
+ r := &refs[i]
+ if r.SpanID == parentSpanID && r.TraceID == traceID {
+ return refs
+ }
+ }
+ newRef := SpanRef{
+ TraceID: traceID,
+ SpanID: parentSpanID,
+ RefType: ChildOf,
+ }
+ if len(refs) == 0 {
+ return append(refs, newRef)
+ }
+ newRefs := make([]SpanRef, len(refs)+1)
+ newRefs[0] = newRef
+ copy(newRefs[1:], refs)
+ return newRefs
+}
+
+// NewChildOfRef creates a new child-of span reference.
+func NewChildOfRef(traceID TraceID, spanID SpanID) SpanRef {
+ return SpanRef{
+ RefType: ChildOf,
+ TraceID: traceID,
+ SpanID: spanID,
+ }
+}
+
+// NewFollowsFromRef creates a new follows-from span reference.
+func NewFollowsFromRef(traceID TraceID, spanID SpanID) SpanRef {
+ return SpanRef{
+ RefType: FollowsFrom,
+ TraceID: traceID,
+ SpanID: spanID,
+ }
+}
diff --git a/vendor/github.com/jaegertracing/jaeger/model/time.go b/vendor/github.com/jaegertracing/jaeger/model/time.go
new file mode 100644
index 0000000..34a66a7
--- /dev/null
+++ b/vendor/github.com/jaegertracing/jaeger/model/time.go
@@ -0,0 +1,44 @@
+// Copyright (c) 2019 The Jaeger Authors.
+// Copyright (c) 2017 Uber Technologies, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package model
+
+import (
+ "time"
+)
+
+// EpochMicrosecondsAsTime converts microseconds since epoch to time.Time value.
+func EpochMicrosecondsAsTime(ts uint64) time.Time {
+ seconds := ts / 1000000
+ nanos := 1000 * (ts % 1000000)
+ return time.Unix(int64(seconds), int64(nanos)).UTC()
+}
+
+// TimeAsEpochMicroseconds converts time.Time to microseconds since epoch,
+// which is the format the StartTime field is stored in the Span.
+func TimeAsEpochMicroseconds(t time.Time) uint64 {
+ return uint64(t.UnixNano() / 1000)
+}
+
+// MicrosecondsAsDuration converts duration in microseconds to time.Duration value.
+func MicrosecondsAsDuration(v uint64) time.Duration {
+ return time.Duration(v) * time.Microsecond
+}
+
+// DurationAsMicroseconds converts time.Duration to microseconds,
+// which is the format the Duration field is stored in the Span.
+func DurationAsMicroseconds(d time.Duration) uint64 {
+ return uint64(d.Nanoseconds() / 1000)
+}
diff --git a/vendor/github.com/jaegertracing/jaeger/model/trace.go b/vendor/github.com/jaegertracing/jaeger/model/trace.go
new file mode 100644
index 0000000..fcc31b0
--- /dev/null
+++ b/vendor/github.com/jaegertracing/jaeger/model/trace.go
@@ -0,0 +1,34 @@
+// Copyright (c) 2019 The Jaeger Authors.
+// Copyright (c) 2017 Uber Technologies, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package model
+
+// FindSpanByID looks for a span with given span ID and returns the first one
+// it finds (search order is unspecified), or nil if no spans have that ID.
+func (t *Trace) FindSpanByID(id SpanID) *Span {
+ for _, span := range t.Spans {
+ if id == span.SpanID {
+ return span
+ }
+ }
+ return nil
+}
+
+// NormalizeTimestamps changes all timestamps in this trace to UTC.
+func (t *Trace) NormalizeTimestamps() {
+ for _, span := range t.Spans {
+ span.NormalizeTimestamps()
+ }
+}
diff --git a/vendor/github.com/matttproud/golang_protobuf_extensions/LICENSE b/vendor/github.com/matttproud/golang_protobuf_extensions/LICENSE
new file mode 100644
index 0000000..8dada3e
--- /dev/null
+++ b/vendor/github.com/matttproud/golang_protobuf_extensions/LICENSE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "{}"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright {yyyy} {name of copyright owner}
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/vendor/github.com/matttproud/golang_protobuf_extensions/NOTICE b/vendor/github.com/matttproud/golang_protobuf_extensions/NOTICE
new file mode 100644
index 0000000..5d8cb5b
--- /dev/null
+++ b/vendor/github.com/matttproud/golang_protobuf_extensions/NOTICE
@@ -0,0 +1 @@
+Copyright 2012 Matt T. Proud (matt.proud@gmail.com)
diff --git a/vendor/github.com/matttproud/golang_protobuf_extensions/pbutil/.gitignore b/vendor/github.com/matttproud/golang_protobuf_extensions/pbutil/.gitignore
new file mode 100644
index 0000000..e16fb94
--- /dev/null
+++ b/vendor/github.com/matttproud/golang_protobuf_extensions/pbutil/.gitignore
@@ -0,0 +1 @@
+cover.dat
diff --git a/vendor/github.com/matttproud/golang_protobuf_extensions/pbutil/Makefile b/vendor/github.com/matttproud/golang_protobuf_extensions/pbutil/Makefile
new file mode 100644
index 0000000..81be214
--- /dev/null
+++ b/vendor/github.com/matttproud/golang_protobuf_extensions/pbutil/Makefile
@@ -0,0 +1,7 @@
+all:
+
+cover:
+ go test -cover -v -coverprofile=cover.dat ./...
+ go tool cover -func cover.dat
+
+.PHONY: cover
diff --git a/vendor/github.com/matttproud/golang_protobuf_extensions/pbutil/decode.go b/vendor/github.com/matttproud/golang_protobuf_extensions/pbutil/decode.go
new file mode 100644
index 0000000..258c063
--- /dev/null
+++ b/vendor/github.com/matttproud/golang_protobuf_extensions/pbutil/decode.go
@@ -0,0 +1,75 @@
+// Copyright 2013 Matt T. Proud
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package pbutil
+
+import (
+ "encoding/binary"
+ "errors"
+ "io"
+
+ "github.com/golang/protobuf/proto"
+)
+
+var errInvalidVarint = errors.New("invalid varint32 encountered")
+
+// ReadDelimited decodes a message from the provided length-delimited stream,
+// where the length is encoded as 32-bit varint prefix to the message body.
+// It returns the total number of bytes read and any applicable error. This is
+// roughly equivalent to the companion Java API's
+// MessageLite#parseDelimitedFrom. As per the reader contract, this function
+// calls r.Read repeatedly as required until exactly one message including its
+// prefix is read and decoded (or an error has occurred). The function never
+// reads more bytes from the stream than required. The function never returns
+// an error if a message has been read and decoded correctly, even if the end
+// of the stream has been reached in doing so. In that case, any subsequent
+// calls return (0, io.EOF).
+func ReadDelimited(r io.Reader, m proto.Message) (n int, err error) {
+ // Per AbstractParser#parsePartialDelimitedFrom with
+ // CodedInputStream#readRawVarint32.
+ var headerBuf [binary.MaxVarintLen32]byte
+ var bytesRead, varIntBytes int
+ var messageLength uint64
+ for varIntBytes == 0 { // i.e. no varint has been decoded yet.
+ if bytesRead >= len(headerBuf) {
+ return bytesRead, errInvalidVarint
+ }
+ // We have to read byte by byte here to avoid reading more bytes
+ // than required. Each read byte is appended to what we have
+ // read before.
+ newBytesRead, err := r.Read(headerBuf[bytesRead : bytesRead+1])
+ if newBytesRead == 0 {
+ if err != nil {
+ return bytesRead, err
+ }
+ // A Reader should not return (0, nil), but if it does,
+ // it should be treated as no-op (according to the
+ // Reader contract). So let's go on...
+ continue
+ }
+ bytesRead += newBytesRead
+ // Now present everything read so far to the varint decoder and
+ // see if a varint can be decoded already.
+ messageLength, varIntBytes = proto.DecodeVarint(headerBuf[:bytesRead])
+ }
+
+ messageBuf := make([]byte, messageLength)
+ newBytesRead, err := io.ReadFull(r, messageBuf)
+ bytesRead += newBytesRead
+ if err != nil {
+ return bytesRead, err
+ }
+
+ return bytesRead, proto.Unmarshal(messageBuf, m)
+}
diff --git a/vendor/github.com/matttproud/golang_protobuf_extensions/pbutil/doc.go b/vendor/github.com/matttproud/golang_protobuf_extensions/pbutil/doc.go
new file mode 100644
index 0000000..c318385
--- /dev/null
+++ b/vendor/github.com/matttproud/golang_protobuf_extensions/pbutil/doc.go
@@ -0,0 +1,16 @@
+// Copyright 2013 Matt T. Proud
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Package pbutil provides record length-delimited Protocol Buffer streaming.
+package pbutil
diff --git a/vendor/github.com/matttproud/golang_protobuf_extensions/pbutil/encode.go b/vendor/github.com/matttproud/golang_protobuf_extensions/pbutil/encode.go
new file mode 100644
index 0000000..8fb59ad
--- /dev/null
+++ b/vendor/github.com/matttproud/golang_protobuf_extensions/pbutil/encode.go
@@ -0,0 +1,46 @@
+// Copyright 2013 Matt T. Proud
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package pbutil
+
+import (
+ "encoding/binary"
+ "io"
+
+ "github.com/golang/protobuf/proto"
+)
+
+// WriteDelimited encodes and dumps a message to the provided writer prefixed
+// with a 32-bit varint indicating the length of the encoded message, producing
+// a length-delimited record stream, which can be used to chain together
+// encoded messages of the same type together in a file. It returns the total
+// number of bytes written and any applicable error. This is roughly
+// equivalent to the companion Java API's MessageLite#writeDelimitedTo.
+func WriteDelimited(w io.Writer, m proto.Message) (n int, err error) {
+ buffer, err := proto.Marshal(m)
+ if err != nil {
+ return 0, err
+ }
+
+ var buf [binary.MaxVarintLen32]byte
+ encodedLength := binary.PutUvarint(buf[:], uint64(len(buffer)))
+
+ sync, err := w.Write(buf[:encodedLength])
+ if err != nil {
+ return sync, err
+ }
+
+ n, err = w.Write(buffer)
+ return n + sync, err
+}
diff --git a/vendor/github.com/open-telemetry/opentelemetry-proto/LICENSE b/vendor/github.com/open-telemetry/opentelemetry-proto/LICENSE
new file mode 100644
index 0000000..261eeb9
--- /dev/null
+++ b/vendor/github.com/open-telemetry/opentelemetry-proto/LICENSE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/vendor/github.com/open-telemetry/opentelemetry-proto/gen/go/collector/metrics/v1/metrics_service.pb.go b/vendor/github.com/open-telemetry/opentelemetry-proto/gen/go/collector/metrics/v1/metrics_service.pb.go
new file mode 100644
index 0000000..39a22f5
--- /dev/null
+++ b/vendor/github.com/open-telemetry/opentelemetry-proto/gen/go/collector/metrics/v1/metrics_service.pb.go
@@ -0,0 +1,215 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// source: opentelemetry/proto/collector/metrics/v1/metrics_service.proto
+
+package v1
+
+import (
+ context "context"
+ fmt "fmt"
+ proto "github.com/golang/protobuf/proto"
+ v1 "github.com/open-telemetry/opentelemetry-proto/gen/go/metrics/v1"
+ grpc "google.golang.org/grpc"
+ codes "google.golang.org/grpc/codes"
+ status "google.golang.org/grpc/status"
+ math "math"
+)
+
+// Reference imports to suppress errors if they are not otherwise used.
+var _ = proto.Marshal
+var _ = fmt.Errorf
+var _ = math.Inf
+
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the proto package it is being compiled against.
+// A compilation error at this line likely means your copy of the
+// proto package needs to be updated.
+const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
+
+type ExportMetricsServiceRequest struct {
+ // An array of ResourceMetrics.
+ // For data coming from a single resource this array will typically contain one
+ // element. Intermediary nodes (such as OpenTelemetry Collector) that receive
+ // data from multiple origins typically batch the data before forwarding further and
+ // in that case this array will contain multiple elements.
+ ResourceMetrics []*v1.ResourceMetrics `protobuf:"bytes,1,rep,name=resource_metrics,json=resourceMetrics,proto3" json:"resource_metrics,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *ExportMetricsServiceRequest) Reset() { *m = ExportMetricsServiceRequest{} }
+func (m *ExportMetricsServiceRequest) String() string { return proto.CompactTextString(m) }
+func (*ExportMetricsServiceRequest) ProtoMessage() {}
+func (*ExportMetricsServiceRequest) Descriptor() ([]byte, []int) {
+ return fileDescriptor_75fb6015e6e64798, []int{0}
+}
+
+func (m *ExportMetricsServiceRequest) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_ExportMetricsServiceRequest.Unmarshal(m, b)
+}
+func (m *ExportMetricsServiceRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_ExportMetricsServiceRequest.Marshal(b, m, deterministic)
+}
+func (m *ExportMetricsServiceRequest) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_ExportMetricsServiceRequest.Merge(m, src)
+}
+func (m *ExportMetricsServiceRequest) XXX_Size() int {
+ return xxx_messageInfo_ExportMetricsServiceRequest.Size(m)
+}
+func (m *ExportMetricsServiceRequest) XXX_DiscardUnknown() {
+ xxx_messageInfo_ExportMetricsServiceRequest.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_ExportMetricsServiceRequest proto.InternalMessageInfo
+
+func (m *ExportMetricsServiceRequest) GetResourceMetrics() []*v1.ResourceMetrics {
+ if m != nil {
+ return m.ResourceMetrics
+ }
+ return nil
+}
+
+type ExportMetricsServiceResponse struct {
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *ExportMetricsServiceResponse) Reset() { *m = ExportMetricsServiceResponse{} }
+func (m *ExportMetricsServiceResponse) String() string { return proto.CompactTextString(m) }
+func (*ExportMetricsServiceResponse) ProtoMessage() {}
+func (*ExportMetricsServiceResponse) Descriptor() ([]byte, []int) {
+ return fileDescriptor_75fb6015e6e64798, []int{1}
+}
+
+func (m *ExportMetricsServiceResponse) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_ExportMetricsServiceResponse.Unmarshal(m, b)
+}
+func (m *ExportMetricsServiceResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_ExportMetricsServiceResponse.Marshal(b, m, deterministic)
+}
+func (m *ExportMetricsServiceResponse) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_ExportMetricsServiceResponse.Merge(m, src)
+}
+func (m *ExportMetricsServiceResponse) XXX_Size() int {
+ return xxx_messageInfo_ExportMetricsServiceResponse.Size(m)
+}
+func (m *ExportMetricsServiceResponse) XXX_DiscardUnknown() {
+ xxx_messageInfo_ExportMetricsServiceResponse.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_ExportMetricsServiceResponse proto.InternalMessageInfo
+
+func init() {
+ proto.RegisterType((*ExportMetricsServiceRequest)(nil), "opentelemetry.proto.collector.metrics.v1.ExportMetricsServiceRequest")
+ proto.RegisterType((*ExportMetricsServiceResponse)(nil), "opentelemetry.proto.collector.metrics.v1.ExportMetricsServiceResponse")
+}
+
+func init() {
+ proto.RegisterFile("opentelemetry/proto/collector/metrics/v1/metrics_service.proto", fileDescriptor_75fb6015e6e64798)
+}
+
+var fileDescriptor_75fb6015e6e64798 = []byte{
+ // 264 bytes of a gzipped FileDescriptorProto
+ 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xb2, 0xcb, 0x2f, 0x48, 0xcd,
+ 0x2b, 0x49, 0xcd, 0x49, 0xcd, 0x4d, 0x2d, 0x29, 0xaa, 0xd4, 0x2f, 0x28, 0xca, 0x2f, 0xc9, 0xd7,
+ 0x4f, 0xce, 0xcf, 0xc9, 0x49, 0x4d, 0x2e, 0xc9, 0x2f, 0xd2, 0x07, 0x89, 0x66, 0x26, 0x17, 0xeb,
+ 0x97, 0x19, 0xc2, 0x98, 0xf1, 0xc5, 0xa9, 0x45, 0x65, 0x99, 0xc9, 0xa9, 0x7a, 0x60, 0xa5, 0x42,
+ 0x1a, 0x28, 0xfa, 0x21, 0x82, 0x7a, 0x70, 0xfd, 0x7a, 0x50, 0x4d, 0x7a, 0x65, 0x86, 0x52, 0x3a,
+ 0xd8, 0x6c, 0xc2, 0x34, 0x1f, 0x62, 0x84, 0x52, 0x25, 0x97, 0xb4, 0x6b, 0x45, 0x41, 0x7e, 0x51,
+ 0x89, 0x2f, 0x44, 0x38, 0x18, 0x62, 0x6b, 0x50, 0x6a, 0x61, 0x69, 0x6a, 0x71, 0x89, 0x50, 0x14,
+ 0x97, 0x40, 0x51, 0x6a, 0x71, 0x7e, 0x69, 0x51, 0x72, 0x6a, 0x3c, 0x54, 0xa3, 0x04, 0xa3, 0x02,
+ 0xb3, 0x06, 0xb7, 0x91, 0xbe, 0x1e, 0x36, 0x17, 0x21, 0xdc, 0xa1, 0x17, 0x04, 0xd5, 0x07, 0x35,
+ 0x38, 0x88, 0xbf, 0x08, 0x55, 0x40, 0x49, 0x8e, 0x4b, 0x06, 0xbb, 0xd5, 0xc5, 0x05, 0xf9, 0x79,
+ 0xc5, 0xa9, 0x46, 0x6b, 0x18, 0xb9, 0xf8, 0x50, 0xa5, 0x84, 0x66, 0x32, 0x72, 0xb1, 0x41, 0xf4,
+ 0x08, 0xb9, 0xea, 0x11, 0x1b, 0x22, 0x7a, 0x78, 0x3c, 0x28, 0xe5, 0x46, 0xa9, 0x31, 0x10, 0xc7,
+ 0x2a, 0x31, 0x38, 0xf5, 0x33, 0x72, 0x69, 0x67, 0xe6, 0x13, 0x6d, 0x9c, 0x93, 0x30, 0xaa, 0x49,
+ 0x01, 0x20, 0x95, 0x01, 0x8c, 0x51, 0x9e, 0xe9, 0x99, 0x25, 0x19, 0xa5, 0x49, 0x7a, 0xc9, 0xf9,
+ 0xb9, 0xfa, 0x20, 0xb3, 0x74, 0x11, 0x51, 0x89, 0x62, 0xb4, 0x2e, 0x24, 0x62, 0xd3, 0x53, 0xf3,
+ 0xf4, 0xd3, 0xb1, 0xa7, 0xa4, 0x24, 0x36, 0xb0, 0x12, 0x63, 0x40, 0x00, 0x00, 0x00, 0xff, 0xff,
+ 0xaa, 0xdd, 0xdf, 0x49, 0x7c, 0x02, 0x00, 0x00,
+}
+
+// Reference imports to suppress errors if they are not otherwise used.
+var _ context.Context
+var _ grpc.ClientConn
+
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the grpc package it is being compiled against.
+const _ = grpc.SupportPackageIsVersion4
+
+// MetricsServiceClient is the client API for MetricsService service.
+//
+// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
+type MetricsServiceClient interface {
+ // For performance reasons, it is recommended to keep this RPC
+ // alive for the entire life of the application.
+ Export(ctx context.Context, in *ExportMetricsServiceRequest, opts ...grpc.CallOption) (*ExportMetricsServiceResponse, error)
+}
+
+type metricsServiceClient struct {
+ cc *grpc.ClientConn
+}
+
+func NewMetricsServiceClient(cc *grpc.ClientConn) MetricsServiceClient {
+ return &metricsServiceClient{cc}
+}
+
+func (c *metricsServiceClient) Export(ctx context.Context, in *ExportMetricsServiceRequest, opts ...grpc.CallOption) (*ExportMetricsServiceResponse, error) {
+ out := new(ExportMetricsServiceResponse)
+ err := c.cc.Invoke(ctx, "/opentelemetry.proto.collector.metrics.v1.MetricsService/Export", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+// MetricsServiceServer is the server API for MetricsService service.
+type MetricsServiceServer interface {
+ // For performance reasons, it is recommended to keep this RPC
+ // alive for the entire life of the application.
+ Export(context.Context, *ExportMetricsServiceRequest) (*ExportMetricsServiceResponse, error)
+}
+
+// UnimplementedMetricsServiceServer can be embedded to have forward compatible implementations.
+type UnimplementedMetricsServiceServer struct {
+}
+
+func (*UnimplementedMetricsServiceServer) Export(ctx context.Context, req *ExportMetricsServiceRequest) (*ExportMetricsServiceResponse, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method Export not implemented")
+}
+
+func RegisterMetricsServiceServer(s *grpc.Server, srv MetricsServiceServer) {
+ s.RegisterService(&_MetricsService_serviceDesc, srv)
+}
+
+func _MetricsService_Export_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(ExportMetricsServiceRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(MetricsServiceServer).Export(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: "/opentelemetry.proto.collector.metrics.v1.MetricsService/Export",
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(MetricsServiceServer).Export(ctx, req.(*ExportMetricsServiceRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+var _MetricsService_serviceDesc = grpc.ServiceDesc{
+ ServiceName: "opentelemetry.proto.collector.metrics.v1.MetricsService",
+ HandlerType: (*MetricsServiceServer)(nil),
+ Methods: []grpc.MethodDesc{
+ {
+ MethodName: "Export",
+ Handler: _MetricsService_Export_Handler,
+ },
+ },
+ Streams: []grpc.StreamDesc{},
+ Metadata: "opentelemetry/proto/collector/metrics/v1/metrics_service.proto",
+}
diff --git a/vendor/github.com/open-telemetry/opentelemetry-proto/gen/go/collector/metrics/v1/metrics_service.pb.gw.go b/vendor/github.com/open-telemetry/opentelemetry-proto/gen/go/collector/metrics/v1/metrics_service.pb.gw.go
new file mode 100644
index 0000000..3bd2374
--- /dev/null
+++ b/vendor/github.com/open-telemetry/opentelemetry-proto/gen/go/collector/metrics/v1/metrics_service.pb.gw.go
@@ -0,0 +1,115 @@
+// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT.
+// source: opentelemetry/proto/collector/metrics/v1/metrics_service.proto
+
+/*
+Package v1 is a reverse proxy.
+
+It translates gRPC into RESTful JSON APIs.
+*/
+package v1
+
+import (
+ "context"
+ "io"
+ "net/http"
+
+ "github.com/golang/protobuf/proto"
+ "github.com/grpc-ecosystem/grpc-gateway/runtime"
+ "github.com/grpc-ecosystem/grpc-gateway/utilities"
+ "google.golang.org/grpc"
+ "google.golang.org/grpc/codes"
+ "google.golang.org/grpc/grpclog"
+ "google.golang.org/grpc/status"
+)
+
+var _ codes.Code
+var _ io.Reader
+var _ status.Status
+var _ = runtime.String
+var _ = utilities.NewDoubleArray
+
+func request_MetricsService_Export_0(ctx context.Context, marshaler runtime.Marshaler, client MetricsServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
+ var protoReq ExportMetricsServiceRequest
+ var metadata runtime.ServerMetadata
+
+ newReader, berr := utilities.IOReaderFactory(req.Body)
+ if berr != nil {
+ return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
+ }
+ if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
+ return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
+ }
+
+ msg, err := client.Export(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
+ return msg, metadata, err
+
+}
+
+// RegisterMetricsServiceHandlerFromEndpoint is same as RegisterMetricsServiceHandler but
+// automatically dials to "endpoint" and closes the connection when "ctx" gets done.
+func RegisterMetricsServiceHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) {
+ conn, err := grpc.Dial(endpoint, opts...)
+ if err != nil {
+ return err
+ }
+ defer func() {
+ if err != nil {
+ if cerr := conn.Close(); cerr != nil {
+ grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr)
+ }
+ return
+ }
+ go func() {
+ <-ctx.Done()
+ if cerr := conn.Close(); cerr != nil {
+ grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr)
+ }
+ }()
+ }()
+
+ return RegisterMetricsServiceHandler(ctx, mux, conn)
+}
+
+// RegisterMetricsServiceHandler registers the http handlers for service MetricsService to "mux".
+// The handlers forward requests to the grpc endpoint over "conn".
+func RegisterMetricsServiceHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error {
+ return RegisterMetricsServiceHandlerClient(ctx, mux, NewMetricsServiceClient(conn))
+}
+
+// RegisterMetricsServiceHandlerClient registers the http handlers for service MetricsService
+// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "MetricsServiceClient".
+// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "MetricsServiceClient"
+// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in
+// "MetricsServiceClient" to call the correct interceptors.
+func RegisterMetricsServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux, client MetricsServiceClient) error {
+
+ mux.Handle("POST", pattern_MetricsService_Export_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
+ ctx, cancel := context.WithCancel(req.Context())
+ defer cancel()
+ inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
+ rctx, err := runtime.AnnotateContext(ctx, mux, req)
+ if err != nil {
+ runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
+ return
+ }
+ resp, md, err := request_MetricsService_Export_0(rctx, inboundMarshaler, client, req, pathParams)
+ ctx = runtime.NewServerMetadataContext(ctx, md)
+ if err != nil {
+ runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
+ return
+ }
+
+ forward_MetricsService_Export_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
+
+ })
+
+ return nil
+}
+
+var (
+ pattern_MetricsService_Export_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "metrics"}, "", runtime.AssumeColonVerbOpt(true)))
+)
+
+var (
+ forward_MetricsService_Export_0 = runtime.ForwardResponseMessage
+)
diff --git a/vendor/github.com/open-telemetry/opentelemetry-proto/gen/go/collector/trace/v1/trace_config.pb.go b/vendor/github.com/open-telemetry/opentelemetry-proto/gen/go/collector/trace/v1/trace_config.pb.go
new file mode 100644
index 0000000..11781cc
--- /dev/null
+++ b/vendor/github.com/open-telemetry/opentelemetry-proto/gen/go/collector/trace/v1/trace_config.pb.go
@@ -0,0 +1,368 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// source: opentelemetry/proto/trace/v1/trace_config.proto
+
+package v1
+
+import (
+ fmt "fmt"
+ proto "github.com/golang/protobuf/proto"
+ math "math"
+)
+
+// Reference imports to suppress errors if they are not otherwise used.
+var _ = proto.Marshal
+var _ = fmt.Errorf
+var _ = math.Inf
+
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the proto package it is being compiled against.
+// A compilation error at this line likely means your copy of the
+// proto package needs to be updated.
+const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
+
+// How spans should be sampled:
+// - Always off
+// - Always on
+// - Always follow the parent Span's decision (off if no parent).
+type ConstantSampler_ConstantDecision int32
+
+const (
+ ConstantSampler_ALWAYS_OFF ConstantSampler_ConstantDecision = 0
+ ConstantSampler_ALWAYS_ON ConstantSampler_ConstantDecision = 1
+ ConstantSampler_ALWAYS_PARENT ConstantSampler_ConstantDecision = 2
+)
+
+var ConstantSampler_ConstantDecision_name = map[int32]string{
+ 0: "ALWAYS_OFF",
+ 1: "ALWAYS_ON",
+ 2: "ALWAYS_PARENT",
+}
+
+var ConstantSampler_ConstantDecision_value = map[string]int32{
+ "ALWAYS_OFF": 0,
+ "ALWAYS_ON": 1,
+ "ALWAYS_PARENT": 2,
+}
+
+func (x ConstantSampler_ConstantDecision) String() string {
+ return proto.EnumName(ConstantSampler_ConstantDecision_name, int32(x))
+}
+
+func (ConstantSampler_ConstantDecision) EnumDescriptor() ([]byte, []int) {
+ return fileDescriptor_5936aa8fa6443e6f, []int{1, 0}
+}
+
+// Global configuration of the trace service. All fields must be specified, or
+// the default (zero) values will be used for each type.
+type TraceConfig struct {
+ // The global default sampler used to make decisions on span sampling.
+ //
+ // Types that are valid to be assigned to Sampler:
+ // *TraceConfig_ConstantSampler
+ // *TraceConfig_ProbabilitySampler
+ // *TraceConfig_RateLimitingSampler
+ Sampler isTraceConfig_Sampler `protobuf_oneof:"sampler"`
+ // The global default max number of attributes per span.
+ MaxNumberOfAttributes int64 `protobuf:"varint,4,opt,name=max_number_of_attributes,json=maxNumberOfAttributes,proto3" json:"max_number_of_attributes,omitempty"`
+ // The global default max number of annotation events per span.
+ MaxNumberOfTimedEvents int64 `protobuf:"varint,5,opt,name=max_number_of_timed_events,json=maxNumberOfTimedEvents,proto3" json:"max_number_of_timed_events,omitempty"`
+ // The global default max number of attributes per timed event.
+ MaxNumberOfAttributesPerTimedEvent int64 `protobuf:"varint,6,opt,name=max_number_of_attributes_per_timed_event,json=maxNumberOfAttributesPerTimedEvent,proto3" json:"max_number_of_attributes_per_timed_event,omitempty"`
+ // The global default max number of link entries per span.
+ MaxNumberOfLinks int64 `protobuf:"varint,7,opt,name=max_number_of_links,json=maxNumberOfLinks,proto3" json:"max_number_of_links,omitempty"`
+ // The global default max number of attributes per span.
+ MaxNumberOfAttributesPerLink int64 `protobuf:"varint,8,opt,name=max_number_of_attributes_per_link,json=maxNumberOfAttributesPerLink,proto3" json:"max_number_of_attributes_per_link,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *TraceConfig) Reset() { *m = TraceConfig{} }
+func (m *TraceConfig) String() string { return proto.CompactTextString(m) }
+func (*TraceConfig) ProtoMessage() {}
+func (*TraceConfig) Descriptor() ([]byte, []int) {
+ return fileDescriptor_5936aa8fa6443e6f, []int{0}
+}
+
+func (m *TraceConfig) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_TraceConfig.Unmarshal(m, b)
+}
+func (m *TraceConfig) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_TraceConfig.Marshal(b, m, deterministic)
+}
+func (m *TraceConfig) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_TraceConfig.Merge(m, src)
+}
+func (m *TraceConfig) XXX_Size() int {
+ return xxx_messageInfo_TraceConfig.Size(m)
+}
+func (m *TraceConfig) XXX_DiscardUnknown() {
+ xxx_messageInfo_TraceConfig.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_TraceConfig proto.InternalMessageInfo
+
+type isTraceConfig_Sampler interface {
+ isTraceConfig_Sampler()
+}
+
+type TraceConfig_ConstantSampler struct {
+ ConstantSampler *ConstantSampler `protobuf:"bytes,1,opt,name=constant_sampler,json=constantSampler,proto3,oneof"`
+}
+
+type TraceConfig_ProbabilitySampler struct {
+ ProbabilitySampler *ProbabilitySampler `protobuf:"bytes,2,opt,name=probability_sampler,json=probabilitySampler,proto3,oneof"`
+}
+
+type TraceConfig_RateLimitingSampler struct {
+ RateLimitingSampler *RateLimitingSampler `protobuf:"bytes,3,opt,name=rate_limiting_sampler,json=rateLimitingSampler,proto3,oneof"`
+}
+
+func (*TraceConfig_ConstantSampler) isTraceConfig_Sampler() {}
+
+func (*TraceConfig_ProbabilitySampler) isTraceConfig_Sampler() {}
+
+func (*TraceConfig_RateLimitingSampler) isTraceConfig_Sampler() {}
+
+func (m *TraceConfig) GetSampler() isTraceConfig_Sampler {
+ if m != nil {
+ return m.Sampler
+ }
+ return nil
+}
+
+func (m *TraceConfig) GetConstantSampler() *ConstantSampler {
+ if x, ok := m.GetSampler().(*TraceConfig_ConstantSampler); ok {
+ return x.ConstantSampler
+ }
+ return nil
+}
+
+func (m *TraceConfig) GetProbabilitySampler() *ProbabilitySampler {
+ if x, ok := m.GetSampler().(*TraceConfig_ProbabilitySampler); ok {
+ return x.ProbabilitySampler
+ }
+ return nil
+}
+
+func (m *TraceConfig) GetRateLimitingSampler() *RateLimitingSampler {
+ if x, ok := m.GetSampler().(*TraceConfig_RateLimitingSampler); ok {
+ return x.RateLimitingSampler
+ }
+ return nil
+}
+
+func (m *TraceConfig) GetMaxNumberOfAttributes() int64 {
+ if m != nil {
+ return m.MaxNumberOfAttributes
+ }
+ return 0
+}
+
+func (m *TraceConfig) GetMaxNumberOfTimedEvents() int64 {
+ if m != nil {
+ return m.MaxNumberOfTimedEvents
+ }
+ return 0
+}
+
+func (m *TraceConfig) GetMaxNumberOfAttributesPerTimedEvent() int64 {
+ if m != nil {
+ return m.MaxNumberOfAttributesPerTimedEvent
+ }
+ return 0
+}
+
+func (m *TraceConfig) GetMaxNumberOfLinks() int64 {
+ if m != nil {
+ return m.MaxNumberOfLinks
+ }
+ return 0
+}
+
+func (m *TraceConfig) GetMaxNumberOfAttributesPerLink() int64 {
+ if m != nil {
+ return m.MaxNumberOfAttributesPerLink
+ }
+ return 0
+}
+
+// XXX_OneofWrappers is for the internal use of the proto package.
+func (*TraceConfig) XXX_OneofWrappers() []interface{} {
+ return []interface{}{
+ (*TraceConfig_ConstantSampler)(nil),
+ (*TraceConfig_ProbabilitySampler)(nil),
+ (*TraceConfig_RateLimitingSampler)(nil),
+ }
+}
+
+// Sampler that always makes a constant decision on span sampling.
+type ConstantSampler struct {
+ Decision ConstantSampler_ConstantDecision `protobuf:"varint,1,opt,name=decision,proto3,enum=opentelemetry.proto.trace.v1.ConstantSampler_ConstantDecision" json:"decision,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *ConstantSampler) Reset() { *m = ConstantSampler{} }
+func (m *ConstantSampler) String() string { return proto.CompactTextString(m) }
+func (*ConstantSampler) ProtoMessage() {}
+func (*ConstantSampler) Descriptor() ([]byte, []int) {
+ return fileDescriptor_5936aa8fa6443e6f, []int{1}
+}
+
+func (m *ConstantSampler) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_ConstantSampler.Unmarshal(m, b)
+}
+func (m *ConstantSampler) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_ConstantSampler.Marshal(b, m, deterministic)
+}
+func (m *ConstantSampler) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_ConstantSampler.Merge(m, src)
+}
+func (m *ConstantSampler) XXX_Size() int {
+ return xxx_messageInfo_ConstantSampler.Size(m)
+}
+func (m *ConstantSampler) XXX_DiscardUnknown() {
+ xxx_messageInfo_ConstantSampler.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_ConstantSampler proto.InternalMessageInfo
+
+func (m *ConstantSampler) GetDecision() ConstantSampler_ConstantDecision {
+ if m != nil {
+ return m.Decision
+ }
+ return ConstantSampler_ALWAYS_OFF
+}
+
+// Sampler that tries to uniformly sample traces with a given probability.
+// The probability of sampling a trace is equal to that of the specified probability.
+type ProbabilitySampler struct {
+ // The desired probability of sampling. Must be within [0.0, 1.0].
+ SamplingProbability float64 `protobuf:"fixed64,1,opt,name=samplingProbability,proto3" json:"samplingProbability,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *ProbabilitySampler) Reset() { *m = ProbabilitySampler{} }
+func (m *ProbabilitySampler) String() string { return proto.CompactTextString(m) }
+func (*ProbabilitySampler) ProtoMessage() {}
+func (*ProbabilitySampler) Descriptor() ([]byte, []int) {
+ return fileDescriptor_5936aa8fa6443e6f, []int{2}
+}
+
+func (m *ProbabilitySampler) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_ProbabilitySampler.Unmarshal(m, b)
+}
+func (m *ProbabilitySampler) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_ProbabilitySampler.Marshal(b, m, deterministic)
+}
+func (m *ProbabilitySampler) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_ProbabilitySampler.Merge(m, src)
+}
+func (m *ProbabilitySampler) XXX_Size() int {
+ return xxx_messageInfo_ProbabilitySampler.Size(m)
+}
+func (m *ProbabilitySampler) XXX_DiscardUnknown() {
+ xxx_messageInfo_ProbabilitySampler.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_ProbabilitySampler proto.InternalMessageInfo
+
+func (m *ProbabilitySampler) GetSamplingProbability() float64 {
+ if m != nil {
+ return m.SamplingProbability
+ }
+ return 0
+}
+
+// Sampler that tries to sample with a rate per time window.
+type RateLimitingSampler struct {
+ // Rate per second.
+ Qps int64 `protobuf:"varint,1,opt,name=qps,proto3" json:"qps,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *RateLimitingSampler) Reset() { *m = RateLimitingSampler{} }
+func (m *RateLimitingSampler) String() string { return proto.CompactTextString(m) }
+func (*RateLimitingSampler) ProtoMessage() {}
+func (*RateLimitingSampler) Descriptor() ([]byte, []int) {
+ return fileDescriptor_5936aa8fa6443e6f, []int{3}
+}
+
+func (m *RateLimitingSampler) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_RateLimitingSampler.Unmarshal(m, b)
+}
+func (m *RateLimitingSampler) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_RateLimitingSampler.Marshal(b, m, deterministic)
+}
+func (m *RateLimitingSampler) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_RateLimitingSampler.Merge(m, src)
+}
+func (m *RateLimitingSampler) XXX_Size() int {
+ return xxx_messageInfo_RateLimitingSampler.Size(m)
+}
+func (m *RateLimitingSampler) XXX_DiscardUnknown() {
+ xxx_messageInfo_RateLimitingSampler.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_RateLimitingSampler proto.InternalMessageInfo
+
+func (m *RateLimitingSampler) GetQps() int64 {
+ if m != nil {
+ return m.Qps
+ }
+ return 0
+}
+
+func init() {
+ proto.RegisterEnum("opentelemetry.proto.trace.v1.ConstantSampler_ConstantDecision", ConstantSampler_ConstantDecision_name, ConstantSampler_ConstantDecision_value)
+ proto.RegisterType((*TraceConfig)(nil), "opentelemetry.proto.trace.v1.TraceConfig")
+ proto.RegisterType((*ConstantSampler)(nil), "opentelemetry.proto.trace.v1.ConstantSampler")
+ proto.RegisterType((*ProbabilitySampler)(nil), "opentelemetry.proto.trace.v1.ProbabilitySampler")
+ proto.RegisterType((*RateLimitingSampler)(nil), "opentelemetry.proto.trace.v1.RateLimitingSampler")
+}
+
+func init() {
+ proto.RegisterFile("opentelemetry/proto/trace/v1/trace_config.proto", fileDescriptor_5936aa8fa6443e6f)
+}
+
+var fileDescriptor_5936aa8fa6443e6f = []byte{
+ // 509 bytes of a gzipped FileDescriptorProto
+ 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x94, 0x4d, 0x6f, 0x9b, 0x4c,
+ 0x14, 0x85, 0x43, 0xfc, 0xe6, 0xeb, 0x46, 0x49, 0x78, 0x07, 0xa5, 0x42, 0x55, 0xa4, 0xa6, 0x6c,
+ 0xea, 0x8d, 0x21, 0x4e, 0x17, 0x95, 0xba, 0xa8, 0x64, 0x27, 0x71, 0xba, 0xb0, 0x1c, 0x44, 0x2c,
+ 0x55, 0xf5, 0x06, 0xc1, 0x64, 0x4c, 0x47, 0x85, 0x19, 0x3a, 0x8c, 0xad, 0x64, 0xd3, 0x5d, 0x7f,
+ 0x51, 0xff, 0x60, 0xc5, 0x98, 0xf2, 0x11, 0x3b, 0x48, 0xdd, 0x71, 0xef, 0xe1, 0x3c, 0x67, 0xc6,
+ 0xbe, 0x5c, 0x70, 0x78, 0x4a, 0x98, 0x24, 0x31, 0x49, 0x88, 0x14, 0x4f, 0x4e, 0x2a, 0xb8, 0xe4,
+ 0x8e, 0x14, 0x01, 0x26, 0xce, 0xb2, 0xbf, 0x7a, 0xf0, 0x31, 0x67, 0x73, 0x1a, 0xd9, 0x4a, 0x43,
+ 0x67, 0x0d, 0xc3, 0xaa, 0x69, 0xab, 0xf7, 0xec, 0x65, 0xdf, 0xfa, 0xb5, 0x03, 0x87, 0xd3, 0xbc,
+ 0xb8, 0x52, 0x1e, 0x34, 0x03, 0x1d, 0x73, 0x96, 0xc9, 0x80, 0x49, 0x3f, 0x0b, 0x92, 0x34, 0x26,
+ 0xc2, 0xd4, 0xce, 0xb5, 0xee, 0xe1, 0x65, 0xcf, 0x6e, 0x03, 0xd9, 0x57, 0x85, 0xeb, 0x7e, 0x65,
+ 0xfa, 0xbc, 0xe5, 0x9d, 0xe0, 0x66, 0x0b, 0x61, 0x30, 0x52, 0xc1, 0xc3, 0x20, 0xa4, 0x31, 0x95,
+ 0x4f, 0x25, 0x7e, 0x5b, 0xe1, 0x2f, 0xda, 0xf1, 0x6e, 0x65, 0xac, 0x12, 0x50, 0xba, 0xd6, 0x45,
+ 0x11, 0x9c, 0x8a, 0x40, 0x12, 0x3f, 0xa6, 0x09, 0x95, 0x94, 0x45, 0x65, 0x4c, 0x47, 0xc5, 0xf4,
+ 0xdb, 0x63, 0xbc, 0x40, 0x92, 0x71, 0xe1, 0xac, 0x72, 0x0c, 0xb1, 0xde, 0x46, 0x1f, 0xc0, 0x4c,
+ 0x82, 0x47, 0x9f, 0x2d, 0x92, 0x90, 0x08, 0x9f, 0xcf, 0xfd, 0x40, 0x4a, 0x41, 0xc3, 0x85, 0x24,
+ 0x99, 0xf9, 0xdf, 0xb9, 0xd6, 0xed, 0x78, 0xa7, 0x49, 0xf0, 0x38, 0x51, 0xf2, 0xdd, 0x7c, 0x50,
+ 0x8a, 0xe8, 0x23, 0xbc, 0x6e, 0x1a, 0x25, 0x4d, 0xc8, 0x83, 0x4f, 0x96, 0x84, 0xc9, 0xcc, 0xdc,
+ 0x51, 0xd6, 0x57, 0x35, 0xeb, 0x34, 0x97, 0x6f, 0x94, 0x8a, 0xa6, 0xd0, 0x7d, 0x29, 0xd4, 0x4f,
+ 0x89, 0xa8, 0xa3, 0xcc, 0x5d, 0x45, 0xb2, 0x36, 0x1e, 0xc2, 0x25, 0xa2, 0xc2, 0xa2, 0x1e, 0x18,
+ 0x4d, 0x6a, 0x4c, 0xd9, 0xf7, 0xcc, 0xdc, 0x53, 0x00, 0xbd, 0x06, 0x18, 0xe7, 0x7d, 0x74, 0x0b,
+ 0x6f, 0x5b, 0x0f, 0x91, 0xbb, 0xcd, 0x7d, 0x65, 0x3e, 0x7b, 0x29, 0x3d, 0x27, 0x0d, 0x0f, 0x60,
+ 0xaf, 0xf8, 0x77, 0xac, 0xdf, 0x1a, 0x9c, 0x3c, 0x1b, 0x21, 0x34, 0x83, 0xfd, 0x07, 0x82, 0x69,
+ 0x46, 0x39, 0x53, 0x33, 0x78, 0x7c, 0xf9, 0xe9, 0x9f, 0x66, 0xb0, 0xac, 0xaf, 0x0b, 0x8a, 0x57,
+ 0xf2, 0xac, 0x6b, 0xd0, 0x9f, 0xab, 0xe8, 0x18, 0x60, 0x30, 0xfe, 0x32, 0xf8, 0x7a, 0xef, 0xdf,
+ 0x8d, 0x46, 0xfa, 0x16, 0x3a, 0x82, 0x83, 0xbf, 0xf5, 0x44, 0xd7, 0xd0, 0xff, 0x70, 0x54, 0x94,
+ 0xee, 0xc0, 0xbb, 0x99, 0x4c, 0xf5, 0x6d, 0x6b, 0x04, 0x68, 0x7d, 0x30, 0xd1, 0x05, 0x18, 0xea,
+ 0x5a, 0x94, 0x45, 0x35, 0x55, 0x5d, 0x41, 0xf3, 0x36, 0x49, 0xd6, 0x3b, 0x30, 0x36, 0x4c, 0x1e,
+ 0xd2, 0xa1, 0xf3, 0x23, 0xcd, 0x94, 0xb1, 0xe3, 0xe5, 0x8f, 0xc3, 0x9f, 0xf0, 0x86, 0xf2, 0xd6,
+ 0x1f, 0x61, 0xa8, 0xd7, 0x3e, 0x67, 0x37, 0x97, 0x5c, 0x6d, 0x76, 0x1b, 0x51, 0xf9, 0x6d, 0x11,
+ 0xda, 0x98, 0x27, 0x6a, 0x7f, 0xf4, 0xaa, 0x05, 0xd2, 0x60, 0xf5, 0x56, 0xeb, 0x24, 0x22, 0xcc,
+ 0x89, 0xb8, 0x83, 0x79, 0x1c, 0x13, 0x2c, 0xb9, 0x28, 0xf7, 0x4b, 0xb8, 0xab, 0x5e, 0x78, 0xff,
+ 0x27, 0x00, 0x00, 0xff, 0xff, 0xe4, 0x80, 0x54, 0x8b, 0x86, 0x04, 0x00, 0x00,
+}
diff --git a/vendor/github.com/open-telemetry/opentelemetry-proto/gen/go/collector/trace/v1/trace_service.pb.go b/vendor/github.com/open-telemetry/opentelemetry-proto/gen/go/collector/trace/v1/trace_service.pb.go
new file mode 100644
index 0000000..705c8c1
--- /dev/null
+++ b/vendor/github.com/open-telemetry/opentelemetry-proto/gen/go/collector/trace/v1/trace_service.pb.go
@@ -0,0 +1,215 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// source: opentelemetry/proto/collector/trace/v1/trace_service.proto
+
+package v1
+
+import (
+ context "context"
+ fmt "fmt"
+ proto "github.com/golang/protobuf/proto"
+ v1 "github.com/open-telemetry/opentelemetry-proto/gen/go/trace/v1"
+ grpc "google.golang.org/grpc"
+ codes "google.golang.org/grpc/codes"
+ status "google.golang.org/grpc/status"
+ math "math"
+)
+
+// Reference imports to suppress errors if they are not otherwise used.
+var _ = proto.Marshal
+var _ = fmt.Errorf
+var _ = math.Inf
+
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the proto package it is being compiled against.
+// A compilation error at this line likely means your copy of the
+// proto package needs to be updated.
+const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
+
+type ExportTraceServiceRequest struct {
+ // An array of ResourceSpans.
+ // For data coming from a single resource this array will typically contain one
+ // element. Intermediary nodes (such as OpenTelemetry Collector) that receive
+ // data from multiple origins typically batch the data before forwarding further and
+ // in that case this array will contain multiple elements.
+ ResourceSpans []*v1.ResourceSpans `protobuf:"bytes,1,rep,name=resource_spans,json=resourceSpans,proto3" json:"resource_spans,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *ExportTraceServiceRequest) Reset() { *m = ExportTraceServiceRequest{} }
+func (m *ExportTraceServiceRequest) String() string { return proto.CompactTextString(m) }
+func (*ExportTraceServiceRequest) ProtoMessage() {}
+func (*ExportTraceServiceRequest) Descriptor() ([]byte, []int) {
+ return fileDescriptor_192a962890318cf4, []int{0}
+}
+
+func (m *ExportTraceServiceRequest) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_ExportTraceServiceRequest.Unmarshal(m, b)
+}
+func (m *ExportTraceServiceRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_ExportTraceServiceRequest.Marshal(b, m, deterministic)
+}
+func (m *ExportTraceServiceRequest) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_ExportTraceServiceRequest.Merge(m, src)
+}
+func (m *ExportTraceServiceRequest) XXX_Size() int {
+ return xxx_messageInfo_ExportTraceServiceRequest.Size(m)
+}
+func (m *ExportTraceServiceRequest) XXX_DiscardUnknown() {
+ xxx_messageInfo_ExportTraceServiceRequest.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_ExportTraceServiceRequest proto.InternalMessageInfo
+
+func (m *ExportTraceServiceRequest) GetResourceSpans() []*v1.ResourceSpans {
+ if m != nil {
+ return m.ResourceSpans
+ }
+ return nil
+}
+
+type ExportTraceServiceResponse struct {
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *ExportTraceServiceResponse) Reset() { *m = ExportTraceServiceResponse{} }
+func (m *ExportTraceServiceResponse) String() string { return proto.CompactTextString(m) }
+func (*ExportTraceServiceResponse) ProtoMessage() {}
+func (*ExportTraceServiceResponse) Descriptor() ([]byte, []int) {
+ return fileDescriptor_192a962890318cf4, []int{1}
+}
+
+func (m *ExportTraceServiceResponse) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_ExportTraceServiceResponse.Unmarshal(m, b)
+}
+func (m *ExportTraceServiceResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_ExportTraceServiceResponse.Marshal(b, m, deterministic)
+}
+func (m *ExportTraceServiceResponse) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_ExportTraceServiceResponse.Merge(m, src)
+}
+func (m *ExportTraceServiceResponse) XXX_Size() int {
+ return xxx_messageInfo_ExportTraceServiceResponse.Size(m)
+}
+func (m *ExportTraceServiceResponse) XXX_DiscardUnknown() {
+ xxx_messageInfo_ExportTraceServiceResponse.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_ExportTraceServiceResponse proto.InternalMessageInfo
+
+func init() {
+ proto.RegisterType((*ExportTraceServiceRequest)(nil), "opentelemetry.proto.collector.trace.v1.ExportTraceServiceRequest")
+ proto.RegisterType((*ExportTraceServiceResponse)(nil), "opentelemetry.proto.collector.trace.v1.ExportTraceServiceResponse")
+}
+
+func init() {
+ proto.RegisterFile("opentelemetry/proto/collector/trace/v1/trace_service.proto", fileDescriptor_192a962890318cf4)
+}
+
+var fileDescriptor_192a962890318cf4 = []byte{
+ // 265 bytes of a gzipped FileDescriptorProto
+ 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xb2, 0xca, 0x2f, 0x48, 0xcd,
+ 0x2b, 0x49, 0xcd, 0x49, 0xcd, 0x4d, 0x2d, 0x29, 0xaa, 0xd4, 0x2f, 0x28, 0xca, 0x2f, 0xc9, 0xd7,
+ 0x4f, 0xce, 0xcf, 0xc9, 0x49, 0x4d, 0x2e, 0xc9, 0x2f, 0xd2, 0x2f, 0x29, 0x4a, 0x4c, 0x4e, 0xd5,
+ 0x2f, 0x33, 0x84, 0x30, 0xe2, 0x8b, 0x53, 0x8b, 0xca, 0x32, 0x93, 0x53, 0xf5, 0xc0, 0xca, 0x84,
+ 0xd4, 0x50, 0xf4, 0x42, 0x04, 0xf5, 0xe0, 0x7a, 0xf5, 0xc0, 0x5a, 0xf4, 0xca, 0x0c, 0xa5, 0x34,
+ 0xb0, 0xd9, 0x81, 0x6a, 0x32, 0x44, 0xb3, 0x52, 0x3e, 0x97, 0xa4, 0x6b, 0x45, 0x41, 0x7e, 0x51,
+ 0x49, 0x08, 0x48, 0x30, 0x18, 0x62, 0x5b, 0x50, 0x6a, 0x61, 0x69, 0x6a, 0x71, 0x89, 0x50, 0x10,
+ 0x17, 0x5f, 0x51, 0x6a, 0x71, 0x7e, 0x69, 0x11, 0xc8, 0x21, 0x05, 0x89, 0x79, 0xc5, 0x12, 0x8c,
+ 0x0a, 0xcc, 0x1a, 0xdc, 0x46, 0xda, 0x7a, 0xd8, 0xdc, 0x01, 0xb3, 0x5d, 0x2f, 0x08, 0xaa, 0x27,
+ 0x18, 0xa4, 0x25, 0x88, 0xb7, 0x08, 0x99, 0xab, 0x24, 0xc3, 0x25, 0x85, 0xcd, 0xc2, 0xe2, 0x82,
+ 0xfc, 0xbc, 0xe2, 0x54, 0xa3, 0x45, 0x8c, 0x5c, 0x3c, 0xc8, 0x12, 0x42, 0x13, 0x19, 0xb9, 0xd8,
+ 0x20, 0xea, 0x85, 0x1c, 0xf5, 0x88, 0xf3, 0xbd, 0x1e, 0x4e, 0x0f, 0x49, 0x39, 0x51, 0x62, 0x04,
+ 0xc4, 0x89, 0x4a, 0x0c, 0x4e, 0x9d, 0x8c, 0x5c, 0x9a, 0x99, 0xf9, 0x44, 0x1a, 0xe5, 0x24, 0x88,
+ 0x6c, 0x4a, 0x00, 0x48, 0x55, 0x00, 0x63, 0x94, 0x7b, 0x7a, 0x66, 0x49, 0x46, 0x69, 0x92, 0x5e,
+ 0x72, 0x7e, 0xae, 0x3e, 0xc8, 0x1c, 0x5d, 0x44, 0x64, 0xa1, 0x18, 0xab, 0x0b, 0x89, 0xba, 0xf4,
+ 0xd4, 0x3c, 0xfd, 0x74, 0x6c, 0xa9, 0x24, 0x89, 0x0d, 0xac, 0xc0, 0x18, 0x10, 0x00, 0x00, 0xff,
+ 0xff, 0xc1, 0x6e, 0x1a, 0x15, 0x56, 0x02, 0x00, 0x00,
+}
+
+// Reference imports to suppress errors if they are not otherwise used.
+var _ context.Context
+var _ grpc.ClientConn
+
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the grpc package it is being compiled against.
+const _ = grpc.SupportPackageIsVersion4
+
+// TraceServiceClient is the client API for TraceService service.
+//
+// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
+type TraceServiceClient interface {
+ // For performance reasons, it is recommended to keep this RPC
+ // alive for the entire life of the application.
+ Export(ctx context.Context, in *ExportTraceServiceRequest, opts ...grpc.CallOption) (*ExportTraceServiceResponse, error)
+}
+
+type traceServiceClient struct {
+ cc *grpc.ClientConn
+}
+
+func NewTraceServiceClient(cc *grpc.ClientConn) TraceServiceClient {
+ return &traceServiceClient{cc}
+}
+
+func (c *traceServiceClient) Export(ctx context.Context, in *ExportTraceServiceRequest, opts ...grpc.CallOption) (*ExportTraceServiceResponse, error) {
+ out := new(ExportTraceServiceResponse)
+ err := c.cc.Invoke(ctx, "/opentelemetry.proto.collector.trace.v1.TraceService/Export", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+// TraceServiceServer is the server API for TraceService service.
+type TraceServiceServer interface {
+ // For performance reasons, it is recommended to keep this RPC
+ // alive for the entire life of the application.
+ Export(context.Context, *ExportTraceServiceRequest) (*ExportTraceServiceResponse, error)
+}
+
+// UnimplementedTraceServiceServer can be embedded to have forward compatible implementations.
+type UnimplementedTraceServiceServer struct {
+}
+
+func (*UnimplementedTraceServiceServer) Export(ctx context.Context, req *ExportTraceServiceRequest) (*ExportTraceServiceResponse, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method Export not implemented")
+}
+
+func RegisterTraceServiceServer(s *grpc.Server, srv TraceServiceServer) {
+ s.RegisterService(&_TraceService_serviceDesc, srv)
+}
+
+func _TraceService_Export_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(ExportTraceServiceRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(TraceServiceServer).Export(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: "/opentelemetry.proto.collector.trace.v1.TraceService/Export",
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(TraceServiceServer).Export(ctx, req.(*ExportTraceServiceRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+var _TraceService_serviceDesc = grpc.ServiceDesc{
+ ServiceName: "opentelemetry.proto.collector.trace.v1.TraceService",
+ HandlerType: (*TraceServiceServer)(nil),
+ Methods: []grpc.MethodDesc{
+ {
+ MethodName: "Export",
+ Handler: _TraceService_Export_Handler,
+ },
+ },
+ Streams: []grpc.StreamDesc{},
+ Metadata: "opentelemetry/proto/collector/trace/v1/trace_service.proto",
+}
diff --git a/vendor/github.com/open-telemetry/opentelemetry-proto/gen/go/collector/trace/v1/trace_service.pb.gw.go b/vendor/github.com/open-telemetry/opentelemetry-proto/gen/go/collector/trace/v1/trace_service.pb.gw.go
new file mode 100644
index 0000000..df329e3
--- /dev/null
+++ b/vendor/github.com/open-telemetry/opentelemetry-proto/gen/go/collector/trace/v1/trace_service.pb.gw.go
@@ -0,0 +1,115 @@
+// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT.
+// source: opentelemetry/proto/collector/trace/v1/trace_service.proto
+
+/*
+Package v1 is a reverse proxy.
+
+It translates gRPC into RESTful JSON APIs.
+*/
+package v1
+
+import (
+ "context"
+ "io"
+ "net/http"
+
+ "github.com/golang/protobuf/proto"
+ "github.com/grpc-ecosystem/grpc-gateway/runtime"
+ "github.com/grpc-ecosystem/grpc-gateway/utilities"
+ "google.golang.org/grpc"
+ "google.golang.org/grpc/codes"
+ "google.golang.org/grpc/grpclog"
+ "google.golang.org/grpc/status"
+)
+
+var _ codes.Code
+var _ io.Reader
+var _ status.Status
+var _ = runtime.String
+var _ = utilities.NewDoubleArray
+
+func request_TraceService_Export_0(ctx context.Context, marshaler runtime.Marshaler, client TraceServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
+ var protoReq ExportTraceServiceRequest
+ var metadata runtime.ServerMetadata
+
+ newReader, berr := utilities.IOReaderFactory(req.Body)
+ if berr != nil {
+ return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
+ }
+ if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
+ return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
+ }
+
+ msg, err := client.Export(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
+ return msg, metadata, err
+
+}
+
+// RegisterTraceServiceHandlerFromEndpoint is same as RegisterTraceServiceHandler but
+// automatically dials to "endpoint" and closes the connection when "ctx" gets done.
+func RegisterTraceServiceHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) {
+ conn, err := grpc.Dial(endpoint, opts...)
+ if err != nil {
+ return err
+ }
+ defer func() {
+ if err != nil {
+ if cerr := conn.Close(); cerr != nil {
+ grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr)
+ }
+ return
+ }
+ go func() {
+ <-ctx.Done()
+ if cerr := conn.Close(); cerr != nil {
+ grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr)
+ }
+ }()
+ }()
+
+ return RegisterTraceServiceHandler(ctx, mux, conn)
+}
+
+// RegisterTraceServiceHandler registers the http handlers for service TraceService to "mux".
+// The handlers forward requests to the grpc endpoint over "conn".
+func RegisterTraceServiceHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error {
+ return RegisterTraceServiceHandlerClient(ctx, mux, NewTraceServiceClient(conn))
+}
+
+// RegisterTraceServiceHandlerClient registers the http handlers for service TraceService
+// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "TraceServiceClient".
+// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "TraceServiceClient"
+// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in
+// "TraceServiceClient" to call the correct interceptors.
+func RegisterTraceServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux, client TraceServiceClient) error {
+
+ mux.Handle("POST", pattern_TraceService_Export_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
+ ctx, cancel := context.WithCancel(req.Context())
+ defer cancel()
+ inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
+ rctx, err := runtime.AnnotateContext(ctx, mux, req)
+ if err != nil {
+ runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
+ return
+ }
+ resp, md, err := request_TraceService_Export_0(rctx, inboundMarshaler, client, req, pathParams)
+ ctx = runtime.NewServerMetadataContext(ctx, md)
+ if err != nil {
+ runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
+ return
+ }
+
+ forward_TraceService_Export_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
+
+ })
+
+ return nil
+}
+
+var (
+ pattern_TraceService_Export_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "trace"}, "", runtime.AssumeColonVerbOpt(true)))
+)
+
+var (
+ forward_TraceService_Export_0 = runtime.ForwardResponseMessage
+)
diff --git a/vendor/github.com/open-telemetry/opentelemetry-proto/gen/go/common/v1/common.pb.go b/vendor/github.com/open-telemetry/opentelemetry-proto/gen/go/common/v1/common.pb.go
new file mode 100644
index 0000000..3930f91
--- /dev/null
+++ b/vendor/github.com/open-telemetry/opentelemetry-proto/gen/go/common/v1/common.pb.go
@@ -0,0 +1,273 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// source: opentelemetry/proto/common/v1/common.proto
+
+package v1
+
+import (
+ fmt "fmt"
+ proto "github.com/golang/protobuf/proto"
+ math "math"
+)
+
+// Reference imports to suppress errors if they are not otherwise used.
+var _ = proto.Marshal
+var _ = fmt.Errorf
+var _ = math.Inf
+
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the proto package it is being compiled against.
+// A compilation error at this line likely means your copy of the
+// proto package needs to be updated.
+const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
+
+// ValueType is the enumeration of possible types that value can have.
+type AttributeKeyValue_ValueType int32
+
+const (
+ AttributeKeyValue_STRING AttributeKeyValue_ValueType = 0
+ AttributeKeyValue_INT AttributeKeyValue_ValueType = 1
+ AttributeKeyValue_DOUBLE AttributeKeyValue_ValueType = 2
+ AttributeKeyValue_BOOL AttributeKeyValue_ValueType = 3
+)
+
+var AttributeKeyValue_ValueType_name = map[int32]string{
+ 0: "STRING",
+ 1: "INT",
+ 2: "DOUBLE",
+ 3: "BOOL",
+}
+
+var AttributeKeyValue_ValueType_value = map[string]int32{
+ "STRING": 0,
+ "INT": 1,
+ "DOUBLE": 2,
+ "BOOL": 3,
+}
+
+func (x AttributeKeyValue_ValueType) String() string {
+ return proto.EnumName(AttributeKeyValue_ValueType_name, int32(x))
+}
+
+func (AttributeKeyValue_ValueType) EnumDescriptor() ([]byte, []int) {
+ return fileDescriptor_62ba46dcb97aa817, []int{0, 0}
+}
+
+// AttributeKeyValue is a key-value pair that is used to store Span attributes, Link
+// attributes, etc.
+type AttributeKeyValue struct {
+ // key part of the key-value pair.
+ Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
+ // type of the value.
+ Type AttributeKeyValue_ValueType `protobuf:"varint,2,opt,name=type,proto3,enum=opentelemetry.proto.common.v1.AttributeKeyValue_ValueType" json:"type,omitempty"`
+ StringValue string `protobuf:"bytes,3,opt,name=string_value,json=stringValue,proto3" json:"string_value,omitempty"`
+ IntValue int64 `protobuf:"varint,4,opt,name=int_value,json=intValue,proto3" json:"int_value,omitempty"`
+ DoubleValue float64 `protobuf:"fixed64,5,opt,name=double_value,json=doubleValue,proto3" json:"double_value,omitempty"`
+ BoolValue bool `protobuf:"varint,6,opt,name=bool_value,json=boolValue,proto3" json:"bool_value,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *AttributeKeyValue) Reset() { *m = AttributeKeyValue{} }
+func (m *AttributeKeyValue) String() string { return proto.CompactTextString(m) }
+func (*AttributeKeyValue) ProtoMessage() {}
+func (*AttributeKeyValue) Descriptor() ([]byte, []int) {
+ return fileDescriptor_62ba46dcb97aa817, []int{0}
+}
+
+func (m *AttributeKeyValue) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_AttributeKeyValue.Unmarshal(m, b)
+}
+func (m *AttributeKeyValue) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_AttributeKeyValue.Marshal(b, m, deterministic)
+}
+func (m *AttributeKeyValue) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_AttributeKeyValue.Merge(m, src)
+}
+func (m *AttributeKeyValue) XXX_Size() int {
+ return xxx_messageInfo_AttributeKeyValue.Size(m)
+}
+func (m *AttributeKeyValue) XXX_DiscardUnknown() {
+ xxx_messageInfo_AttributeKeyValue.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_AttributeKeyValue proto.InternalMessageInfo
+
+func (m *AttributeKeyValue) GetKey() string {
+ if m != nil {
+ return m.Key
+ }
+ return ""
+}
+
+func (m *AttributeKeyValue) GetType() AttributeKeyValue_ValueType {
+ if m != nil {
+ return m.Type
+ }
+ return AttributeKeyValue_STRING
+}
+
+func (m *AttributeKeyValue) GetStringValue() string {
+ if m != nil {
+ return m.StringValue
+ }
+ return ""
+}
+
+func (m *AttributeKeyValue) GetIntValue() int64 {
+ if m != nil {
+ return m.IntValue
+ }
+ return 0
+}
+
+func (m *AttributeKeyValue) GetDoubleValue() float64 {
+ if m != nil {
+ return m.DoubleValue
+ }
+ return 0
+}
+
+func (m *AttributeKeyValue) GetBoolValue() bool {
+ if m != nil {
+ return m.BoolValue
+ }
+ return false
+}
+
+// StringKeyValue is a pair of key/value strings. This is the simpler (and faster) version
+// of AttributeKeyValue that only supports string values.
+type StringKeyValue struct {
+ Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
+ Value string `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *StringKeyValue) Reset() { *m = StringKeyValue{} }
+func (m *StringKeyValue) String() string { return proto.CompactTextString(m) }
+func (*StringKeyValue) ProtoMessage() {}
+func (*StringKeyValue) Descriptor() ([]byte, []int) {
+ return fileDescriptor_62ba46dcb97aa817, []int{1}
+}
+
+func (m *StringKeyValue) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_StringKeyValue.Unmarshal(m, b)
+}
+func (m *StringKeyValue) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_StringKeyValue.Marshal(b, m, deterministic)
+}
+func (m *StringKeyValue) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_StringKeyValue.Merge(m, src)
+}
+func (m *StringKeyValue) XXX_Size() int {
+ return xxx_messageInfo_StringKeyValue.Size(m)
+}
+func (m *StringKeyValue) XXX_DiscardUnknown() {
+ xxx_messageInfo_StringKeyValue.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_StringKeyValue proto.InternalMessageInfo
+
+func (m *StringKeyValue) GetKey() string {
+ if m != nil {
+ return m.Key
+ }
+ return ""
+}
+
+func (m *StringKeyValue) GetValue() string {
+ if m != nil {
+ return m.Value
+ }
+ return ""
+}
+
+// InstrumentationLibrary is a message representing the instrumentation library information
+// such as the fully qualified name and version.
+type InstrumentationLibrary struct {
+ Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
+ Version string `protobuf:"bytes,2,opt,name=version,proto3" json:"version,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *InstrumentationLibrary) Reset() { *m = InstrumentationLibrary{} }
+func (m *InstrumentationLibrary) String() string { return proto.CompactTextString(m) }
+func (*InstrumentationLibrary) ProtoMessage() {}
+func (*InstrumentationLibrary) Descriptor() ([]byte, []int) {
+ return fileDescriptor_62ba46dcb97aa817, []int{2}
+}
+
+func (m *InstrumentationLibrary) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_InstrumentationLibrary.Unmarshal(m, b)
+}
+func (m *InstrumentationLibrary) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_InstrumentationLibrary.Marshal(b, m, deterministic)
+}
+func (m *InstrumentationLibrary) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_InstrumentationLibrary.Merge(m, src)
+}
+func (m *InstrumentationLibrary) XXX_Size() int {
+ return xxx_messageInfo_InstrumentationLibrary.Size(m)
+}
+func (m *InstrumentationLibrary) XXX_DiscardUnknown() {
+ xxx_messageInfo_InstrumentationLibrary.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_InstrumentationLibrary proto.InternalMessageInfo
+
+func (m *InstrumentationLibrary) GetName() string {
+ if m != nil {
+ return m.Name
+ }
+ return ""
+}
+
+func (m *InstrumentationLibrary) GetVersion() string {
+ if m != nil {
+ return m.Version
+ }
+ return ""
+}
+
+func init() {
+ proto.RegisterEnum("opentelemetry.proto.common.v1.AttributeKeyValue_ValueType", AttributeKeyValue_ValueType_name, AttributeKeyValue_ValueType_value)
+ proto.RegisterType((*AttributeKeyValue)(nil), "opentelemetry.proto.common.v1.AttributeKeyValue")
+ proto.RegisterType((*StringKeyValue)(nil), "opentelemetry.proto.common.v1.StringKeyValue")
+ proto.RegisterType((*InstrumentationLibrary)(nil), "opentelemetry.proto.common.v1.InstrumentationLibrary")
+}
+
+func init() {
+ proto.RegisterFile("opentelemetry/proto/common/v1/common.proto", fileDescriptor_62ba46dcb97aa817)
+}
+
+var fileDescriptor_62ba46dcb97aa817 = []byte{
+ // 377 bytes of a gzipped FileDescriptorProto
+ 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x92, 0xdb, 0x8b, 0x9b, 0x40,
+ 0x18, 0xc5, 0x3b, 0x6a, 0x2e, 0x7e, 0x09, 0xc1, 0x0e, 0xa5, 0x08, 0x25, 0x60, 0x7c, 0x92, 0x42,
+ 0x94, 0xb4, 0x50, 0x4a, 0x1f, 0x0a, 0xb5, 0x37, 0x42, 0x43, 0x12, 0x4c, 0xda, 0x87, 0xbe, 0x14,
+ 0x6d, 0x07, 0x3b, 0xac, 0xce, 0xb8, 0x93, 0x51, 0xf0, 0xaf, 0xda, 0x7f, 0x71, 0x71, 0xc6, 0xbd,
+ 0x84, 0x85, 0xbc, 0xc8, 0x99, 0xdf, 0x39, 0x9e, 0xf9, 0xd0, 0x0f, 0x5e, 0xf3, 0x8a, 0x30, 0x49,
+ 0x0a, 0x52, 0x12, 0x29, 0xda, 0xa8, 0x12, 0x5c, 0xf2, 0xe8, 0x2f, 0x2f, 0x4b, 0xce, 0xa2, 0x66,
+ 0xd5, 0xab, 0x50, 0x61, 0x3c, 0x3f, 0xcb, 0x6a, 0x18, 0xf6, 0x89, 0x66, 0xe5, 0xdf, 0x18, 0xf0,
+ 0xfc, 0x93, 0x94, 0x82, 0x66, 0xb5, 0x24, 0x3f, 0x48, 0xfb, 0x2b, 0x2d, 0x6a, 0x82, 0x1d, 0x30,
+ 0xaf, 0x48, 0xeb, 0x22, 0x0f, 0x05, 0x76, 0xd2, 0x49, 0xbc, 0x05, 0x4b, 0xb6, 0x15, 0x71, 0x0d,
+ 0x0f, 0x05, 0xb3, 0x37, 0x1f, 0xc2, 0x8b, 0xad, 0xe1, 0x93, 0xc6, 0x50, 0x3d, 0x8f, 0x6d, 0x45,
+ 0x12, 0xd5, 0x83, 0x17, 0x30, 0x3d, 0x49, 0x41, 0x59, 0xfe, 0xa7, 0xe9, 0x1c, 0xd7, 0x54, 0x57,
+ 0x4d, 0x34, 0xd3, 0x43, 0xbc, 0x02, 0x9b, 0x32, 0xd9, 0xfb, 0x96, 0x87, 0x02, 0x33, 0x19, 0x53,
+ 0x26, 0xb5, 0xb9, 0x80, 0xe9, 0x3f, 0x5e, 0x67, 0x05, 0xe9, 0xfd, 0x81, 0x87, 0x02, 0x94, 0x4c,
+ 0x34, 0xd3, 0x91, 0x39, 0x40, 0xc6, 0x79, 0xd1, 0x07, 0x86, 0x1e, 0x0a, 0xc6, 0x89, 0xdd, 0x11,
+ 0x65, 0xfb, 0xef, 0xc0, 0xbe, 0x1f, 0x0a, 0x03, 0x0c, 0x0f, 0xc7, 0x64, 0xbd, 0xfd, 0xee, 0x3c,
+ 0xc3, 0x23, 0x30, 0xd7, 0xdb, 0xa3, 0x83, 0x3a, 0xf8, 0x65, 0xf7, 0x33, 0xde, 0x7c, 0x75, 0x0c,
+ 0x3c, 0x06, 0x2b, 0xde, 0xed, 0x36, 0x8e, 0xe9, 0xbf, 0x87, 0xd9, 0x41, 0x4d, 0x79, 0xe1, 0x6b,
+ 0xbd, 0x80, 0x81, 0xbe, 0xd5, 0x50, 0x4c, 0x1f, 0xfc, 0x6f, 0xf0, 0x72, 0xcd, 0x4e, 0x52, 0xd4,
+ 0x25, 0x61, 0x32, 0x95, 0x94, 0xb3, 0x0d, 0xcd, 0x44, 0x2a, 0x5a, 0x8c, 0xc1, 0x62, 0x69, 0x49,
+ 0xfa, 0x0a, 0xa5, 0xb1, 0x0b, 0xa3, 0x86, 0x88, 0x13, 0xe5, 0xac, 0x6f, 0xb9, 0x3b, 0xc6, 0xd7,
+ 0xe0, 0x51, 0x7e, 0xf9, 0x0f, 0xc4, 0x93, 0xcf, 0x4a, 0xee, 0x3b, 0xbc, 0x47, 0xbf, 0x3f, 0xe6,
+ 0x54, 0xfe, 0xaf, 0xb3, 0x2e, 0x10, 0x75, 0x2f, 0x2e, 0x1f, 0xb6, 0xe7, 0xac, 0x67, 0xa9, 0x77,
+ 0x29, 0x27, 0x2c, 0xca, 0x1f, 0xad, 0x54, 0x36, 0x54, 0xfc, 0xed, 0x6d, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x84, 0x93, 0x08, 0x5f, 0x7a, 0x02, 0x00, 0x00,
+}
diff --git a/vendor/github.com/open-telemetry/opentelemetry-proto/gen/go/metrics/v1/metrics.pb.go b/vendor/github.com/open-telemetry/opentelemetry-proto/gen/go/metrics/v1/metrics.pb.go
new file mode 100644
index 0000000..546c770
--- /dev/null
+++ b/vendor/github.com/open-telemetry/opentelemetry-proto/gen/go/metrics/v1/metrics.pb.go
@@ -0,0 +1,1131 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// source: opentelemetry/proto/metrics/v1/metrics.proto
+
+package v1
+
+import (
+ fmt "fmt"
+ proto "github.com/golang/protobuf/proto"
+ v11 "github.com/open-telemetry/opentelemetry-proto/gen/go/common/v1"
+ v1 "github.com/open-telemetry/opentelemetry-proto/gen/go/resource/v1"
+ math "math"
+)
+
+// Reference imports to suppress errors if they are not otherwise used.
+var _ = proto.Marshal
+var _ = fmt.Errorf
+var _ = math.Inf
+
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the proto package it is being compiled against.
+// A compilation error at this line likely means your copy of the
+// proto package needs to be updated.
+const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
+
+// Type is the type of values a metric has.
+type MetricDescriptor_Type int32
+
+const (
+ // INVALID_TYPE is the default Type, it MUST not be used.
+ MetricDescriptor_INVALID_TYPE MetricDescriptor_Type = 0
+ // INT64 values are signed 64-bit integers.
+ //
+ // A Metric of this Type MUST store its values as Int64DataPoint.
+ MetricDescriptor_INT64 MetricDescriptor_Type = 1
+ // MONOTONIC_INT64 values are monotonically increasing signed 64-bit
+ // integers.
+ //
+ // A Metric of this Type MUST store its values as Int64DataPoint.
+ MetricDescriptor_MONOTONIC_INT64 MetricDescriptor_Type = 2
+ // DOUBLE values are double-precision floating-point numbers.
+ //
+ // A Metric of this Type MUST store its values as DoubleDataPoint.
+ MetricDescriptor_DOUBLE MetricDescriptor_Type = 3
+ // MONOTONIC_DOUBLE values are monotonically increasing double-precision
+ // floating-point numbers.
+ //
+ // A Metric of this Type MUST store its values as DoubleDataPoint.
+ MetricDescriptor_MONOTONIC_DOUBLE MetricDescriptor_Type = 4
+ // Histogram measurement.
+ // Corresponding values are stored in HistogramDataPoint.
+ MetricDescriptor_HISTOGRAM MetricDescriptor_Type = 5
+ // Summary value. Some frameworks implemented Histograms as a summary of observations
+ // (usually things like request durations and response sizes). While it
+ // also provides a total count of observations and a sum of all observed
+ // values, it calculates configurable percentiles over a sliding time
+ // window.
+ // Corresponding values are stored in SummaryDataPoint.
+ MetricDescriptor_SUMMARY MetricDescriptor_Type = 6
+)
+
+var MetricDescriptor_Type_name = map[int32]string{
+ 0: "INVALID_TYPE",
+ 1: "INT64",
+ 2: "MONOTONIC_INT64",
+ 3: "DOUBLE",
+ 4: "MONOTONIC_DOUBLE",
+ 5: "HISTOGRAM",
+ 6: "SUMMARY",
+}
+
+var MetricDescriptor_Type_value = map[string]int32{
+ "INVALID_TYPE": 0,
+ "INT64": 1,
+ "MONOTONIC_INT64": 2,
+ "DOUBLE": 3,
+ "MONOTONIC_DOUBLE": 4,
+ "HISTOGRAM": 5,
+ "SUMMARY": 6,
+}
+
+func (x MetricDescriptor_Type) String() string {
+ return proto.EnumName(MetricDescriptor_Type_name, int32(x))
+}
+
+func (MetricDescriptor_Type) EnumDescriptor() ([]byte, []int) {
+ return fileDescriptor_3c3112f9fa006917, []int{3, 0}
+}
+
+// Temporality is the temporal quality values of a metric have. It
+// describes how those values relate to the time interval over which they
+// are reported.
+type MetricDescriptor_Temporality int32
+
+const (
+ // INVALID_TEMPORALITY is the default Temporality, it MUST not be
+ // used.
+ MetricDescriptor_INVALID_TEMPORALITY MetricDescriptor_Temporality = 0
+ // INSTANTANEOUS is a metric whose values are measured at a particular
+ // instant. The values are not aggregated over any time interval and are
+ // unique per timestamp. As such, these metrics are not expected to have
+ // an associated start time.
+ MetricDescriptor_INSTANTANEOUS MetricDescriptor_Temporality = 1
+ // DELTA is a metric whose values are the aggregation of measurements
+ // made over a time interval. Successive metrics contain aggregation of
+ // values from continuous and non-overlapping intervals.
+ //
+ // The values for a DELTA metric are based only on the time interval
+ // associated with one measurement cycle. There is no dependency on
+ // previous measurements like is the case for CUMULATIVE metrics.
+ //
+ // For example, consider a system measuring the number of requests that
+ // it receives and reports the sum of these requests every second as a
+ // DELTA metric:
+ //
+ // 1. The system starts receiving at time=t_0.
+ // 2. A request is received, the system measures 1 request.
+ // 3. A request is received, the system measures 1 request.
+ // 4. A request is received, the system measures 1 request.
+ // 5. The 1 second collection cycle ends. A metric is exported for the
+ // number of requests received over the interval of time t_0 to
+ // t_0+1 with a value of 3.
+ // 6. A request is received, the system measures 1 request.
+ // 7. A request is received, the system measures 1 request.
+ // 8. The 1 second collection cycle ends. A metric is exported for the
+ // number of requests received over the interval of time t_0+1 to
+ // t_0+2 with a value of 2.
+ MetricDescriptor_DELTA MetricDescriptor_Temporality = 2
+ // CUMULATIVE is a metric whose values are the aggregation of
+ // successively made measurements from a fixed start time until the last
+ // reported measurement. This means that current values of a CUMULATIVE
+ // metric depend on all previous measurements since the start time.
+ // Because of this, the sender is required to retain this state in some
+ // form. If this state is lost or invalidated, the CUMULATIVE metric
+ // values MUST be reset and a new fixed start time following the last
+ // reported measurement time sent MUST be used.
+ //
+ // For example, consider a system measuring the number of requests that
+ // it receives and reports the sum of these requests every second as a
+ // CUMULATIVE metric:
+ //
+ // 1. The system starts receiving at time=t_0.
+ // 2. A request is received, the system measures 1 request.
+ // 3. A request is received, the system measures 1 request.
+ // 4. A request is received, the system measures 1 request.
+ // 5. The 1 second collection cycle ends. A metric is exported for the
+ // number of requests received over the interval of time t_0 to
+ // t_0+1 with a value of 3.
+ // 6. A request is received, the system measures 1 request.
+ // 7. A request is received, the system measures 1 request.
+ // 8. The 1 second collection cycle ends. A metric is exported for the
+ // number of requests received over the interval of time t_0 to
+ // t_0+2 with a value of 5.
+ // 9. The system experiences a fault and loses state.
+ // 10. The system recovers and resumes receiving at time=t_1.
+ // 11. A request is received, the system measures 1 request.
+ // 12. The 1 second collection cycle ends. A metric is exported for the
+ // number of requests received over the interval of time t_1 to
+ // t_0+1 with a value of 1.
+ MetricDescriptor_CUMULATIVE MetricDescriptor_Temporality = 3
+)
+
+var MetricDescriptor_Temporality_name = map[int32]string{
+ 0: "INVALID_TEMPORALITY",
+ 1: "INSTANTANEOUS",
+ 2: "DELTA",
+ 3: "CUMULATIVE",
+}
+
+var MetricDescriptor_Temporality_value = map[string]int32{
+ "INVALID_TEMPORALITY": 0,
+ "INSTANTANEOUS": 1,
+ "DELTA": 2,
+ "CUMULATIVE": 3,
+}
+
+func (x MetricDescriptor_Temporality) String() string {
+ return proto.EnumName(MetricDescriptor_Temporality_name, int32(x))
+}
+
+func (MetricDescriptor_Temporality) EnumDescriptor() ([]byte, []int) {
+ return fileDescriptor_3c3112f9fa006917, []int{3, 1}
+}
+
+// A collection of InstrumentationLibraryMetrics from a Resource.
+type ResourceMetrics struct {
+ // The resource for the metrics in this message.
+ // If this field is not set then no resource info is known.
+ Resource *v1.Resource `protobuf:"bytes,1,opt,name=resource,proto3" json:"resource,omitempty"`
+ // A list of metrics that originate from a resource.
+ InstrumentationLibraryMetrics []*InstrumentationLibraryMetrics `protobuf:"bytes,2,rep,name=instrumentation_library_metrics,json=instrumentationLibraryMetrics,proto3" json:"instrumentation_library_metrics,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *ResourceMetrics) Reset() { *m = ResourceMetrics{} }
+func (m *ResourceMetrics) String() string { return proto.CompactTextString(m) }
+func (*ResourceMetrics) ProtoMessage() {}
+func (*ResourceMetrics) Descriptor() ([]byte, []int) {
+ return fileDescriptor_3c3112f9fa006917, []int{0}
+}
+
+func (m *ResourceMetrics) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_ResourceMetrics.Unmarshal(m, b)
+}
+func (m *ResourceMetrics) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_ResourceMetrics.Marshal(b, m, deterministic)
+}
+func (m *ResourceMetrics) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_ResourceMetrics.Merge(m, src)
+}
+func (m *ResourceMetrics) XXX_Size() int {
+ return xxx_messageInfo_ResourceMetrics.Size(m)
+}
+func (m *ResourceMetrics) XXX_DiscardUnknown() {
+ xxx_messageInfo_ResourceMetrics.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_ResourceMetrics proto.InternalMessageInfo
+
+func (m *ResourceMetrics) GetResource() *v1.Resource {
+ if m != nil {
+ return m.Resource
+ }
+ return nil
+}
+
+func (m *ResourceMetrics) GetInstrumentationLibraryMetrics() []*InstrumentationLibraryMetrics {
+ if m != nil {
+ return m.InstrumentationLibraryMetrics
+ }
+ return nil
+}
+
+// A collection of Metrics produced by an InstrumentationLibrary.
+type InstrumentationLibraryMetrics struct {
+ // The instrumentation library information for the metrics in this message.
+ // If this field is not set then no library info is known.
+ InstrumentationLibrary *v11.InstrumentationLibrary `protobuf:"bytes,1,opt,name=instrumentation_library,json=instrumentationLibrary,proto3" json:"instrumentation_library,omitempty"`
+ // A list of metrics that originate from an instrumentation library.
+ Metrics []*Metric `protobuf:"bytes,2,rep,name=metrics,proto3" json:"metrics,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *InstrumentationLibraryMetrics) Reset() { *m = InstrumentationLibraryMetrics{} }
+func (m *InstrumentationLibraryMetrics) String() string { return proto.CompactTextString(m) }
+func (*InstrumentationLibraryMetrics) ProtoMessage() {}
+func (*InstrumentationLibraryMetrics) Descriptor() ([]byte, []int) {
+ return fileDescriptor_3c3112f9fa006917, []int{1}
+}
+
+func (m *InstrumentationLibraryMetrics) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_InstrumentationLibraryMetrics.Unmarshal(m, b)
+}
+func (m *InstrumentationLibraryMetrics) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_InstrumentationLibraryMetrics.Marshal(b, m, deterministic)
+}
+func (m *InstrumentationLibraryMetrics) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_InstrumentationLibraryMetrics.Merge(m, src)
+}
+func (m *InstrumentationLibraryMetrics) XXX_Size() int {
+ return xxx_messageInfo_InstrumentationLibraryMetrics.Size(m)
+}
+func (m *InstrumentationLibraryMetrics) XXX_DiscardUnknown() {
+ xxx_messageInfo_InstrumentationLibraryMetrics.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_InstrumentationLibraryMetrics proto.InternalMessageInfo
+
+func (m *InstrumentationLibraryMetrics) GetInstrumentationLibrary() *v11.InstrumentationLibrary {
+ if m != nil {
+ return m.InstrumentationLibrary
+ }
+ return nil
+}
+
+func (m *InstrumentationLibraryMetrics) GetMetrics() []*Metric {
+ if m != nil {
+ return m.Metrics
+ }
+ return nil
+}
+
+// Defines a Metric which has one or more timeseries.
+//
+// The data model and relation between entities is shown in the diagram below.
+//
+// - Metric is composed of a MetricDescriptor and a list of data points.
+// - MetricDescriptor contains a list of label keys (shown horizontally).
+// - Data is a list of DataPoints (shown vertically).
+// - DataPoint contains a list of label values and a value.
+//
+// Metric
+// +----------+ +------------------------+
+// |descriptor|-------->| MetricDescriptor |
+// | | |+-----+-----+ +-----+ |
+// | | ||label|label|...|label| |
+// | data|--+ ||key1 |key2 | |keyN | |
+// +----------+ | |+-----+-----+ +-----+ |
+// | +------------------------+
+// |
+// | +---------------------------+
+// | |DataPoint 1 |
+// v |+------+------+ +------+ |
+// +-----+ ||label |label |...|label | |
+// | 1 |-->||value1|value2|...|valueN| |
+// +-----+ |+------+------+ +------+ |
+// | . | |+-----+ |
+// | . | ||value| |
+// | . | |+-----+ |
+// | . | +---------------------------+
+// | . | .
+// | . | .
+// | . | .
+// | . | +---------------------------+
+// | . | |DataPoint M |
+// +-----+ |+------+------+ +------+ |
+// | M |-->||label |label |...|label | |
+// +-----+ ||value1|value2|...|valueN| |
+// |+------+------+ +------+ |
+// |+-----+ |
+// ||value| |
+// |+-----+ |
+// +---------------------------+
+//
+//-----------------------------------------------------------------------
+// DataPoint is a value of specific type corresponding to a given moment in
+// time. Each DataPoint is timestamped.
+//
+// DataPoint is strongly typed: each DataPoint type has a specific Protobuf message
+// depending on the value type of the metric and thus there are currently 4 DataPoint
+// messages, which correspond to the types of metric values.
+type Metric struct {
+ // metric_descriptor describes the Metric.
+ MetricDescriptor *MetricDescriptor `protobuf:"bytes,1,opt,name=metric_descriptor,json=metricDescriptor,proto3" json:"metric_descriptor,omitempty"`
+ // Data is a list of one or more DataPoints for a single metric. Only one of the
+ // following fields is used for the data, depending on the type of the metric defined
+ // by MetricDescriptor.type field.
+ Int64DataPoints []*Int64DataPoint `protobuf:"bytes,2,rep,name=int64_data_points,json=int64DataPoints,proto3" json:"int64_data_points,omitempty"`
+ DoubleDataPoints []*DoubleDataPoint `protobuf:"bytes,3,rep,name=double_data_points,json=doubleDataPoints,proto3" json:"double_data_points,omitempty"`
+ HistogramDataPoints []*HistogramDataPoint `protobuf:"bytes,4,rep,name=histogram_data_points,json=histogramDataPoints,proto3" json:"histogram_data_points,omitempty"`
+ SummaryDataPoints []*SummaryDataPoint `protobuf:"bytes,5,rep,name=summary_data_points,json=summaryDataPoints,proto3" json:"summary_data_points,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *Metric) Reset() { *m = Metric{} }
+func (m *Metric) String() string { return proto.CompactTextString(m) }
+func (*Metric) ProtoMessage() {}
+func (*Metric) Descriptor() ([]byte, []int) {
+ return fileDescriptor_3c3112f9fa006917, []int{2}
+}
+
+func (m *Metric) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_Metric.Unmarshal(m, b)
+}
+func (m *Metric) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_Metric.Marshal(b, m, deterministic)
+}
+func (m *Metric) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_Metric.Merge(m, src)
+}
+func (m *Metric) XXX_Size() int {
+ return xxx_messageInfo_Metric.Size(m)
+}
+func (m *Metric) XXX_DiscardUnknown() {
+ xxx_messageInfo_Metric.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_Metric proto.InternalMessageInfo
+
+func (m *Metric) GetMetricDescriptor() *MetricDescriptor {
+ if m != nil {
+ return m.MetricDescriptor
+ }
+ return nil
+}
+
+func (m *Metric) GetInt64DataPoints() []*Int64DataPoint {
+ if m != nil {
+ return m.Int64DataPoints
+ }
+ return nil
+}
+
+func (m *Metric) GetDoubleDataPoints() []*DoubleDataPoint {
+ if m != nil {
+ return m.DoubleDataPoints
+ }
+ return nil
+}
+
+func (m *Metric) GetHistogramDataPoints() []*HistogramDataPoint {
+ if m != nil {
+ return m.HistogramDataPoints
+ }
+ return nil
+}
+
+func (m *Metric) GetSummaryDataPoints() []*SummaryDataPoint {
+ if m != nil {
+ return m.SummaryDataPoints
+ }
+ return nil
+}
+
+// Defines a metric type and its schema.
+type MetricDescriptor struct {
+ // name of the metric, including its DNS name prefix. It must be unique.
+ Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
+ // description of the metric, which can be used in documentation.
+ Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"`
+ // unit in which the metric value is reported. Follows the format
+ // described by http://unitsofmeasure.org/ucum.html.
+ Unit string `protobuf:"bytes,3,opt,name=unit,proto3" json:"unit,omitempty"`
+ // type is the type of values this metric has.
+ Type MetricDescriptor_Type `protobuf:"varint,4,opt,name=type,proto3,enum=opentelemetry.proto.metrics.v1.MetricDescriptor_Type" json:"type,omitempty"`
+ // temporality is the Temporality of values this metric has.
+ Temporality MetricDescriptor_Temporality `protobuf:"varint,5,opt,name=temporality,proto3,enum=opentelemetry.proto.metrics.v1.MetricDescriptor_Temporality" json:"temporality,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *MetricDescriptor) Reset() { *m = MetricDescriptor{} }
+func (m *MetricDescriptor) String() string { return proto.CompactTextString(m) }
+func (*MetricDescriptor) ProtoMessage() {}
+func (*MetricDescriptor) Descriptor() ([]byte, []int) {
+ return fileDescriptor_3c3112f9fa006917, []int{3}
+}
+
+func (m *MetricDescriptor) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_MetricDescriptor.Unmarshal(m, b)
+}
+func (m *MetricDescriptor) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_MetricDescriptor.Marshal(b, m, deterministic)
+}
+func (m *MetricDescriptor) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_MetricDescriptor.Merge(m, src)
+}
+func (m *MetricDescriptor) XXX_Size() int {
+ return xxx_messageInfo_MetricDescriptor.Size(m)
+}
+func (m *MetricDescriptor) XXX_DiscardUnknown() {
+ xxx_messageInfo_MetricDescriptor.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_MetricDescriptor proto.InternalMessageInfo
+
+func (m *MetricDescriptor) GetName() string {
+ if m != nil {
+ return m.Name
+ }
+ return ""
+}
+
+func (m *MetricDescriptor) GetDescription() string {
+ if m != nil {
+ return m.Description
+ }
+ return ""
+}
+
+func (m *MetricDescriptor) GetUnit() string {
+ if m != nil {
+ return m.Unit
+ }
+ return ""
+}
+
+func (m *MetricDescriptor) GetType() MetricDescriptor_Type {
+ if m != nil {
+ return m.Type
+ }
+ return MetricDescriptor_INVALID_TYPE
+}
+
+func (m *MetricDescriptor) GetTemporality() MetricDescriptor_Temporality {
+ if m != nil {
+ return m.Temporality
+ }
+ return MetricDescriptor_INVALID_TEMPORALITY
+}
+
+// Int64DataPoint is a single data point in a timeseries that describes the time-varying
+// values of a int64 metric.
+type Int64DataPoint struct {
+ // The set of labels that uniquely identify this timeseries.
+ Labels []*v11.StringKeyValue `protobuf:"bytes,1,rep,name=labels,proto3" json:"labels,omitempty"`
+ // start_time_unix_nano is the time when the cumulative value was reset to zero.
+ // This is used for Counter type only. For Gauge the value is not specified and
+ // defaults to 0.
+ //
+ // The cumulative value is over the time interval (start_time_unix_nano, time_unix_nano].
+ // Value is UNIX Epoch time in nanoseconds since 00:00:00 UTC on 1 January 1970.
+ //
+ // Value of 0 indicates that the timestamp is unspecified. In that case the timestamp
+ // may be decided by the backend.
+ StartTimeUnixNano uint64 `protobuf:"fixed64,2,opt,name=start_time_unix_nano,json=startTimeUnixNano,proto3" json:"start_time_unix_nano,omitempty"`
+ // time_unix_nano is the moment when this value was recorded.
+ // Value is UNIX Epoch time in nanoseconds since 00:00:00 UTC on 1 January 1970.
+ TimeUnixNano uint64 `protobuf:"fixed64,3,opt,name=time_unix_nano,json=timeUnixNano,proto3" json:"time_unix_nano,omitempty"`
+ // value itself.
+ Value int64 `protobuf:"varint,4,opt,name=value,proto3" json:"value,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *Int64DataPoint) Reset() { *m = Int64DataPoint{} }
+func (m *Int64DataPoint) String() string { return proto.CompactTextString(m) }
+func (*Int64DataPoint) ProtoMessage() {}
+func (*Int64DataPoint) Descriptor() ([]byte, []int) {
+ return fileDescriptor_3c3112f9fa006917, []int{4}
+}
+
+func (m *Int64DataPoint) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_Int64DataPoint.Unmarshal(m, b)
+}
+func (m *Int64DataPoint) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_Int64DataPoint.Marshal(b, m, deterministic)
+}
+func (m *Int64DataPoint) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_Int64DataPoint.Merge(m, src)
+}
+func (m *Int64DataPoint) XXX_Size() int {
+ return xxx_messageInfo_Int64DataPoint.Size(m)
+}
+func (m *Int64DataPoint) XXX_DiscardUnknown() {
+ xxx_messageInfo_Int64DataPoint.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_Int64DataPoint proto.InternalMessageInfo
+
+func (m *Int64DataPoint) GetLabels() []*v11.StringKeyValue {
+ if m != nil {
+ return m.Labels
+ }
+ return nil
+}
+
+func (m *Int64DataPoint) GetStartTimeUnixNano() uint64 {
+ if m != nil {
+ return m.StartTimeUnixNano
+ }
+ return 0
+}
+
+func (m *Int64DataPoint) GetTimeUnixNano() uint64 {
+ if m != nil {
+ return m.TimeUnixNano
+ }
+ return 0
+}
+
+func (m *Int64DataPoint) GetValue() int64 {
+ if m != nil {
+ return m.Value
+ }
+ return 0
+}
+
+// DoubleDataPoint is a single data point in a timeseries that describes the time-varying
+// value of a double metric.
+type DoubleDataPoint struct {
+ // The set of labels that uniquely identify this timeseries.
+ Labels []*v11.StringKeyValue `protobuf:"bytes,1,rep,name=labels,proto3" json:"labels,omitempty"`
+ // start_time_unix_nano is the time when the cumulative value was reset to zero.
+ // This is used for Counter type only. For Gauge the value is not specified and
+ // defaults to 0.
+ //
+ // The cumulative value is over the time interval (start_time_unix_nano, time_unix_nano].
+ // Value is UNIX Epoch time in nanoseconds since 00:00:00 UTC on 1 January 1970.
+ //
+ // Value of 0 indicates that the timestamp is unspecified. In that case the timestamp
+ // may be decided by the backend.
+ StartTimeUnixNano uint64 `protobuf:"fixed64,2,opt,name=start_time_unix_nano,json=startTimeUnixNano,proto3" json:"start_time_unix_nano,omitempty"`
+ // time_unix_nano is the moment when this value was recorded.
+ // Value is UNIX Epoch time in nanoseconds since 00:00:00 UTC on 1 January 1970.
+ TimeUnixNano uint64 `protobuf:"fixed64,3,opt,name=time_unix_nano,json=timeUnixNano,proto3" json:"time_unix_nano,omitempty"`
+ // value itself.
+ Value float64 `protobuf:"fixed64,4,opt,name=value,proto3" json:"value,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *DoubleDataPoint) Reset() { *m = DoubleDataPoint{} }
+func (m *DoubleDataPoint) String() string { return proto.CompactTextString(m) }
+func (*DoubleDataPoint) ProtoMessage() {}
+func (*DoubleDataPoint) Descriptor() ([]byte, []int) {
+ return fileDescriptor_3c3112f9fa006917, []int{5}
+}
+
+func (m *DoubleDataPoint) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_DoubleDataPoint.Unmarshal(m, b)
+}
+func (m *DoubleDataPoint) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_DoubleDataPoint.Marshal(b, m, deterministic)
+}
+func (m *DoubleDataPoint) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_DoubleDataPoint.Merge(m, src)
+}
+func (m *DoubleDataPoint) XXX_Size() int {
+ return xxx_messageInfo_DoubleDataPoint.Size(m)
+}
+func (m *DoubleDataPoint) XXX_DiscardUnknown() {
+ xxx_messageInfo_DoubleDataPoint.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_DoubleDataPoint proto.InternalMessageInfo
+
+func (m *DoubleDataPoint) GetLabels() []*v11.StringKeyValue {
+ if m != nil {
+ return m.Labels
+ }
+ return nil
+}
+
+func (m *DoubleDataPoint) GetStartTimeUnixNano() uint64 {
+ if m != nil {
+ return m.StartTimeUnixNano
+ }
+ return 0
+}
+
+func (m *DoubleDataPoint) GetTimeUnixNano() uint64 {
+ if m != nil {
+ return m.TimeUnixNano
+ }
+ return 0
+}
+
+func (m *DoubleDataPoint) GetValue() float64 {
+ if m != nil {
+ return m.Value
+ }
+ return 0
+}
+
+// HistogramDataPoint is a single data point in a timeseries that describes the time-varying
+// values of a Histogram. A Histogram contains summary statistics for a population of values,
+// it may optionally contain the distribution of those values across a set of buckets.
+type HistogramDataPoint struct {
+ // The set of labels that uniquely identify this timeseries.
+ Labels []*v11.StringKeyValue `protobuf:"bytes,1,rep,name=labels,proto3" json:"labels,omitempty"`
+ // start_time_unix_nano is the time when the cumulative value was reset to zero.
+ //
+ // The cumulative value is over the time interval (start_time_unix_nano, time_unix_nano].
+ // Value is UNIX Epoch time in nanoseconds since 00:00:00 UTC on 1 January 1970.
+ //
+ // Value of 0 indicates that the timestamp is unspecified. In that case the timestamp
+ // may be decided by the backend.
+ // Note: this field is always unspecified and ignored if MetricDescriptor.type==GAUGE_HISTOGRAM.
+ StartTimeUnixNano uint64 `protobuf:"fixed64,2,opt,name=start_time_unix_nano,json=startTimeUnixNano,proto3" json:"start_time_unix_nano,omitempty"`
+ // time_unix_nano is the moment when this value was recorded.
+ // Value is UNIX Epoch time in nanoseconds since 00:00:00 UTC on 1 January 1970.
+ TimeUnixNano uint64 `protobuf:"fixed64,3,opt,name=time_unix_nano,json=timeUnixNano,proto3" json:"time_unix_nano,omitempty"`
+ // count is the number of values in the population. Must be non-negative. This value
+ // must be equal to the sum of the "count" fields in buckets if a histogram is provided.
+ Count uint64 `protobuf:"varint,4,opt,name=count,proto3" json:"count,omitempty"`
+ // sum of the values in the population. If count is zero then this field
+ // must be zero. This value must be equal to the sum of the "sum" fields in buckets if
+ // a histogram is provided.
+ Sum float64 `protobuf:"fixed64,5,opt,name=sum,proto3" json:"sum,omitempty"`
+ // buckets is an optional field contains the values of histogram for each bucket.
+ //
+ // The sum of the values in the buckets "count" field must equal the value in the count field.
+ //
+ // The number of elements in buckets array must be by one greater than the
+ // number of elements in bucket_bounds array.
+ //
+ // Note: if HistogramDataPoint.bucket_options defines bucket bounds then this field
+ // must also be present and number of elements in this field must be equal to the
+ // number of buckets defined by bucket_options.
+ Buckets []*HistogramDataPoint_Bucket `protobuf:"bytes,6,rep,name=buckets,proto3" json:"buckets,omitempty"`
+ // explicit_bounds specifies buckets with explicitly defined bounds for values.
+ // The bucket boundaries are described by "bounds" field.
+ //
+ // This defines size(bounds) + 1 (= N) buckets. The boundaries for bucket
+ // at index i are:
+ //
+ // [0, bounds[i]) for i == 0
+ // [bounds[i-1], bounds[i]) for 0 < i < N-1
+ // [bounds[i], +infinity) for i == N-1
+ // The values in bounds array must be strictly increasing and > 0.
+ //
+ // Note: only [a, b) intervals are currently supported for each bucket. If we decides
+ // to also support (a, b] intervals we should add support for these by defining a boolean
+ // value which decides what type of intervals to use.
+ ExplicitBounds []float64 `protobuf:"fixed64,7,rep,packed,name=explicit_bounds,json=explicitBounds,proto3" json:"explicit_bounds,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *HistogramDataPoint) Reset() { *m = HistogramDataPoint{} }
+func (m *HistogramDataPoint) String() string { return proto.CompactTextString(m) }
+func (*HistogramDataPoint) ProtoMessage() {}
+func (*HistogramDataPoint) Descriptor() ([]byte, []int) {
+ return fileDescriptor_3c3112f9fa006917, []int{6}
+}
+
+func (m *HistogramDataPoint) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_HistogramDataPoint.Unmarshal(m, b)
+}
+func (m *HistogramDataPoint) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_HistogramDataPoint.Marshal(b, m, deterministic)
+}
+func (m *HistogramDataPoint) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_HistogramDataPoint.Merge(m, src)
+}
+func (m *HistogramDataPoint) XXX_Size() int {
+ return xxx_messageInfo_HistogramDataPoint.Size(m)
+}
+func (m *HistogramDataPoint) XXX_DiscardUnknown() {
+ xxx_messageInfo_HistogramDataPoint.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_HistogramDataPoint proto.InternalMessageInfo
+
+func (m *HistogramDataPoint) GetLabels() []*v11.StringKeyValue {
+ if m != nil {
+ return m.Labels
+ }
+ return nil
+}
+
+func (m *HistogramDataPoint) GetStartTimeUnixNano() uint64 {
+ if m != nil {
+ return m.StartTimeUnixNano
+ }
+ return 0
+}
+
+func (m *HistogramDataPoint) GetTimeUnixNano() uint64 {
+ if m != nil {
+ return m.TimeUnixNano
+ }
+ return 0
+}
+
+func (m *HistogramDataPoint) GetCount() uint64 {
+ if m != nil {
+ return m.Count
+ }
+ return 0
+}
+
+func (m *HistogramDataPoint) GetSum() float64 {
+ if m != nil {
+ return m.Sum
+ }
+ return 0
+}
+
+func (m *HistogramDataPoint) GetBuckets() []*HistogramDataPoint_Bucket {
+ if m != nil {
+ return m.Buckets
+ }
+ return nil
+}
+
+func (m *HistogramDataPoint) GetExplicitBounds() []float64 {
+ if m != nil {
+ return m.ExplicitBounds
+ }
+ return nil
+}
+
+// Bucket contains values for a bucket.
+type HistogramDataPoint_Bucket struct {
+ // The number of values in each bucket of the histogram, as described by
+ // bucket_options.
+ Count uint64 `protobuf:"varint,1,opt,name=count,proto3" json:"count,omitempty"`
+ // exemplar is an optional representative value of the bucket.
+ Exemplar *HistogramDataPoint_Bucket_Exemplar `protobuf:"bytes,2,opt,name=exemplar,proto3" json:"exemplar,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *HistogramDataPoint_Bucket) Reset() { *m = HistogramDataPoint_Bucket{} }
+func (m *HistogramDataPoint_Bucket) String() string { return proto.CompactTextString(m) }
+func (*HistogramDataPoint_Bucket) ProtoMessage() {}
+func (*HistogramDataPoint_Bucket) Descriptor() ([]byte, []int) {
+ return fileDescriptor_3c3112f9fa006917, []int{6, 0}
+}
+
+func (m *HistogramDataPoint_Bucket) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_HistogramDataPoint_Bucket.Unmarshal(m, b)
+}
+func (m *HistogramDataPoint_Bucket) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_HistogramDataPoint_Bucket.Marshal(b, m, deterministic)
+}
+func (m *HistogramDataPoint_Bucket) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_HistogramDataPoint_Bucket.Merge(m, src)
+}
+func (m *HistogramDataPoint_Bucket) XXX_Size() int {
+ return xxx_messageInfo_HistogramDataPoint_Bucket.Size(m)
+}
+func (m *HistogramDataPoint_Bucket) XXX_DiscardUnknown() {
+ xxx_messageInfo_HistogramDataPoint_Bucket.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_HistogramDataPoint_Bucket proto.InternalMessageInfo
+
+func (m *HistogramDataPoint_Bucket) GetCount() uint64 {
+ if m != nil {
+ return m.Count
+ }
+ return 0
+}
+
+func (m *HistogramDataPoint_Bucket) GetExemplar() *HistogramDataPoint_Bucket_Exemplar {
+ if m != nil {
+ return m.Exemplar
+ }
+ return nil
+}
+
+// Exemplars are example points that may be used to annotate aggregated
+// Histogram values. They are metadata that gives information about a
+// particular value added to a Histogram bucket.
+type HistogramDataPoint_Bucket_Exemplar struct {
+ // Value of the exemplar point. It determines which bucket the exemplar belongs to.
+ // If bucket_options define bounds for this bucket then this value must be within
+ // the defined bounds.
+ Value float64 `protobuf:"fixed64,1,opt,name=value,proto3" json:"value,omitempty"`
+ // time_unix_nano is the moment when this exemplar was recorded.
+ // Value is UNIX Epoch time in nanoseconds since 00:00:00 UTC on 1 January 1970.
+ TimeUnixNano uint64 `protobuf:"fixed64,2,opt,name=time_unix_nano,json=timeUnixNano,proto3" json:"time_unix_nano,omitempty"`
+ // exemplar_attachments are contextual information about the example value.
+ // Keys in this list must be unique.
+ Attachments []*v11.StringKeyValue `protobuf:"bytes,3,rep,name=attachments,proto3" json:"attachments,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *HistogramDataPoint_Bucket_Exemplar) Reset() { *m = HistogramDataPoint_Bucket_Exemplar{} }
+func (m *HistogramDataPoint_Bucket_Exemplar) String() string { return proto.CompactTextString(m) }
+func (*HistogramDataPoint_Bucket_Exemplar) ProtoMessage() {}
+func (*HistogramDataPoint_Bucket_Exemplar) Descriptor() ([]byte, []int) {
+ return fileDescriptor_3c3112f9fa006917, []int{6, 0, 0}
+}
+
+func (m *HistogramDataPoint_Bucket_Exemplar) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_HistogramDataPoint_Bucket_Exemplar.Unmarshal(m, b)
+}
+func (m *HistogramDataPoint_Bucket_Exemplar) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_HistogramDataPoint_Bucket_Exemplar.Marshal(b, m, deterministic)
+}
+func (m *HistogramDataPoint_Bucket_Exemplar) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_HistogramDataPoint_Bucket_Exemplar.Merge(m, src)
+}
+func (m *HistogramDataPoint_Bucket_Exemplar) XXX_Size() int {
+ return xxx_messageInfo_HistogramDataPoint_Bucket_Exemplar.Size(m)
+}
+func (m *HistogramDataPoint_Bucket_Exemplar) XXX_DiscardUnknown() {
+ xxx_messageInfo_HistogramDataPoint_Bucket_Exemplar.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_HistogramDataPoint_Bucket_Exemplar proto.InternalMessageInfo
+
+func (m *HistogramDataPoint_Bucket_Exemplar) GetValue() float64 {
+ if m != nil {
+ return m.Value
+ }
+ return 0
+}
+
+func (m *HistogramDataPoint_Bucket_Exemplar) GetTimeUnixNano() uint64 {
+ if m != nil {
+ return m.TimeUnixNano
+ }
+ return 0
+}
+
+func (m *HistogramDataPoint_Bucket_Exemplar) GetAttachments() []*v11.StringKeyValue {
+ if m != nil {
+ return m.Attachments
+ }
+ return nil
+}
+
+// SummaryDataPoint is a single data point in a timeseries that describes the time-varying
+// values of a Summary metric.
+type SummaryDataPoint struct {
+ // The set of labels that uniquely identify this timeseries.
+ Labels []*v11.StringKeyValue `protobuf:"bytes,1,rep,name=labels,proto3" json:"labels,omitempty"`
+ // start_time_unix_nano is the time when the cumulative value was reset to zero.
+ //
+ // The cumulative value is over the time interval (start_time_unix_nano, time_unix_nano].
+ // Value is UNIX Epoch time in nanoseconds since 00:00:00 UTC on 1 January 1970.
+ //
+ // Value of 0 indicates that the timestamp is unspecified. In that case the timestamp
+ // may be decided by the backend.
+ StartTimeUnixNano uint64 `protobuf:"fixed64,2,opt,name=start_time_unix_nano,json=startTimeUnixNano,proto3" json:"start_time_unix_nano,omitempty"`
+ // time_unix_nano is the moment when this value was recorded.
+ // Value is UNIX Epoch time in nanoseconds since 00:00:00 UTC on 1 January 1970.
+ TimeUnixNano uint64 `protobuf:"fixed64,3,opt,name=time_unix_nano,json=timeUnixNano,proto3" json:"time_unix_nano,omitempty"`
+ // The total number of recorded values since start_time. Optional since
+ // some systems don't expose this.
+ Count uint64 `protobuf:"varint,4,opt,name=count,proto3" json:"count,omitempty"`
+ // The total sum of recorded values since start_time. Optional since some
+ // systems don't expose this. If count is zero then this field must be zero.
+ Sum float64 `protobuf:"fixed64,5,opt,name=sum,proto3" json:"sum,omitempty"`
+ // A list of values at different percentiles of the distribution calculated
+ // from the current snapshot. The percentiles must be strictly increasing.
+ PercentileValues []*SummaryDataPoint_ValueAtPercentile `protobuf:"bytes,6,rep,name=percentile_values,json=percentileValues,proto3" json:"percentile_values,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *SummaryDataPoint) Reset() { *m = SummaryDataPoint{} }
+func (m *SummaryDataPoint) String() string { return proto.CompactTextString(m) }
+func (*SummaryDataPoint) ProtoMessage() {}
+func (*SummaryDataPoint) Descriptor() ([]byte, []int) {
+ return fileDescriptor_3c3112f9fa006917, []int{7}
+}
+
+func (m *SummaryDataPoint) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_SummaryDataPoint.Unmarshal(m, b)
+}
+func (m *SummaryDataPoint) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_SummaryDataPoint.Marshal(b, m, deterministic)
+}
+func (m *SummaryDataPoint) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_SummaryDataPoint.Merge(m, src)
+}
+func (m *SummaryDataPoint) XXX_Size() int {
+ return xxx_messageInfo_SummaryDataPoint.Size(m)
+}
+func (m *SummaryDataPoint) XXX_DiscardUnknown() {
+ xxx_messageInfo_SummaryDataPoint.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_SummaryDataPoint proto.InternalMessageInfo
+
+func (m *SummaryDataPoint) GetLabels() []*v11.StringKeyValue {
+ if m != nil {
+ return m.Labels
+ }
+ return nil
+}
+
+func (m *SummaryDataPoint) GetStartTimeUnixNano() uint64 {
+ if m != nil {
+ return m.StartTimeUnixNano
+ }
+ return 0
+}
+
+func (m *SummaryDataPoint) GetTimeUnixNano() uint64 {
+ if m != nil {
+ return m.TimeUnixNano
+ }
+ return 0
+}
+
+func (m *SummaryDataPoint) GetCount() uint64 {
+ if m != nil {
+ return m.Count
+ }
+ return 0
+}
+
+func (m *SummaryDataPoint) GetSum() float64 {
+ if m != nil {
+ return m.Sum
+ }
+ return 0
+}
+
+func (m *SummaryDataPoint) GetPercentileValues() []*SummaryDataPoint_ValueAtPercentile {
+ if m != nil {
+ return m.PercentileValues
+ }
+ return nil
+}
+
+// Represents the value at a given percentile of a distribution.
+//
+// To record Min and Max values following conventions are used:
+// - The 100th percentile is equivalent to the maximum value observed.
+// - The 0th percentile is equivalent to the minimum value observed.
+//
+// See the following issue for more context:
+// https://github.com/open-telemetry/opentelemetry-proto/issues/125
+type SummaryDataPoint_ValueAtPercentile struct {
+ // The percentile of a distribution. Must be in the interval
+ // [0.0, 100.0].
+ Percentile float64 `protobuf:"fixed64,1,opt,name=percentile,proto3" json:"percentile,omitempty"`
+ // The value at the given percentile of a distribution.
+ Value float64 `protobuf:"fixed64,2,opt,name=value,proto3" json:"value,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *SummaryDataPoint_ValueAtPercentile) Reset() { *m = SummaryDataPoint_ValueAtPercentile{} }
+func (m *SummaryDataPoint_ValueAtPercentile) String() string { return proto.CompactTextString(m) }
+func (*SummaryDataPoint_ValueAtPercentile) ProtoMessage() {}
+func (*SummaryDataPoint_ValueAtPercentile) Descriptor() ([]byte, []int) {
+ return fileDescriptor_3c3112f9fa006917, []int{7, 0}
+}
+
+func (m *SummaryDataPoint_ValueAtPercentile) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_SummaryDataPoint_ValueAtPercentile.Unmarshal(m, b)
+}
+func (m *SummaryDataPoint_ValueAtPercentile) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_SummaryDataPoint_ValueAtPercentile.Marshal(b, m, deterministic)
+}
+func (m *SummaryDataPoint_ValueAtPercentile) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_SummaryDataPoint_ValueAtPercentile.Merge(m, src)
+}
+func (m *SummaryDataPoint_ValueAtPercentile) XXX_Size() int {
+ return xxx_messageInfo_SummaryDataPoint_ValueAtPercentile.Size(m)
+}
+func (m *SummaryDataPoint_ValueAtPercentile) XXX_DiscardUnknown() {
+ xxx_messageInfo_SummaryDataPoint_ValueAtPercentile.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_SummaryDataPoint_ValueAtPercentile proto.InternalMessageInfo
+
+func (m *SummaryDataPoint_ValueAtPercentile) GetPercentile() float64 {
+ if m != nil {
+ return m.Percentile
+ }
+ return 0
+}
+
+func (m *SummaryDataPoint_ValueAtPercentile) GetValue() float64 {
+ if m != nil {
+ return m.Value
+ }
+ return 0
+}
+
+func init() {
+ proto.RegisterEnum("opentelemetry.proto.metrics.v1.MetricDescriptor_Type", MetricDescriptor_Type_name, MetricDescriptor_Type_value)
+ proto.RegisterEnum("opentelemetry.proto.metrics.v1.MetricDescriptor_Temporality", MetricDescriptor_Temporality_name, MetricDescriptor_Temporality_value)
+ proto.RegisterType((*ResourceMetrics)(nil), "opentelemetry.proto.metrics.v1.ResourceMetrics")
+ proto.RegisterType((*InstrumentationLibraryMetrics)(nil), "opentelemetry.proto.metrics.v1.InstrumentationLibraryMetrics")
+ proto.RegisterType((*Metric)(nil), "opentelemetry.proto.metrics.v1.Metric")
+ proto.RegisterType((*MetricDescriptor)(nil), "opentelemetry.proto.metrics.v1.MetricDescriptor")
+ proto.RegisterType((*Int64DataPoint)(nil), "opentelemetry.proto.metrics.v1.Int64DataPoint")
+ proto.RegisterType((*DoubleDataPoint)(nil), "opentelemetry.proto.metrics.v1.DoubleDataPoint")
+ proto.RegisterType((*HistogramDataPoint)(nil), "opentelemetry.proto.metrics.v1.HistogramDataPoint")
+ proto.RegisterType((*HistogramDataPoint_Bucket)(nil), "opentelemetry.proto.metrics.v1.HistogramDataPoint.Bucket")
+ proto.RegisterType((*HistogramDataPoint_Bucket_Exemplar)(nil), "opentelemetry.proto.metrics.v1.HistogramDataPoint.Bucket.Exemplar")
+ proto.RegisterType((*SummaryDataPoint)(nil), "opentelemetry.proto.metrics.v1.SummaryDataPoint")
+ proto.RegisterType((*SummaryDataPoint_ValueAtPercentile)(nil), "opentelemetry.proto.metrics.v1.SummaryDataPoint.ValueAtPercentile")
+}
+
+func init() {
+ proto.RegisterFile("opentelemetry/proto/metrics/v1/metrics.proto", fileDescriptor_3c3112f9fa006917)
+}
+
+var fileDescriptor_3c3112f9fa006917 = []byte{
+ // 1012 bytes of a gzipped FileDescriptorProto
+ 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xdc, 0x57, 0xdd, 0x6e, 0xe3, 0x44,
+ 0x14, 0x5e, 0xc7, 0x69, 0xda, 0x9e, 0x74, 0x5b, 0x67, 0x5a, 0xd8, 0xa8, 0xd2, 0x2e, 0x25, 0x42,
+ 0x50, 0x10, 0x75, 0x68, 0x29, 0x95, 0x90, 0x40, 0x90, 0x6c, 0x22, 0xd6, 0x22, 0x7f, 0x9a, 0x38,
+ 0x95, 0xba, 0xd2, 0xae, 0x71, 0x92, 0x21, 0x1d, 0x61, 0x8f, 0x2d, 0x7b, 0x1c, 0x35, 0x0f, 0xc0,
+ 0x1b, 0x20, 0xc1, 0x03, 0xc1, 0x03, 0x70, 0xc1, 0x3d, 0x0f, 0xc0, 0x1d, 0x2f, 0x80, 0x3c, 0xb6,
+ 0x63, 0x27, 0x4d, 0x1b, 0xca, 0x15, 0x70, 0x37, 0xfe, 0xce, 0x39, 0xdf, 0xf9, 0xce, 0xcf, 0xc4,
+ 0x0e, 0x7c, 0xe8, 0xb8, 0x84, 0x71, 0x62, 0x11, 0x9b, 0x70, 0x6f, 0x56, 0x75, 0x3d, 0x87, 0x3b,
+ 0xd5, 0xf0, 0x4c, 0x47, 0x7e, 0x75, 0x7a, 0x9a, 0x1c, 0x55, 0x61, 0x40, 0xcf, 0x16, 0xbc, 0x23,
+ 0x50, 0x4d, 0x5c, 0xa6, 0xa7, 0x87, 0x1f, 0xac, 0x62, 0x1b, 0x39, 0xb6, 0xed, 0xb0, 0x90, 0x2c,
+ 0x3a, 0x45, 0x61, 0x87, 0xea, 0x2a, 0x5f, 0x8f, 0xf8, 0x4e, 0xe0, 0x8d, 0x48, 0xe8, 0x9d, 0x9c,
+ 0x23, 0xff, 0xca, 0xef, 0x12, 0xec, 0xe1, 0x18, 0x6a, 0x47, 0x29, 0x51, 0x13, 0xb6, 0x12, 0xaf,
+ 0xb2, 0x74, 0x24, 0x1d, 0x17, 0xcf, 0xde, 0x57, 0x57, 0x49, 0x9c, 0x53, 0x4d, 0x4f, 0xd5, 0x84,
+ 0x03, 0xcf, 0x43, 0xd1, 0xf7, 0x12, 0xbc, 0x45, 0x99, 0xcf, 0xbd, 0xc0, 0x26, 0x8c, 0x9b, 0x9c,
+ 0x3a, 0xcc, 0xb0, 0xe8, 0xd0, 0x33, 0xbd, 0x99, 0x11, 0x57, 0x57, 0xce, 0x1d, 0xc9, 0xc7, 0xc5,
+ 0xb3, 0xcf, 0xd5, 0xfb, 0x3b, 0xa0, 0x6a, 0x8b, 0x34, 0xad, 0x88, 0x25, 0xd6, 0x8b, 0x9f, 0xd2,
+ 0xfb, 0xcc, 0x95, 0x5f, 0x25, 0x78, 0x7a, 0x2f, 0x01, 0x62, 0xf0, 0xe4, 0x0e, 0xa1, 0x71, 0xfd,
+ 0x9f, 0xac, 0x14, 0x18, 0x37, 0xfe, 0x4e, 0x7d, 0xf8, 0xcd, 0xd5, 0xc2, 0xd0, 0x97, 0xb0, 0xb9,
+ 0xd8, 0x80, 0x77, 0xd7, 0x35, 0x20, 0x52, 0x8a, 0x93, 0xb0, 0xca, 0x1f, 0x32, 0x14, 0x22, 0x0c,
+ 0xbd, 0x82, 0x52, 0x84, 0x1a, 0x63, 0xe2, 0x8f, 0x3c, 0xea, 0x72, 0xc7, 0x8b, 0x65, 0x7f, 0xf4,
+ 0xf7, 0x68, 0x1b, 0xf3, 0x38, 0xac, 0xd8, 0x4b, 0x08, 0x7a, 0x09, 0x25, 0xca, 0xf8, 0xc5, 0xb9,
+ 0x31, 0x36, 0xb9, 0x69, 0xb8, 0x0e, 0x65, 0x3c, 0x51, 0xad, 0xae, 0x1f, 0x1b, 0xbf, 0x38, 0x6f,
+ 0x98, 0xdc, 0xec, 0x85, 0x61, 0x78, 0x8f, 0x2e, 0x3c, 0xfb, 0xe8, 0x15, 0xa0, 0xb1, 0x13, 0x0c,
+ 0x2d, 0xb2, 0x40, 0x2e, 0x0b, 0xf2, 0xea, 0x3a, 0xf2, 0x86, 0x88, 0x4c, 0xd9, 0x95, 0xf1, 0x22,
+ 0xe0, 0xa3, 0x6f, 0xe1, 0x8d, 0x6b, 0xea, 0x73, 0x67, 0xe2, 0x99, 0xf6, 0x42, 0x86, 0xbc, 0xc8,
+ 0x70, 0xb6, 0x2e, 0xc3, 0x8b, 0x24, 0x38, 0x4d, 0xb2, 0x7f, 0x7d, 0x0b, 0xf3, 0xd1, 0x37, 0xb0,
+ 0xef, 0x07, 0xb6, 0x1d, 0xee, 0x75, 0x36, 0xcb, 0x86, 0xc8, 0xb2, 0x76, 0x06, 0xfd, 0x28, 0x34,
+ 0xcd, 0x51, 0xf2, 0x97, 0x10, 0xbf, 0xf2, 0x9b, 0x0c, 0xca, 0xf2, 0xac, 0x10, 0x82, 0x3c, 0x33,
+ 0xed, 0xe8, 0x8a, 0x6e, 0x63, 0x71, 0x46, 0x47, 0x50, 0x4c, 0xb6, 0x80, 0x3a, 0xac, 0x9c, 0x13,
+ 0xa6, 0x2c, 0x14, 0x46, 0x05, 0x8c, 0xf2, 0xb2, 0x1c, 0x45, 0x85, 0x67, 0xa4, 0x41, 0x9e, 0xcf,
+ 0x5c, 0x52, 0xce, 0x1f, 0x49, 0xc7, 0xbb, 0x77, 0x2c, 0xfb, 0x3d, 0x5b, 0xa3, 0xea, 0x33, 0x97,
+ 0x60, 0x41, 0x81, 0x5e, 0x43, 0x91, 0x13, 0xdb, 0x75, 0x3c, 0xd3, 0xa2, 0x7c, 0x56, 0xde, 0x10,
+ 0x8c, 0x9f, 0x3d, 0x9c, 0x31, 0xe5, 0xc0, 0x59, 0xc2, 0xca, 0x14, 0xf2, 0x61, 0x36, 0xa4, 0xc0,
+ 0x8e, 0xd6, 0xb9, 0xac, 0xb5, 0xb4, 0x86, 0xa1, 0x5f, 0xf5, 0x9a, 0xca, 0x23, 0xb4, 0x0d, 0x1b,
+ 0x5a, 0x47, 0xbf, 0x38, 0x57, 0x24, 0xb4, 0x0f, 0x7b, 0xed, 0x6e, 0xa7, 0xab, 0x77, 0x3b, 0xda,
+ 0x73, 0x23, 0x02, 0x73, 0x08, 0xa0, 0xd0, 0xe8, 0x0e, 0xea, 0xad, 0xa6, 0x22, 0xa3, 0x03, 0x50,
+ 0x52, 0x87, 0x18, 0xcd, 0xa3, 0xc7, 0xb0, 0xfd, 0x42, 0xeb, 0xeb, 0xdd, 0xaf, 0x70, 0xad, 0xad,
+ 0x6c, 0xa0, 0x22, 0x6c, 0xf6, 0x07, 0xed, 0x76, 0x0d, 0x5f, 0x29, 0x85, 0x8a, 0x0e, 0xc5, 0x8c,
+ 0x26, 0xf4, 0x04, 0xf6, 0xe7, 0xe9, 0x9b, 0xed, 0x5e, 0x17, 0xd7, 0x5a, 0x9a, 0x7e, 0xa5, 0x3c,
+ 0x42, 0x25, 0x78, 0xac, 0x75, 0xfa, 0x7a, 0xad, 0xa3, 0xd7, 0x3a, 0xcd, 0xee, 0xa0, 0xaf, 0x48,
+ 0xa1, 0xb0, 0x46, 0xb3, 0xa5, 0xd7, 0x94, 0x1c, 0xda, 0x05, 0x78, 0x3e, 0x68, 0x0f, 0x5a, 0x35,
+ 0x5d, 0xbb, 0x6c, 0x2a, 0x72, 0xe5, 0x67, 0x09, 0x76, 0x17, 0x2f, 0x09, 0x6a, 0x42, 0xc1, 0x32,
+ 0x87, 0xc4, 0xf2, 0xcb, 0x92, 0xd8, 0x9f, 0x93, 0x35, 0x3f, 0x3d, 0x7d, 0xee, 0x51, 0x36, 0xf9,
+ 0x9a, 0xcc, 0x2e, 0x4d, 0x2b, 0x20, 0x38, 0x0e, 0x46, 0x55, 0x38, 0xf0, 0xb9, 0xe9, 0x71, 0x83,
+ 0x53, 0x9b, 0x18, 0x01, 0xa3, 0x37, 0x06, 0x33, 0x99, 0x23, 0x36, 0xa2, 0x80, 0x4b, 0xc2, 0xa6,
+ 0x53, 0x9b, 0x0c, 0x18, 0xbd, 0xe9, 0x98, 0xcc, 0x41, 0xef, 0xc0, 0xee, 0x92, 0xab, 0x2c, 0x5c,
+ 0x77, 0x78, 0xd6, 0xeb, 0x00, 0x36, 0xa6, 0x61, 0x1e, 0xb1, 0x2a, 0x32, 0x8e, 0x1e, 0x2a, 0xbf,
+ 0x48, 0xb0, 0xb7, 0x74, 0x1d, 0xff, 0x4b, 0x75, 0x48, 0x49, 0x1d, 0x7f, 0xe6, 0x01, 0xdd, 0xbe,
+ 0xf4, 0xff, 0xfe, 0x52, 0x46, 0x4e, 0xc0, 0xb8, 0x28, 0x25, 0x8f, 0xa3, 0x07, 0xa4, 0x80, 0xec,
+ 0x07, 0xb6, 0xb8, 0x7f, 0x12, 0x0e, 0x8f, 0xa8, 0x0f, 0x9b, 0xc3, 0x60, 0xf4, 0x1d, 0xe1, 0x7e,
+ 0xb9, 0x20, 0xca, 0xf8, 0xf4, 0xe1, 0xbf, 0x7f, 0x6a, 0x5d, 0x30, 0xe0, 0x84, 0x09, 0xbd, 0x07,
+ 0x7b, 0xe4, 0xc6, 0xb5, 0xe8, 0x88, 0x72, 0x63, 0xe8, 0x04, 0x6c, 0xec, 0x97, 0x37, 0x8f, 0xe4,
+ 0x63, 0x09, 0xef, 0x26, 0x70, 0x5d, 0xa0, 0x87, 0x3f, 0xe5, 0xa0, 0x10, 0x05, 0xa7, 0x82, 0xa5,
+ 0xac, 0xe0, 0xd7, 0xb0, 0x45, 0x6e, 0x88, 0xed, 0x5a, 0xa6, 0x27, 0x3a, 0x52, 0x3c, 0xab, 0xff,
+ 0x63, 0x7d, 0x6a, 0x33, 0x66, 0xc2, 0x73, 0xce, 0xc3, 0x1f, 0x25, 0xd8, 0x4a, 0xe0, 0x74, 0xfc,
+ 0x52, 0x66, 0xfc, 0x2b, 0xfa, 0x9d, 0x5b, 0xd1, 0xef, 0x2e, 0x14, 0x4d, 0xce, 0xcd, 0xd1, 0x75,
+ 0xf8, 0x5a, 0x4f, 0xde, 0x56, 0x0f, 0x5c, 0x89, 0x2c, 0x43, 0xe5, 0x07, 0x19, 0x94, 0xe5, 0x97,
+ 0xc0, 0xff, 0x64, 0xe7, 0x1c, 0x28, 0xb9, 0xc4, 0x1b, 0x11, 0xc6, 0xa9, 0x45, 0x0c, 0xd1, 0xe5,
+ 0x64, 0xfb, 0xea, 0x0f, 0x7d, 0x2f, 0xaa, 0xa2, 0xb2, 0x1a, 0xef, 0xcd, 0x09, 0xb1, 0x92, 0x92,
+ 0x0b, 0xa3, 0x7f, 0xa8, 0x41, 0xe9, 0x96, 0x1b, 0x7a, 0x06, 0x90, 0x3a, 0xc6, 0x23, 0xcf, 0x20,
+ 0xe9, 0x36, 0xe4, 0x32, 0xdb, 0x50, 0xe7, 0xf0, 0x36, 0x75, 0xd6, 0x88, 0xac, 0xef, 0xc4, 0x9f,
+ 0x90, 0xbd, 0xd0, 0xd0, 0x93, 0x5e, 0x7e, 0x31, 0xa1, 0xfc, 0x3a, 0x18, 0x86, 0x83, 0xa9, 0x86,
+ 0xa1, 0x27, 0xe9, 0xa7, 0xf8, 0x02, 0xd3, 0x49, 0xf4, 0x61, 0x3e, 0x21, 0xac, 0x3a, 0xc9, 0xfe,
+ 0x33, 0x18, 0x16, 0x84, 0xe1, 0xe3, 0xbf, 0x02, 0x00, 0x00, 0xff, 0xff, 0x3f, 0x02, 0x26, 0x81,
+ 0x42, 0x0c, 0x00, 0x00,
+}
diff --git a/vendor/github.com/open-telemetry/opentelemetry-proto/gen/go/resource/v1/resource.pb.go b/vendor/github.com/open-telemetry/opentelemetry-proto/gen/go/resource/v1/resource.pb.go
new file mode 100644
index 0000000..cfc41c4
--- /dev/null
+++ b/vendor/github.com/open-telemetry/opentelemetry-proto/gen/go/resource/v1/resource.pb.go
@@ -0,0 +1,100 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// source: opentelemetry/proto/resource/v1/resource.proto
+
+package v1
+
+import (
+ fmt "fmt"
+ proto "github.com/golang/protobuf/proto"
+ v1 "github.com/open-telemetry/opentelemetry-proto/gen/go/common/v1"
+ math "math"
+)
+
+// Reference imports to suppress errors if they are not otherwise used.
+var _ = proto.Marshal
+var _ = fmt.Errorf
+var _ = math.Inf
+
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the proto package it is being compiled against.
+// A compilation error at this line likely means your copy of the
+// proto package needs to be updated.
+const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
+
+// Resource information.
+type Resource struct {
+ // Set of labels that describe the resource.
+ Attributes []*v1.AttributeKeyValue `protobuf:"bytes,1,rep,name=attributes,proto3" json:"attributes,omitempty"`
+ // dropped_attributes_count is the number of dropped attributes. If the value is 0, then
+ // no attributes were dropped.
+ DroppedAttributesCount uint32 `protobuf:"varint,2,opt,name=dropped_attributes_count,json=droppedAttributesCount,proto3" json:"dropped_attributes_count,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *Resource) Reset() { *m = Resource{} }
+func (m *Resource) String() string { return proto.CompactTextString(m) }
+func (*Resource) ProtoMessage() {}
+func (*Resource) Descriptor() ([]byte, []int) {
+ return fileDescriptor_446f73eacf88f3f5, []int{0}
+}
+
+func (m *Resource) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_Resource.Unmarshal(m, b)
+}
+func (m *Resource) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_Resource.Marshal(b, m, deterministic)
+}
+func (m *Resource) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_Resource.Merge(m, src)
+}
+func (m *Resource) XXX_Size() int {
+ return xxx_messageInfo_Resource.Size(m)
+}
+func (m *Resource) XXX_DiscardUnknown() {
+ xxx_messageInfo_Resource.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_Resource proto.InternalMessageInfo
+
+func (m *Resource) GetAttributes() []*v1.AttributeKeyValue {
+ if m != nil {
+ return m.Attributes
+ }
+ return nil
+}
+
+func (m *Resource) GetDroppedAttributesCount() uint32 {
+ if m != nil {
+ return m.DroppedAttributesCount
+ }
+ return 0
+}
+
+func init() {
+ proto.RegisterType((*Resource)(nil), "opentelemetry.proto.resource.v1.Resource")
+}
+
+func init() {
+ proto.RegisterFile("opentelemetry/proto/resource/v1/resource.proto", fileDescriptor_446f73eacf88f3f5)
+}
+
+var fileDescriptor_446f73eacf88f3f5 = []byte{
+ // 231 bytes of a gzipped FileDescriptorProto
+ 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xd2, 0xcb, 0x2f, 0x48, 0xcd,
+ 0x2b, 0x49, 0xcd, 0x49, 0xcd, 0x4d, 0x2d, 0x29, 0xaa, 0xd4, 0x2f, 0x28, 0xca, 0x2f, 0xc9, 0xd7,
+ 0x2f, 0x4a, 0x2d, 0xce, 0x2f, 0x2d, 0x4a, 0x4e, 0xd5, 0x2f, 0x33, 0x84, 0xb3, 0xf5, 0xc0, 0x52,
+ 0x42, 0xf2, 0x28, 0xea, 0x21, 0x82, 0x7a, 0x70, 0x35, 0x65, 0x86, 0x52, 0x5a, 0xd8, 0x0c, 0x4c,
+ 0xce, 0xcf, 0xcd, 0xcd, 0xcf, 0x03, 0x19, 0x07, 0x61, 0x41, 0xf4, 0x29, 0x4d, 0x63, 0xe4, 0xe2,
+ 0x08, 0x82, 0xea, 0x15, 0x0a, 0xe0, 0xe2, 0x4a, 0x2c, 0x29, 0x29, 0xca, 0x4c, 0x2a, 0x2d, 0x49,
+ 0x2d, 0x96, 0x60, 0x54, 0x60, 0xd6, 0xe0, 0x36, 0x32, 0xd0, 0xc3, 0x66, 0x1d, 0xd4, 0x8c, 0x32,
+ 0x43, 0x3d, 0x47, 0x98, 0x06, 0xef, 0xd4, 0xca, 0xb0, 0xc4, 0x9c, 0xd2, 0xd4, 0x20, 0x24, 0x33,
+ 0x84, 0x2c, 0xb8, 0x24, 0x52, 0x8a, 0xf2, 0x0b, 0x0a, 0x52, 0x53, 0xe2, 0x11, 0xa2, 0xf1, 0xc9,
+ 0xf9, 0xa5, 0x79, 0x25, 0x12, 0x4c, 0x0a, 0x8c, 0x1a, 0xbc, 0x41, 0x62, 0x50, 0x79, 0xb8, 0x39,
+ 0xc5, 0xce, 0x20, 0x59, 0xa7, 0x72, 0x2e, 0xa5, 0xcc, 0x7c, 0x3d, 0x02, 0x5e, 0x75, 0xe2, 0x85,
+ 0xb9, 0x3d, 0x00, 0x24, 0x15, 0xc0, 0x18, 0xe5, 0x90, 0x9e, 0x59, 0x92, 0x51, 0x9a, 0x04, 0x72,
+ 0xa0, 0x3e, 0x48, 0xb3, 0x2e, 0x22, 0x1c, 0x50, 0xcc, 0xd2, 0x85, 0x84, 0x4a, 0x7a, 0x6a, 0x9e,
+ 0x7e, 0x3a, 0x4a, 0x68, 0x27, 0xb1, 0x81, 0x65, 0x8c, 0x01, 0x01, 0x00, 0x00, 0xff, 0xff, 0xc9,
+ 0xc6, 0x84, 0x9f, 0x97, 0x01, 0x00, 0x00,
+}
diff --git a/vendor/github.com/open-telemetry/opentelemetry-proto/gen/go/trace/v1/trace.pb.go b/vendor/github.com/open-telemetry/opentelemetry-proto/gen/go/trace/v1/trace.pb.go
new file mode 100644
index 0000000..7bda6aa
--- /dev/null
+++ b/vendor/github.com/open-telemetry/opentelemetry-proto/gen/go/trace/v1/trace.pb.go
@@ -0,0 +1,767 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// source: opentelemetry/proto/trace/v1/trace.proto
+
+package v1
+
+import (
+ fmt "fmt"
+ proto "github.com/golang/protobuf/proto"
+ v11 "github.com/open-telemetry/opentelemetry-proto/gen/go/common/v1"
+ v1 "github.com/open-telemetry/opentelemetry-proto/gen/go/resource/v1"
+ math "math"
+)
+
+// Reference imports to suppress errors if they are not otherwise used.
+var _ = proto.Marshal
+var _ = fmt.Errorf
+var _ = math.Inf
+
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the proto package it is being compiled against.
+// A compilation error at this line likely means your copy of the
+// proto package needs to be updated.
+const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
+
+// SpanKind is the type of span. Can be used to specify additional relationships between spans
+// in addition to a parent/child relationship.
+type Span_SpanKind int32
+
+const (
+ // Unspecified. Do NOT use as default.
+ // Implementations MAY assume SpanKind to be INTERNAL when receiving UNSPECIFIED.
+ Span_SPAN_KIND_UNSPECIFIED Span_SpanKind = 0
+ // Indicates that the span represents an internal operation within an application,
+ // as opposed to an operations happening at the boundaries. Default value.
+ Span_INTERNAL Span_SpanKind = 1
+ // Indicates that the span covers server-side handling of an RPC or other
+ // remote network request.
+ Span_SERVER Span_SpanKind = 2
+ // Indicates that the span describes a request to some remote service.
+ Span_CLIENT Span_SpanKind = 3
+ // Indicates that the span describes a producer sending a message to a broker.
+ // Unlike CLIENT and SERVER, there is often no direct critical path latency relationship
+ // between producer and consumer spans. A PRODUCER span ends when the message was accepted
+ // by the broker while the logical processing of the message might span a much longer time.
+ Span_PRODUCER Span_SpanKind = 4
+ // Indicates that the span describes consumer receiving a message from a broker.
+ // Like the PRODUCER kind, there is often no direct critical path latency relationship
+ // between producer and consumer spans.
+ Span_CONSUMER Span_SpanKind = 5
+)
+
+var Span_SpanKind_name = map[int32]string{
+ 0: "SPAN_KIND_UNSPECIFIED",
+ 1: "INTERNAL",
+ 2: "SERVER",
+ 3: "CLIENT",
+ 4: "PRODUCER",
+ 5: "CONSUMER",
+}
+
+var Span_SpanKind_value = map[string]int32{
+ "SPAN_KIND_UNSPECIFIED": 0,
+ "INTERNAL": 1,
+ "SERVER": 2,
+ "CLIENT": 3,
+ "PRODUCER": 4,
+ "CONSUMER": 5,
+}
+
+func (x Span_SpanKind) String() string {
+ return proto.EnumName(Span_SpanKind_name, int32(x))
+}
+
+func (Span_SpanKind) EnumDescriptor() ([]byte, []int) {
+ return fileDescriptor_5c407ac9c675a601, []int{2, 0}
+}
+
+// StatusCode mirrors the codes defined at
+// https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/api-tracing.md#statuscanonicalcode
+type Status_StatusCode int32
+
+const (
+ Status_Ok Status_StatusCode = 0
+ Status_Cancelled Status_StatusCode = 1
+ Status_UnknownError Status_StatusCode = 2
+ Status_InvalidArgument Status_StatusCode = 3
+ Status_DeadlineExceeded Status_StatusCode = 4
+ Status_NotFound Status_StatusCode = 5
+ Status_AlreadyExists Status_StatusCode = 6
+ Status_PermissionDenied Status_StatusCode = 7
+ Status_ResourceExhausted Status_StatusCode = 8
+ Status_FailedPrecondition Status_StatusCode = 9
+ Status_Aborted Status_StatusCode = 10
+ Status_OutOfRange Status_StatusCode = 11
+ Status_Unimplemented Status_StatusCode = 12
+ Status_InternalError Status_StatusCode = 13
+ Status_Unavailable Status_StatusCode = 14
+ Status_DataLoss Status_StatusCode = 15
+ Status_Unauthenticated Status_StatusCode = 16
+)
+
+var Status_StatusCode_name = map[int32]string{
+ 0: "Ok",
+ 1: "Cancelled",
+ 2: "UnknownError",
+ 3: "InvalidArgument",
+ 4: "DeadlineExceeded",
+ 5: "NotFound",
+ 6: "AlreadyExists",
+ 7: "PermissionDenied",
+ 8: "ResourceExhausted",
+ 9: "FailedPrecondition",
+ 10: "Aborted",
+ 11: "OutOfRange",
+ 12: "Unimplemented",
+ 13: "InternalError",
+ 14: "Unavailable",
+ 15: "DataLoss",
+ 16: "Unauthenticated",
+}
+
+var Status_StatusCode_value = map[string]int32{
+ "Ok": 0,
+ "Cancelled": 1,
+ "UnknownError": 2,
+ "InvalidArgument": 3,
+ "DeadlineExceeded": 4,
+ "NotFound": 5,
+ "AlreadyExists": 6,
+ "PermissionDenied": 7,
+ "ResourceExhausted": 8,
+ "FailedPrecondition": 9,
+ "Aborted": 10,
+ "OutOfRange": 11,
+ "Unimplemented": 12,
+ "InternalError": 13,
+ "Unavailable": 14,
+ "DataLoss": 15,
+ "Unauthenticated": 16,
+}
+
+func (x Status_StatusCode) String() string {
+ return proto.EnumName(Status_StatusCode_name, int32(x))
+}
+
+func (Status_StatusCode) EnumDescriptor() ([]byte, []int) {
+ return fileDescriptor_5c407ac9c675a601, []int{3, 0}
+}
+
+// A collection of InstrumentationLibrarySpans from a Resource.
+type ResourceSpans struct {
+ // The resource for the spans in this message.
+ // If this field is not set then no resource info is known.
+ Resource *v1.Resource `protobuf:"bytes,1,opt,name=resource,proto3" json:"resource,omitempty"`
+ // A list of InstrumentationLibrarySpans that originate from a resource.
+ InstrumentationLibrarySpans []*InstrumentationLibrarySpans `protobuf:"bytes,2,rep,name=instrumentation_library_spans,json=instrumentationLibrarySpans,proto3" json:"instrumentation_library_spans,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *ResourceSpans) Reset() { *m = ResourceSpans{} }
+func (m *ResourceSpans) String() string { return proto.CompactTextString(m) }
+func (*ResourceSpans) ProtoMessage() {}
+func (*ResourceSpans) Descriptor() ([]byte, []int) {
+ return fileDescriptor_5c407ac9c675a601, []int{0}
+}
+
+func (m *ResourceSpans) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_ResourceSpans.Unmarshal(m, b)
+}
+func (m *ResourceSpans) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_ResourceSpans.Marshal(b, m, deterministic)
+}
+func (m *ResourceSpans) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_ResourceSpans.Merge(m, src)
+}
+func (m *ResourceSpans) XXX_Size() int {
+ return xxx_messageInfo_ResourceSpans.Size(m)
+}
+func (m *ResourceSpans) XXX_DiscardUnknown() {
+ xxx_messageInfo_ResourceSpans.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_ResourceSpans proto.InternalMessageInfo
+
+func (m *ResourceSpans) GetResource() *v1.Resource {
+ if m != nil {
+ return m.Resource
+ }
+ return nil
+}
+
+func (m *ResourceSpans) GetInstrumentationLibrarySpans() []*InstrumentationLibrarySpans {
+ if m != nil {
+ return m.InstrumentationLibrarySpans
+ }
+ return nil
+}
+
+// A collection of Spans produced by an InstrumentationLibrary.
+type InstrumentationLibrarySpans struct {
+ // The instrumentation library information for the spans in this message.
+ // If this field is not set then no library info is known.
+ InstrumentationLibrary *v11.InstrumentationLibrary `protobuf:"bytes,1,opt,name=instrumentation_library,json=instrumentationLibrary,proto3" json:"instrumentation_library,omitempty"`
+ // A list of Spans that originate from an instrumentation library.
+ Spans []*Span `protobuf:"bytes,2,rep,name=spans,proto3" json:"spans,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *InstrumentationLibrarySpans) Reset() { *m = InstrumentationLibrarySpans{} }
+func (m *InstrumentationLibrarySpans) String() string { return proto.CompactTextString(m) }
+func (*InstrumentationLibrarySpans) ProtoMessage() {}
+func (*InstrumentationLibrarySpans) Descriptor() ([]byte, []int) {
+ return fileDescriptor_5c407ac9c675a601, []int{1}
+}
+
+func (m *InstrumentationLibrarySpans) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_InstrumentationLibrarySpans.Unmarshal(m, b)
+}
+func (m *InstrumentationLibrarySpans) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_InstrumentationLibrarySpans.Marshal(b, m, deterministic)
+}
+func (m *InstrumentationLibrarySpans) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_InstrumentationLibrarySpans.Merge(m, src)
+}
+func (m *InstrumentationLibrarySpans) XXX_Size() int {
+ return xxx_messageInfo_InstrumentationLibrarySpans.Size(m)
+}
+func (m *InstrumentationLibrarySpans) XXX_DiscardUnknown() {
+ xxx_messageInfo_InstrumentationLibrarySpans.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_InstrumentationLibrarySpans proto.InternalMessageInfo
+
+func (m *InstrumentationLibrarySpans) GetInstrumentationLibrary() *v11.InstrumentationLibrary {
+ if m != nil {
+ return m.InstrumentationLibrary
+ }
+ return nil
+}
+
+func (m *InstrumentationLibrarySpans) GetSpans() []*Span {
+ if m != nil {
+ return m.Spans
+ }
+ return nil
+}
+
+// Span represents a single operation within a trace. Spans can be
+// nested to form a trace tree. Spans may also be linked to other spans
+// from the same or different trace and form graphs. Often, a trace
+// contains a root span that describes the end-to-end latency, and one
+// or more subspans for its sub-operations. A trace can also contain
+// multiple root spans, or none at all. Spans do not need to be
+// contiguous - there may be gaps or overlaps between spans in a trace.
+//
+// The next available field id is 17.
+type Span struct {
+ // A unique identifier for a trace. All spans from the same trace share
+ // the same `trace_id`. The ID is a 16-byte array. An ID with all zeroes
+ // is considered invalid.
+ //
+ // This field is semantically required. Receiver should generate new
+ // random trace_id if empty or invalid trace_id was received.
+ //
+ // This field is required.
+ TraceId []byte `protobuf:"bytes,1,opt,name=trace_id,json=traceId,proto3" json:"trace_id,omitempty"`
+ // A unique identifier for a span within a trace, assigned when the span
+ // is created. The ID is an 8-byte array. An ID with all zeroes is considered
+ // invalid.
+ //
+ // This field is semantically required. Receiver should generate new
+ // random span_id if empty or invalid span_id was received.
+ //
+ // This field is required.
+ SpanId []byte `protobuf:"bytes,2,opt,name=span_id,json=spanId,proto3" json:"span_id,omitempty"`
+ // trace_state conveys information about request position in multiple distributed tracing graphs.
+ // It is a trace_state in w3c-trace-context format: https://www.w3.org/TR/trace-context/#tracestate-header
+ // See also https://github.com/w3c/distributed-tracing for more details about this field.
+ TraceState string `protobuf:"bytes,3,opt,name=trace_state,json=traceState,proto3" json:"trace_state,omitempty"`
+ // The `span_id` of this span's parent span. If this is a root span, then this
+ // field must be empty. The ID is an 8-byte array.
+ ParentSpanId []byte `protobuf:"bytes,4,opt,name=parent_span_id,json=parentSpanId,proto3" json:"parent_span_id,omitempty"`
+ // A description of the span's operation.
+ //
+ // For example, the name can be a qualified method name or a file name
+ // and a line number where the operation is called. A best practice is to use
+ // the same display name at the same call point in an application.
+ // This makes it easier to correlate spans in different traces.
+ //
+ // This field is semantically required to be set to non-empty string.
+ // When null or empty string received - receiver may use string "name"
+ // as a replacement. There might be smarted algorithms implemented by
+ // receiver to fix the empty span name.
+ //
+ // This field is required.
+ Name string `protobuf:"bytes,5,opt,name=name,proto3" json:"name,omitempty"`
+ // Distinguishes between spans generated in a particular context. For example,
+ // two spans with the same name may be distinguished using `CLIENT` (caller)
+ // and `SERVER` (callee) to identify queueing latency associated with the span.
+ Kind Span_SpanKind `protobuf:"varint,6,opt,name=kind,proto3,enum=opentelemetry.proto.trace.v1.Span_SpanKind" json:"kind,omitempty"`
+ // start_time_unix_nano is the start time of the span. On the client side, this is the time
+ // kept by the local machine where the span execution starts. On the server side, this
+ // is the time when the server's application handler starts running.
+ // Value is UNIX Epoch time in nanoseconds since 00:00:00 UTC on 1 January 1970.
+ //
+ // This field is semantically required and it is expected that end_time >= start_time.
+ StartTimeUnixNano uint64 `protobuf:"fixed64,7,opt,name=start_time_unix_nano,json=startTimeUnixNano,proto3" json:"start_time_unix_nano,omitempty"`
+ // end_time_unix_nano is the end time of the span. On the client side, this is the time
+ // kept by the local machine where the span execution ends. On the server side, this
+ // is the time when the server application handler stops running.
+ // Value is UNIX Epoch time in nanoseconds since 00:00:00 UTC on 1 January 1970.
+ //
+ // This field is semantically required and it is expected that end_time >= start_time.
+ EndTimeUnixNano uint64 `protobuf:"fixed64,8,opt,name=end_time_unix_nano,json=endTimeUnixNano,proto3" json:"end_time_unix_nano,omitempty"`
+ // attributes is a collection of key/value pairs. The value can be a string,
+ // an integer, a double or the Boolean values `true` or `false`. Note, global attributes
+ // like server name can be set using the resource API. Examples of attributes:
+ //
+ // "/http/user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36"
+ // "/http/server_latency": 300
+ // "abc.com/myattribute": true
+ // "abc.com/score": 10.239
+ Attributes []*v11.AttributeKeyValue `protobuf:"bytes,9,rep,name=attributes,proto3" json:"attributes,omitempty"`
+ // dropped_attributes_count is the number of attributes that were discarded. Attributes
+ // can be discarded because their keys are too long or because there are too many
+ // attributes. If this value is 0, then no attributes were dropped.
+ DroppedAttributesCount uint32 `protobuf:"varint,10,opt,name=dropped_attributes_count,json=droppedAttributesCount,proto3" json:"dropped_attributes_count,omitempty"`
+ // events is a collection of Event items.
+ Events []*Span_Event `protobuf:"bytes,11,rep,name=events,proto3" json:"events,omitempty"`
+ // dropped_events_count is the number of dropped events. If the value is 0, then no
+ // events were dropped.
+ DroppedEventsCount uint32 `protobuf:"varint,12,opt,name=dropped_events_count,json=droppedEventsCount,proto3" json:"dropped_events_count,omitempty"`
+ // links is a collection of Links, which are references from this span to a span
+ // in the same or different trace.
+ Links []*Span_Link `protobuf:"bytes,13,rep,name=links,proto3" json:"links,omitempty"`
+ // dropped_links_count is the number of dropped links after the maximum size was
+ // enforced. If this value is 0, then no links were dropped.
+ DroppedLinksCount uint32 `protobuf:"varint,14,opt,name=dropped_links_count,json=droppedLinksCount,proto3" json:"dropped_links_count,omitempty"`
+ // An optional final status for this span. Semantically when Status
+ // wasn't set it is means span ended without errors and assume
+ // Status.Ok (code = 0).
+ Status *Status `protobuf:"bytes,15,opt,name=status,proto3" json:"status,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *Span) Reset() { *m = Span{} }
+func (m *Span) String() string { return proto.CompactTextString(m) }
+func (*Span) ProtoMessage() {}
+func (*Span) Descriptor() ([]byte, []int) {
+ return fileDescriptor_5c407ac9c675a601, []int{2}
+}
+
+func (m *Span) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_Span.Unmarshal(m, b)
+}
+func (m *Span) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_Span.Marshal(b, m, deterministic)
+}
+func (m *Span) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_Span.Merge(m, src)
+}
+func (m *Span) XXX_Size() int {
+ return xxx_messageInfo_Span.Size(m)
+}
+func (m *Span) XXX_DiscardUnknown() {
+ xxx_messageInfo_Span.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_Span proto.InternalMessageInfo
+
+func (m *Span) GetTraceId() []byte {
+ if m != nil {
+ return m.TraceId
+ }
+ return nil
+}
+
+func (m *Span) GetSpanId() []byte {
+ if m != nil {
+ return m.SpanId
+ }
+ return nil
+}
+
+func (m *Span) GetTraceState() string {
+ if m != nil {
+ return m.TraceState
+ }
+ return ""
+}
+
+func (m *Span) GetParentSpanId() []byte {
+ if m != nil {
+ return m.ParentSpanId
+ }
+ return nil
+}
+
+func (m *Span) GetName() string {
+ if m != nil {
+ return m.Name
+ }
+ return ""
+}
+
+func (m *Span) GetKind() Span_SpanKind {
+ if m != nil {
+ return m.Kind
+ }
+ return Span_SPAN_KIND_UNSPECIFIED
+}
+
+func (m *Span) GetStartTimeUnixNano() uint64 {
+ if m != nil {
+ return m.StartTimeUnixNano
+ }
+ return 0
+}
+
+func (m *Span) GetEndTimeUnixNano() uint64 {
+ if m != nil {
+ return m.EndTimeUnixNano
+ }
+ return 0
+}
+
+func (m *Span) GetAttributes() []*v11.AttributeKeyValue {
+ if m != nil {
+ return m.Attributes
+ }
+ return nil
+}
+
+func (m *Span) GetDroppedAttributesCount() uint32 {
+ if m != nil {
+ return m.DroppedAttributesCount
+ }
+ return 0
+}
+
+func (m *Span) GetEvents() []*Span_Event {
+ if m != nil {
+ return m.Events
+ }
+ return nil
+}
+
+func (m *Span) GetDroppedEventsCount() uint32 {
+ if m != nil {
+ return m.DroppedEventsCount
+ }
+ return 0
+}
+
+func (m *Span) GetLinks() []*Span_Link {
+ if m != nil {
+ return m.Links
+ }
+ return nil
+}
+
+func (m *Span) GetDroppedLinksCount() uint32 {
+ if m != nil {
+ return m.DroppedLinksCount
+ }
+ return 0
+}
+
+func (m *Span) GetStatus() *Status {
+ if m != nil {
+ return m.Status
+ }
+ return nil
+}
+
+// Event is a time-stamped annotation of the span, consisting of user-supplied
+// text description and key-value pairs.
+type Span_Event struct {
+ // time_unix_nano is the time the event occurred.
+ TimeUnixNano uint64 `protobuf:"fixed64,1,opt,name=time_unix_nano,json=timeUnixNano,proto3" json:"time_unix_nano,omitempty"`
+ // name of the event.
+ // This field is semantically required to be set to non-empty string.
+ Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`
+ // attributes is a collection of attribute key/value pairs on the event.
+ Attributes []*v11.AttributeKeyValue `protobuf:"bytes,3,rep,name=attributes,proto3" json:"attributes,omitempty"`
+ // dropped_attributes_count is the number of dropped attributes. If the value is 0,
+ // then no attributes were dropped.
+ DroppedAttributesCount uint32 `protobuf:"varint,4,opt,name=dropped_attributes_count,json=droppedAttributesCount,proto3" json:"dropped_attributes_count,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *Span_Event) Reset() { *m = Span_Event{} }
+func (m *Span_Event) String() string { return proto.CompactTextString(m) }
+func (*Span_Event) ProtoMessage() {}
+func (*Span_Event) Descriptor() ([]byte, []int) {
+ return fileDescriptor_5c407ac9c675a601, []int{2, 0}
+}
+
+func (m *Span_Event) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_Span_Event.Unmarshal(m, b)
+}
+func (m *Span_Event) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_Span_Event.Marshal(b, m, deterministic)
+}
+func (m *Span_Event) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_Span_Event.Merge(m, src)
+}
+func (m *Span_Event) XXX_Size() int {
+ return xxx_messageInfo_Span_Event.Size(m)
+}
+func (m *Span_Event) XXX_DiscardUnknown() {
+ xxx_messageInfo_Span_Event.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_Span_Event proto.InternalMessageInfo
+
+func (m *Span_Event) GetTimeUnixNano() uint64 {
+ if m != nil {
+ return m.TimeUnixNano
+ }
+ return 0
+}
+
+func (m *Span_Event) GetName() string {
+ if m != nil {
+ return m.Name
+ }
+ return ""
+}
+
+func (m *Span_Event) GetAttributes() []*v11.AttributeKeyValue {
+ if m != nil {
+ return m.Attributes
+ }
+ return nil
+}
+
+func (m *Span_Event) GetDroppedAttributesCount() uint32 {
+ if m != nil {
+ return m.DroppedAttributesCount
+ }
+ return 0
+}
+
+// A pointer from the current span to another span in the same trace or in a
+// different trace. For example, this can be used in batching operations,
+// where a single batch handler processes multiple requests from different
+// traces or when the handler receives a request from a different project.
+type Span_Link struct {
+ // A unique identifier of a trace that this linked span is part of. The ID is a
+ // 16-byte array.
+ TraceId []byte `protobuf:"bytes,1,opt,name=trace_id,json=traceId,proto3" json:"trace_id,omitempty"`
+ // A unique identifier for the linked span. The ID is an 8-byte array.
+ SpanId []byte `protobuf:"bytes,2,opt,name=span_id,json=spanId,proto3" json:"span_id,omitempty"`
+ // The trace_state associated with the link.
+ TraceState string `protobuf:"bytes,3,opt,name=trace_state,json=traceState,proto3" json:"trace_state,omitempty"`
+ // attributes is a collection of attribute key/value pairs on the link.
+ Attributes []*v11.AttributeKeyValue `protobuf:"bytes,4,rep,name=attributes,proto3" json:"attributes,omitempty"`
+ // dropped_attributes_count is the number of dropped attributes. If the value is 0,
+ // then no attributes were dropped.
+ DroppedAttributesCount uint32 `protobuf:"varint,5,opt,name=dropped_attributes_count,json=droppedAttributesCount,proto3" json:"dropped_attributes_count,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *Span_Link) Reset() { *m = Span_Link{} }
+func (m *Span_Link) String() string { return proto.CompactTextString(m) }
+func (*Span_Link) ProtoMessage() {}
+func (*Span_Link) Descriptor() ([]byte, []int) {
+ return fileDescriptor_5c407ac9c675a601, []int{2, 1}
+}
+
+func (m *Span_Link) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_Span_Link.Unmarshal(m, b)
+}
+func (m *Span_Link) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_Span_Link.Marshal(b, m, deterministic)
+}
+func (m *Span_Link) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_Span_Link.Merge(m, src)
+}
+func (m *Span_Link) XXX_Size() int {
+ return xxx_messageInfo_Span_Link.Size(m)
+}
+func (m *Span_Link) XXX_DiscardUnknown() {
+ xxx_messageInfo_Span_Link.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_Span_Link proto.InternalMessageInfo
+
+func (m *Span_Link) GetTraceId() []byte {
+ if m != nil {
+ return m.TraceId
+ }
+ return nil
+}
+
+func (m *Span_Link) GetSpanId() []byte {
+ if m != nil {
+ return m.SpanId
+ }
+ return nil
+}
+
+func (m *Span_Link) GetTraceState() string {
+ if m != nil {
+ return m.TraceState
+ }
+ return ""
+}
+
+func (m *Span_Link) GetAttributes() []*v11.AttributeKeyValue {
+ if m != nil {
+ return m.Attributes
+ }
+ return nil
+}
+
+func (m *Span_Link) GetDroppedAttributesCount() uint32 {
+ if m != nil {
+ return m.DroppedAttributesCount
+ }
+ return 0
+}
+
+// The Status type defines a logical error model that is suitable for different
+// programming environments, including REST APIs and RPC APIs.
+type Status struct {
+ // The status code. This is optional field. It is safe to assume 0 (OK)
+ // when not set.
+ Code Status_StatusCode `protobuf:"varint,1,opt,name=code,proto3,enum=opentelemetry.proto.trace.v1.Status_StatusCode" json:"code,omitempty"`
+ // A developer-facing human readable error message.
+ Message string `protobuf:"bytes,2,opt,name=message,proto3" json:"message,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *Status) Reset() { *m = Status{} }
+func (m *Status) String() string { return proto.CompactTextString(m) }
+func (*Status) ProtoMessage() {}
+func (*Status) Descriptor() ([]byte, []int) {
+ return fileDescriptor_5c407ac9c675a601, []int{3}
+}
+
+func (m *Status) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_Status.Unmarshal(m, b)
+}
+func (m *Status) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_Status.Marshal(b, m, deterministic)
+}
+func (m *Status) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_Status.Merge(m, src)
+}
+func (m *Status) XXX_Size() int {
+ return xxx_messageInfo_Status.Size(m)
+}
+func (m *Status) XXX_DiscardUnknown() {
+ xxx_messageInfo_Status.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_Status proto.InternalMessageInfo
+
+func (m *Status) GetCode() Status_StatusCode {
+ if m != nil {
+ return m.Code
+ }
+ return Status_Ok
+}
+
+func (m *Status) GetMessage() string {
+ if m != nil {
+ return m.Message
+ }
+ return ""
+}
+
+func init() {
+ proto.RegisterEnum("opentelemetry.proto.trace.v1.Span_SpanKind", Span_SpanKind_name, Span_SpanKind_value)
+ proto.RegisterEnum("opentelemetry.proto.trace.v1.Status_StatusCode", Status_StatusCode_name, Status_StatusCode_value)
+ proto.RegisterType((*ResourceSpans)(nil), "opentelemetry.proto.trace.v1.ResourceSpans")
+ proto.RegisterType((*InstrumentationLibrarySpans)(nil), "opentelemetry.proto.trace.v1.InstrumentationLibrarySpans")
+ proto.RegisterType((*Span)(nil), "opentelemetry.proto.trace.v1.Span")
+ proto.RegisterType((*Span_Event)(nil), "opentelemetry.proto.trace.v1.Span.Event")
+ proto.RegisterType((*Span_Link)(nil), "opentelemetry.proto.trace.v1.Span.Link")
+ proto.RegisterType((*Status)(nil), "opentelemetry.proto.trace.v1.Status")
+}
+
+func init() {
+ proto.RegisterFile("opentelemetry/proto/trace/v1/trace.proto", fileDescriptor_5c407ac9c675a601)
+}
+
+var fileDescriptor_5c407ac9c675a601 = []byte{
+ // 1008 bytes of a gzipped FileDescriptorProto
+ 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x56, 0xcd, 0x6e, 0x1b, 0x37,
+ 0x10, 0xce, 0xea, 0xdf, 0xa3, 0x1f, 0xaf, 0x19, 0xc7, 0xd9, 0x38, 0x2d, 0x22, 0x08, 0x01, 0xaa,
+ 0x36, 0x88, 0x14, 0xbb, 0x28, 0x90, 0x02, 0x0d, 0x5a, 0x45, 0x5a, 0x03, 0x82, 0x5d, 0x59, 0xa0,
+ 0xac, 0x1c, 0x7a, 0x59, 0x50, 0x22, 0x2b, 0x13, 0x5e, 0x91, 0xc2, 0x2e, 0x57, 0xb5, 0x0f, 0xbd,
+ 0xf5, 0x5d, 0xfa, 0x14, 0x3d, 0xf7, 0xd4, 0x63, 0x9f, 0xa1, 0xaf, 0x51, 0x90, 0xbb, 0x6b, 0x5b,
+ 0x81, 0x2c, 0xfb, 0xe2, 0x8b, 0x44, 0xce, 0x7c, 0xdf, 0x7c, 0x33, 0x9c, 0x59, 0x90, 0xd0, 0x94,
+ 0x0b, 0x26, 0x14, 0xf3, 0xd9, 0x9c, 0xa9, 0xe0, 0xaa, 0xbd, 0x08, 0xa4, 0x92, 0x6d, 0x15, 0x90,
+ 0x29, 0x6b, 0x2f, 0x0f, 0xe2, 0x45, 0xcb, 0x18, 0xd1, 0x17, 0x2b, 0xc8, 0xd8, 0xd8, 0x8a, 0x01,
+ 0xcb, 0x83, 0xfd, 0x6f, 0xd6, 0xc5, 0x99, 0xca, 0xf9, 0x5c, 0x0a, 0x1d, 0x28, 0x5e, 0xc5, 0xa4,
+ 0xfd, 0xd6, 0x3a, 0x6c, 0xc0, 0x42, 0x19, 0x05, 0xb1, 0x6c, 0xba, 0x8e, 0xf1, 0x8d, 0x7f, 0x2d,
+ 0xa8, 0xe2, 0xc4, 0x34, 0x5a, 0x10, 0x11, 0x22, 0x17, 0x4a, 0x29, 0xc6, 0xb1, 0xea, 0x56, 0xb3,
+ 0x7c, 0xf8, 0x75, 0x6b, 0x5d, 0x7a, 0xd7, 0x81, 0x96, 0x07, 0xad, 0x34, 0x02, 0xbe, 0xa6, 0xa2,
+ 0xdf, 0xe1, 0x4b, 0x2e, 0x42, 0x15, 0x44, 0x73, 0x26, 0x14, 0x51, 0x5c, 0x0a, 0xcf, 0xe7, 0x93,
+ 0x80, 0x04, 0x57, 0x5e, 0xa8, 0x75, 0x9c, 0x4c, 0x3d, 0xdb, 0x2c, 0x1f, 0x7e, 0xdf, 0xda, 0x54,
+ 0x7a, 0xab, 0xbf, 0x1a, 0xe2, 0x24, 0x8e, 0x60, 0x12, 0xc5, 0x2f, 0xf9, 0xdd, 0xce, 0xc6, 0xdf,
+ 0x16, 0xbc, 0xdc, 0x40, 0x46, 0x02, 0x9e, 0xdf, 0x91, 0x5e, 0x52, 0xf4, 0x77, 0x6b, 0x13, 0x4b,
+ 0xce, 0xfa, 0xce, 0xcc, 0xf0, 0xde, 0xfa, 0xa4, 0xd0, 0x7b, 0xc8, 0xdf, 0x2e, 0xbb, 0xb1, 0xb9,
+ 0x6c, 0x9d, 0x23, 0x8e, 0x09, 0x8d, 0x3f, 0x00, 0x72, 0x7a, 0x8f, 0x5e, 0x40, 0xc9, 0x00, 0x3c,
+ 0x4e, 0x4d, 0x8e, 0x15, 0x5c, 0x34, 0xfb, 0x3e, 0x45, 0xcf, 0xa1, 0xa8, 0xc1, 0xda, 0x93, 0x31,
+ 0x9e, 0x82, 0xde, 0xf6, 0x29, 0x7a, 0x05, 0xe5, 0x98, 0x13, 0x2a, 0xa2, 0x98, 0x93, 0xad, 0x5b,
+ 0xcd, 0x2d, 0x0c, 0xc6, 0x34, 0xd2, 0x16, 0xf4, 0x1a, 0x6a, 0x0b, 0x12, 0x30, 0xa1, 0xbc, 0x34,
+ 0x40, 0xce, 0x04, 0xa8, 0xc4, 0xd6, 0x51, 0x1c, 0x06, 0x41, 0x4e, 0x90, 0x39, 0x73, 0xf2, 0x86,
+ 0x6f, 0xd6, 0xe8, 0x47, 0xc8, 0x5d, 0x70, 0x41, 0x9d, 0x42, 0xdd, 0x6a, 0xd6, 0x0e, 0xdf, 0xdc,
+ 0x5f, 0x90, 0xf9, 0x39, 0xe6, 0x82, 0x62, 0x43, 0x44, 0x6d, 0xd8, 0x0d, 0x15, 0x09, 0x94, 0xa7,
+ 0xf8, 0x9c, 0x79, 0x91, 0xe0, 0x97, 0x9e, 0x20, 0x42, 0x3a, 0xc5, 0xba, 0xd5, 0x2c, 0xe0, 0x1d,
+ 0xe3, 0x3b, 0xe3, 0x73, 0x36, 0x16, 0xfc, 0x72, 0x40, 0x84, 0x44, 0x6f, 0x00, 0x31, 0x41, 0x3f,
+ 0x87, 0x97, 0x0c, 0x7c, 0x9b, 0x09, 0xba, 0x02, 0x1e, 0x02, 0x10, 0xa5, 0x02, 0x3e, 0x89, 0x14,
+ 0x0b, 0x9d, 0x2d, 0x73, 0xea, 0xef, 0xee, 0xe9, 0x69, 0x27, 0x25, 0x1c, 0xb3, 0xab, 0x4f, 0xc4,
+ 0x8f, 0x18, 0xbe, 0x15, 0x03, 0xbd, 0x07, 0x87, 0x06, 0x72, 0xb1, 0x60, 0xd4, 0xbb, 0xb1, 0x7a,
+ 0x53, 0x19, 0x09, 0xe5, 0x40, 0xdd, 0x6a, 0x56, 0xf1, 0x5e, 0xe2, 0xbf, 0x8e, 0x13, 0x76, 0xb5,
+ 0x17, 0xfd, 0x04, 0x05, 0xb6, 0x64, 0x42, 0x85, 0x4e, 0xd9, 0xe4, 0xd1, 0x7c, 0xc0, 0x61, 0xb9,
+ 0x9a, 0x80, 0x13, 0x1e, 0x7a, 0x07, 0xbb, 0xa9, 0x76, 0x6c, 0x49, 0x74, 0x2b, 0x46, 0x17, 0x25,
+ 0x3e, 0xc3, 0x49, 0x34, 0x3f, 0x40, 0xde, 0xe7, 0xe2, 0x22, 0x74, 0xaa, 0x46, 0xf2, 0xab, 0x07,
+ 0x48, 0x9e, 0x70, 0x71, 0x81, 0x63, 0x16, 0x6a, 0xc1, 0xd3, 0x54, 0xd0, 0x18, 0x12, 0xbd, 0x9a,
+ 0xd1, 0xdb, 0x49, 0x5c, 0x9a, 0x90, 0xc8, 0xfd, 0x00, 0x05, 0x3d, 0x62, 0x51, 0xe8, 0x6c, 0x9b,
+ 0xcf, 0xe7, 0xf5, 0x3d, 0x7a, 0x06, 0x8b, 0x13, 0xce, 0xfe, 0x3f, 0x16, 0xe4, 0x4d, 0xf2, 0x7a,
+ 0x1e, 0x3f, 0xeb, 0xaf, 0x65, 0xfa, 0x5b, 0x51, 0xb7, 0x9b, 0x9b, 0xce, 0x63, 0xe6, 0xd6, 0x3c,
+ 0xae, 0x36, 0x3c, 0xfb, 0xc8, 0x0d, 0xcf, 0x6d, 0x6a, 0xf8, 0xfe, 0x7f, 0x16, 0xe4, 0xf4, 0xe1,
+ 0x3c, 0xce, 0x37, 0xbb, 0x5a, 0x69, 0xee, 0x91, 0x2b, 0xcd, 0x6f, 0xaa, 0xb4, 0x31, 0x83, 0x52,
+ 0xfa, 0x59, 0xa3, 0x17, 0xf0, 0x6c, 0x34, 0xec, 0x0c, 0xbc, 0xe3, 0xfe, 0xa0, 0xe7, 0x8d, 0x07,
+ 0xa3, 0xa1, 0xdb, 0xed, 0x1f, 0xf5, 0xdd, 0x9e, 0xfd, 0x04, 0x55, 0xa0, 0xd4, 0x1f, 0x9c, 0xb9,
+ 0x78, 0xd0, 0x39, 0xb1, 0x2d, 0x04, 0x50, 0x18, 0xb9, 0xf8, 0x93, 0x8b, 0xed, 0x8c, 0x5e, 0x77,
+ 0x4f, 0xfa, 0xee, 0xe0, 0xcc, 0xce, 0x6a, 0xd4, 0x10, 0x9f, 0xf6, 0xc6, 0x5d, 0x17, 0xdb, 0x39,
+ 0xbd, 0xeb, 0x9e, 0x0e, 0x46, 0xe3, 0x9f, 0x5d, 0x6c, 0xe7, 0x1b, 0x7f, 0x66, 0xa1, 0x10, 0x4f,
+ 0x0d, 0xea, 0x42, 0x6e, 0x2a, 0x69, 0x7c, 0x3b, 0xd5, 0x0e, 0xdb, 0x0f, 0x99, 0xb4, 0xe4, 0xaf,
+ 0x2b, 0x29, 0xc3, 0x86, 0x8c, 0x1c, 0x28, 0xce, 0x59, 0x18, 0x92, 0x59, 0x3a, 0x45, 0xe9, 0xb6,
+ 0xf1, 0x57, 0x06, 0xe0, 0x06, 0x8e, 0x0a, 0x90, 0x39, 0xbd, 0xb0, 0x9f, 0xa0, 0x2a, 0x6c, 0x75,
+ 0x89, 0x98, 0x32, 0xdf, 0x67, 0xd4, 0xb6, 0x90, 0x0d, 0x95, 0xb1, 0xb8, 0x10, 0xf2, 0x37, 0xe1,
+ 0x06, 0x81, 0x0c, 0xec, 0x0c, 0x7a, 0x0a, 0xdb, 0x7d, 0xb1, 0x24, 0x3e, 0xa7, 0x9d, 0x60, 0x66,
+ 0x6e, 0x00, 0x3b, 0x8b, 0x76, 0xc1, 0xee, 0x31, 0x42, 0x7d, 0x2e, 0x98, 0x7b, 0x39, 0x65, 0x8c,
+ 0x32, 0x1a, 0x97, 0x36, 0x90, 0xea, 0x48, 0x46, 0x82, 0xda, 0x79, 0xb4, 0x03, 0xd5, 0x8e, 0x1f,
+ 0x30, 0x42, 0xaf, 0xdc, 0x4b, 0x1e, 0xaa, 0xd0, 0x2e, 0x68, 0xda, 0x90, 0x05, 0x73, 0x1e, 0x86,
+ 0x5c, 0x8a, 0x1e, 0x13, 0x9c, 0x51, 0xbb, 0x88, 0x9e, 0xc1, 0x4e, 0x7a, 0xd3, 0xba, 0x97, 0xe7,
+ 0x24, 0x0a, 0x15, 0xa3, 0x76, 0x09, 0xed, 0x01, 0x3a, 0x22, 0xdc, 0x67, 0x74, 0x18, 0xb0, 0xa9,
+ 0x14, 0x94, 0xeb, 0x8b, 0xc7, 0xde, 0x42, 0x65, 0x28, 0x76, 0x26, 0x32, 0xd0, 0x20, 0x40, 0x35,
+ 0x80, 0xd3, 0x48, 0x9d, 0xfe, 0x8a, 0x89, 0x98, 0x31, 0xbb, 0xac, 0x45, 0xc7, 0x82, 0xcf, 0x17,
+ 0xfa, 0xd8, 0x84, 0x86, 0x54, 0xb4, 0xa9, 0x2f, 0x14, 0x0b, 0x04, 0xf1, 0xe3, 0x9a, 0xaa, 0x68,
+ 0x1b, 0xca, 0x63, 0x41, 0x96, 0x84, 0xfb, 0x64, 0xe2, 0x33, 0xbb, 0xa6, 0x33, 0xef, 0x11, 0x45,
+ 0x4e, 0x64, 0x18, 0xda, 0xdb, 0xba, 0xe4, 0xb1, 0x20, 0x91, 0x3a, 0x67, 0x42, 0xf1, 0x29, 0xd1,
+ 0x61, 0xec, 0x8f, 0x02, 0x5e, 0x71, 0xb9, 0xb1, 0x29, 0x1f, 0xe1, 0x4c, 0xaf, 0x86, 0xda, 0x38,
+ 0xb4, 0x7e, 0xf9, 0x30, 0xe3, 0xea, 0x3c, 0x9a, 0xe8, 0x69, 0x6d, 0x6b, 0xda, 0xdb, 0x9b, 0xf7,
+ 0xcb, 0x4a, 0x94, 0xb7, 0xf1, 0x6b, 0x66, 0xc6, 0x44, 0x7b, 0x76, 0xf3, 0x90, 0x9a, 0x14, 0x8c,
+ 0xf9, 0xdb, 0xff, 0x03, 0x00, 0x00, 0xff, 0xff, 0x17, 0xf4, 0x60, 0x4c, 0x6f, 0x09, 0x00, 0x00,
+}
diff --git a/vendor/github.com/opentracing/opentracing-go/.gitignore b/vendor/github.com/opentracing/opentracing-go/.gitignore
new file mode 100644
index 0000000..c57100a
--- /dev/null
+++ b/vendor/github.com/opentracing/opentracing-go/.gitignore
@@ -0,0 +1 @@
+coverage.txt
diff --git a/vendor/github.com/opentracing/opentracing-go/.travis.yml b/vendor/github.com/opentracing/opentracing-go/.travis.yml
new file mode 100644
index 0000000..8d5b75e
--- /dev/null
+++ b/vendor/github.com/opentracing/opentracing-go/.travis.yml
@@ -0,0 +1,20 @@
+language: go
+
+matrix:
+ include:
+ - go: "1.11.x"
+ - go: "1.12.x"
+ - go: "tip"
+ env:
+ - LINT=true
+ - COVERAGE=true
+
+install:
+ - if [ "$LINT" == true ]; then go get -u golang.org/x/lint/golint/... ; else echo 'skipping lint'; fi
+ - go get -u github.com/stretchr/testify/...
+
+script:
+ - make test
+ - go build ./...
+ - if [ "$LINT" == true ]; then make lint ; else echo 'skipping lint'; fi
+ - if [ "$COVERAGE" == true ]; then make cover && bash <(curl -s https://codecov.io/bash) ; else echo 'skipping coverage'; fi
diff --git a/vendor/github.com/opentracing/opentracing-go/CHANGELOG.md b/vendor/github.com/opentracing/opentracing-go/CHANGELOG.md
new file mode 100644
index 0000000..7c14feb
--- /dev/null
+++ b/vendor/github.com/opentracing/opentracing-go/CHANGELOG.md
@@ -0,0 +1,46 @@
+Changes by Version
+==================
+
+1.1.0 (2019-03-23)
+-------------------
+
+Notable changes:
+- The library is now released under Apache 2.0 license
+- Use Set() instead of Add() in HTTPHeadersCarrier is functionally a breaking change (fixes issue [#159](https://github.com/opentracing/opentracing-go/issues/159))
+- 'golang.org/x/net/context' is replaced with 'context' from the standard library
+
+List of all changes:
+
+- Export StartSpanFromContextWithTracer (#214)
+- Add IsGlobalTracerRegistered() to indicate if a tracer has been registered (#201)
+- Use Set() instead of Add() in HTTPHeadersCarrier (#191)
+- Update license to Apache 2.0 (#181)
+- Replace 'golang.org/x/net/context' with 'context' (#176)
+- Port of Python opentracing/harness/api_check.py to Go (#146)
+- Fix race condition in MockSpan.Context() (#170)
+- Add PeerHostIPv4.SetString() (#155)
+- Add a Noop log field type to log to allow for optional fields (#150)
+
+
+1.0.2 (2017-04-26)
+-------------------
+
+- Add more semantic tags (#139)
+
+
+1.0.1 (2017-02-06)
+-------------------
+
+- Correct spelling in comments
+- Address race in nextMockID() (#123)
+- log: avoid panic marshaling nil error (#131)
+- Deprecate InitGlobalTracer in favor of SetGlobalTracer (#128)
+- Drop Go 1.5 that fails in Travis (#129)
+- Add convenience methods Key() and Value() to log.Field
+- Add convenience methods to log.Field (2 years, 6 months ago)
+
+1.0.0 (2016-09-26)
+-------------------
+
+- This release implements OpenTracing Specification 1.0 (https://opentracing.io/spec)
+
diff --git a/vendor/github.com/opentracing/opentracing-go/LICENSE b/vendor/github.com/opentracing/opentracing-go/LICENSE
new file mode 100644
index 0000000..f002734
--- /dev/null
+++ b/vendor/github.com/opentracing/opentracing-go/LICENSE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "{}"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright 2016 The OpenTracing Authors
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/vendor/github.com/opentracing/opentracing-go/Makefile b/vendor/github.com/opentracing/opentracing-go/Makefile
new file mode 100644
index 0000000..62abb63
--- /dev/null
+++ b/vendor/github.com/opentracing/opentracing-go/Makefile
@@ -0,0 +1,20 @@
+.DEFAULT_GOAL := test-and-lint
+
+.PHONY: test-and-lint
+test-and-lint: test lint
+
+.PHONY: test
+test:
+ go test -v -cover -race ./...
+
+.PHONY: cover
+cover:
+ go test -v -coverprofile=coverage.txt -covermode=atomic -race ./...
+
+.PHONY: lint
+lint:
+ go fmt ./...
+ golint ./...
+ @# Run again with magic to exit non-zero if golint outputs anything.
+ @! (golint ./... | read dummy)
+ go vet ./...
diff --git a/vendor/github.com/opentracing/opentracing-go/README.md b/vendor/github.com/opentracing/opentracing-go/README.md
new file mode 100644
index 0000000..6ef1d7c
--- /dev/null
+++ b/vendor/github.com/opentracing/opentracing-go/README.md
@@ -0,0 +1,171 @@
+[![Gitter chat](http://img.shields.io/badge/gitter-join%20chat%20%E2%86%92-brightgreen.svg)](https://gitter.im/opentracing/public) [![Build Status](https://travis-ci.org/opentracing/opentracing-go.svg?branch=master)](https://travis-ci.org/opentracing/opentracing-go) [![GoDoc](https://godoc.org/github.com/opentracing/opentracing-go?status.svg)](http://godoc.org/github.com/opentracing/opentracing-go)
+[![Sourcegraph Badge](https://sourcegraph.com/github.com/opentracing/opentracing-go/-/badge.svg)](https://sourcegraph.com/github.com/opentracing/opentracing-go?badge)
+
+# OpenTracing API for Go
+
+This package is a Go platform API for OpenTracing.
+
+## Required Reading
+
+In order to understand the Go platform API, one must first be familiar with the
+[OpenTracing project](https://opentracing.io) and
+[terminology](https://opentracing.io/specification/) more specifically.
+
+## API overview for those adding instrumentation
+
+Everyday consumers of this `opentracing` package really only need to worry
+about a couple of key abstractions: the `StartSpan` function, the `Span`
+interface, and binding a `Tracer` at `main()`-time. Here are code snippets
+demonstrating some important use cases.
+
+#### Singleton initialization
+
+The simplest starting point is `./default_tracer.go`. As early as possible, call
+
+```go
+ import "github.com/opentracing/opentracing-go"
+ import ".../some_tracing_impl"
+
+ func main() {
+ opentracing.SetGlobalTracer(
+ // tracing impl specific:
+ some_tracing_impl.New(...),
+ )
+ ...
+ }
+```
+
+#### Non-Singleton initialization
+
+If you prefer direct control to singletons, manage ownership of the
+`opentracing.Tracer` implementation explicitly.
+
+#### Creating a Span given an existing Go `context.Context`
+
+If you use `context.Context` in your application, OpenTracing's Go library will
+happily rely on it for `Span` propagation. To start a new (blocking child)
+`Span`, you can use `StartSpanFromContext`.
+
+```go
+ func xyz(ctx context.Context, ...) {
+ ...
+ span, ctx := opentracing.StartSpanFromContext(ctx, "operation_name")
+ defer span.Finish()
+ span.LogFields(
+ log.String("event", "soft error"),
+ log.String("type", "cache timeout"),
+ log.Int("waited.millis", 1500))
+ ...
+ }
+```
+
+#### Starting an empty trace by creating a "root span"
+
+It's always possible to create a "root" `Span` with no parent or other causal
+reference.
+
+```go
+ func xyz() {
+ ...
+ sp := opentracing.StartSpan("operation_name")
+ defer sp.Finish()
+ ...
+ }
+```
+
+#### Creating a (child) Span given an existing (parent) Span
+
+```go
+ func xyz(parentSpan opentracing.Span, ...) {
+ ...
+ sp := opentracing.StartSpan(
+ "operation_name",
+ opentracing.ChildOf(parentSpan.Context()))
+ defer sp.Finish()
+ ...
+ }
+```
+
+#### Serializing to the wire
+
+```go
+ func makeSomeRequest(ctx context.Context) ... {
+ if span := opentracing.SpanFromContext(ctx); span != nil {
+ httpClient := &http.Client{}
+ httpReq, _ := http.NewRequest("GET", "http://myservice/", nil)
+
+ // Transmit the span's TraceContext as HTTP headers on our
+ // outbound request.
+ opentracing.GlobalTracer().Inject(
+ span.Context(),
+ opentracing.HTTPHeaders,
+ opentracing.HTTPHeadersCarrier(httpReq.Header))
+
+ resp, err := httpClient.Do(httpReq)
+ ...
+ }
+ ...
+ }
+```
+
+#### Deserializing from the wire
+
+```go
+ http.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
+ var serverSpan opentracing.Span
+ appSpecificOperationName := ...
+ wireContext, err := opentracing.GlobalTracer().Extract(
+ opentracing.HTTPHeaders,
+ opentracing.HTTPHeadersCarrier(req.Header))
+ if err != nil {
+ // Optionally record something about err here
+ }
+
+ // Create the span referring to the RPC client if available.
+ // If wireContext == nil, a root span will be created.
+ serverSpan = opentracing.StartSpan(
+ appSpecificOperationName,
+ ext.RPCServerOption(wireContext))
+
+ defer serverSpan.Finish()
+
+ ctx := opentracing.ContextWithSpan(context.Background(), serverSpan)
+ ...
+ }
+```
+
+#### Conditionally capture a field using `log.Noop`
+
+In some situations, you may want to dynamically decide whether or not
+to log a field. For example, you may want to capture additional data,
+such as a customer ID, in non-production environments:
+
+```go
+ func Customer(order *Order) log.Field {
+ if os.Getenv("ENVIRONMENT") == "dev" {
+ return log.String("customer", order.Customer.ID)
+ }
+ return log.Noop()
+ }
+```
+
+#### Goroutine-safety
+
+The entire public API is goroutine-safe and does not require external
+synchronization.
+
+## API pointers for those implementing a tracing system
+
+Tracing system implementors may be able to reuse or copy-paste-modify the `basictracer` package, found [here](https://github.com/opentracing/basictracer-go). In particular, see `basictracer.New(...)`.
+
+## API compatibility
+
+For the time being, "mild" backwards-incompatible changes may be made without changing the major version number. As OpenTracing and `opentracing-go` mature, backwards compatibility will become more of a priority.
+
+## Tracer test suite
+
+A test suite is available in the [harness](https://godoc.org/github.com/opentracing/opentracing-go/harness) package that can assist Tracer implementors to assert that their Tracer is working correctly.
+
+## Licensing
+
+[Apache 2.0 License](./LICENSE).
diff --git a/vendor/github.com/opentracing/opentracing-go/ext/tags.go b/vendor/github.com/opentracing/opentracing-go/ext/tags.go
new file mode 100644
index 0000000..52e8895
--- /dev/null
+++ b/vendor/github.com/opentracing/opentracing-go/ext/tags.go
@@ -0,0 +1,210 @@
+package ext
+
+import "github.com/opentracing/opentracing-go"
+
+// These constants define common tag names recommended for better portability across
+// tracing systems and languages/platforms.
+//
+// The tag names are defined as typed strings, so that in addition to the usual use
+//
+// span.setTag(TagName, value)
+//
+// they also support value type validation via this additional syntax:
+//
+// TagName.Set(span, value)
+//
+var (
+ //////////////////////////////////////////////////////////////////////
+ // SpanKind (client/server or producer/consumer)
+ //////////////////////////////////////////////////////////////////////
+
+ // SpanKind hints at relationship between spans, e.g. client/server
+ SpanKind = spanKindTagName("span.kind")
+
+ // SpanKindRPCClient marks a span representing the client-side of an RPC
+ // or other remote call
+ SpanKindRPCClientEnum = SpanKindEnum("client")
+ SpanKindRPCClient = opentracing.Tag{Key: string(SpanKind), Value: SpanKindRPCClientEnum}
+
+ // SpanKindRPCServer marks a span representing the server-side of an RPC
+ // or other remote call
+ SpanKindRPCServerEnum = SpanKindEnum("server")
+ SpanKindRPCServer = opentracing.Tag{Key: string(SpanKind), Value: SpanKindRPCServerEnum}
+
+ // SpanKindProducer marks a span representing the producer-side of a
+ // message bus
+ SpanKindProducerEnum = SpanKindEnum("producer")
+ SpanKindProducer = opentracing.Tag{Key: string(SpanKind), Value: SpanKindProducerEnum}
+
+ // SpanKindConsumer marks a span representing the consumer-side of a
+ // message bus
+ SpanKindConsumerEnum = SpanKindEnum("consumer")
+ SpanKindConsumer = opentracing.Tag{Key: string(SpanKind), Value: SpanKindConsumerEnum}
+
+ //////////////////////////////////////////////////////////////////////
+ // Component name
+ //////////////////////////////////////////////////////////////////////
+
+ // Component is a low-cardinality identifier of the module, library,
+ // or package that is generating a span.
+ Component = stringTagName("component")
+
+ //////////////////////////////////////////////////////////////////////
+ // Sampling hint
+ //////////////////////////////////////////////////////////////////////
+
+ // SamplingPriority determines the priority of sampling this Span.
+ SamplingPriority = uint16TagName("sampling.priority")
+
+ //////////////////////////////////////////////////////////////////////
+ // Peer tags. These tags can be emitted by either client-side of
+ // server-side to describe the other side/service in a peer-to-peer
+ // communications, like an RPC call.
+ //////////////////////////////////////////////////////////////////////
+
+ // PeerService records the service name of the peer.
+ PeerService = stringTagName("peer.service")
+
+ // PeerAddress records the address name of the peer. This may be a "ip:port",
+ // a bare "hostname", a FQDN or even a database DSN substring
+ // like "mysql://username@127.0.0.1:3306/dbname"
+ PeerAddress = stringTagName("peer.address")
+
+ // PeerHostname records the host name of the peer
+ PeerHostname = stringTagName("peer.hostname")
+
+ // PeerHostIPv4 records IP v4 host address of the peer
+ PeerHostIPv4 = ipv4Tag("peer.ipv4")
+
+ // PeerHostIPv6 records IP v6 host address of the peer
+ PeerHostIPv6 = stringTagName("peer.ipv6")
+
+ // PeerPort records port number of the peer
+ PeerPort = uint16TagName("peer.port")
+
+ //////////////////////////////////////////////////////////////////////
+ // HTTP Tags
+ //////////////////////////////////////////////////////////////////////
+
+ // HTTPUrl should be the URL of the request being handled in this segment
+ // of the trace, in standard URI format. The protocol is optional.
+ HTTPUrl = stringTagName("http.url")
+
+ // HTTPMethod is the HTTP method of the request, and is case-insensitive.
+ HTTPMethod = stringTagName("http.method")
+
+ // HTTPStatusCode is the numeric HTTP status code (200, 404, etc) of the
+ // HTTP response.
+ HTTPStatusCode = uint16TagName("http.status_code")
+
+ //////////////////////////////////////////////////////////////////////
+ // DB Tags
+ //////////////////////////////////////////////////////////////////////
+
+ // DBInstance is database instance name.
+ DBInstance = stringTagName("db.instance")
+
+ // DBStatement is a database statement for the given database type.
+ // It can be a query or a prepared statement (i.e., before substitution).
+ DBStatement = stringTagName("db.statement")
+
+ // DBType is a database type. For any SQL database, "sql".
+ // For others, the lower-case database category, e.g. "redis"
+ DBType = stringTagName("db.type")
+
+ // DBUser is a username for accessing database.
+ DBUser = stringTagName("db.user")
+
+ //////////////////////////////////////////////////////////////////////
+ // Message Bus Tag
+ //////////////////////////////////////////////////////////////////////
+
+ // MessageBusDestination is an address at which messages can be exchanged
+ MessageBusDestination = stringTagName("message_bus.destination")
+
+ //////////////////////////////////////////////////////////////////////
+ // Error Tag
+ //////////////////////////////////////////////////////////////////////
+
+ // Error indicates that operation represented by the span resulted in an error.
+ Error = boolTagName("error")
+)
+
+// ---
+
+// SpanKindEnum represents common span types
+type SpanKindEnum string
+
+type spanKindTagName string
+
+// Set adds a string tag to the `span`
+func (tag spanKindTagName) Set(span opentracing.Span, value SpanKindEnum) {
+ span.SetTag(string(tag), value)
+}
+
+type rpcServerOption struct {
+ clientContext opentracing.SpanContext
+}
+
+func (r rpcServerOption) Apply(o *opentracing.StartSpanOptions) {
+ if r.clientContext != nil {
+ opentracing.ChildOf(r.clientContext).Apply(o)
+ }
+ SpanKindRPCServer.Apply(o)
+}
+
+// RPCServerOption returns a StartSpanOption appropriate for an RPC server span
+// with `client` representing the metadata for the remote peer Span if available.
+// In case client == nil, due to the client not being instrumented, this RPC
+// server span will be a root span.
+func RPCServerOption(client opentracing.SpanContext) opentracing.StartSpanOption {
+ return rpcServerOption{client}
+}
+
+// ---
+
+type stringTagName string
+
+// Set adds a string tag to the `span`
+func (tag stringTagName) Set(span opentracing.Span, value string) {
+ span.SetTag(string(tag), value)
+}
+
+// ---
+
+type uint32TagName string
+
+// Set adds a uint32 tag to the `span`
+func (tag uint32TagName) Set(span opentracing.Span, value uint32) {
+ span.SetTag(string(tag), value)
+}
+
+// ---
+
+type uint16TagName string
+
+// Set adds a uint16 tag to the `span`
+func (tag uint16TagName) Set(span opentracing.Span, value uint16) {
+ span.SetTag(string(tag), value)
+}
+
+// ---
+
+type boolTagName string
+
+// Add adds a bool tag to the `span`
+func (tag boolTagName) Set(span opentracing.Span, value bool) {
+ span.SetTag(string(tag), value)
+}
+
+type ipv4Tag string
+
+// Set adds IP v4 host address of the peer as an uint32 value to the `span`, keep this for backward and zipkin compatibility
+func (tag ipv4Tag) Set(span opentracing.Span, value uint32) {
+ span.SetTag(string(tag), value)
+}
+
+// SetString records IP v4 host address of the peer as a .-separated tuple to the `span`. E.g., "127.0.0.1"
+func (tag ipv4Tag) SetString(span opentracing.Span, value string) {
+ span.SetTag(string(tag), value)
+}
diff --git a/vendor/github.com/opentracing/opentracing-go/globaltracer.go b/vendor/github.com/opentracing/opentracing-go/globaltracer.go
new file mode 100644
index 0000000..4f7066a
--- /dev/null
+++ b/vendor/github.com/opentracing/opentracing-go/globaltracer.go
@@ -0,0 +1,42 @@
+package opentracing
+
+type registeredTracer struct {
+ tracer Tracer
+ isRegistered bool
+}
+
+var (
+ globalTracer = registeredTracer{NoopTracer{}, false}
+)
+
+// SetGlobalTracer sets the [singleton] opentracing.Tracer returned by
+// GlobalTracer(). Those who use GlobalTracer (rather than directly manage an
+// opentracing.Tracer instance) should call SetGlobalTracer as early as
+// possible in main(), prior to calling the `StartSpan` global func below.
+// Prior to calling `SetGlobalTracer`, any Spans started via the `StartSpan`
+// (etc) globals are noops.
+func SetGlobalTracer(tracer Tracer) {
+ globalTracer = registeredTracer{tracer, true}
+}
+
+// GlobalTracer returns the global singleton `Tracer` implementation.
+// Before `SetGlobalTracer()` is called, the `GlobalTracer()` is a noop
+// implementation that drops all data handed to it.
+func GlobalTracer() Tracer {
+ return globalTracer.tracer
+}
+
+// StartSpan defers to `Tracer.StartSpan`. See `GlobalTracer()`.
+func StartSpan(operationName string, opts ...StartSpanOption) Span {
+ return globalTracer.tracer.StartSpan(operationName, opts...)
+}
+
+// InitGlobalTracer is deprecated. Please use SetGlobalTracer.
+func InitGlobalTracer(tracer Tracer) {
+ SetGlobalTracer(tracer)
+}
+
+// IsGlobalTracerRegistered returns a `bool` to indicate if a tracer has been globally registered
+func IsGlobalTracerRegistered() bool {
+ return globalTracer.isRegistered
+}
diff --git a/vendor/github.com/opentracing/opentracing-go/gocontext.go b/vendor/github.com/opentracing/opentracing-go/gocontext.go
new file mode 100644
index 0000000..08c00c0
--- /dev/null
+++ b/vendor/github.com/opentracing/opentracing-go/gocontext.go
@@ -0,0 +1,60 @@
+package opentracing
+
+import "context"
+
+type contextKey struct{}
+
+var activeSpanKey = contextKey{}
+
+// ContextWithSpan returns a new `context.Context` that holds a reference to
+// `span`'s SpanContext.
+func ContextWithSpan(ctx context.Context, span Span) context.Context {
+ return context.WithValue(ctx, activeSpanKey, span)
+}
+
+// SpanFromContext returns the `Span` previously associated with `ctx`, or
+// `nil` if no such `Span` could be found.
+//
+// NOTE: context.Context != SpanContext: the former is Go's intra-process
+// context propagation mechanism, and the latter houses OpenTracing's per-Span
+// identity and baggage information.
+func SpanFromContext(ctx context.Context) Span {
+ val := ctx.Value(activeSpanKey)
+ if sp, ok := val.(Span); ok {
+ return sp
+ }
+ return nil
+}
+
+// StartSpanFromContext starts and returns a Span with `operationName`, using
+// any Span found within `ctx` as a ChildOfRef. If no such parent could be
+// found, StartSpanFromContext creates a root (parentless) Span.
+//
+// The second return value is a context.Context object built around the
+// returned Span.
+//
+// Example usage:
+//
+// SomeFunction(ctx context.Context, ...) {
+// sp, ctx := opentracing.StartSpanFromContext(ctx, "SomeFunction")
+// defer sp.Finish()
+// ...
+// }
+func StartSpanFromContext(ctx context.Context, operationName string, opts ...StartSpanOption) (Span, context.Context) {
+ return StartSpanFromContextWithTracer(ctx, GlobalTracer(), operationName, opts...)
+}
+
+// StartSpanFromContextWithTracer starts and returns a span with `operationName`
+// using a span found within the context as a ChildOfRef. If that doesn't exist
+// it creates a root span. It also returns a context.Context object built
+// around the returned span.
+//
+// It's behavior is identical to StartSpanFromContext except that it takes an explicit
+// tracer as opposed to using the global tracer.
+func StartSpanFromContextWithTracer(ctx context.Context, tracer Tracer, operationName string, opts ...StartSpanOption) (Span, context.Context) {
+ if parentSpan := SpanFromContext(ctx); parentSpan != nil {
+ opts = append(opts, ChildOf(parentSpan.Context()))
+ }
+ span := tracer.StartSpan(operationName, opts...)
+ return span, ContextWithSpan(ctx, span)
+}
diff --git a/vendor/github.com/opentracing/opentracing-go/log/field.go b/vendor/github.com/opentracing/opentracing-go/log/field.go
new file mode 100644
index 0000000..50feea3
--- /dev/null
+++ b/vendor/github.com/opentracing/opentracing-go/log/field.go
@@ -0,0 +1,269 @@
+package log
+
+import (
+ "fmt"
+ "math"
+)
+
+type fieldType int
+
+const (
+ stringType fieldType = iota
+ boolType
+ intType
+ int32Type
+ uint32Type
+ int64Type
+ uint64Type
+ float32Type
+ float64Type
+ errorType
+ objectType
+ lazyLoggerType
+ noopType
+)
+
+// Field instances are constructed via LogBool, LogString, and so on.
+// Tracing implementations may then handle them via the Field.Marshal
+// method.
+//
+// "heavily influenced by" (i.e., partially stolen from)
+// https://github.com/uber-go/zap
+type Field struct {
+ key string
+ fieldType fieldType
+ numericVal int64
+ stringVal string
+ interfaceVal interface{}
+}
+
+// String adds a string-valued key:value pair to a Span.LogFields() record
+func String(key, val string) Field {
+ return Field{
+ key: key,
+ fieldType: stringType,
+ stringVal: val,
+ }
+}
+
+// Bool adds a bool-valued key:value pair to a Span.LogFields() record
+func Bool(key string, val bool) Field {
+ var numericVal int64
+ if val {
+ numericVal = 1
+ }
+ return Field{
+ key: key,
+ fieldType: boolType,
+ numericVal: numericVal,
+ }
+}
+
+// Int adds an int-valued key:value pair to a Span.LogFields() record
+func Int(key string, val int) Field {
+ return Field{
+ key: key,
+ fieldType: intType,
+ numericVal: int64(val),
+ }
+}
+
+// Int32 adds an int32-valued key:value pair to a Span.LogFields() record
+func Int32(key string, val int32) Field {
+ return Field{
+ key: key,
+ fieldType: int32Type,
+ numericVal: int64(val),
+ }
+}
+
+// Int64 adds an int64-valued key:value pair to a Span.LogFields() record
+func Int64(key string, val int64) Field {
+ return Field{
+ key: key,
+ fieldType: int64Type,
+ numericVal: val,
+ }
+}
+
+// Uint32 adds a uint32-valued key:value pair to a Span.LogFields() record
+func Uint32(key string, val uint32) Field {
+ return Field{
+ key: key,
+ fieldType: uint32Type,
+ numericVal: int64(val),
+ }
+}
+
+// Uint64 adds a uint64-valued key:value pair to a Span.LogFields() record
+func Uint64(key string, val uint64) Field {
+ return Field{
+ key: key,
+ fieldType: uint64Type,
+ numericVal: int64(val),
+ }
+}
+
+// Float32 adds a float32-valued key:value pair to a Span.LogFields() record
+func Float32(key string, val float32) Field {
+ return Field{
+ key: key,
+ fieldType: float32Type,
+ numericVal: int64(math.Float32bits(val)),
+ }
+}
+
+// Float64 adds a float64-valued key:value pair to a Span.LogFields() record
+func Float64(key string, val float64) Field {
+ return Field{
+ key: key,
+ fieldType: float64Type,
+ numericVal: int64(math.Float64bits(val)),
+ }
+}
+
+// Error adds an error with the key "error" to a Span.LogFields() record
+func Error(err error) Field {
+ return Field{
+ key: "error",
+ fieldType: errorType,
+ interfaceVal: err,
+ }
+}
+
+// Object adds an object-valued key:value pair to a Span.LogFields() record
+func Object(key string, obj interface{}) Field {
+ return Field{
+ key: key,
+ fieldType: objectType,
+ interfaceVal: obj,
+ }
+}
+
+// LazyLogger allows for user-defined, late-bound logging of arbitrary data
+type LazyLogger func(fv Encoder)
+
+// Lazy adds a LazyLogger to a Span.LogFields() record; the tracing
+// implementation will call the LazyLogger function at an indefinite time in
+// the future (after Lazy() returns).
+func Lazy(ll LazyLogger) Field {
+ return Field{
+ fieldType: lazyLoggerType,
+ interfaceVal: ll,
+ }
+}
+
+// Noop creates a no-op log field that should be ignored by the tracer.
+// It can be used to capture optional fields, for example those that should
+// only be logged in non-production environment:
+//
+// func customerField(order *Order) log.Field {
+// if os.Getenv("ENVIRONMENT") == "dev" {
+// return log.String("customer", order.Customer.ID)
+// }
+// return log.Noop()
+// }
+//
+// span.LogFields(log.String("event", "purchase"), customerField(order))
+//
+func Noop() Field {
+ return Field{
+ fieldType: noopType,
+ }
+}
+
+// Encoder allows access to the contents of a Field (via a call to
+// Field.Marshal).
+//
+// Tracer implementations typically provide an implementation of Encoder;
+// OpenTracing callers typically do not need to concern themselves with it.
+type Encoder interface {
+ EmitString(key, value string)
+ EmitBool(key string, value bool)
+ EmitInt(key string, value int)
+ EmitInt32(key string, value int32)
+ EmitInt64(key string, value int64)
+ EmitUint32(key string, value uint32)
+ EmitUint64(key string, value uint64)
+ EmitFloat32(key string, value float32)
+ EmitFloat64(key string, value float64)
+ EmitObject(key string, value interface{})
+ EmitLazyLogger(value LazyLogger)
+}
+
+// Marshal passes a Field instance through to the appropriate
+// field-type-specific method of an Encoder.
+func (lf Field) Marshal(visitor Encoder) {
+ switch lf.fieldType {
+ case stringType:
+ visitor.EmitString(lf.key, lf.stringVal)
+ case boolType:
+ visitor.EmitBool(lf.key, lf.numericVal != 0)
+ case intType:
+ visitor.EmitInt(lf.key, int(lf.numericVal))
+ case int32Type:
+ visitor.EmitInt32(lf.key, int32(lf.numericVal))
+ case int64Type:
+ visitor.EmitInt64(lf.key, int64(lf.numericVal))
+ case uint32Type:
+ visitor.EmitUint32(lf.key, uint32(lf.numericVal))
+ case uint64Type:
+ visitor.EmitUint64(lf.key, uint64(lf.numericVal))
+ case float32Type:
+ visitor.EmitFloat32(lf.key, math.Float32frombits(uint32(lf.numericVal)))
+ case float64Type:
+ visitor.EmitFloat64(lf.key, math.Float64frombits(uint64(lf.numericVal)))
+ case errorType:
+ if err, ok := lf.interfaceVal.(error); ok {
+ visitor.EmitString(lf.key, err.Error())
+ } else {
+ visitor.EmitString(lf.key, "")
+ }
+ case objectType:
+ visitor.EmitObject(lf.key, lf.interfaceVal)
+ case lazyLoggerType:
+ visitor.EmitLazyLogger(lf.interfaceVal.(LazyLogger))
+ case noopType:
+ // intentionally left blank
+ }
+}
+
+// Key returns the field's key.
+func (lf Field) Key() string {
+ return lf.key
+}
+
+// Value returns the field's value as interface{}.
+func (lf Field) Value() interface{} {
+ switch lf.fieldType {
+ case stringType:
+ return lf.stringVal
+ case boolType:
+ return lf.numericVal != 0
+ case intType:
+ return int(lf.numericVal)
+ case int32Type:
+ return int32(lf.numericVal)
+ case int64Type:
+ return int64(lf.numericVal)
+ case uint32Type:
+ return uint32(lf.numericVal)
+ case uint64Type:
+ return uint64(lf.numericVal)
+ case float32Type:
+ return math.Float32frombits(uint32(lf.numericVal))
+ case float64Type:
+ return math.Float64frombits(uint64(lf.numericVal))
+ case errorType, objectType, lazyLoggerType:
+ return lf.interfaceVal
+ case noopType:
+ return nil
+ default:
+ return nil
+ }
+}
+
+// String returns a string representation of the key and value.
+func (lf Field) String() string {
+ return fmt.Sprint(lf.key, ":", lf.Value())
+}
diff --git a/vendor/github.com/opentracing/opentracing-go/log/util.go b/vendor/github.com/opentracing/opentracing-go/log/util.go
new file mode 100644
index 0000000..3832feb
--- /dev/null
+++ b/vendor/github.com/opentracing/opentracing-go/log/util.go
@@ -0,0 +1,54 @@
+package log
+
+import "fmt"
+
+// InterleavedKVToFields converts keyValues a la Span.LogKV() to a Field slice
+// a la Span.LogFields().
+func InterleavedKVToFields(keyValues ...interface{}) ([]Field, error) {
+ if len(keyValues)%2 != 0 {
+ return nil, fmt.Errorf("non-even keyValues len: %d", len(keyValues))
+ }
+ fields := make([]Field, len(keyValues)/2)
+ for i := 0; i*2 < len(keyValues); i++ {
+ key, ok := keyValues[i*2].(string)
+ if !ok {
+ return nil, fmt.Errorf(
+ "non-string key (pair #%d): %T",
+ i, keyValues[i*2])
+ }
+ switch typedVal := keyValues[i*2+1].(type) {
+ case bool:
+ fields[i] = Bool(key, typedVal)
+ case string:
+ fields[i] = String(key, typedVal)
+ case int:
+ fields[i] = Int(key, typedVal)
+ case int8:
+ fields[i] = Int32(key, int32(typedVal))
+ case int16:
+ fields[i] = Int32(key, int32(typedVal))
+ case int32:
+ fields[i] = Int32(key, typedVal)
+ case int64:
+ fields[i] = Int64(key, typedVal)
+ case uint:
+ fields[i] = Uint64(key, uint64(typedVal))
+ case uint64:
+ fields[i] = Uint64(key, typedVal)
+ case uint8:
+ fields[i] = Uint32(key, uint32(typedVal))
+ case uint16:
+ fields[i] = Uint32(key, uint32(typedVal))
+ case uint32:
+ fields[i] = Uint32(key, typedVal)
+ case float32:
+ fields[i] = Float32(key, typedVal)
+ case float64:
+ fields[i] = Float64(key, typedVal)
+ default:
+ // When in doubt, coerce to a string
+ fields[i] = String(key, fmt.Sprint(typedVal))
+ }
+ }
+ return fields, nil
+}
diff --git a/vendor/github.com/opentracing/opentracing-go/noop.go b/vendor/github.com/opentracing/opentracing-go/noop.go
new file mode 100644
index 0000000..0d32f69
--- /dev/null
+++ b/vendor/github.com/opentracing/opentracing-go/noop.go
@@ -0,0 +1,64 @@
+package opentracing
+
+import "github.com/opentracing/opentracing-go/log"
+
+// A NoopTracer is a trivial, minimum overhead implementation of Tracer
+// for which all operations are no-ops.
+//
+// The primary use of this implementation is in libraries, such as RPC
+// frameworks, that make tracing an optional feature controlled by the
+// end user. A no-op implementation allows said libraries to use it
+// as the default Tracer and to write instrumentation that does
+// not need to keep checking if the tracer instance is nil.
+//
+// For the same reason, the NoopTracer is the default "global" tracer
+// (see GlobalTracer and SetGlobalTracer functions).
+//
+// WARNING: NoopTracer does not support baggage propagation.
+type NoopTracer struct{}
+
+type noopSpan struct{}
+type noopSpanContext struct{}
+
+var (
+ defaultNoopSpanContext = noopSpanContext{}
+ defaultNoopSpan = noopSpan{}
+ defaultNoopTracer = NoopTracer{}
+)
+
+const (
+ emptyString = ""
+)
+
+// noopSpanContext:
+func (n noopSpanContext) ForeachBaggageItem(handler func(k, v string) bool) {}
+
+// noopSpan:
+func (n noopSpan) Context() SpanContext { return defaultNoopSpanContext }
+func (n noopSpan) SetBaggageItem(key, val string) Span { return defaultNoopSpan }
+func (n noopSpan) BaggageItem(key string) string { return emptyString }
+func (n noopSpan) SetTag(key string, value interface{}) Span { return n }
+func (n noopSpan) LogFields(fields ...log.Field) {}
+func (n noopSpan) LogKV(keyVals ...interface{}) {}
+func (n noopSpan) Finish() {}
+func (n noopSpan) FinishWithOptions(opts FinishOptions) {}
+func (n noopSpan) SetOperationName(operationName string) Span { return n }
+func (n noopSpan) Tracer() Tracer { return defaultNoopTracer }
+func (n noopSpan) LogEvent(event string) {}
+func (n noopSpan) LogEventWithPayload(event string, payload interface{}) {}
+func (n noopSpan) Log(data LogData) {}
+
+// StartSpan belongs to the Tracer interface.
+func (n NoopTracer) StartSpan(operationName string, opts ...StartSpanOption) Span {
+ return defaultNoopSpan
+}
+
+// Inject belongs to the Tracer interface.
+func (n NoopTracer) Inject(sp SpanContext, format interface{}, carrier interface{}) error {
+ return nil
+}
+
+// Extract belongs to the Tracer interface.
+func (n NoopTracer) Extract(format interface{}, carrier interface{}) (SpanContext, error) {
+ return nil, ErrSpanContextNotFound
+}
diff --git a/vendor/github.com/opentracing/opentracing-go/propagation.go b/vendor/github.com/opentracing/opentracing-go/propagation.go
new file mode 100644
index 0000000..b0c275e
--- /dev/null
+++ b/vendor/github.com/opentracing/opentracing-go/propagation.go
@@ -0,0 +1,176 @@
+package opentracing
+
+import (
+ "errors"
+ "net/http"
+)
+
+///////////////////////////////////////////////////////////////////////////////
+// CORE PROPAGATION INTERFACES:
+///////////////////////////////////////////////////////////////////////////////
+
+var (
+ // ErrUnsupportedFormat occurs when the `format` passed to Tracer.Inject() or
+ // Tracer.Extract() is not recognized by the Tracer implementation.
+ ErrUnsupportedFormat = errors.New("opentracing: Unknown or unsupported Inject/Extract format")
+
+ // ErrSpanContextNotFound occurs when the `carrier` passed to
+ // Tracer.Extract() is valid and uncorrupted but has insufficient
+ // information to extract a SpanContext.
+ ErrSpanContextNotFound = errors.New("opentracing: SpanContext not found in Extract carrier")
+
+ // ErrInvalidSpanContext errors occur when Tracer.Inject() is asked to
+ // operate on a SpanContext which it is not prepared to handle (for
+ // example, since it was created by a different tracer implementation).
+ ErrInvalidSpanContext = errors.New("opentracing: SpanContext type incompatible with tracer")
+
+ // ErrInvalidCarrier errors occur when Tracer.Inject() or Tracer.Extract()
+ // implementations expect a different type of `carrier` than they are
+ // given.
+ ErrInvalidCarrier = errors.New("opentracing: Invalid Inject/Extract carrier")
+
+ // ErrSpanContextCorrupted occurs when the `carrier` passed to
+ // Tracer.Extract() is of the expected type but is corrupted.
+ ErrSpanContextCorrupted = errors.New("opentracing: SpanContext data corrupted in Extract carrier")
+)
+
+///////////////////////////////////////////////////////////////////////////////
+// BUILTIN PROPAGATION FORMATS:
+///////////////////////////////////////////////////////////////////////////////
+
+// BuiltinFormat is used to demarcate the values within package `opentracing`
+// that are intended for use with the Tracer.Inject() and Tracer.Extract()
+// methods.
+type BuiltinFormat byte
+
+const (
+ // Binary represents SpanContexts as opaque binary data.
+ //
+ // For Tracer.Inject(): the carrier must be an `io.Writer`.
+ //
+ // For Tracer.Extract(): the carrier must be an `io.Reader`.
+ Binary BuiltinFormat = iota
+
+ // TextMap represents SpanContexts as key:value string pairs.
+ //
+ // Unlike HTTPHeaders, the TextMap format does not restrict the key or
+ // value character sets in any way.
+ //
+ // For Tracer.Inject(): the carrier must be a `TextMapWriter`.
+ //
+ // For Tracer.Extract(): the carrier must be a `TextMapReader`.
+ TextMap
+
+ // HTTPHeaders represents SpanContexts as HTTP header string pairs.
+ //
+ // Unlike TextMap, the HTTPHeaders format requires that the keys and values
+ // be valid as HTTP headers as-is (i.e., character casing may be unstable
+ // and special characters are disallowed in keys, values should be
+ // URL-escaped, etc).
+ //
+ // For Tracer.Inject(): the carrier must be a `TextMapWriter`.
+ //
+ // For Tracer.Extract(): the carrier must be a `TextMapReader`.
+ //
+ // See HTTPHeadersCarrier for an implementation of both TextMapWriter
+ // and TextMapReader that defers to an http.Header instance for storage.
+ // For example, Inject():
+ //
+ // carrier := opentracing.HTTPHeadersCarrier(httpReq.Header)
+ // err := span.Tracer().Inject(
+ // span.Context(), opentracing.HTTPHeaders, carrier)
+ //
+ // Or Extract():
+ //
+ // carrier := opentracing.HTTPHeadersCarrier(httpReq.Header)
+ // clientContext, err := tracer.Extract(
+ // opentracing.HTTPHeaders, carrier)
+ //
+ HTTPHeaders
+)
+
+// TextMapWriter is the Inject() carrier for the TextMap builtin format. With
+// it, the caller can encode a SpanContext for propagation as entries in a map
+// of unicode strings.
+type TextMapWriter interface {
+ // Set a key:value pair to the carrier. Multiple calls to Set() for the
+ // same key leads to undefined behavior.
+ //
+ // NOTE: The backing store for the TextMapWriter may contain data unrelated
+ // to SpanContext. As such, Inject() and Extract() implementations that
+ // call the TextMapWriter and TextMapReader interfaces must agree on a
+ // prefix or other convention to distinguish their own key:value pairs.
+ Set(key, val string)
+}
+
+// TextMapReader is the Extract() carrier for the TextMap builtin format. With it,
+// the caller can decode a propagated SpanContext as entries in a map of
+// unicode strings.
+type TextMapReader interface {
+ // ForeachKey returns TextMap contents via repeated calls to the `handler`
+ // function. If any call to `handler` returns a non-nil error, ForeachKey
+ // terminates and returns that error.
+ //
+ // NOTE: The backing store for the TextMapReader may contain data unrelated
+ // to SpanContext. As such, Inject() and Extract() implementations that
+ // call the TextMapWriter and TextMapReader interfaces must agree on a
+ // prefix or other convention to distinguish their own key:value pairs.
+ //
+ // The "foreach" callback pattern reduces unnecessary copying in some cases
+ // and also allows implementations to hold locks while the map is read.
+ ForeachKey(handler func(key, val string) error) error
+}
+
+// TextMapCarrier allows the use of regular map[string]string
+// as both TextMapWriter and TextMapReader.
+type TextMapCarrier map[string]string
+
+// ForeachKey conforms to the TextMapReader interface.
+func (c TextMapCarrier) ForeachKey(handler func(key, val string) error) error {
+ for k, v := range c {
+ if err := handler(k, v); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// Set implements Set() of opentracing.TextMapWriter
+func (c TextMapCarrier) Set(key, val string) {
+ c[key] = val
+}
+
+// HTTPHeadersCarrier satisfies both TextMapWriter and TextMapReader.
+//
+// Example usage for server side:
+//
+// carrier := opentracing.HTTPHeadersCarrier(httpReq.Header)
+// clientContext, err := tracer.Extract(opentracing.HTTPHeaders, carrier)
+//
+// Example usage for client side:
+//
+// carrier := opentracing.HTTPHeadersCarrier(httpReq.Header)
+// err := tracer.Inject(
+// span.Context(),
+// opentracing.HTTPHeaders,
+// carrier)
+//
+type HTTPHeadersCarrier http.Header
+
+// Set conforms to the TextMapWriter interface.
+func (c HTTPHeadersCarrier) Set(key, val string) {
+ h := http.Header(c)
+ h.Set(key, val)
+}
+
+// ForeachKey conforms to the TextMapReader interface.
+func (c HTTPHeadersCarrier) ForeachKey(handler func(key, val string) error) error {
+ for k, vals := range c {
+ for _, v := range vals {
+ if err := handler(k, v); err != nil {
+ return err
+ }
+ }
+ }
+ return nil
+}
diff --git a/vendor/github.com/opentracing/opentracing-go/span.go b/vendor/github.com/opentracing/opentracing-go/span.go
new file mode 100644
index 0000000..0d3fb53
--- /dev/null
+++ b/vendor/github.com/opentracing/opentracing-go/span.go
@@ -0,0 +1,189 @@
+package opentracing
+
+import (
+ "time"
+
+ "github.com/opentracing/opentracing-go/log"
+)
+
+// SpanContext represents Span state that must propagate to descendant Spans and across process
+// boundaries (e.g., a tuple).
+type SpanContext interface {
+ // ForeachBaggageItem grants access to all baggage items stored in the
+ // SpanContext.
+ // The handler function will be called for each baggage key/value pair.
+ // The ordering of items is not guaranteed.
+ //
+ // The bool return value indicates if the handler wants to continue iterating
+ // through the rest of the baggage items; for example if the handler is trying to
+ // find some baggage item by pattern matching the name, it can return false
+ // as soon as the item is found to stop further iterations.
+ ForeachBaggageItem(handler func(k, v string) bool)
+}
+
+// Span represents an active, un-finished span in the OpenTracing system.
+//
+// Spans are created by the Tracer interface.
+type Span interface {
+ // Sets the end timestamp and finalizes Span state.
+ //
+ // With the exception of calls to Context() (which are always allowed),
+ // Finish() must be the last call made to any span instance, and to do
+ // otherwise leads to undefined behavior.
+ Finish()
+ // FinishWithOptions is like Finish() but with explicit control over
+ // timestamps and log data.
+ FinishWithOptions(opts FinishOptions)
+
+ // Context() yields the SpanContext for this Span. Note that the return
+ // value of Context() is still valid after a call to Span.Finish(), as is
+ // a call to Span.Context() after a call to Span.Finish().
+ Context() SpanContext
+
+ // Sets or changes the operation name.
+ //
+ // Returns a reference to this Span for chaining.
+ SetOperationName(operationName string) Span
+
+ // Adds a tag to the span.
+ //
+ // If there is a pre-existing tag set for `key`, it is overwritten.
+ //
+ // Tag values can be numeric types, strings, or bools. The behavior of
+ // other tag value types is undefined at the OpenTracing level. If a
+ // tracing system does not know how to handle a particular value type, it
+ // may ignore the tag, but shall not panic.
+ //
+ // Returns a reference to this Span for chaining.
+ SetTag(key string, value interface{}) Span
+
+ // LogFields is an efficient and type-checked way to record key:value
+ // logging data about a Span, though the programming interface is a little
+ // more verbose than LogKV(). Here's an example:
+ //
+ // span.LogFields(
+ // log.String("event", "soft error"),
+ // log.String("type", "cache timeout"),
+ // log.Int("waited.millis", 1500))
+ //
+ // Also see Span.FinishWithOptions() and FinishOptions.BulkLogData.
+ LogFields(fields ...log.Field)
+
+ // LogKV is a concise, readable way to record key:value logging data about
+ // a Span, though unfortunately this also makes it less efficient and less
+ // type-safe than LogFields(). Here's an example:
+ //
+ // span.LogKV(
+ // "event", "soft error",
+ // "type", "cache timeout",
+ // "waited.millis", 1500)
+ //
+ // For LogKV (as opposed to LogFields()), the parameters must appear as
+ // key-value pairs, like
+ //
+ // span.LogKV(key1, val1, key2, val2, key3, val3, ...)
+ //
+ // The keys must all be strings. The values may be strings, numeric types,
+ // bools, Go error instances, or arbitrary structs.
+ //
+ // (Note to implementors: consider the log.InterleavedKVToFields() helper)
+ LogKV(alternatingKeyValues ...interface{})
+
+ // SetBaggageItem sets a key:value pair on this Span and its SpanContext
+ // that also propagates to descendants of this Span.
+ //
+ // SetBaggageItem() enables powerful functionality given a full-stack
+ // opentracing integration (e.g., arbitrary application data from a mobile
+ // app can make it, transparently, all the way into the depths of a storage
+ // system), and with it some powerful costs: use this feature with care.
+ //
+ // IMPORTANT NOTE #1: SetBaggageItem() will only propagate baggage items to
+ // *future* causal descendants of the associated Span.
+ //
+ // IMPORTANT NOTE #2: Use this thoughtfully and with care. Every key and
+ // value is copied into every local *and remote* child of the associated
+ // Span, and that can add up to a lot of network and cpu overhead.
+ //
+ // Returns a reference to this Span for chaining.
+ SetBaggageItem(restrictedKey, value string) Span
+
+ // Gets the value for a baggage item given its key. Returns the empty string
+ // if the value isn't found in this Span.
+ BaggageItem(restrictedKey string) string
+
+ // Provides access to the Tracer that created this Span.
+ Tracer() Tracer
+
+ // Deprecated: use LogFields or LogKV
+ LogEvent(event string)
+ // Deprecated: use LogFields or LogKV
+ LogEventWithPayload(event string, payload interface{})
+ // Deprecated: use LogFields or LogKV
+ Log(data LogData)
+}
+
+// LogRecord is data associated with a single Span log. Every LogRecord
+// instance must specify at least one Field.
+type LogRecord struct {
+ Timestamp time.Time
+ Fields []log.Field
+}
+
+// FinishOptions allows Span.FinishWithOptions callers to override the finish
+// timestamp and provide log data via a bulk interface.
+type FinishOptions struct {
+ // FinishTime overrides the Span's finish time, or implicitly becomes
+ // time.Now() if FinishTime.IsZero().
+ //
+ // FinishTime must resolve to a timestamp that's >= the Span's StartTime
+ // (per StartSpanOptions).
+ FinishTime time.Time
+
+ // LogRecords allows the caller to specify the contents of many LogFields()
+ // calls with a single slice. May be nil.
+ //
+ // None of the LogRecord.Timestamp values may be .IsZero() (i.e., they must
+ // be set explicitly). Also, they must be >= the Span's start timestamp and
+ // <= the FinishTime (or time.Now() if FinishTime.IsZero()). Otherwise the
+ // behavior of FinishWithOptions() is undefined.
+ //
+ // If specified, the caller hands off ownership of LogRecords at
+ // FinishWithOptions() invocation time.
+ //
+ // If specified, the (deprecated) BulkLogData must be nil or empty.
+ LogRecords []LogRecord
+
+ // BulkLogData is DEPRECATED.
+ BulkLogData []LogData
+}
+
+// LogData is DEPRECATED
+type LogData struct {
+ Timestamp time.Time
+ Event string
+ Payload interface{}
+}
+
+// ToLogRecord converts a deprecated LogData to a non-deprecated LogRecord
+func (ld *LogData) ToLogRecord() LogRecord {
+ var literalTimestamp time.Time
+ if ld.Timestamp.IsZero() {
+ literalTimestamp = time.Now()
+ } else {
+ literalTimestamp = ld.Timestamp
+ }
+ rval := LogRecord{
+ Timestamp: literalTimestamp,
+ }
+ if ld.Payload == nil {
+ rval.Fields = []log.Field{
+ log.String("event", ld.Event),
+ }
+ } else {
+ rval.Fields = []log.Field{
+ log.String("event", ld.Event),
+ log.Object("payload", ld.Payload),
+ }
+ }
+ return rval
+}
diff --git a/vendor/github.com/opentracing/opentracing-go/tracer.go b/vendor/github.com/opentracing/opentracing-go/tracer.go
new file mode 100644
index 0000000..715f0ce
--- /dev/null
+++ b/vendor/github.com/opentracing/opentracing-go/tracer.go
@@ -0,0 +1,304 @@
+package opentracing
+
+import "time"
+
+// Tracer is a simple, thin interface for Span creation and SpanContext
+// propagation.
+type Tracer interface {
+
+ // Create, start, and return a new Span with the given `operationName` and
+ // incorporate the given StartSpanOption `opts`. (Note that `opts` borrows
+ // from the "functional options" pattern, per
+ // http://dave.cheney.net/2014/10/17/functional-options-for-friendly-apis)
+ //
+ // A Span with no SpanReference options (e.g., opentracing.ChildOf() or
+ // opentracing.FollowsFrom()) becomes the root of its own trace.
+ //
+ // Examples:
+ //
+ // var tracer opentracing.Tracer = ...
+ //
+ // // The root-span case:
+ // sp := tracer.StartSpan("GetFeed")
+ //
+ // // The vanilla child span case:
+ // sp := tracer.StartSpan(
+ // "GetFeed",
+ // opentracing.ChildOf(parentSpan.Context()))
+ //
+ // // All the bells and whistles:
+ // sp := tracer.StartSpan(
+ // "GetFeed",
+ // opentracing.ChildOf(parentSpan.Context()),
+ // opentracing.Tag{"user_agent", loggedReq.UserAgent},
+ // opentracing.StartTime(loggedReq.Timestamp),
+ // )
+ //
+ StartSpan(operationName string, opts ...StartSpanOption) Span
+
+ // Inject() takes the `sm` SpanContext instance and injects it for
+ // propagation within `carrier`. The actual type of `carrier` depends on
+ // the value of `format`.
+ //
+ // OpenTracing defines a common set of `format` values (see BuiltinFormat),
+ // and each has an expected carrier type.
+ //
+ // Other packages may declare their own `format` values, much like the keys
+ // used by `context.Context` (see https://godoc.org/context#WithValue).
+ //
+ // Example usage (sans error handling):
+ //
+ // carrier := opentracing.HTTPHeadersCarrier(httpReq.Header)
+ // err := tracer.Inject(
+ // span.Context(),
+ // opentracing.HTTPHeaders,
+ // carrier)
+ //
+ // NOTE: All opentracing.Tracer implementations MUST support all
+ // BuiltinFormats.
+ //
+ // Implementations may return opentracing.ErrUnsupportedFormat if `format`
+ // is not supported by (or not known by) the implementation.
+ //
+ // Implementations may return opentracing.ErrInvalidCarrier or any other
+ // implementation-specific error if the format is supported but injection
+ // fails anyway.
+ //
+ // See Tracer.Extract().
+ Inject(sm SpanContext, format interface{}, carrier interface{}) error
+
+ // Extract() returns a SpanContext instance given `format` and `carrier`.
+ //
+ // OpenTracing defines a common set of `format` values (see BuiltinFormat),
+ // and each has an expected carrier type.
+ //
+ // Other packages may declare their own `format` values, much like the keys
+ // used by `context.Context` (see
+ // https://godoc.org/golang.org/x/net/context#WithValue).
+ //
+ // Example usage (with StartSpan):
+ //
+ //
+ // carrier := opentracing.HTTPHeadersCarrier(httpReq.Header)
+ // clientContext, err := tracer.Extract(opentracing.HTTPHeaders, carrier)
+ //
+ // // ... assuming the ultimate goal here is to resume the trace with a
+ // // server-side Span:
+ // var serverSpan opentracing.Span
+ // if err == nil {
+ // span = tracer.StartSpan(
+ // rpcMethodName, ext.RPCServerOption(clientContext))
+ // } else {
+ // span = tracer.StartSpan(rpcMethodName)
+ // }
+ //
+ //
+ // NOTE: All opentracing.Tracer implementations MUST support all
+ // BuiltinFormats.
+ //
+ // Return values:
+ // - A successful Extract returns a SpanContext instance and a nil error
+ // - If there was simply no SpanContext to extract in `carrier`, Extract()
+ // returns (nil, opentracing.ErrSpanContextNotFound)
+ // - If `format` is unsupported or unrecognized, Extract() returns (nil,
+ // opentracing.ErrUnsupportedFormat)
+ // - If there are more fundamental problems with the `carrier` object,
+ // Extract() may return opentracing.ErrInvalidCarrier,
+ // opentracing.ErrSpanContextCorrupted, or implementation-specific
+ // errors.
+ //
+ // See Tracer.Inject().
+ Extract(format interface{}, carrier interface{}) (SpanContext, error)
+}
+
+// StartSpanOptions allows Tracer.StartSpan() callers and implementors a
+// mechanism to override the start timestamp, specify Span References, and make
+// a single Tag or multiple Tags available at Span start time.
+//
+// StartSpan() callers should look at the StartSpanOption interface and
+// implementations available in this package.
+//
+// Tracer implementations can convert a slice of `StartSpanOption` instances
+// into a `StartSpanOptions` struct like so:
+//
+// func StartSpan(opName string, opts ...opentracing.StartSpanOption) {
+// sso := opentracing.StartSpanOptions{}
+// for _, o := range opts {
+// o.Apply(&sso)
+// }
+// ...
+// }
+//
+type StartSpanOptions struct {
+ // Zero or more causal references to other Spans (via their SpanContext).
+ // If empty, start a "root" Span (i.e., start a new trace).
+ References []SpanReference
+
+ // StartTime overrides the Span's start time, or implicitly becomes
+ // time.Now() if StartTime.IsZero().
+ StartTime time.Time
+
+ // Tags may have zero or more entries; the restrictions on map values are
+ // identical to those for Span.SetTag(). May be nil.
+ //
+ // If specified, the caller hands off ownership of Tags at
+ // StartSpan() invocation time.
+ Tags map[string]interface{}
+}
+
+// StartSpanOption instances (zero or more) may be passed to Tracer.StartSpan.
+//
+// StartSpanOption borrows from the "functional options" pattern, per
+// http://dave.cheney.net/2014/10/17/functional-options-for-friendly-apis
+type StartSpanOption interface {
+ Apply(*StartSpanOptions)
+}
+
+// SpanReferenceType is an enum type describing different categories of
+// relationships between two Spans. If Span-2 refers to Span-1, the
+// SpanReferenceType describes Span-1 from Span-2's perspective. For example,
+// ChildOfRef means that Span-1 created Span-2.
+//
+// NOTE: Span-1 and Span-2 do *not* necessarily depend on each other for
+// completion; e.g., Span-2 may be part of a background job enqueued by Span-1,
+// or Span-2 may be sitting in a distributed queue behind Span-1.
+type SpanReferenceType int
+
+const (
+ // ChildOfRef refers to a parent Span that caused *and* somehow depends
+ // upon the new child Span. Often (but not always), the parent Span cannot
+ // finish until the child Span does.
+ //
+ // An timing diagram for a ChildOfRef that's blocked on the new Span:
+ //
+ // [-Parent Span---------]
+ // [-Child Span----]
+ //
+ // See http://opentracing.io/spec/
+ //
+ // See opentracing.ChildOf()
+ ChildOfRef SpanReferenceType = iota
+
+ // FollowsFromRef refers to a parent Span that does not depend in any way
+ // on the result of the new child Span. For instance, one might use
+ // FollowsFromRefs to describe pipeline stages separated by queues,
+ // or a fire-and-forget cache insert at the tail end of a web request.
+ //
+ // A FollowsFromRef Span is part of the same logical trace as the new Span:
+ // i.e., the new Span is somehow caused by the work of its FollowsFromRef.
+ //
+ // All of the following could be valid timing diagrams for children that
+ // "FollowFrom" a parent.
+ //
+ // [-Parent Span-] [-Child Span-]
+ //
+ //
+ // [-Parent Span--]
+ // [-Child Span-]
+ //
+ //
+ // [-Parent Span-]
+ // [-Child Span-]
+ //
+ // See http://opentracing.io/spec/
+ //
+ // See opentracing.FollowsFrom()
+ FollowsFromRef
+)
+
+// SpanReference is a StartSpanOption that pairs a SpanReferenceType and a
+// referenced SpanContext. See the SpanReferenceType documentation for
+// supported relationships. If SpanReference is created with
+// ReferencedContext==nil, it has no effect. Thus it allows for a more concise
+// syntax for starting spans:
+//
+// sc, _ := tracer.Extract(someFormat, someCarrier)
+// span := tracer.StartSpan("operation", opentracing.ChildOf(sc))
+//
+// The `ChildOf(sc)` option above will not panic if sc == nil, it will just
+// not add the parent span reference to the options.
+type SpanReference struct {
+ Type SpanReferenceType
+ ReferencedContext SpanContext
+}
+
+// Apply satisfies the StartSpanOption interface.
+func (r SpanReference) Apply(o *StartSpanOptions) {
+ if r.ReferencedContext != nil {
+ o.References = append(o.References, r)
+ }
+}
+
+// ChildOf returns a StartSpanOption pointing to a dependent parent span.
+// If sc == nil, the option has no effect.
+//
+// See ChildOfRef, SpanReference
+func ChildOf(sc SpanContext) SpanReference {
+ return SpanReference{
+ Type: ChildOfRef,
+ ReferencedContext: sc,
+ }
+}
+
+// FollowsFrom returns a StartSpanOption pointing to a parent Span that caused
+// the child Span but does not directly depend on its result in any way.
+// If sc == nil, the option has no effect.
+//
+// See FollowsFromRef, SpanReference
+func FollowsFrom(sc SpanContext) SpanReference {
+ return SpanReference{
+ Type: FollowsFromRef,
+ ReferencedContext: sc,
+ }
+}
+
+// StartTime is a StartSpanOption that sets an explicit start timestamp for the
+// new Span.
+type StartTime time.Time
+
+// Apply satisfies the StartSpanOption interface.
+func (t StartTime) Apply(o *StartSpanOptions) {
+ o.StartTime = time.Time(t)
+}
+
+// Tags are a generic map from an arbitrary string key to an opaque value type.
+// The underlying tracing system is responsible for interpreting and
+// serializing the values.
+type Tags map[string]interface{}
+
+// Apply satisfies the StartSpanOption interface.
+func (t Tags) Apply(o *StartSpanOptions) {
+ if o.Tags == nil {
+ o.Tags = make(map[string]interface{})
+ }
+ for k, v := range t {
+ o.Tags[k] = v
+ }
+}
+
+// Tag may be passed as a StartSpanOption to add a tag to new spans,
+// or its Set method may be used to apply the tag to an existing Span,
+// for example:
+//
+// tracer.StartSpan("opName", Tag{"Key", value})
+//
+// or
+//
+// Tag{"key", value}.Set(span)
+type Tag struct {
+ Key string
+ Value interface{}
+}
+
+// Apply satisfies the StartSpanOption interface.
+func (t Tag) Apply(o *StartSpanOptions) {
+ if o.Tags == nil {
+ o.Tags = make(map[string]interface{})
+ }
+ o.Tags[t.Key] = t.Value
+}
+
+// Set applies the tag to an existing Span.
+func (t Tag) Set(s Span) {
+ s.SetTag(t.Key, t.Value)
+}
diff --git a/vendor/github.com/pmezard/go-difflib/LICENSE b/vendor/github.com/pmezard/go-difflib/LICENSE
new file mode 100644
index 0000000..c67dad6
--- /dev/null
+++ b/vendor/github.com/pmezard/go-difflib/LICENSE
@@ -0,0 +1,27 @@
+Copyright (c) 2013, Patrick Mezard
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+ The names of its contributors may not be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/vendor/github.com/pmezard/go-difflib/difflib/difflib.go b/vendor/github.com/pmezard/go-difflib/difflib/difflib.go
new file mode 100644
index 0000000..003e99f
--- /dev/null
+++ b/vendor/github.com/pmezard/go-difflib/difflib/difflib.go
@@ -0,0 +1,772 @@
+// Package difflib is a partial port of Python difflib module.
+//
+// It provides tools to compare sequences of strings and generate textual diffs.
+//
+// The following class and functions have been ported:
+//
+// - SequenceMatcher
+//
+// - unified_diff
+//
+// - context_diff
+//
+// Getting unified diffs was the main goal of the port. Keep in mind this code
+// is mostly suitable to output text differences in a human friendly way, there
+// are no guarantees generated diffs are consumable by patch(1).
+package difflib
+
+import (
+ "bufio"
+ "bytes"
+ "fmt"
+ "io"
+ "strings"
+)
+
+func min(a, b int) int {
+ if a < b {
+ return a
+ }
+ return b
+}
+
+func max(a, b int) int {
+ if a > b {
+ return a
+ }
+ return b
+}
+
+func calculateRatio(matches, length int) float64 {
+ if length > 0 {
+ return 2.0 * float64(matches) / float64(length)
+ }
+ return 1.0
+}
+
+type Match struct {
+ A int
+ B int
+ Size int
+}
+
+type OpCode struct {
+ Tag byte
+ I1 int
+ I2 int
+ J1 int
+ J2 int
+}
+
+// SequenceMatcher compares sequence of strings. The basic
+// algorithm predates, and is a little fancier than, an algorithm
+// published in the late 1980's by Ratcliff and Obershelp under the
+// hyperbolic name "gestalt pattern matching". The basic idea is to find
+// the longest contiguous matching subsequence that contains no "junk"
+// elements (R-O doesn't address junk). The same idea is then applied
+// recursively to the pieces of the sequences to the left and to the right
+// of the matching subsequence. This does not yield minimal edit
+// sequences, but does tend to yield matches that "look right" to people.
+//
+// SequenceMatcher tries to compute a "human-friendly diff" between two
+// sequences. Unlike e.g. UNIX(tm) diff, the fundamental notion is the
+// longest *contiguous* & junk-free matching subsequence. That's what
+// catches peoples' eyes. The Windows(tm) windiff has another interesting
+// notion, pairing up elements that appear uniquely in each sequence.
+// That, and the method here, appear to yield more intuitive difference
+// reports than does diff. This method appears to be the least vulnerable
+// to synching up on blocks of "junk lines", though (like blank lines in
+// ordinary text files, or maybe "
" lines in HTML files). That may be
+// because this is the only method of the 3 that has a *concept* of
+// "junk" .
+//
+// Timing: Basic R-O is cubic time worst case and quadratic time expected
+// case. SequenceMatcher is quadratic time for the worst case and has
+// expected-case behavior dependent in a complicated way on how many
+// elements the sequences have in common; best case time is linear.
+type SequenceMatcher struct {
+ a []string
+ b []string
+ b2j map[string][]int
+ IsJunk func(string) bool
+ autoJunk bool
+ bJunk map[string]struct{}
+ matchingBlocks []Match
+ fullBCount map[string]int
+ bPopular map[string]struct{}
+ opCodes []OpCode
+}
+
+func NewMatcher(a, b []string) *SequenceMatcher {
+ m := SequenceMatcher{autoJunk: true}
+ m.SetSeqs(a, b)
+ return &m
+}
+
+func NewMatcherWithJunk(a, b []string, autoJunk bool,
+ isJunk func(string) bool) *SequenceMatcher {
+
+ m := SequenceMatcher{IsJunk: isJunk, autoJunk: autoJunk}
+ m.SetSeqs(a, b)
+ return &m
+}
+
+// Set two sequences to be compared.
+func (m *SequenceMatcher) SetSeqs(a, b []string) {
+ m.SetSeq1(a)
+ m.SetSeq2(b)
+}
+
+// Set the first sequence to be compared. The second sequence to be compared is
+// not changed.
+//
+// SequenceMatcher computes and caches detailed information about the second
+// sequence, so if you want to compare one sequence S against many sequences,
+// use .SetSeq2(s) once and call .SetSeq1(x) repeatedly for each of the other
+// sequences.
+//
+// See also SetSeqs() and SetSeq2().
+func (m *SequenceMatcher) SetSeq1(a []string) {
+ if &a == &m.a {
+ return
+ }
+ m.a = a
+ m.matchingBlocks = nil
+ m.opCodes = nil
+}
+
+// Set the second sequence to be compared. The first sequence to be compared is
+// not changed.
+func (m *SequenceMatcher) SetSeq2(b []string) {
+ if &b == &m.b {
+ return
+ }
+ m.b = b
+ m.matchingBlocks = nil
+ m.opCodes = nil
+ m.fullBCount = nil
+ m.chainB()
+}
+
+func (m *SequenceMatcher) chainB() {
+ // Populate line -> index mapping
+ b2j := map[string][]int{}
+ for i, s := range m.b {
+ indices := b2j[s]
+ indices = append(indices, i)
+ b2j[s] = indices
+ }
+
+ // Purge junk elements
+ m.bJunk = map[string]struct{}{}
+ if m.IsJunk != nil {
+ junk := m.bJunk
+ for s, _ := range b2j {
+ if m.IsJunk(s) {
+ junk[s] = struct{}{}
+ }
+ }
+ for s, _ := range junk {
+ delete(b2j, s)
+ }
+ }
+
+ // Purge remaining popular elements
+ popular := map[string]struct{}{}
+ n := len(m.b)
+ if m.autoJunk && n >= 200 {
+ ntest := n/100 + 1
+ for s, indices := range b2j {
+ if len(indices) > ntest {
+ popular[s] = struct{}{}
+ }
+ }
+ for s, _ := range popular {
+ delete(b2j, s)
+ }
+ }
+ m.bPopular = popular
+ m.b2j = b2j
+}
+
+func (m *SequenceMatcher) isBJunk(s string) bool {
+ _, ok := m.bJunk[s]
+ return ok
+}
+
+// Find longest matching block in a[alo:ahi] and b[blo:bhi].
+//
+// If IsJunk is not defined:
+//
+// Return (i,j,k) such that a[i:i+k] is equal to b[j:j+k], where
+// alo <= i <= i+k <= ahi
+// blo <= j <= j+k <= bhi
+// and for all (i',j',k') meeting those conditions,
+// k >= k'
+// i <= i'
+// and if i == i', j <= j'
+//
+// In other words, of all maximal matching blocks, return one that
+// starts earliest in a, and of all those maximal matching blocks that
+// start earliest in a, return the one that starts earliest in b.
+//
+// If IsJunk is defined, first the longest matching block is
+// determined as above, but with the additional restriction that no
+// junk element appears in the block. Then that block is extended as
+// far as possible by matching (only) junk elements on both sides. So
+// the resulting block never matches on junk except as identical junk
+// happens to be adjacent to an "interesting" match.
+//
+// If no blocks match, return (alo, blo, 0).
+func (m *SequenceMatcher) findLongestMatch(alo, ahi, blo, bhi int) Match {
+ // CAUTION: stripping common prefix or suffix would be incorrect.
+ // E.g.,
+ // ab
+ // acab
+ // Longest matching block is "ab", but if common prefix is
+ // stripped, it's "a" (tied with "b"). UNIX(tm) diff does so
+ // strip, so ends up claiming that ab is changed to acab by
+ // inserting "ca" in the middle. That's minimal but unintuitive:
+ // "it's obvious" that someone inserted "ac" at the front.
+ // Windiff ends up at the same place as diff, but by pairing up
+ // the unique 'b's and then matching the first two 'a's.
+ besti, bestj, bestsize := alo, blo, 0
+
+ // find longest junk-free match
+ // during an iteration of the loop, j2len[j] = length of longest
+ // junk-free match ending with a[i-1] and b[j]
+ j2len := map[int]int{}
+ for i := alo; i != ahi; i++ {
+ // look at all instances of a[i] in b; note that because
+ // b2j has no junk keys, the loop is skipped if a[i] is junk
+ newj2len := map[int]int{}
+ for _, j := range m.b2j[m.a[i]] {
+ // a[i] matches b[j]
+ if j < blo {
+ continue
+ }
+ if j >= bhi {
+ break
+ }
+ k := j2len[j-1] + 1
+ newj2len[j] = k
+ if k > bestsize {
+ besti, bestj, bestsize = i-k+1, j-k+1, k
+ }
+ }
+ j2len = newj2len
+ }
+
+ // Extend the best by non-junk elements on each end. In particular,
+ // "popular" non-junk elements aren't in b2j, which greatly speeds
+ // the inner loop above, but also means "the best" match so far
+ // doesn't contain any junk *or* popular non-junk elements.
+ for besti > alo && bestj > blo && !m.isBJunk(m.b[bestj-1]) &&
+ m.a[besti-1] == m.b[bestj-1] {
+ besti, bestj, bestsize = besti-1, bestj-1, bestsize+1
+ }
+ for besti+bestsize < ahi && bestj+bestsize < bhi &&
+ !m.isBJunk(m.b[bestj+bestsize]) &&
+ m.a[besti+bestsize] == m.b[bestj+bestsize] {
+ bestsize += 1
+ }
+
+ // Now that we have a wholly interesting match (albeit possibly
+ // empty!), we may as well suck up the matching junk on each
+ // side of it too. Can't think of a good reason not to, and it
+ // saves post-processing the (possibly considerable) expense of
+ // figuring out what to do with it. In the case of an empty
+ // interesting match, this is clearly the right thing to do,
+ // because no other kind of match is possible in the regions.
+ for besti > alo && bestj > blo && m.isBJunk(m.b[bestj-1]) &&
+ m.a[besti-1] == m.b[bestj-1] {
+ besti, bestj, bestsize = besti-1, bestj-1, bestsize+1
+ }
+ for besti+bestsize < ahi && bestj+bestsize < bhi &&
+ m.isBJunk(m.b[bestj+bestsize]) &&
+ m.a[besti+bestsize] == m.b[bestj+bestsize] {
+ bestsize += 1
+ }
+
+ return Match{A: besti, B: bestj, Size: bestsize}
+}
+
+// Return list of triples describing matching subsequences.
+//
+// Each triple is of the form (i, j, n), and means that
+// a[i:i+n] == b[j:j+n]. The triples are monotonically increasing in
+// i and in j. It's also guaranteed that if (i, j, n) and (i', j', n') are
+// adjacent triples in the list, and the second is not the last triple in the
+// list, then i+n != i' or j+n != j'. IOW, adjacent triples never describe
+// adjacent equal blocks.
+//
+// The last triple is a dummy, (len(a), len(b), 0), and is the only
+// triple with n==0.
+func (m *SequenceMatcher) GetMatchingBlocks() []Match {
+ if m.matchingBlocks != nil {
+ return m.matchingBlocks
+ }
+
+ var matchBlocks func(alo, ahi, blo, bhi int, matched []Match) []Match
+ matchBlocks = func(alo, ahi, blo, bhi int, matched []Match) []Match {
+ match := m.findLongestMatch(alo, ahi, blo, bhi)
+ i, j, k := match.A, match.B, match.Size
+ if match.Size > 0 {
+ if alo < i && blo < j {
+ matched = matchBlocks(alo, i, blo, j, matched)
+ }
+ matched = append(matched, match)
+ if i+k < ahi && j+k < bhi {
+ matched = matchBlocks(i+k, ahi, j+k, bhi, matched)
+ }
+ }
+ return matched
+ }
+ matched := matchBlocks(0, len(m.a), 0, len(m.b), nil)
+
+ // It's possible that we have adjacent equal blocks in the
+ // matching_blocks list now.
+ nonAdjacent := []Match{}
+ i1, j1, k1 := 0, 0, 0
+ for _, b := range matched {
+ // Is this block adjacent to i1, j1, k1?
+ i2, j2, k2 := b.A, b.B, b.Size
+ if i1+k1 == i2 && j1+k1 == j2 {
+ // Yes, so collapse them -- this just increases the length of
+ // the first block by the length of the second, and the first
+ // block so lengthened remains the block to compare against.
+ k1 += k2
+ } else {
+ // Not adjacent. Remember the first block (k1==0 means it's
+ // the dummy we started with), and make the second block the
+ // new block to compare against.
+ if k1 > 0 {
+ nonAdjacent = append(nonAdjacent, Match{i1, j1, k1})
+ }
+ i1, j1, k1 = i2, j2, k2
+ }
+ }
+ if k1 > 0 {
+ nonAdjacent = append(nonAdjacent, Match{i1, j1, k1})
+ }
+
+ nonAdjacent = append(nonAdjacent, Match{len(m.a), len(m.b), 0})
+ m.matchingBlocks = nonAdjacent
+ return m.matchingBlocks
+}
+
+// Return list of 5-tuples describing how to turn a into b.
+//
+// Each tuple is of the form (tag, i1, i2, j1, j2). The first tuple
+// has i1 == j1 == 0, and remaining tuples have i1 == the i2 from the
+// tuple preceding it, and likewise for j1 == the previous j2.
+//
+// The tags are characters, with these meanings:
+//
+// 'r' (replace): a[i1:i2] should be replaced by b[j1:j2]
+//
+// 'd' (delete): a[i1:i2] should be deleted, j1==j2 in this case.
+//
+// 'i' (insert): b[j1:j2] should be inserted at a[i1:i1], i1==i2 in this case.
+//
+// 'e' (equal): a[i1:i2] == b[j1:j2]
+func (m *SequenceMatcher) GetOpCodes() []OpCode {
+ if m.opCodes != nil {
+ return m.opCodes
+ }
+ i, j := 0, 0
+ matching := m.GetMatchingBlocks()
+ opCodes := make([]OpCode, 0, len(matching))
+ for _, m := range matching {
+ // invariant: we've pumped out correct diffs to change
+ // a[:i] into b[:j], and the next matching block is
+ // a[ai:ai+size] == b[bj:bj+size]. So we need to pump
+ // out a diff to change a[i:ai] into b[j:bj], pump out
+ // the matching block, and move (i,j) beyond the match
+ ai, bj, size := m.A, m.B, m.Size
+ tag := byte(0)
+ if i < ai && j < bj {
+ tag = 'r'
+ } else if i < ai {
+ tag = 'd'
+ } else if j < bj {
+ tag = 'i'
+ }
+ if tag > 0 {
+ opCodes = append(opCodes, OpCode{tag, i, ai, j, bj})
+ }
+ i, j = ai+size, bj+size
+ // the list of matching blocks is terminated by a
+ // sentinel with size 0
+ if size > 0 {
+ opCodes = append(opCodes, OpCode{'e', ai, i, bj, j})
+ }
+ }
+ m.opCodes = opCodes
+ return m.opCodes
+}
+
+// Isolate change clusters by eliminating ranges with no changes.
+//
+// Return a generator of groups with up to n lines of context.
+// Each group is in the same format as returned by GetOpCodes().
+func (m *SequenceMatcher) GetGroupedOpCodes(n int) [][]OpCode {
+ if n < 0 {
+ n = 3
+ }
+ codes := m.GetOpCodes()
+ if len(codes) == 0 {
+ codes = []OpCode{OpCode{'e', 0, 1, 0, 1}}
+ }
+ // Fixup leading and trailing groups if they show no changes.
+ if codes[0].Tag == 'e' {
+ c := codes[0]
+ i1, i2, j1, j2 := c.I1, c.I2, c.J1, c.J2
+ codes[0] = OpCode{c.Tag, max(i1, i2-n), i2, max(j1, j2-n), j2}
+ }
+ if codes[len(codes)-1].Tag == 'e' {
+ c := codes[len(codes)-1]
+ i1, i2, j1, j2 := c.I1, c.I2, c.J1, c.J2
+ codes[len(codes)-1] = OpCode{c.Tag, i1, min(i2, i1+n), j1, min(j2, j1+n)}
+ }
+ nn := n + n
+ groups := [][]OpCode{}
+ group := []OpCode{}
+ for _, c := range codes {
+ i1, i2, j1, j2 := c.I1, c.I2, c.J1, c.J2
+ // End the current group and start a new one whenever
+ // there is a large range with no changes.
+ if c.Tag == 'e' && i2-i1 > nn {
+ group = append(group, OpCode{c.Tag, i1, min(i2, i1+n),
+ j1, min(j2, j1+n)})
+ groups = append(groups, group)
+ group = []OpCode{}
+ i1, j1 = max(i1, i2-n), max(j1, j2-n)
+ }
+ group = append(group, OpCode{c.Tag, i1, i2, j1, j2})
+ }
+ if len(group) > 0 && !(len(group) == 1 && group[0].Tag == 'e') {
+ groups = append(groups, group)
+ }
+ return groups
+}
+
+// Return a measure of the sequences' similarity (float in [0,1]).
+//
+// Where T is the total number of elements in both sequences, and
+// M is the number of matches, this is 2.0*M / T.
+// Note that this is 1 if the sequences are identical, and 0 if
+// they have nothing in common.
+//
+// .Ratio() is expensive to compute if you haven't already computed
+// .GetMatchingBlocks() or .GetOpCodes(), in which case you may
+// want to try .QuickRatio() or .RealQuickRation() first to get an
+// upper bound.
+func (m *SequenceMatcher) Ratio() float64 {
+ matches := 0
+ for _, m := range m.GetMatchingBlocks() {
+ matches += m.Size
+ }
+ return calculateRatio(matches, len(m.a)+len(m.b))
+}
+
+// Return an upper bound on ratio() relatively quickly.
+//
+// This isn't defined beyond that it is an upper bound on .Ratio(), and
+// is faster to compute.
+func (m *SequenceMatcher) QuickRatio() float64 {
+ // viewing a and b as multisets, set matches to the cardinality
+ // of their intersection; this counts the number of matches
+ // without regard to order, so is clearly an upper bound
+ if m.fullBCount == nil {
+ m.fullBCount = map[string]int{}
+ for _, s := range m.b {
+ m.fullBCount[s] = m.fullBCount[s] + 1
+ }
+ }
+
+ // avail[x] is the number of times x appears in 'b' less the
+ // number of times we've seen it in 'a' so far ... kinda
+ avail := map[string]int{}
+ matches := 0
+ for _, s := range m.a {
+ n, ok := avail[s]
+ if !ok {
+ n = m.fullBCount[s]
+ }
+ avail[s] = n - 1
+ if n > 0 {
+ matches += 1
+ }
+ }
+ return calculateRatio(matches, len(m.a)+len(m.b))
+}
+
+// Return an upper bound on ratio() very quickly.
+//
+// This isn't defined beyond that it is an upper bound on .Ratio(), and
+// is faster to compute than either .Ratio() or .QuickRatio().
+func (m *SequenceMatcher) RealQuickRatio() float64 {
+ la, lb := len(m.a), len(m.b)
+ return calculateRatio(min(la, lb), la+lb)
+}
+
+// Convert range to the "ed" format
+func formatRangeUnified(start, stop int) string {
+ // Per the diff spec at http://www.unix.org/single_unix_specification/
+ beginning := start + 1 // lines start numbering with one
+ length := stop - start
+ if length == 1 {
+ return fmt.Sprintf("%d", beginning)
+ }
+ if length == 0 {
+ beginning -= 1 // empty ranges begin at line just before the range
+ }
+ return fmt.Sprintf("%d,%d", beginning, length)
+}
+
+// Unified diff parameters
+type UnifiedDiff struct {
+ A []string // First sequence lines
+ FromFile string // First file name
+ FromDate string // First file time
+ B []string // Second sequence lines
+ ToFile string // Second file name
+ ToDate string // Second file time
+ Eol string // Headers end of line, defaults to LF
+ Context int // Number of context lines
+}
+
+// Compare two sequences of lines; generate the delta as a unified diff.
+//
+// Unified diffs are a compact way of showing line changes and a few
+// lines of context. The number of context lines is set by 'n' which
+// defaults to three.
+//
+// By default, the diff control lines (those with ---, +++, or @@) are
+// created with a trailing newline. This is helpful so that inputs
+// created from file.readlines() result in diffs that are suitable for
+// file.writelines() since both the inputs and outputs have trailing
+// newlines.
+//
+// For inputs that do not have trailing newlines, set the lineterm
+// argument to "" so that the output will be uniformly newline free.
+//
+// The unidiff format normally has a header for filenames and modification
+// times. Any or all of these may be specified using strings for
+// 'fromfile', 'tofile', 'fromfiledate', and 'tofiledate'.
+// The modification times are normally expressed in the ISO 8601 format.
+func WriteUnifiedDiff(writer io.Writer, diff UnifiedDiff) error {
+ buf := bufio.NewWriter(writer)
+ defer buf.Flush()
+ wf := func(format string, args ...interface{}) error {
+ _, err := buf.WriteString(fmt.Sprintf(format, args...))
+ return err
+ }
+ ws := func(s string) error {
+ _, err := buf.WriteString(s)
+ return err
+ }
+
+ if len(diff.Eol) == 0 {
+ diff.Eol = "\n"
+ }
+
+ started := false
+ m := NewMatcher(diff.A, diff.B)
+ for _, g := range m.GetGroupedOpCodes(diff.Context) {
+ if !started {
+ started = true
+ fromDate := ""
+ if len(diff.FromDate) > 0 {
+ fromDate = "\t" + diff.FromDate
+ }
+ toDate := ""
+ if len(diff.ToDate) > 0 {
+ toDate = "\t" + diff.ToDate
+ }
+ if diff.FromFile != "" || diff.ToFile != "" {
+ err := wf("--- %s%s%s", diff.FromFile, fromDate, diff.Eol)
+ if err != nil {
+ return err
+ }
+ err = wf("+++ %s%s%s", diff.ToFile, toDate, diff.Eol)
+ if err != nil {
+ return err
+ }
+ }
+ }
+ first, last := g[0], g[len(g)-1]
+ range1 := formatRangeUnified(first.I1, last.I2)
+ range2 := formatRangeUnified(first.J1, last.J2)
+ if err := wf("@@ -%s +%s @@%s", range1, range2, diff.Eol); err != nil {
+ return err
+ }
+ for _, c := range g {
+ i1, i2, j1, j2 := c.I1, c.I2, c.J1, c.J2
+ if c.Tag == 'e' {
+ for _, line := range diff.A[i1:i2] {
+ if err := ws(" " + line); err != nil {
+ return err
+ }
+ }
+ continue
+ }
+ if c.Tag == 'r' || c.Tag == 'd' {
+ for _, line := range diff.A[i1:i2] {
+ if err := ws("-" + line); err != nil {
+ return err
+ }
+ }
+ }
+ if c.Tag == 'r' || c.Tag == 'i' {
+ for _, line := range diff.B[j1:j2] {
+ if err := ws("+" + line); err != nil {
+ return err
+ }
+ }
+ }
+ }
+ }
+ return nil
+}
+
+// Like WriteUnifiedDiff but returns the diff a string.
+func GetUnifiedDiffString(diff UnifiedDiff) (string, error) {
+ w := &bytes.Buffer{}
+ err := WriteUnifiedDiff(w, diff)
+ return string(w.Bytes()), err
+}
+
+// Convert range to the "ed" format.
+func formatRangeContext(start, stop int) string {
+ // Per the diff spec at http://www.unix.org/single_unix_specification/
+ beginning := start + 1 // lines start numbering with one
+ length := stop - start
+ if length == 0 {
+ beginning -= 1 // empty ranges begin at line just before the range
+ }
+ if length <= 1 {
+ return fmt.Sprintf("%d", beginning)
+ }
+ return fmt.Sprintf("%d,%d", beginning, beginning+length-1)
+}
+
+type ContextDiff UnifiedDiff
+
+// Compare two sequences of lines; generate the delta as a context diff.
+//
+// Context diffs are a compact way of showing line changes and a few
+// lines of context. The number of context lines is set by diff.Context
+// which defaults to three.
+//
+// By default, the diff control lines (those with *** or ---) are
+// created with a trailing newline.
+//
+// For inputs that do not have trailing newlines, set the diff.Eol
+// argument to "" so that the output will be uniformly newline free.
+//
+// The context diff format normally has a header for filenames and
+// modification times. Any or all of these may be specified using
+// strings for diff.FromFile, diff.ToFile, diff.FromDate, diff.ToDate.
+// The modification times are normally expressed in the ISO 8601 format.
+// If not specified, the strings default to blanks.
+func WriteContextDiff(writer io.Writer, diff ContextDiff) error {
+ buf := bufio.NewWriter(writer)
+ defer buf.Flush()
+ var diffErr error
+ wf := func(format string, args ...interface{}) {
+ _, err := buf.WriteString(fmt.Sprintf(format, args...))
+ if diffErr == nil && err != nil {
+ diffErr = err
+ }
+ }
+ ws := func(s string) {
+ _, err := buf.WriteString(s)
+ if diffErr == nil && err != nil {
+ diffErr = err
+ }
+ }
+
+ if len(diff.Eol) == 0 {
+ diff.Eol = "\n"
+ }
+
+ prefix := map[byte]string{
+ 'i': "+ ",
+ 'd': "- ",
+ 'r': "! ",
+ 'e': " ",
+ }
+
+ started := false
+ m := NewMatcher(diff.A, diff.B)
+ for _, g := range m.GetGroupedOpCodes(diff.Context) {
+ if !started {
+ started = true
+ fromDate := ""
+ if len(diff.FromDate) > 0 {
+ fromDate = "\t" + diff.FromDate
+ }
+ toDate := ""
+ if len(diff.ToDate) > 0 {
+ toDate = "\t" + diff.ToDate
+ }
+ if diff.FromFile != "" || diff.ToFile != "" {
+ wf("*** %s%s%s", diff.FromFile, fromDate, diff.Eol)
+ wf("--- %s%s%s", diff.ToFile, toDate, diff.Eol)
+ }
+ }
+
+ first, last := g[0], g[len(g)-1]
+ ws("***************" + diff.Eol)
+
+ range1 := formatRangeContext(first.I1, last.I2)
+ wf("*** %s ****%s", range1, diff.Eol)
+ for _, c := range g {
+ if c.Tag == 'r' || c.Tag == 'd' {
+ for _, cc := range g {
+ if cc.Tag == 'i' {
+ continue
+ }
+ for _, line := range diff.A[cc.I1:cc.I2] {
+ ws(prefix[cc.Tag] + line)
+ }
+ }
+ break
+ }
+ }
+
+ range2 := formatRangeContext(first.J1, last.J2)
+ wf("--- %s ----%s", range2, diff.Eol)
+ for _, c := range g {
+ if c.Tag == 'r' || c.Tag == 'i' {
+ for _, cc := range g {
+ if cc.Tag == 'd' {
+ continue
+ }
+ for _, line := range diff.B[cc.J1:cc.J2] {
+ ws(prefix[cc.Tag] + line)
+ }
+ }
+ break
+ }
+ }
+ }
+ return diffErr
+}
+
+// Like WriteContextDiff but returns the diff a string.
+func GetContextDiffString(diff ContextDiff) (string, error) {
+ w := &bytes.Buffer{}
+ err := WriteContextDiff(w, diff)
+ return string(w.Bytes()), err
+}
+
+// Split a string on "\n" while preserving them. The output can be used
+// as input for UnifiedDiff and ContextDiff structures.
+func SplitLines(s string) []string {
+ lines := strings.SplitAfter(s, "\n")
+ lines[len(lines)-1] += "\n"
+ return lines
+}
diff --git a/vendor/github.com/prometheus/client_golang/LICENSE b/vendor/github.com/prometheus/client_golang/LICENSE
new file mode 100644
index 0000000..261eeb9
--- /dev/null
+++ b/vendor/github.com/prometheus/client_golang/LICENSE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/vendor/github.com/prometheus/client_golang/NOTICE b/vendor/github.com/prometheus/client_golang/NOTICE
new file mode 100644
index 0000000..dd878a3
--- /dev/null
+++ b/vendor/github.com/prometheus/client_golang/NOTICE
@@ -0,0 +1,23 @@
+Prometheus instrumentation library for Go applications
+Copyright 2012-2015 The Prometheus Authors
+
+This product includes software developed at
+SoundCloud Ltd. (http://soundcloud.com/).
+
+
+The following components are included in this product:
+
+perks - a fork of https://github.com/bmizerany/perks
+https://github.com/beorn7/perks
+Copyright 2013-2015 Blake Mizerany, Björn Rabenstein
+See https://github.com/beorn7/perks/blob/master/README.md for license details.
+
+Go support for Protocol Buffers - Google's data interchange format
+http://github.com/golang/protobuf/
+Copyright 2010 The Go Authors
+See source code for license details.
+
+Support for streaming Protocol Buffer messages for the Go language (golang).
+https://github.com/matttproud/golang_protobuf_extensions
+Copyright 2013 Matt T. Proud
+Licensed under the Apache License, Version 2.0
diff --git a/vendor/github.com/prometheus/client_golang/prometheus/.gitignore b/vendor/github.com/prometheus/client_golang/prometheus/.gitignore
new file mode 100644
index 0000000..3460f03
--- /dev/null
+++ b/vendor/github.com/prometheus/client_golang/prometheus/.gitignore
@@ -0,0 +1 @@
+command-line-arguments.test
diff --git a/vendor/github.com/prometheus/client_golang/prometheus/README.md b/vendor/github.com/prometheus/client_golang/prometheus/README.md
new file mode 100644
index 0000000..44986bf
--- /dev/null
+++ b/vendor/github.com/prometheus/client_golang/prometheus/README.md
@@ -0,0 +1 @@
+See [![go-doc](https://godoc.org/github.com/prometheus/client_golang/prometheus?status.svg)](https://godoc.org/github.com/prometheus/client_golang/prometheus).
diff --git a/vendor/github.com/prometheus/client_golang/prometheus/build_info.go b/vendor/github.com/prometheus/client_golang/prometheus/build_info.go
new file mode 100644
index 0000000..288f0e8
--- /dev/null
+++ b/vendor/github.com/prometheus/client_golang/prometheus/build_info.go
@@ -0,0 +1,29 @@
+// Copyright 2019 The Prometheus Authors
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// +build go1.12
+
+package prometheus
+
+import "runtime/debug"
+
+// readBuildInfo is a wrapper around debug.ReadBuildInfo for Go 1.12+.
+func readBuildInfo() (path, version, sum string) {
+ path, version, sum = "unknown", "unknown", "unknown"
+ if bi, ok := debug.ReadBuildInfo(); ok {
+ path = bi.Main.Path
+ version = bi.Main.Version
+ sum = bi.Main.Sum
+ }
+ return
+}
diff --git a/vendor/github.com/prometheus/client_golang/prometheus/build_info_pre_1.12.go b/vendor/github.com/prometheus/client_golang/prometheus/build_info_pre_1.12.go
new file mode 100644
index 0000000..6609e28
--- /dev/null
+++ b/vendor/github.com/prometheus/client_golang/prometheus/build_info_pre_1.12.go
@@ -0,0 +1,22 @@
+// Copyright 2019 The Prometheus Authors
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// +build !go1.12
+
+package prometheus
+
+// readBuildInfo is a wrapper around debug.ReadBuildInfo for Go versions before
+// 1.12. Remove this whole file once the minimum supported Go version is 1.12.
+func readBuildInfo() (path, version, sum string) {
+ return "unknown", "unknown", "unknown"
+}
diff --git a/vendor/github.com/prometheus/client_golang/prometheus/collector.go b/vendor/github.com/prometheus/client_golang/prometheus/collector.go
new file mode 100644
index 0000000..1e83965
--- /dev/null
+++ b/vendor/github.com/prometheus/client_golang/prometheus/collector.go
@@ -0,0 +1,120 @@
+// Copyright 2014 The Prometheus Authors
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package prometheus
+
+// Collector is the interface implemented by anything that can be used by
+// Prometheus to collect metrics. A Collector has to be registered for
+// collection. See Registerer.Register.
+//
+// The stock metrics provided by this package (Gauge, Counter, Summary,
+// Histogram, Untyped) are also Collectors (which only ever collect one metric,
+// namely itself). An implementer of Collector may, however, collect multiple
+// metrics in a coordinated fashion and/or create metrics on the fly. Examples
+// for collectors already implemented in this library are the metric vectors
+// (i.e. collection of multiple instances of the same Metric but with different
+// label values) like GaugeVec or SummaryVec, and the ExpvarCollector.
+type Collector interface {
+ // Describe sends the super-set of all possible descriptors of metrics
+ // collected by this Collector to the provided channel and returns once
+ // the last descriptor has been sent. The sent descriptors fulfill the
+ // consistency and uniqueness requirements described in the Desc
+ // documentation.
+ //
+ // It is valid if one and the same Collector sends duplicate
+ // descriptors. Those duplicates are simply ignored. However, two
+ // different Collectors must not send duplicate descriptors.
+ //
+ // Sending no descriptor at all marks the Collector as “unchecked”,
+ // i.e. no checks will be performed at registration time, and the
+ // Collector may yield any Metric it sees fit in its Collect method.
+ //
+ // This method idempotently sends the same descriptors throughout the
+ // lifetime of the Collector. It may be called concurrently and
+ // therefore must be implemented in a concurrency safe way.
+ //
+ // If a Collector encounters an error while executing this method, it
+ // must send an invalid descriptor (created with NewInvalidDesc) to
+ // signal the error to the registry.
+ Describe(chan<- *Desc)
+ // Collect is called by the Prometheus registry when collecting
+ // metrics. The implementation sends each collected metric via the
+ // provided channel and returns once the last metric has been sent. The
+ // descriptor of each sent metric is one of those returned by Describe
+ // (unless the Collector is unchecked, see above). Returned metrics that
+ // share the same descriptor must differ in their variable label
+ // values.
+ //
+ // This method may be called concurrently and must therefore be
+ // implemented in a concurrency safe way. Blocking occurs at the expense
+ // of total performance of rendering all registered metrics. Ideally,
+ // Collector implementations support concurrent readers.
+ Collect(chan<- Metric)
+}
+
+// DescribeByCollect is a helper to implement the Describe method of a custom
+// Collector. It collects the metrics from the provided Collector and sends
+// their descriptors to the provided channel.
+//
+// If a Collector collects the same metrics throughout its lifetime, its
+// Describe method can simply be implemented as:
+//
+// func (c customCollector) Describe(ch chan<- *Desc) {
+// DescribeByCollect(c, ch)
+// }
+//
+// However, this will not work if the metrics collected change dynamically over
+// the lifetime of the Collector in a way that their combined set of descriptors
+// changes as well. The shortcut implementation will then violate the contract
+// of the Describe method. If a Collector sometimes collects no metrics at all
+// (for example vectors like CounterVec, GaugeVec, etc., which only collect
+// metrics after a metric with a fully specified label set has been accessed),
+// it might even get registered as an unchecked Collector (cf. the Register
+// method of the Registerer interface). Hence, only use this shortcut
+// implementation of Describe if you are certain to fulfill the contract.
+//
+// The Collector example demonstrates a use of DescribeByCollect.
+func DescribeByCollect(c Collector, descs chan<- *Desc) {
+ metrics := make(chan Metric)
+ go func() {
+ c.Collect(metrics)
+ close(metrics)
+ }()
+ for m := range metrics {
+ descs <- m.Desc()
+ }
+}
+
+// selfCollector implements Collector for a single Metric so that the Metric
+// collects itself. Add it as an anonymous field to a struct that implements
+// Metric, and call init with the Metric itself as an argument.
+type selfCollector struct {
+ self Metric
+}
+
+// init provides the selfCollector with a reference to the metric it is supposed
+// to collect. It is usually called within the factory function to create a
+// metric. See example.
+func (c *selfCollector) init(self Metric) {
+ c.self = self
+}
+
+// Describe implements Collector.
+func (c *selfCollector) Describe(ch chan<- *Desc) {
+ ch <- c.self.Desc()
+}
+
+// Collect implements Collector.
+func (c *selfCollector) Collect(ch chan<- Metric) {
+ ch <- c.self
+}
diff --git a/vendor/github.com/prometheus/client_golang/prometheus/counter.go b/vendor/github.com/prometheus/client_golang/prometheus/counter.go
new file mode 100644
index 0000000..d463e36
--- /dev/null
+++ b/vendor/github.com/prometheus/client_golang/prometheus/counter.go
@@ -0,0 +1,277 @@
+// Copyright 2014 The Prometheus Authors
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package prometheus
+
+import (
+ "errors"
+ "math"
+ "sync/atomic"
+
+ dto "github.com/prometheus/client_model/go"
+)
+
+// Counter is a Metric that represents a single numerical value that only ever
+// goes up. That implies that it cannot be used to count items whose number can
+// also go down, e.g. the number of currently running goroutines. Those
+// "counters" are represented by Gauges.
+//
+// A Counter is typically used to count requests served, tasks completed, errors
+// occurred, etc.
+//
+// To create Counter instances, use NewCounter.
+type Counter interface {
+ Metric
+ Collector
+
+ // Inc increments the counter by 1. Use Add to increment it by arbitrary
+ // non-negative values.
+ Inc()
+ // Add adds the given value to the counter. It panics if the value is <
+ // 0.
+ Add(float64)
+}
+
+// CounterOpts is an alias for Opts. See there for doc comments.
+type CounterOpts Opts
+
+// NewCounter creates a new Counter based on the provided CounterOpts.
+//
+// The returned implementation tracks the counter value in two separate
+// variables, a float64 and a uint64. The latter is used to track calls of the
+// Inc method and calls of the Add method with a value that can be represented
+// as a uint64. This allows atomic increments of the counter with optimal
+// performance. (It is common to have an Inc call in very hot execution paths.)
+// Both internal tracking values are added up in the Write method. This has to
+// be taken into account when it comes to precision and overflow behavior.
+func NewCounter(opts CounterOpts) Counter {
+ desc := NewDesc(
+ BuildFQName(opts.Namespace, opts.Subsystem, opts.Name),
+ opts.Help,
+ nil,
+ opts.ConstLabels,
+ )
+ result := &counter{desc: desc, labelPairs: desc.constLabelPairs}
+ result.init(result) // Init self-collection.
+ return result
+}
+
+type counter struct {
+ // valBits contains the bits of the represented float64 value, while
+ // valInt stores values that are exact integers. Both have to go first
+ // in the struct to guarantee alignment for atomic operations.
+ // http://golang.org/pkg/sync/atomic/#pkg-note-BUG
+ valBits uint64
+ valInt uint64
+
+ selfCollector
+ desc *Desc
+
+ labelPairs []*dto.LabelPair
+}
+
+func (c *counter) Desc() *Desc {
+ return c.desc
+}
+
+func (c *counter) Add(v float64) {
+ if v < 0 {
+ panic(errors.New("counter cannot decrease in value"))
+ }
+ ival := uint64(v)
+ if float64(ival) == v {
+ atomic.AddUint64(&c.valInt, ival)
+ return
+ }
+
+ for {
+ oldBits := atomic.LoadUint64(&c.valBits)
+ newBits := math.Float64bits(math.Float64frombits(oldBits) + v)
+ if atomic.CompareAndSwapUint64(&c.valBits, oldBits, newBits) {
+ return
+ }
+ }
+}
+
+func (c *counter) Inc() {
+ atomic.AddUint64(&c.valInt, 1)
+}
+
+func (c *counter) Write(out *dto.Metric) error {
+ fval := math.Float64frombits(atomic.LoadUint64(&c.valBits))
+ ival := atomic.LoadUint64(&c.valInt)
+ val := fval + float64(ival)
+
+ return populateMetric(CounterValue, val, c.labelPairs, out)
+}
+
+// CounterVec is a Collector that bundles a set of Counters that all share the
+// same Desc, but have different values for their variable labels. This is used
+// if you want to count the same thing partitioned by various dimensions
+// (e.g. number of HTTP requests, partitioned by response code and
+// method). Create instances with NewCounterVec.
+type CounterVec struct {
+ *metricVec
+}
+
+// NewCounterVec creates a new CounterVec based on the provided CounterOpts and
+// partitioned by the given label names.
+func NewCounterVec(opts CounterOpts, labelNames []string) *CounterVec {
+ desc := NewDesc(
+ BuildFQName(opts.Namespace, opts.Subsystem, opts.Name),
+ opts.Help,
+ labelNames,
+ opts.ConstLabels,
+ )
+ return &CounterVec{
+ metricVec: newMetricVec(desc, func(lvs ...string) Metric {
+ if len(lvs) != len(desc.variableLabels) {
+ panic(makeInconsistentCardinalityError(desc.fqName, desc.variableLabels, lvs))
+ }
+ result := &counter{desc: desc, labelPairs: makeLabelPairs(desc, lvs)}
+ result.init(result) // Init self-collection.
+ return result
+ }),
+ }
+}
+
+// GetMetricWithLabelValues returns the Counter for the given slice of label
+// values (same order as the VariableLabels in Desc). If that combination of
+// label values is accessed for the first time, a new Counter is created.
+//
+// It is possible to call this method without using the returned Counter to only
+// create the new Counter but leave it at its starting value 0. See also the
+// SummaryVec example.
+//
+// Keeping the Counter for later use is possible (and should be considered if
+// performance is critical), but keep in mind that Reset, DeleteLabelValues and
+// Delete can be used to delete the Counter from the CounterVec. In that case,
+// the Counter will still exist, but it will not be exported anymore, even if a
+// Counter with the same label values is created later.
+//
+// An error is returned if the number of label values is not the same as the
+// number of VariableLabels in Desc (minus any curried labels).
+//
+// Note that for more than one label value, this method is prone to mistakes
+// caused by an incorrect order of arguments. Consider GetMetricWith(Labels) as
+// an alternative to avoid that type of mistake. For higher label numbers, the
+// latter has a much more readable (albeit more verbose) syntax, but it comes
+// with a performance overhead (for creating and processing the Labels map).
+// See also the GaugeVec example.
+func (v *CounterVec) GetMetricWithLabelValues(lvs ...string) (Counter, error) {
+ metric, err := v.metricVec.getMetricWithLabelValues(lvs...)
+ if metric != nil {
+ return metric.(Counter), err
+ }
+ return nil, err
+}
+
+// GetMetricWith returns the Counter for the given Labels map (the label names
+// must match those of the VariableLabels in Desc). If that label map is
+// accessed for the first time, a new Counter is created. Implications of
+// creating a Counter without using it and keeping the Counter for later use are
+// the same as for GetMetricWithLabelValues.
+//
+// An error is returned if the number and names of the Labels are inconsistent
+// with those of the VariableLabels in Desc (minus any curried labels).
+//
+// This method is used for the same purpose as
+// GetMetricWithLabelValues(...string). See there for pros and cons of the two
+// methods.
+func (v *CounterVec) GetMetricWith(labels Labels) (Counter, error) {
+ metric, err := v.metricVec.getMetricWith(labels)
+ if metric != nil {
+ return metric.(Counter), err
+ }
+ return nil, err
+}
+
+// WithLabelValues works as GetMetricWithLabelValues, but panics where
+// GetMetricWithLabelValues would have returned an error. Not returning an
+// error allows shortcuts like
+// myVec.WithLabelValues("404", "GET").Add(42)
+func (v *CounterVec) WithLabelValues(lvs ...string) Counter {
+ c, err := v.GetMetricWithLabelValues(lvs...)
+ if err != nil {
+ panic(err)
+ }
+ return c
+}
+
+// With works as GetMetricWith, but panics where GetMetricWithLabels would have
+// returned an error. Not returning an error allows shortcuts like
+// myVec.With(prometheus.Labels{"code": "404", "method": "GET"}).Add(42)
+func (v *CounterVec) With(labels Labels) Counter {
+ c, err := v.GetMetricWith(labels)
+ if err != nil {
+ panic(err)
+ }
+ return c
+}
+
+// CurryWith returns a vector curried with the provided labels, i.e. the
+// returned vector has those labels pre-set for all labeled operations performed
+// on it. The cardinality of the curried vector is reduced accordingly. The
+// order of the remaining labels stays the same (just with the curried labels
+// taken out of the sequence – which is relevant for the
+// (GetMetric)WithLabelValues methods). It is possible to curry a curried
+// vector, but only with labels not yet used for currying before.
+//
+// The metrics contained in the CounterVec are shared between the curried and
+// uncurried vectors. They are just accessed differently. Curried and uncurried
+// vectors behave identically in terms of collection. Only one must be
+// registered with a given registry (usually the uncurried version). The Reset
+// method deletes all metrics, even if called on a curried vector.
+func (v *CounterVec) CurryWith(labels Labels) (*CounterVec, error) {
+ vec, err := v.curryWith(labels)
+ if vec != nil {
+ return &CounterVec{vec}, err
+ }
+ return nil, err
+}
+
+// MustCurryWith works as CurryWith but panics where CurryWith would have
+// returned an error.
+func (v *CounterVec) MustCurryWith(labels Labels) *CounterVec {
+ vec, err := v.CurryWith(labels)
+ if err != nil {
+ panic(err)
+ }
+ return vec
+}
+
+// CounterFunc is a Counter whose value is determined at collect time by calling a
+// provided function.
+//
+// To create CounterFunc instances, use NewCounterFunc.
+type CounterFunc interface {
+ Metric
+ Collector
+}
+
+// NewCounterFunc creates a new CounterFunc based on the provided
+// CounterOpts. The value reported is determined by calling the given function
+// from within the Write method. Take into account that metric collection may
+// happen concurrently. If that results in concurrent calls to Write, like in
+// the case where a CounterFunc is directly registered with Prometheus, the
+// provided function must be concurrency-safe. The function should also honor
+// the contract for a Counter (values only go up, not down), but compliance will
+// not be checked.
+func NewCounterFunc(opts CounterOpts, function func() float64) CounterFunc {
+ return newValueFunc(NewDesc(
+ BuildFQName(opts.Namespace, opts.Subsystem, opts.Name),
+ opts.Help,
+ nil,
+ opts.ConstLabels,
+ ), CounterValue, function)
+}
diff --git a/vendor/github.com/prometheus/client_golang/prometheus/desc.go b/vendor/github.com/prometheus/client_golang/prometheus/desc.go
new file mode 100644
index 0000000..1d034f8
--- /dev/null
+++ b/vendor/github.com/prometheus/client_golang/prometheus/desc.go
@@ -0,0 +1,184 @@
+// Copyright 2016 The Prometheus Authors
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package prometheus
+
+import (
+ "errors"
+ "fmt"
+ "sort"
+ "strings"
+
+ "github.com/golang/protobuf/proto"
+ "github.com/prometheus/common/model"
+
+ dto "github.com/prometheus/client_model/go"
+)
+
+// Desc is the descriptor used by every Prometheus Metric. It is essentially
+// the immutable meta-data of a Metric. The normal Metric implementations
+// included in this package manage their Desc under the hood. Users only have to
+// deal with Desc if they use advanced features like the ExpvarCollector or
+// custom Collectors and Metrics.
+//
+// Descriptors registered with the same registry have to fulfill certain
+// consistency and uniqueness criteria if they share the same fully-qualified
+// name: They must have the same help string and the same label names (aka label
+// dimensions) in each, constLabels and variableLabels, but they must differ in
+// the values of the constLabels.
+//
+// Descriptors that share the same fully-qualified names and the same label
+// values of their constLabels are considered equal.
+//
+// Use NewDesc to create new Desc instances.
+type Desc struct {
+ // fqName has been built from Namespace, Subsystem, and Name.
+ fqName string
+ // help provides some helpful information about this metric.
+ help string
+ // constLabelPairs contains precalculated DTO label pairs based on
+ // the constant labels.
+ constLabelPairs []*dto.LabelPair
+ // VariableLabels contains names of labels for which the metric
+ // maintains variable values.
+ variableLabels []string
+ // id is a hash of the values of the ConstLabels and fqName. This
+ // must be unique among all registered descriptors and can therefore be
+ // used as an identifier of the descriptor.
+ id uint64
+ // dimHash is a hash of the label names (preset and variable) and the
+ // Help string. Each Desc with the same fqName must have the same
+ // dimHash.
+ dimHash uint64
+ // err is an error that occurred during construction. It is reported on
+ // registration time.
+ err error
+}
+
+// NewDesc allocates and initializes a new Desc. Errors are recorded in the Desc
+// and will be reported on registration time. variableLabels and constLabels can
+// be nil if no such labels should be set. fqName must not be empty.
+//
+// variableLabels only contain the label names. Their label values are variable
+// and therefore not part of the Desc. (They are managed within the Metric.)
+//
+// For constLabels, the label values are constant. Therefore, they are fully
+// specified in the Desc. See the Collector example for a usage pattern.
+func NewDesc(fqName, help string, variableLabels []string, constLabels Labels) *Desc {
+ d := &Desc{
+ fqName: fqName,
+ help: help,
+ variableLabels: variableLabels,
+ }
+ if !model.IsValidMetricName(model.LabelValue(fqName)) {
+ d.err = fmt.Errorf("%q is not a valid metric name", fqName)
+ return d
+ }
+ // labelValues contains the label values of const labels (in order of
+ // their sorted label names) plus the fqName (at position 0).
+ labelValues := make([]string, 1, len(constLabels)+1)
+ labelValues[0] = fqName
+ labelNames := make([]string, 0, len(constLabels)+len(variableLabels))
+ labelNameSet := map[string]struct{}{}
+ // First add only the const label names and sort them...
+ for labelName := range constLabels {
+ if !checkLabelName(labelName) {
+ d.err = fmt.Errorf("%q is not a valid label name for metric %q", labelName, fqName)
+ return d
+ }
+ labelNames = append(labelNames, labelName)
+ labelNameSet[labelName] = struct{}{}
+ }
+ sort.Strings(labelNames)
+ // ... so that we can now add const label values in the order of their names.
+ for _, labelName := range labelNames {
+ labelValues = append(labelValues, constLabels[labelName])
+ }
+ // Validate the const label values. They can't have a wrong cardinality, so
+ // use in len(labelValues) as expectedNumberOfValues.
+ if err := validateLabelValues(labelValues, len(labelValues)); err != nil {
+ d.err = err
+ return d
+ }
+ // Now add the variable label names, but prefix them with something that
+ // cannot be in a regular label name. That prevents matching the label
+ // dimension with a different mix between preset and variable labels.
+ for _, labelName := range variableLabels {
+ if !checkLabelName(labelName) {
+ d.err = fmt.Errorf("%q is not a valid label name for metric %q", labelName, fqName)
+ return d
+ }
+ labelNames = append(labelNames, "$"+labelName)
+ labelNameSet[labelName] = struct{}{}
+ }
+ if len(labelNames) != len(labelNameSet) {
+ d.err = errors.New("duplicate label names")
+ return d
+ }
+
+ vh := hashNew()
+ for _, val := range labelValues {
+ vh = hashAdd(vh, val)
+ vh = hashAddByte(vh, separatorByte)
+ }
+ d.id = vh
+ // Sort labelNames so that order doesn't matter for the hash.
+ sort.Strings(labelNames)
+ // Now hash together (in this order) the help string and the sorted
+ // label names.
+ lh := hashNew()
+ lh = hashAdd(lh, help)
+ lh = hashAddByte(lh, separatorByte)
+ for _, labelName := range labelNames {
+ lh = hashAdd(lh, labelName)
+ lh = hashAddByte(lh, separatorByte)
+ }
+ d.dimHash = lh
+
+ d.constLabelPairs = make([]*dto.LabelPair, 0, len(constLabels))
+ for n, v := range constLabels {
+ d.constLabelPairs = append(d.constLabelPairs, &dto.LabelPair{
+ Name: proto.String(n),
+ Value: proto.String(v),
+ })
+ }
+ sort.Sort(labelPairSorter(d.constLabelPairs))
+ return d
+}
+
+// NewInvalidDesc returns an invalid descriptor, i.e. a descriptor with the
+// provided error set. If a collector returning such a descriptor is registered,
+// registration will fail with the provided error. NewInvalidDesc can be used by
+// a Collector to signal inability to describe itself.
+func NewInvalidDesc(err error) *Desc {
+ return &Desc{
+ err: err,
+ }
+}
+
+func (d *Desc) String() string {
+ lpStrings := make([]string, 0, len(d.constLabelPairs))
+ for _, lp := range d.constLabelPairs {
+ lpStrings = append(
+ lpStrings,
+ fmt.Sprintf("%s=%q", lp.GetName(), lp.GetValue()),
+ )
+ }
+ return fmt.Sprintf(
+ "Desc{fqName: %q, help: %q, constLabels: {%s}, variableLabels: %v}",
+ d.fqName,
+ d.help,
+ strings.Join(lpStrings, ","),
+ d.variableLabels,
+ )
+}
diff --git a/vendor/github.com/prometheus/client_golang/prometheus/doc.go b/vendor/github.com/prometheus/client_golang/prometheus/doc.go
new file mode 100644
index 0000000..01977de
--- /dev/null
+++ b/vendor/github.com/prometheus/client_golang/prometheus/doc.go
@@ -0,0 +1,200 @@
+// Copyright 2014 The Prometheus Authors
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Package prometheus is the core instrumentation package. It provides metrics
+// primitives to instrument code for monitoring. It also offers a registry for
+// metrics. Sub-packages allow to expose the registered metrics via HTTP
+// (package promhttp) or push them to a Pushgateway (package push). There is
+// also a sub-package promauto, which provides metrics constructors with
+// automatic registration.
+//
+// All exported functions and methods are safe to be used concurrently unless
+// specified otherwise.
+//
+// A Basic Example
+//
+// As a starting point, a very basic usage example:
+//
+// package main
+//
+// import (
+// "log"
+// "net/http"
+//
+// "github.com/prometheus/client_golang/prometheus"
+// "github.com/prometheus/client_golang/prometheus/promhttp"
+// )
+//
+// var (
+// cpuTemp = prometheus.NewGauge(prometheus.GaugeOpts{
+// Name: "cpu_temperature_celsius",
+// Help: "Current temperature of the CPU.",
+// })
+// hdFailures = prometheus.NewCounterVec(
+// prometheus.CounterOpts{
+// Name: "hd_errors_total",
+// Help: "Number of hard-disk errors.",
+// },
+// []string{"device"},
+// )
+// )
+//
+// func init() {
+// // Metrics have to be registered to be exposed:
+// prometheus.MustRegister(cpuTemp)
+// prometheus.MustRegister(hdFailures)
+// }
+//
+// func main() {
+// cpuTemp.Set(65.3)
+// hdFailures.With(prometheus.Labels{"device":"/dev/sda"}).Inc()
+//
+// // The Handler function provides a default handler to expose metrics
+// // via an HTTP server. "/metrics" is the usual endpoint for that.
+// http.Handle("/metrics", promhttp.Handler())
+// log.Fatal(http.ListenAndServe(":8080", nil))
+// }
+//
+//
+// This is a complete program that exports two metrics, a Gauge and a Counter,
+// the latter with a label attached to turn it into a (one-dimensional) vector.
+//
+// Metrics
+//
+// The number of exported identifiers in this package might appear a bit
+// overwhelming. However, in addition to the basic plumbing shown in the example
+// above, you only need to understand the different metric types and their
+// vector versions for basic usage. Furthermore, if you are not concerned with
+// fine-grained control of when and how to register metrics with the registry,
+// have a look at the promauto package, which will effectively allow you to
+// ignore registration altogether in simple cases.
+//
+// Above, you have already touched the Counter and the Gauge. There are two more
+// advanced metric types: the Summary and Histogram. A more thorough description
+// of those four metric types can be found in the Prometheus docs:
+// https://prometheus.io/docs/concepts/metric_types/
+//
+// A fifth "type" of metric is Untyped. It behaves like a Gauge, but signals the
+// Prometheus server not to assume anything about its type.
+//
+// In addition to the fundamental metric types Gauge, Counter, Summary,
+// Histogram, and Untyped, a very important part of the Prometheus data model is
+// the partitioning of samples along dimensions called labels, which results in
+// metric vectors. The fundamental types are GaugeVec, CounterVec, SummaryVec,
+// HistogramVec, and UntypedVec.
+//
+// While only the fundamental metric types implement the Metric interface, both
+// the metrics and their vector versions implement the Collector interface. A
+// Collector manages the collection of a number of Metrics, but for convenience,
+// a Metric can also “collect itself”. Note that Gauge, Counter, Summary,
+// Histogram, and Untyped are interfaces themselves while GaugeVec, CounterVec,
+// SummaryVec, HistogramVec, and UntypedVec are not.
+//
+// To create instances of Metrics and their vector versions, you need a suitable
+// …Opts struct, i.e. GaugeOpts, CounterOpts, SummaryOpts, HistogramOpts, or
+// UntypedOpts.
+//
+// Custom Collectors and constant Metrics
+//
+// While you could create your own implementations of Metric, most likely you
+// will only ever implement the Collector interface on your own. At a first
+// glance, a custom Collector seems handy to bundle Metrics for common
+// registration (with the prime example of the different metric vectors above,
+// which bundle all the metrics of the same name but with different labels).
+//
+// There is a more involved use case, too: If you already have metrics
+// available, created outside of the Prometheus context, you don't need the
+// interface of the various Metric types. You essentially want to mirror the
+// existing numbers into Prometheus Metrics during collection. An own
+// implementation of the Collector interface is perfect for that. You can create
+// Metric instances “on the fly” using NewConstMetric, NewConstHistogram, and
+// NewConstSummary (and their respective Must… versions). That will happen in
+// the Collect method. The Describe method has to return separate Desc
+// instances, representative of the “throw-away” metrics to be created later.
+// NewDesc comes in handy to create those Desc instances. Alternatively, you
+// could return no Desc at all, which will mark the Collector “unchecked”. No
+// checks are performed at registration time, but metric consistency will still
+// be ensured at scrape time, i.e. any inconsistencies will lead to scrape
+// errors. Thus, with unchecked Collectors, the responsibility to not collect
+// metrics that lead to inconsistencies in the total scrape result lies with the
+// implementer of the Collector. While this is not a desirable state, it is
+// sometimes necessary. The typical use case is a situation where the exact
+// metrics to be returned by a Collector cannot be predicted at registration
+// time, but the implementer has sufficient knowledge of the whole system to
+// guarantee metric consistency.
+//
+// The Collector example illustrates the use case. You can also look at the
+// source code of the processCollector (mirroring process metrics), the
+// goCollector (mirroring Go metrics), or the expvarCollector (mirroring expvar
+// metrics) as examples that are used in this package itself.
+//
+// If you just need to call a function to get a single float value to collect as
+// a metric, GaugeFunc, CounterFunc, or UntypedFunc might be interesting
+// shortcuts.
+//
+// Advanced Uses of the Registry
+//
+// While MustRegister is the by far most common way of registering a Collector,
+// sometimes you might want to handle the errors the registration might cause.
+// As suggested by the name, MustRegister panics if an error occurs. With the
+// Register function, the error is returned and can be handled.
+//
+// An error is returned if the registered Collector is incompatible or
+// inconsistent with already registered metrics. The registry aims for
+// consistency of the collected metrics according to the Prometheus data model.
+// Inconsistencies are ideally detected at registration time, not at collect
+// time. The former will usually be detected at start-up time of a program,
+// while the latter will only happen at scrape time, possibly not even on the
+// first scrape if the inconsistency only becomes relevant later. That is the
+// main reason why a Collector and a Metric have to describe themselves to the
+// registry.
+//
+// So far, everything we did operated on the so-called default registry, as it
+// can be found in the global DefaultRegisterer variable. With NewRegistry, you
+// can create a custom registry, or you can even implement the Registerer or
+// Gatherer interfaces yourself. The methods Register and Unregister work in the
+// same way on a custom registry as the global functions Register and Unregister
+// on the default registry.
+//
+// There are a number of uses for custom registries: You can use registries with
+// special properties, see NewPedanticRegistry. You can avoid global state, as
+// it is imposed by the DefaultRegisterer. You can use multiple registries at
+// the same time to expose different metrics in different ways. You can use
+// separate registries for testing purposes.
+//
+// Also note that the DefaultRegisterer comes registered with a Collector for Go
+// runtime metrics (via NewGoCollector) and a Collector for process metrics (via
+// NewProcessCollector). With a custom registry, you are in control and decide
+// yourself about the Collectors to register.
+//
+// HTTP Exposition
+//
+// The Registry implements the Gatherer interface. The caller of the Gather
+// method can then expose the gathered metrics in some way. Usually, the metrics
+// are served via HTTP on the /metrics endpoint. That's happening in the example
+// above. The tools to expose metrics via HTTP are in the promhttp sub-package.
+//
+// Pushing to the Pushgateway
+//
+// Function for pushing to the Pushgateway can be found in the push sub-package.
+//
+// Graphite Bridge
+//
+// Functions and examples to push metrics from a Gatherer to Graphite can be
+// found in the graphite sub-package.
+//
+// Other Means of Exposition
+//
+// More ways of exposing metrics can easily be added by following the approaches
+// of the existing implementations.
+package prometheus
diff --git a/vendor/github.com/prometheus/client_golang/prometheus/expvar_collector.go b/vendor/github.com/prometheus/client_golang/prometheus/expvar_collector.go
new file mode 100644
index 0000000..18a99d5
--- /dev/null
+++ b/vendor/github.com/prometheus/client_golang/prometheus/expvar_collector.go
@@ -0,0 +1,119 @@
+// Copyright 2014 The Prometheus Authors
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package prometheus
+
+import (
+ "encoding/json"
+ "expvar"
+)
+
+type expvarCollector struct {
+ exports map[string]*Desc
+}
+
+// NewExpvarCollector returns a newly allocated expvar Collector that still has
+// to be registered with a Prometheus registry.
+//
+// An expvar Collector collects metrics from the expvar interface. It provides a
+// quick way to expose numeric values that are already exported via expvar as
+// Prometheus metrics. Note that the data models of expvar and Prometheus are
+// fundamentally different, and that the expvar Collector is inherently slower
+// than native Prometheus metrics. Thus, the expvar Collector is probably great
+// for experiments and prototying, but you should seriously consider a more
+// direct implementation of Prometheus metrics for monitoring production
+// systems.
+//
+// The exports map has the following meaning:
+//
+// The keys in the map correspond to expvar keys, i.e. for every expvar key you
+// want to export as Prometheus metric, you need an entry in the exports
+// map. The descriptor mapped to each key describes how to export the expvar
+// value. It defines the name and the help string of the Prometheus metric
+// proxying the expvar value. The type will always be Untyped.
+//
+// For descriptors without variable labels, the expvar value must be a number or
+// a bool. The number is then directly exported as the Prometheus sample
+// value. (For a bool, 'false' translates to 0 and 'true' to 1). Expvar values
+// that are not numbers or bools are silently ignored.
+//
+// If the descriptor has one variable label, the expvar value must be an expvar
+// map. The keys in the expvar map become the various values of the one
+// Prometheus label. The values in the expvar map must be numbers or bools again
+// as above.
+//
+// For descriptors with more than one variable label, the expvar must be a
+// nested expvar map, i.e. where the values of the topmost map are maps again
+// etc. until a depth is reached that corresponds to the number of labels. The
+// leaves of that structure must be numbers or bools as above to serve as the
+// sample values.
+//
+// Anything that does not fit into the scheme above is silently ignored.
+func NewExpvarCollector(exports map[string]*Desc) Collector {
+ return &expvarCollector{
+ exports: exports,
+ }
+}
+
+// Describe implements Collector.
+func (e *expvarCollector) Describe(ch chan<- *Desc) {
+ for _, desc := range e.exports {
+ ch <- desc
+ }
+}
+
+// Collect implements Collector.
+func (e *expvarCollector) Collect(ch chan<- Metric) {
+ for name, desc := range e.exports {
+ var m Metric
+ expVar := expvar.Get(name)
+ if expVar == nil {
+ continue
+ }
+ var v interface{}
+ labels := make([]string, len(desc.variableLabels))
+ if err := json.Unmarshal([]byte(expVar.String()), &v); err != nil {
+ ch <- NewInvalidMetric(desc, err)
+ continue
+ }
+ var processValue func(v interface{}, i int)
+ processValue = func(v interface{}, i int) {
+ if i >= len(labels) {
+ copiedLabels := append(make([]string, 0, len(labels)), labels...)
+ switch v := v.(type) {
+ case float64:
+ m = MustNewConstMetric(desc, UntypedValue, v, copiedLabels...)
+ case bool:
+ if v {
+ m = MustNewConstMetric(desc, UntypedValue, 1, copiedLabels...)
+ } else {
+ m = MustNewConstMetric(desc, UntypedValue, 0, copiedLabels...)
+ }
+ default:
+ return
+ }
+ ch <- m
+ return
+ }
+ vm, ok := v.(map[string]interface{})
+ if !ok {
+ return
+ }
+ for lv, val := range vm {
+ labels[i] = lv
+ processValue(val, i+1)
+ }
+ }
+ processValue(v, 0)
+ }
+}
diff --git a/vendor/github.com/prometheus/client_golang/prometheus/fnv.go b/vendor/github.com/prometheus/client_golang/prometheus/fnv.go
new file mode 100644
index 0000000..3d383a7
--- /dev/null
+++ b/vendor/github.com/prometheus/client_golang/prometheus/fnv.go
@@ -0,0 +1,42 @@
+// Copyright 2018 The Prometheus Authors
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package prometheus
+
+// Inline and byte-free variant of hash/fnv's fnv64a.
+
+const (
+ offset64 = 14695981039346656037
+ prime64 = 1099511628211
+)
+
+// hashNew initializies a new fnv64a hash value.
+func hashNew() uint64 {
+ return offset64
+}
+
+// hashAdd adds a string to a fnv64a hash value, returning the updated hash.
+func hashAdd(h uint64, s string) uint64 {
+ for i := 0; i < len(s); i++ {
+ h ^= uint64(s[i])
+ h *= prime64
+ }
+ return h
+}
+
+// hashAddByte adds a byte to a fnv64a hash value, returning the updated hash.
+func hashAddByte(h uint64, b byte) uint64 {
+ h ^= uint64(b)
+ h *= prime64
+ return h
+}
diff --git a/vendor/github.com/prometheus/client_golang/prometheus/gauge.go b/vendor/github.com/prometheus/client_golang/prometheus/gauge.go
new file mode 100644
index 0000000..71d406b
--- /dev/null
+++ b/vendor/github.com/prometheus/client_golang/prometheus/gauge.go
@@ -0,0 +1,286 @@
+// Copyright 2014 The Prometheus Authors
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package prometheus
+
+import (
+ "math"
+ "sync/atomic"
+ "time"
+
+ dto "github.com/prometheus/client_model/go"
+)
+
+// Gauge is a Metric that represents a single numerical value that can
+// arbitrarily go up and down.
+//
+// A Gauge is typically used for measured values like temperatures or current
+// memory usage, but also "counts" that can go up and down, like the number of
+// running goroutines.
+//
+// To create Gauge instances, use NewGauge.
+type Gauge interface {
+ Metric
+ Collector
+
+ // Set sets the Gauge to an arbitrary value.
+ Set(float64)
+ // Inc increments the Gauge by 1. Use Add to increment it by arbitrary
+ // values.
+ Inc()
+ // Dec decrements the Gauge by 1. Use Sub to decrement it by arbitrary
+ // values.
+ Dec()
+ // Add adds the given value to the Gauge. (The value can be negative,
+ // resulting in a decrease of the Gauge.)
+ Add(float64)
+ // Sub subtracts the given value from the Gauge. (The value can be
+ // negative, resulting in an increase of the Gauge.)
+ Sub(float64)
+
+ // SetToCurrentTime sets the Gauge to the current Unix time in seconds.
+ SetToCurrentTime()
+}
+
+// GaugeOpts is an alias for Opts. See there for doc comments.
+type GaugeOpts Opts
+
+// NewGauge creates a new Gauge based on the provided GaugeOpts.
+//
+// The returned implementation is optimized for a fast Set method. If you have a
+// choice for managing the value of a Gauge via Set vs. Inc/Dec/Add/Sub, pick
+// the former. For example, the Inc method of the returned Gauge is slower than
+// the Inc method of a Counter returned by NewCounter. This matches the typical
+// scenarios for Gauges and Counters, where the former tends to be Set-heavy and
+// the latter Inc-heavy.
+func NewGauge(opts GaugeOpts) Gauge {
+ desc := NewDesc(
+ BuildFQName(opts.Namespace, opts.Subsystem, opts.Name),
+ opts.Help,
+ nil,
+ opts.ConstLabels,
+ )
+ result := &gauge{desc: desc, labelPairs: desc.constLabelPairs}
+ result.init(result) // Init self-collection.
+ return result
+}
+
+type gauge struct {
+ // valBits contains the bits of the represented float64 value. It has
+ // to go first in the struct to guarantee alignment for atomic
+ // operations. http://golang.org/pkg/sync/atomic/#pkg-note-BUG
+ valBits uint64
+
+ selfCollector
+
+ desc *Desc
+ labelPairs []*dto.LabelPair
+}
+
+func (g *gauge) Desc() *Desc {
+ return g.desc
+}
+
+func (g *gauge) Set(val float64) {
+ atomic.StoreUint64(&g.valBits, math.Float64bits(val))
+}
+
+func (g *gauge) SetToCurrentTime() {
+ g.Set(float64(time.Now().UnixNano()) / 1e9)
+}
+
+func (g *gauge) Inc() {
+ g.Add(1)
+}
+
+func (g *gauge) Dec() {
+ g.Add(-1)
+}
+
+func (g *gauge) Add(val float64) {
+ for {
+ oldBits := atomic.LoadUint64(&g.valBits)
+ newBits := math.Float64bits(math.Float64frombits(oldBits) + val)
+ if atomic.CompareAndSwapUint64(&g.valBits, oldBits, newBits) {
+ return
+ }
+ }
+}
+
+func (g *gauge) Sub(val float64) {
+ g.Add(val * -1)
+}
+
+func (g *gauge) Write(out *dto.Metric) error {
+ val := math.Float64frombits(atomic.LoadUint64(&g.valBits))
+ return populateMetric(GaugeValue, val, g.labelPairs, out)
+}
+
+// GaugeVec is a Collector that bundles a set of Gauges that all share the same
+// Desc, but have different values for their variable labels. This is used if
+// you want to count the same thing partitioned by various dimensions
+// (e.g. number of operations queued, partitioned by user and operation
+// type). Create instances with NewGaugeVec.
+type GaugeVec struct {
+ *metricVec
+}
+
+// NewGaugeVec creates a new GaugeVec based on the provided GaugeOpts and
+// partitioned by the given label names.
+func NewGaugeVec(opts GaugeOpts, labelNames []string) *GaugeVec {
+ desc := NewDesc(
+ BuildFQName(opts.Namespace, opts.Subsystem, opts.Name),
+ opts.Help,
+ labelNames,
+ opts.ConstLabels,
+ )
+ return &GaugeVec{
+ metricVec: newMetricVec(desc, func(lvs ...string) Metric {
+ if len(lvs) != len(desc.variableLabels) {
+ panic(makeInconsistentCardinalityError(desc.fqName, desc.variableLabels, lvs))
+ }
+ result := &gauge{desc: desc, labelPairs: makeLabelPairs(desc, lvs)}
+ result.init(result) // Init self-collection.
+ return result
+ }),
+ }
+}
+
+// GetMetricWithLabelValues returns the Gauge for the given slice of label
+// values (same order as the VariableLabels in Desc). If that combination of
+// label values is accessed for the first time, a new Gauge is created.
+//
+// It is possible to call this method without using the returned Gauge to only
+// create the new Gauge but leave it at its starting value 0. See also the
+// SummaryVec example.
+//
+// Keeping the Gauge for later use is possible (and should be considered if
+// performance is critical), but keep in mind that Reset, DeleteLabelValues and
+// Delete can be used to delete the Gauge from the GaugeVec. In that case, the
+// Gauge will still exist, but it will not be exported anymore, even if a
+// Gauge with the same label values is created later. See also the CounterVec
+// example.
+//
+// An error is returned if the number of label values is not the same as the
+// number of VariableLabels in Desc (minus any curried labels).
+//
+// Note that for more than one label value, this method is prone to mistakes
+// caused by an incorrect order of arguments. Consider GetMetricWith(Labels) as
+// an alternative to avoid that type of mistake. For higher label numbers, the
+// latter has a much more readable (albeit more verbose) syntax, but it comes
+// with a performance overhead (for creating and processing the Labels map).
+func (v *GaugeVec) GetMetricWithLabelValues(lvs ...string) (Gauge, error) {
+ metric, err := v.metricVec.getMetricWithLabelValues(lvs...)
+ if metric != nil {
+ return metric.(Gauge), err
+ }
+ return nil, err
+}
+
+// GetMetricWith returns the Gauge for the given Labels map (the label names
+// must match those of the VariableLabels in Desc). If that label map is
+// accessed for the first time, a new Gauge is created. Implications of
+// creating a Gauge without using it and keeping the Gauge for later use are
+// the same as for GetMetricWithLabelValues.
+//
+// An error is returned if the number and names of the Labels are inconsistent
+// with those of the VariableLabels in Desc (minus any curried labels).
+//
+// This method is used for the same purpose as
+// GetMetricWithLabelValues(...string). See there for pros and cons of the two
+// methods.
+func (v *GaugeVec) GetMetricWith(labels Labels) (Gauge, error) {
+ metric, err := v.metricVec.getMetricWith(labels)
+ if metric != nil {
+ return metric.(Gauge), err
+ }
+ return nil, err
+}
+
+// WithLabelValues works as GetMetricWithLabelValues, but panics where
+// GetMetricWithLabelValues would have returned an error. Not returning an
+// error allows shortcuts like
+// myVec.WithLabelValues("404", "GET").Add(42)
+func (v *GaugeVec) WithLabelValues(lvs ...string) Gauge {
+ g, err := v.GetMetricWithLabelValues(lvs...)
+ if err != nil {
+ panic(err)
+ }
+ return g
+}
+
+// With works as GetMetricWith, but panics where GetMetricWithLabels would have
+// returned an error. Not returning an error allows shortcuts like
+// myVec.With(prometheus.Labels{"code": "404", "method": "GET"}).Add(42)
+func (v *GaugeVec) With(labels Labels) Gauge {
+ g, err := v.GetMetricWith(labels)
+ if err != nil {
+ panic(err)
+ }
+ return g
+}
+
+// CurryWith returns a vector curried with the provided labels, i.e. the
+// returned vector has those labels pre-set for all labeled operations performed
+// on it. The cardinality of the curried vector is reduced accordingly. The
+// order of the remaining labels stays the same (just with the curried labels
+// taken out of the sequence – which is relevant for the
+// (GetMetric)WithLabelValues methods). It is possible to curry a curried
+// vector, but only with labels not yet used for currying before.
+//
+// The metrics contained in the GaugeVec are shared between the curried and
+// uncurried vectors. They are just accessed differently. Curried and uncurried
+// vectors behave identically in terms of collection. Only one must be
+// registered with a given registry (usually the uncurried version). The Reset
+// method deletes all metrics, even if called on a curried vector.
+func (v *GaugeVec) CurryWith(labels Labels) (*GaugeVec, error) {
+ vec, err := v.curryWith(labels)
+ if vec != nil {
+ return &GaugeVec{vec}, err
+ }
+ return nil, err
+}
+
+// MustCurryWith works as CurryWith but panics where CurryWith would have
+// returned an error.
+func (v *GaugeVec) MustCurryWith(labels Labels) *GaugeVec {
+ vec, err := v.CurryWith(labels)
+ if err != nil {
+ panic(err)
+ }
+ return vec
+}
+
+// GaugeFunc is a Gauge whose value is determined at collect time by calling a
+// provided function.
+//
+// To create GaugeFunc instances, use NewGaugeFunc.
+type GaugeFunc interface {
+ Metric
+ Collector
+}
+
+// NewGaugeFunc creates a new GaugeFunc based on the provided GaugeOpts. The
+// value reported is determined by calling the given function from within the
+// Write method. Take into account that metric collection may happen
+// concurrently. If that results in concurrent calls to Write, like in the case
+// where a GaugeFunc is directly registered with Prometheus, the provided
+// function must be concurrency-safe.
+func NewGaugeFunc(opts GaugeOpts, function func() float64) GaugeFunc {
+ return newValueFunc(NewDesc(
+ BuildFQName(opts.Namespace, opts.Subsystem, opts.Name),
+ opts.Help,
+ nil,
+ opts.ConstLabels,
+ ), GaugeValue, function)
+}
diff --git a/vendor/github.com/prometheus/client_golang/prometheus/go_collector.go b/vendor/github.com/prometheus/client_golang/prometheus/go_collector.go
new file mode 100644
index 0000000..dc9247f
--- /dev/null
+++ b/vendor/github.com/prometheus/client_golang/prometheus/go_collector.go
@@ -0,0 +1,396 @@
+// Copyright 2018 The Prometheus Authors
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package prometheus
+
+import (
+ "runtime"
+ "runtime/debug"
+ "sync"
+ "time"
+)
+
+type goCollector struct {
+ goroutinesDesc *Desc
+ threadsDesc *Desc
+ gcDesc *Desc
+ goInfoDesc *Desc
+
+ // ms... are memstats related.
+ msLast *runtime.MemStats // Previously collected memstats.
+ msLastTimestamp time.Time
+ msMtx sync.Mutex // Protects msLast and msLastTimestamp.
+ msMetrics memStatsMetrics
+ msRead func(*runtime.MemStats) // For mocking in tests.
+ msMaxWait time.Duration // Wait time for fresh memstats.
+ msMaxAge time.Duration // Maximum allowed age of old memstats.
+}
+
+// NewGoCollector returns a collector that exports metrics about the current Go
+// process. This includes memory stats. To collect those, runtime.ReadMemStats
+// is called. This requires to “stop the world”, which usually only happens for
+// garbage collection (GC). Take the following implications into account when
+// deciding whether to use the Go collector:
+//
+// 1. The performance impact of stopping the world is the more relevant the more
+// frequently metrics are collected. However, with Go1.9 or later the
+// stop-the-world time per metrics collection is very short (~25µs) so that the
+// performance impact will only matter in rare cases. However, with older Go
+// versions, the stop-the-world duration depends on the heap size and can be
+// quite significant (~1.7 ms/GiB as per
+// https://go-review.googlesource.com/c/go/+/34937).
+//
+// 2. During an ongoing GC, nothing else can stop the world. Therefore, if the
+// metrics collection happens to coincide with GC, it will only complete after
+// GC has finished. Usually, GC is fast enough to not cause problems. However,
+// with a very large heap, GC might take multiple seconds, which is enough to
+// cause scrape timeouts in common setups. To avoid this problem, the Go
+// collector will use the memstats from a previous collection if
+// runtime.ReadMemStats takes more than 1s. However, if there are no previously
+// collected memstats, or their collection is more than 5m ago, the collection
+// will block until runtime.ReadMemStats succeeds. (The problem might be solved
+// in Go1.13, see https://github.com/golang/go/issues/19812 for the related Go
+// issue.)
+func NewGoCollector() Collector {
+ return &goCollector{
+ goroutinesDesc: NewDesc(
+ "go_goroutines",
+ "Number of goroutines that currently exist.",
+ nil, nil),
+ threadsDesc: NewDesc(
+ "go_threads",
+ "Number of OS threads created.",
+ nil, nil),
+ gcDesc: NewDesc(
+ "go_gc_duration_seconds",
+ "A summary of the GC invocation durations.",
+ nil, nil),
+ goInfoDesc: NewDesc(
+ "go_info",
+ "Information about the Go environment.",
+ nil, Labels{"version": runtime.Version()}),
+ msLast: &runtime.MemStats{},
+ msRead: runtime.ReadMemStats,
+ msMaxWait: time.Second,
+ msMaxAge: 5 * time.Minute,
+ msMetrics: memStatsMetrics{
+ {
+ desc: NewDesc(
+ memstatNamespace("alloc_bytes"),
+ "Number of bytes allocated and still in use.",
+ nil, nil,
+ ),
+ eval: func(ms *runtime.MemStats) float64 { return float64(ms.Alloc) },
+ valType: GaugeValue,
+ }, {
+ desc: NewDesc(
+ memstatNamespace("alloc_bytes_total"),
+ "Total number of bytes allocated, even if freed.",
+ nil, nil,
+ ),
+ eval: func(ms *runtime.MemStats) float64 { return float64(ms.TotalAlloc) },
+ valType: CounterValue,
+ }, {
+ desc: NewDesc(
+ memstatNamespace("sys_bytes"),
+ "Number of bytes obtained from system.",
+ nil, nil,
+ ),
+ eval: func(ms *runtime.MemStats) float64 { return float64(ms.Sys) },
+ valType: GaugeValue,
+ }, {
+ desc: NewDesc(
+ memstatNamespace("lookups_total"),
+ "Total number of pointer lookups.",
+ nil, nil,
+ ),
+ eval: func(ms *runtime.MemStats) float64 { return float64(ms.Lookups) },
+ valType: CounterValue,
+ }, {
+ desc: NewDesc(
+ memstatNamespace("mallocs_total"),
+ "Total number of mallocs.",
+ nil, nil,
+ ),
+ eval: func(ms *runtime.MemStats) float64 { return float64(ms.Mallocs) },
+ valType: CounterValue,
+ }, {
+ desc: NewDesc(
+ memstatNamespace("frees_total"),
+ "Total number of frees.",
+ nil, nil,
+ ),
+ eval: func(ms *runtime.MemStats) float64 { return float64(ms.Frees) },
+ valType: CounterValue,
+ }, {
+ desc: NewDesc(
+ memstatNamespace("heap_alloc_bytes"),
+ "Number of heap bytes allocated and still in use.",
+ nil, nil,
+ ),
+ eval: func(ms *runtime.MemStats) float64 { return float64(ms.HeapAlloc) },
+ valType: GaugeValue,
+ }, {
+ desc: NewDesc(
+ memstatNamespace("heap_sys_bytes"),
+ "Number of heap bytes obtained from system.",
+ nil, nil,
+ ),
+ eval: func(ms *runtime.MemStats) float64 { return float64(ms.HeapSys) },
+ valType: GaugeValue,
+ }, {
+ desc: NewDesc(
+ memstatNamespace("heap_idle_bytes"),
+ "Number of heap bytes waiting to be used.",
+ nil, nil,
+ ),
+ eval: func(ms *runtime.MemStats) float64 { return float64(ms.HeapIdle) },
+ valType: GaugeValue,
+ }, {
+ desc: NewDesc(
+ memstatNamespace("heap_inuse_bytes"),
+ "Number of heap bytes that are in use.",
+ nil, nil,
+ ),
+ eval: func(ms *runtime.MemStats) float64 { return float64(ms.HeapInuse) },
+ valType: GaugeValue,
+ }, {
+ desc: NewDesc(
+ memstatNamespace("heap_released_bytes"),
+ "Number of heap bytes released to OS.",
+ nil, nil,
+ ),
+ eval: func(ms *runtime.MemStats) float64 { return float64(ms.HeapReleased) },
+ valType: GaugeValue,
+ }, {
+ desc: NewDesc(
+ memstatNamespace("heap_objects"),
+ "Number of allocated objects.",
+ nil, nil,
+ ),
+ eval: func(ms *runtime.MemStats) float64 { return float64(ms.HeapObjects) },
+ valType: GaugeValue,
+ }, {
+ desc: NewDesc(
+ memstatNamespace("stack_inuse_bytes"),
+ "Number of bytes in use by the stack allocator.",
+ nil, nil,
+ ),
+ eval: func(ms *runtime.MemStats) float64 { return float64(ms.StackInuse) },
+ valType: GaugeValue,
+ }, {
+ desc: NewDesc(
+ memstatNamespace("stack_sys_bytes"),
+ "Number of bytes obtained from system for stack allocator.",
+ nil, nil,
+ ),
+ eval: func(ms *runtime.MemStats) float64 { return float64(ms.StackSys) },
+ valType: GaugeValue,
+ }, {
+ desc: NewDesc(
+ memstatNamespace("mspan_inuse_bytes"),
+ "Number of bytes in use by mspan structures.",
+ nil, nil,
+ ),
+ eval: func(ms *runtime.MemStats) float64 { return float64(ms.MSpanInuse) },
+ valType: GaugeValue,
+ }, {
+ desc: NewDesc(
+ memstatNamespace("mspan_sys_bytes"),
+ "Number of bytes used for mspan structures obtained from system.",
+ nil, nil,
+ ),
+ eval: func(ms *runtime.MemStats) float64 { return float64(ms.MSpanSys) },
+ valType: GaugeValue,
+ }, {
+ desc: NewDesc(
+ memstatNamespace("mcache_inuse_bytes"),
+ "Number of bytes in use by mcache structures.",
+ nil, nil,
+ ),
+ eval: func(ms *runtime.MemStats) float64 { return float64(ms.MCacheInuse) },
+ valType: GaugeValue,
+ }, {
+ desc: NewDesc(
+ memstatNamespace("mcache_sys_bytes"),
+ "Number of bytes used for mcache structures obtained from system.",
+ nil, nil,
+ ),
+ eval: func(ms *runtime.MemStats) float64 { return float64(ms.MCacheSys) },
+ valType: GaugeValue,
+ }, {
+ desc: NewDesc(
+ memstatNamespace("buck_hash_sys_bytes"),
+ "Number of bytes used by the profiling bucket hash table.",
+ nil, nil,
+ ),
+ eval: func(ms *runtime.MemStats) float64 { return float64(ms.BuckHashSys) },
+ valType: GaugeValue,
+ }, {
+ desc: NewDesc(
+ memstatNamespace("gc_sys_bytes"),
+ "Number of bytes used for garbage collection system metadata.",
+ nil, nil,
+ ),
+ eval: func(ms *runtime.MemStats) float64 { return float64(ms.GCSys) },
+ valType: GaugeValue,
+ }, {
+ desc: NewDesc(
+ memstatNamespace("other_sys_bytes"),
+ "Number of bytes used for other system allocations.",
+ nil, nil,
+ ),
+ eval: func(ms *runtime.MemStats) float64 { return float64(ms.OtherSys) },
+ valType: GaugeValue,
+ }, {
+ desc: NewDesc(
+ memstatNamespace("next_gc_bytes"),
+ "Number of heap bytes when next garbage collection will take place.",
+ nil, nil,
+ ),
+ eval: func(ms *runtime.MemStats) float64 { return float64(ms.NextGC) },
+ valType: GaugeValue,
+ }, {
+ desc: NewDesc(
+ memstatNamespace("last_gc_time_seconds"),
+ "Number of seconds since 1970 of last garbage collection.",
+ nil, nil,
+ ),
+ eval: func(ms *runtime.MemStats) float64 { return float64(ms.LastGC) / 1e9 },
+ valType: GaugeValue,
+ }, {
+ desc: NewDesc(
+ memstatNamespace("gc_cpu_fraction"),
+ "The fraction of this program's available CPU time used by the GC since the program started.",
+ nil, nil,
+ ),
+ eval: func(ms *runtime.MemStats) float64 { return ms.GCCPUFraction },
+ valType: GaugeValue,
+ },
+ },
+ }
+}
+
+func memstatNamespace(s string) string {
+ return "go_memstats_" + s
+}
+
+// Describe returns all descriptions of the collector.
+func (c *goCollector) Describe(ch chan<- *Desc) {
+ ch <- c.goroutinesDesc
+ ch <- c.threadsDesc
+ ch <- c.gcDesc
+ ch <- c.goInfoDesc
+ for _, i := range c.msMetrics {
+ ch <- i.desc
+ }
+}
+
+// Collect returns the current state of all metrics of the collector.
+func (c *goCollector) Collect(ch chan<- Metric) {
+ var (
+ ms = &runtime.MemStats{}
+ done = make(chan struct{})
+ )
+ // Start reading memstats first as it might take a while.
+ go func() {
+ c.msRead(ms)
+ c.msMtx.Lock()
+ c.msLast = ms
+ c.msLastTimestamp = time.Now()
+ c.msMtx.Unlock()
+ close(done)
+ }()
+
+ ch <- MustNewConstMetric(c.goroutinesDesc, GaugeValue, float64(runtime.NumGoroutine()))
+ n, _ := runtime.ThreadCreateProfile(nil)
+ ch <- MustNewConstMetric(c.threadsDesc, GaugeValue, float64(n))
+
+ var stats debug.GCStats
+ stats.PauseQuantiles = make([]time.Duration, 5)
+ debug.ReadGCStats(&stats)
+
+ quantiles := make(map[float64]float64)
+ for idx, pq := range stats.PauseQuantiles[1:] {
+ quantiles[float64(idx+1)/float64(len(stats.PauseQuantiles)-1)] = pq.Seconds()
+ }
+ quantiles[0.0] = stats.PauseQuantiles[0].Seconds()
+ ch <- MustNewConstSummary(c.gcDesc, uint64(stats.NumGC), stats.PauseTotal.Seconds(), quantiles)
+
+ ch <- MustNewConstMetric(c.goInfoDesc, GaugeValue, 1)
+
+ timer := time.NewTimer(c.msMaxWait)
+ select {
+ case <-done: // Our own ReadMemStats succeeded in time. Use it.
+ timer.Stop() // Important for high collection frequencies to not pile up timers.
+ c.msCollect(ch, ms)
+ return
+ case <-timer.C: // Time out, use last memstats if possible. Continue below.
+ }
+ c.msMtx.Lock()
+ if time.Since(c.msLastTimestamp) < c.msMaxAge {
+ // Last memstats are recent enough. Collect from them under the lock.
+ c.msCollect(ch, c.msLast)
+ c.msMtx.Unlock()
+ return
+ }
+ // If we are here, the last memstats are too old or don't exist. We have
+ // to wait until our own ReadMemStats finally completes. For that to
+ // happen, we have to release the lock.
+ c.msMtx.Unlock()
+ <-done
+ c.msCollect(ch, ms)
+}
+
+func (c *goCollector) msCollect(ch chan<- Metric, ms *runtime.MemStats) {
+ for _, i := range c.msMetrics {
+ ch <- MustNewConstMetric(i.desc, i.valType, i.eval(ms))
+ }
+}
+
+// memStatsMetrics provide description, value, and value type for memstat metrics.
+type memStatsMetrics []struct {
+ desc *Desc
+ eval func(*runtime.MemStats) float64
+ valType ValueType
+}
+
+// NewBuildInfoCollector returns a collector collecting a single metric
+// "go_build_info" with the constant value 1 and three labels "path", "version",
+// and "checksum". Their label values contain the main module path, version, and
+// checksum, respectively. The labels will only have meaningful values if the
+// binary is built with Go module support and from source code retrieved from
+// the source repository (rather than the local file system). This is usually
+// accomplished by building from outside of GOPATH, specifying the full address
+// of the main package, e.g. "GO111MODULE=on go run
+// github.com/prometheus/client_golang/examples/random". If built without Go
+// module support, all label values will be "unknown". If built with Go module
+// support but using the source code from the local file system, the "path" will
+// be set appropriately, but "checksum" will be empty and "version" will be
+// "(devel)".
+//
+// This collector uses only the build information for the main module. See
+// https://github.com/povilasv/prommod for an example of a collector for the
+// module dependencies.
+func NewBuildInfoCollector() Collector {
+ path, version, sum := readBuildInfo()
+ c := &selfCollector{MustNewConstMetric(
+ NewDesc(
+ "go_build_info",
+ "Build information about the main Go module.",
+ nil, Labels{"path": path, "version": version, "checksum": sum},
+ ),
+ GaugeValue, 1)}
+ c.init(c.self)
+ return c
+}
diff --git a/vendor/github.com/prometheus/client_golang/prometheus/histogram.go b/vendor/github.com/prometheus/client_golang/prometheus/histogram.go
new file mode 100644
index 0000000..d7ea67b
--- /dev/null
+++ b/vendor/github.com/prometheus/client_golang/prometheus/histogram.go
@@ -0,0 +1,586 @@
+// Copyright 2015 The Prometheus Authors
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package prometheus
+
+import (
+ "fmt"
+ "math"
+ "runtime"
+ "sort"
+ "sync"
+ "sync/atomic"
+
+ "github.com/golang/protobuf/proto"
+
+ dto "github.com/prometheus/client_model/go"
+)
+
+// A Histogram counts individual observations from an event or sample stream in
+// configurable buckets. Similar to a summary, it also provides a sum of
+// observations and an observation count.
+//
+// On the Prometheus server, quantiles can be calculated from a Histogram using
+// the histogram_quantile function in the query language.
+//
+// Note that Histograms, in contrast to Summaries, can be aggregated with the
+// Prometheus query language (see the documentation for detailed
+// procedures). However, Histograms require the user to pre-define suitable
+// buckets, and they are in general less accurate. The Observe method of a
+// Histogram has a very low performance overhead in comparison with the Observe
+// method of a Summary.
+//
+// To create Histogram instances, use NewHistogram.
+type Histogram interface {
+ Metric
+ Collector
+
+ // Observe adds a single observation to the histogram.
+ Observe(float64)
+}
+
+// bucketLabel is used for the label that defines the upper bound of a
+// bucket of a histogram ("le" -> "less or equal").
+const bucketLabel = "le"
+
+// DefBuckets are the default Histogram buckets. The default buckets are
+// tailored to broadly measure the response time (in seconds) of a network
+// service. Most likely, however, you will be required to define buckets
+// customized to your use case.
+var (
+ DefBuckets = []float64{.005, .01, .025, .05, .1, .25, .5, 1, 2.5, 5, 10}
+
+ errBucketLabelNotAllowed = fmt.Errorf(
+ "%q is not allowed as label name in histograms", bucketLabel,
+ )
+)
+
+// LinearBuckets creates 'count' buckets, each 'width' wide, where the lowest
+// bucket has an upper bound of 'start'. The final +Inf bucket is not counted
+// and not included in the returned slice. The returned slice is meant to be
+// used for the Buckets field of HistogramOpts.
+//
+// The function panics if 'count' is zero or negative.
+func LinearBuckets(start, width float64, count int) []float64 {
+ if count < 1 {
+ panic("LinearBuckets needs a positive count")
+ }
+ buckets := make([]float64, count)
+ for i := range buckets {
+ buckets[i] = start
+ start += width
+ }
+ return buckets
+}
+
+// ExponentialBuckets creates 'count' buckets, where the lowest bucket has an
+// upper bound of 'start' and each following bucket's upper bound is 'factor'
+// times the previous bucket's upper bound. The final +Inf bucket is not counted
+// and not included in the returned slice. The returned slice is meant to be
+// used for the Buckets field of HistogramOpts.
+//
+// The function panics if 'count' is 0 or negative, if 'start' is 0 or negative,
+// or if 'factor' is less than or equal 1.
+func ExponentialBuckets(start, factor float64, count int) []float64 {
+ if count < 1 {
+ panic("ExponentialBuckets needs a positive count")
+ }
+ if start <= 0 {
+ panic("ExponentialBuckets needs a positive start value")
+ }
+ if factor <= 1 {
+ panic("ExponentialBuckets needs a factor greater than 1")
+ }
+ buckets := make([]float64, count)
+ for i := range buckets {
+ buckets[i] = start
+ start *= factor
+ }
+ return buckets
+}
+
+// HistogramOpts bundles the options for creating a Histogram metric. It is
+// mandatory to set Name to a non-empty string. All other fields are optional
+// and can safely be left at their zero value, although it is strongly
+// encouraged to set a Help string.
+type HistogramOpts struct {
+ // Namespace, Subsystem, and Name are components of the fully-qualified
+ // name of the Histogram (created by joining these components with
+ // "_"). Only Name is mandatory, the others merely help structuring the
+ // name. Note that the fully-qualified name of the Histogram must be a
+ // valid Prometheus metric name.
+ Namespace string
+ Subsystem string
+ Name string
+
+ // Help provides information about this Histogram.
+ //
+ // Metrics with the same fully-qualified name must have the same Help
+ // string.
+ Help string
+
+ // ConstLabels are used to attach fixed labels to this metric. Metrics
+ // with the same fully-qualified name must have the same label names in
+ // their ConstLabels.
+ //
+ // ConstLabels are only used rarely. In particular, do not use them to
+ // attach the same labels to all your metrics. Those use cases are
+ // better covered by target labels set by the scraping Prometheus
+ // server, or by one specific metric (e.g. a build_info or a
+ // machine_role metric). See also
+ // https://prometheus.io/docs/instrumenting/writing_exporters/#target-labels,-not-static-scraped-labels
+ ConstLabels Labels
+
+ // Buckets defines the buckets into which observations are counted. Each
+ // element in the slice is the upper inclusive bound of a bucket. The
+ // values must be sorted in strictly increasing order. There is no need
+ // to add a highest bucket with +Inf bound, it will be added
+ // implicitly. The default value is DefBuckets.
+ Buckets []float64
+}
+
+// NewHistogram creates a new Histogram based on the provided HistogramOpts. It
+// panics if the buckets in HistogramOpts are not in strictly increasing order.
+func NewHistogram(opts HistogramOpts) Histogram {
+ return newHistogram(
+ NewDesc(
+ BuildFQName(opts.Namespace, opts.Subsystem, opts.Name),
+ opts.Help,
+ nil,
+ opts.ConstLabels,
+ ),
+ opts,
+ )
+}
+
+func newHistogram(desc *Desc, opts HistogramOpts, labelValues ...string) Histogram {
+ if len(desc.variableLabels) != len(labelValues) {
+ panic(makeInconsistentCardinalityError(desc.fqName, desc.variableLabels, labelValues))
+ }
+
+ for _, n := range desc.variableLabels {
+ if n == bucketLabel {
+ panic(errBucketLabelNotAllowed)
+ }
+ }
+ for _, lp := range desc.constLabelPairs {
+ if lp.GetName() == bucketLabel {
+ panic(errBucketLabelNotAllowed)
+ }
+ }
+
+ if len(opts.Buckets) == 0 {
+ opts.Buckets = DefBuckets
+ }
+
+ h := &histogram{
+ desc: desc,
+ upperBounds: opts.Buckets,
+ labelPairs: makeLabelPairs(desc, labelValues),
+ counts: [2]*histogramCounts{&histogramCounts{}, &histogramCounts{}},
+ }
+ for i, upperBound := range h.upperBounds {
+ if i < len(h.upperBounds)-1 {
+ if upperBound >= h.upperBounds[i+1] {
+ panic(fmt.Errorf(
+ "histogram buckets must be in increasing order: %f >= %f",
+ upperBound, h.upperBounds[i+1],
+ ))
+ }
+ } else {
+ if math.IsInf(upperBound, +1) {
+ // The +Inf bucket is implicit. Remove it here.
+ h.upperBounds = h.upperBounds[:i]
+ }
+ }
+ }
+ // Finally we know the final length of h.upperBounds and can make buckets
+ // for both counts:
+ h.counts[0].buckets = make([]uint64, len(h.upperBounds))
+ h.counts[1].buckets = make([]uint64, len(h.upperBounds))
+
+ h.init(h) // Init self-collection.
+ return h
+}
+
+type histogramCounts struct {
+ // sumBits contains the bits of the float64 representing the sum of all
+ // observations. sumBits and count have to go first in the struct to
+ // guarantee alignment for atomic operations.
+ // http://golang.org/pkg/sync/atomic/#pkg-note-BUG
+ sumBits uint64
+ count uint64
+ buckets []uint64
+}
+
+type histogram struct {
+ // countAndHotIdx enables lock-free writes with use of atomic updates.
+ // The most significant bit is the hot index [0 or 1] of the count field
+ // below. Observe calls update the hot one. All remaining bits count the
+ // number of Observe calls. Observe starts by incrementing this counter,
+ // and finish by incrementing the count field in the respective
+ // histogramCounts, as a marker for completion.
+ //
+ // Calls of the Write method (which are non-mutating reads from the
+ // perspective of the histogram) swap the hot–cold under the writeMtx
+ // lock. A cooldown is awaited (while locked) by comparing the number of
+ // observations with the initiation count. Once they match, then the
+ // last observation on the now cool one has completed. All cool fields must
+ // be merged into the new hot before releasing writeMtx.
+ //
+ // Fields with atomic access first! See alignment constraint:
+ // http://golang.org/pkg/sync/atomic/#pkg-note-BUG
+ countAndHotIdx uint64
+
+ selfCollector
+ desc *Desc
+ writeMtx sync.Mutex // Only used in the Write method.
+
+ // Two counts, one is "hot" for lock-free observations, the other is
+ // "cold" for writing out a dto.Metric. It has to be an array of
+ // pointers to guarantee 64bit alignment of the histogramCounts, see
+ // http://golang.org/pkg/sync/atomic/#pkg-note-BUG.
+ counts [2]*histogramCounts
+
+ upperBounds []float64
+ labelPairs []*dto.LabelPair
+}
+
+func (h *histogram) Desc() *Desc {
+ return h.desc
+}
+
+func (h *histogram) Observe(v float64) {
+ // TODO(beorn7): For small numbers of buckets (<30), a linear search is
+ // slightly faster than the binary search. If we really care, we could
+ // switch from one search strategy to the other depending on the number
+ // of buckets.
+ //
+ // Microbenchmarks (BenchmarkHistogramNoLabels):
+ // 11 buckets: 38.3 ns/op linear - binary 48.7 ns/op
+ // 100 buckets: 78.1 ns/op linear - binary 54.9 ns/op
+ // 300 buckets: 154 ns/op linear - binary 61.6 ns/op
+ i := sort.SearchFloat64s(h.upperBounds, v)
+
+ // We increment h.countAndHotIdx so that the counter in the lower
+ // 63 bits gets incremented. At the same time, we get the new value
+ // back, which we can use to find the currently-hot counts.
+ n := atomic.AddUint64(&h.countAndHotIdx, 1)
+ hotCounts := h.counts[n>>63]
+
+ if i < len(h.upperBounds) {
+ atomic.AddUint64(&hotCounts.buckets[i], 1)
+ }
+ for {
+ oldBits := atomic.LoadUint64(&hotCounts.sumBits)
+ newBits := math.Float64bits(math.Float64frombits(oldBits) + v)
+ if atomic.CompareAndSwapUint64(&hotCounts.sumBits, oldBits, newBits) {
+ break
+ }
+ }
+ // Increment count last as we take it as a signal that the observation
+ // is complete.
+ atomic.AddUint64(&hotCounts.count, 1)
+}
+
+func (h *histogram) Write(out *dto.Metric) error {
+ // For simplicity, we protect this whole method by a mutex. It is not in
+ // the hot path, i.e. Observe is called much more often than Write. The
+ // complication of making Write lock-free isn't worth it, if possible at
+ // all.
+ h.writeMtx.Lock()
+ defer h.writeMtx.Unlock()
+
+ // Adding 1<<63 switches the hot index (from 0 to 1 or from 1 to 0)
+ // without touching the count bits. See the struct comments for a full
+ // description of the algorithm.
+ n := atomic.AddUint64(&h.countAndHotIdx, 1<<63)
+ // count is contained unchanged in the lower 63 bits.
+ count := n & ((1 << 63) - 1)
+ // The most significant bit tells us which counts is hot. The complement
+ // is thus the cold one.
+ hotCounts := h.counts[n>>63]
+ coldCounts := h.counts[(^n)>>63]
+
+ // Await cooldown.
+ for count != atomic.LoadUint64(&coldCounts.count) {
+ runtime.Gosched() // Let observations get work done.
+ }
+
+ his := &dto.Histogram{
+ Bucket: make([]*dto.Bucket, len(h.upperBounds)),
+ SampleCount: proto.Uint64(count),
+ SampleSum: proto.Float64(math.Float64frombits(atomic.LoadUint64(&coldCounts.sumBits))),
+ }
+ var cumCount uint64
+ for i, upperBound := range h.upperBounds {
+ cumCount += atomic.LoadUint64(&coldCounts.buckets[i])
+ his.Bucket[i] = &dto.Bucket{
+ CumulativeCount: proto.Uint64(cumCount),
+ UpperBound: proto.Float64(upperBound),
+ }
+ }
+
+ out.Histogram = his
+ out.Label = h.labelPairs
+
+ // Finally add all the cold counts to the new hot counts and reset the cold counts.
+ atomic.AddUint64(&hotCounts.count, count)
+ atomic.StoreUint64(&coldCounts.count, 0)
+ for {
+ oldBits := atomic.LoadUint64(&hotCounts.sumBits)
+ newBits := math.Float64bits(math.Float64frombits(oldBits) + his.GetSampleSum())
+ if atomic.CompareAndSwapUint64(&hotCounts.sumBits, oldBits, newBits) {
+ atomic.StoreUint64(&coldCounts.sumBits, 0)
+ break
+ }
+ }
+ for i := range h.upperBounds {
+ atomic.AddUint64(&hotCounts.buckets[i], atomic.LoadUint64(&coldCounts.buckets[i]))
+ atomic.StoreUint64(&coldCounts.buckets[i], 0)
+ }
+ return nil
+}
+
+// HistogramVec is a Collector that bundles a set of Histograms that all share the
+// same Desc, but have different values for their variable labels. This is used
+// if you want to count the same thing partitioned by various dimensions
+// (e.g. HTTP request latencies, partitioned by status code and method). Create
+// instances with NewHistogramVec.
+type HistogramVec struct {
+ *metricVec
+}
+
+// NewHistogramVec creates a new HistogramVec based on the provided HistogramOpts and
+// partitioned by the given label names.
+func NewHistogramVec(opts HistogramOpts, labelNames []string) *HistogramVec {
+ desc := NewDesc(
+ BuildFQName(opts.Namespace, opts.Subsystem, opts.Name),
+ opts.Help,
+ labelNames,
+ opts.ConstLabels,
+ )
+ return &HistogramVec{
+ metricVec: newMetricVec(desc, func(lvs ...string) Metric {
+ return newHistogram(desc, opts, lvs...)
+ }),
+ }
+}
+
+// GetMetricWithLabelValues returns the Histogram for the given slice of label
+// values (same order as the VariableLabels in Desc). If that combination of
+// label values is accessed for the first time, a new Histogram is created.
+//
+// It is possible to call this method without using the returned Histogram to only
+// create the new Histogram but leave it at its starting value, a Histogram without
+// any observations.
+//
+// Keeping the Histogram for later use is possible (and should be considered if
+// performance is critical), but keep in mind that Reset, DeleteLabelValues and
+// Delete can be used to delete the Histogram from the HistogramVec. In that case, the
+// Histogram will still exist, but it will not be exported anymore, even if a
+// Histogram with the same label values is created later. See also the CounterVec
+// example.
+//
+// An error is returned if the number of label values is not the same as the
+// number of VariableLabels in Desc (minus any curried labels).
+//
+// Note that for more than one label value, this method is prone to mistakes
+// caused by an incorrect order of arguments. Consider GetMetricWith(Labels) as
+// an alternative to avoid that type of mistake. For higher label numbers, the
+// latter has a much more readable (albeit more verbose) syntax, but it comes
+// with a performance overhead (for creating and processing the Labels map).
+// See also the GaugeVec example.
+func (v *HistogramVec) GetMetricWithLabelValues(lvs ...string) (Observer, error) {
+ metric, err := v.metricVec.getMetricWithLabelValues(lvs...)
+ if metric != nil {
+ return metric.(Observer), err
+ }
+ return nil, err
+}
+
+// GetMetricWith returns the Histogram for the given Labels map (the label names
+// must match those of the VariableLabels in Desc). If that label map is
+// accessed for the first time, a new Histogram is created. Implications of
+// creating a Histogram without using it and keeping the Histogram for later use
+// are the same as for GetMetricWithLabelValues.
+//
+// An error is returned if the number and names of the Labels are inconsistent
+// with those of the VariableLabels in Desc (minus any curried labels).
+//
+// This method is used for the same purpose as
+// GetMetricWithLabelValues(...string). See there for pros and cons of the two
+// methods.
+func (v *HistogramVec) GetMetricWith(labels Labels) (Observer, error) {
+ metric, err := v.metricVec.getMetricWith(labels)
+ if metric != nil {
+ return metric.(Observer), err
+ }
+ return nil, err
+}
+
+// WithLabelValues works as GetMetricWithLabelValues, but panics where
+// GetMetricWithLabelValues would have returned an error. Not returning an
+// error allows shortcuts like
+// myVec.WithLabelValues("404", "GET").Observe(42.21)
+func (v *HistogramVec) WithLabelValues(lvs ...string) Observer {
+ h, err := v.GetMetricWithLabelValues(lvs...)
+ if err != nil {
+ panic(err)
+ }
+ return h
+}
+
+// With works as GetMetricWith but panics where GetMetricWithLabels would have
+// returned an error. Not returning an error allows shortcuts like
+// myVec.With(prometheus.Labels{"code": "404", "method": "GET"}).Observe(42.21)
+func (v *HistogramVec) With(labels Labels) Observer {
+ h, err := v.GetMetricWith(labels)
+ if err != nil {
+ panic(err)
+ }
+ return h
+}
+
+// CurryWith returns a vector curried with the provided labels, i.e. the
+// returned vector has those labels pre-set for all labeled operations performed
+// on it. The cardinality of the curried vector is reduced accordingly. The
+// order of the remaining labels stays the same (just with the curried labels
+// taken out of the sequence – which is relevant for the
+// (GetMetric)WithLabelValues methods). It is possible to curry a curried
+// vector, but only with labels not yet used for currying before.
+//
+// The metrics contained in the HistogramVec are shared between the curried and
+// uncurried vectors. They are just accessed differently. Curried and uncurried
+// vectors behave identically in terms of collection. Only one must be
+// registered with a given registry (usually the uncurried version). The Reset
+// method deletes all metrics, even if called on a curried vector.
+func (v *HistogramVec) CurryWith(labels Labels) (ObserverVec, error) {
+ vec, err := v.curryWith(labels)
+ if vec != nil {
+ return &HistogramVec{vec}, err
+ }
+ return nil, err
+}
+
+// MustCurryWith works as CurryWith but panics where CurryWith would have
+// returned an error.
+func (v *HistogramVec) MustCurryWith(labels Labels) ObserverVec {
+ vec, err := v.CurryWith(labels)
+ if err != nil {
+ panic(err)
+ }
+ return vec
+}
+
+type constHistogram struct {
+ desc *Desc
+ count uint64
+ sum float64
+ buckets map[float64]uint64
+ labelPairs []*dto.LabelPair
+}
+
+func (h *constHistogram) Desc() *Desc {
+ return h.desc
+}
+
+func (h *constHistogram) Write(out *dto.Metric) error {
+ his := &dto.Histogram{}
+ buckets := make([]*dto.Bucket, 0, len(h.buckets))
+
+ his.SampleCount = proto.Uint64(h.count)
+ his.SampleSum = proto.Float64(h.sum)
+
+ for upperBound, count := range h.buckets {
+ buckets = append(buckets, &dto.Bucket{
+ CumulativeCount: proto.Uint64(count),
+ UpperBound: proto.Float64(upperBound),
+ })
+ }
+
+ if len(buckets) > 0 {
+ sort.Sort(buckSort(buckets))
+ }
+ his.Bucket = buckets
+
+ out.Histogram = his
+ out.Label = h.labelPairs
+
+ return nil
+}
+
+// NewConstHistogram returns a metric representing a Prometheus histogram with
+// fixed values for the count, sum, and bucket counts. As those parameters
+// cannot be changed, the returned value does not implement the Histogram
+// interface (but only the Metric interface). Users of this package will not
+// have much use for it in regular operations. However, when implementing custom
+// Collectors, it is useful as a throw-away metric that is generated on the fly
+// to send it to Prometheus in the Collect method.
+//
+// buckets is a map of upper bounds to cumulative counts, excluding the +Inf
+// bucket.
+//
+// NewConstHistogram returns an error if the length of labelValues is not
+// consistent with the variable labels in Desc or if Desc is invalid.
+func NewConstHistogram(
+ desc *Desc,
+ count uint64,
+ sum float64,
+ buckets map[float64]uint64,
+ labelValues ...string,
+) (Metric, error) {
+ if desc.err != nil {
+ return nil, desc.err
+ }
+ if err := validateLabelValues(labelValues, len(desc.variableLabels)); err != nil {
+ return nil, err
+ }
+ return &constHistogram{
+ desc: desc,
+ count: count,
+ sum: sum,
+ buckets: buckets,
+ labelPairs: makeLabelPairs(desc, labelValues),
+ }, nil
+}
+
+// MustNewConstHistogram is a version of NewConstHistogram that panics where
+// NewConstMetric would have returned an error.
+func MustNewConstHistogram(
+ desc *Desc,
+ count uint64,
+ sum float64,
+ buckets map[float64]uint64,
+ labelValues ...string,
+) Metric {
+ m, err := NewConstHistogram(desc, count, sum, buckets, labelValues...)
+ if err != nil {
+ panic(err)
+ }
+ return m
+}
+
+type buckSort []*dto.Bucket
+
+func (s buckSort) Len() int {
+ return len(s)
+}
+
+func (s buckSort) Swap(i, j int) {
+ s[i], s[j] = s[j], s[i]
+}
+
+func (s buckSort) Less(i, j int) bool {
+ return s[i].GetUpperBound() < s[j].GetUpperBound()
+}
diff --git a/vendor/github.com/prometheus/client_golang/prometheus/internal/metric.go b/vendor/github.com/prometheus/client_golang/prometheus/internal/metric.go
new file mode 100644
index 0000000..351c26e
--- /dev/null
+++ b/vendor/github.com/prometheus/client_golang/prometheus/internal/metric.go
@@ -0,0 +1,85 @@
+// Copyright 2018 The Prometheus Authors
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package internal
+
+import (
+ "sort"
+
+ dto "github.com/prometheus/client_model/go"
+)
+
+// metricSorter is a sortable slice of *dto.Metric.
+type metricSorter []*dto.Metric
+
+func (s metricSorter) Len() int {
+ return len(s)
+}
+
+func (s metricSorter) Swap(i, j int) {
+ s[i], s[j] = s[j], s[i]
+}
+
+func (s metricSorter) Less(i, j int) bool {
+ if len(s[i].Label) != len(s[j].Label) {
+ // This should not happen. The metrics are
+ // inconsistent. However, we have to deal with the fact, as
+ // people might use custom collectors or metric family injection
+ // to create inconsistent metrics. So let's simply compare the
+ // number of labels in this case. That will still yield
+ // reproducible sorting.
+ return len(s[i].Label) < len(s[j].Label)
+ }
+ for n, lp := range s[i].Label {
+ vi := lp.GetValue()
+ vj := s[j].Label[n].GetValue()
+ if vi != vj {
+ return vi < vj
+ }
+ }
+
+ // We should never arrive here. Multiple metrics with the same
+ // label set in the same scrape will lead to undefined ingestion
+ // behavior. However, as above, we have to provide stable sorting
+ // here, even for inconsistent metrics. So sort equal metrics
+ // by their timestamp, with missing timestamps (implying "now")
+ // coming last.
+ if s[i].TimestampMs == nil {
+ return false
+ }
+ if s[j].TimestampMs == nil {
+ return true
+ }
+ return s[i].GetTimestampMs() < s[j].GetTimestampMs()
+}
+
+// NormalizeMetricFamilies returns a MetricFamily slice with empty
+// MetricFamilies pruned and the remaining MetricFamilies sorted by name within
+// the slice, with the contained Metrics sorted within each MetricFamily.
+func NormalizeMetricFamilies(metricFamiliesByName map[string]*dto.MetricFamily) []*dto.MetricFamily {
+ for _, mf := range metricFamiliesByName {
+ sort.Sort(metricSorter(mf.Metric))
+ }
+ names := make([]string, 0, len(metricFamiliesByName))
+ for name, mf := range metricFamiliesByName {
+ if len(mf.Metric) > 0 {
+ names = append(names, name)
+ }
+ }
+ sort.Strings(names)
+ result := make([]*dto.MetricFamily, 0, len(names))
+ for _, name := range names {
+ result = append(result, metricFamiliesByName[name])
+ }
+ return result
+}
diff --git a/vendor/github.com/prometheus/client_golang/prometheus/labels.go b/vendor/github.com/prometheus/client_golang/prometheus/labels.go
new file mode 100644
index 0000000..2744443
--- /dev/null
+++ b/vendor/github.com/prometheus/client_golang/prometheus/labels.go
@@ -0,0 +1,87 @@
+// Copyright 2018 The Prometheus Authors
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package prometheus
+
+import (
+ "errors"
+ "fmt"
+ "strings"
+ "unicode/utf8"
+
+ "github.com/prometheus/common/model"
+)
+
+// Labels represents a collection of label name -> value mappings. This type is
+// commonly used with the With(Labels) and GetMetricWith(Labels) methods of
+// metric vector Collectors, e.g.:
+// myVec.With(Labels{"code": "404", "method": "GET"}).Add(42)
+//
+// The other use-case is the specification of constant label pairs in Opts or to
+// create a Desc.
+type Labels map[string]string
+
+// reservedLabelPrefix is a prefix which is not legal in user-supplied
+// label names.
+const reservedLabelPrefix = "__"
+
+var errInconsistentCardinality = errors.New("inconsistent label cardinality")
+
+func makeInconsistentCardinalityError(fqName string, labels, labelValues []string) error {
+ return fmt.Errorf(
+ "%s: %q has %d variable labels named %q but %d values %q were provided",
+ errInconsistentCardinality, fqName,
+ len(labels), labels,
+ len(labelValues), labelValues,
+ )
+}
+
+func validateValuesInLabels(labels Labels, expectedNumberOfValues int) error {
+ if len(labels) != expectedNumberOfValues {
+ return fmt.Errorf(
+ "%s: expected %d label values but got %d in %#v",
+ errInconsistentCardinality, expectedNumberOfValues,
+ len(labels), labels,
+ )
+ }
+
+ for name, val := range labels {
+ if !utf8.ValidString(val) {
+ return fmt.Errorf("label %s: value %q is not valid UTF-8", name, val)
+ }
+ }
+
+ return nil
+}
+
+func validateLabelValues(vals []string, expectedNumberOfValues int) error {
+ if len(vals) != expectedNumberOfValues {
+ return fmt.Errorf(
+ "%s: expected %d label values but got %d in %#v",
+ errInconsistentCardinality, expectedNumberOfValues,
+ len(vals), vals,
+ )
+ }
+
+ for _, val := range vals {
+ if !utf8.ValidString(val) {
+ return fmt.Errorf("label value %q is not valid UTF-8", val)
+ }
+ }
+
+ return nil
+}
+
+func checkLabelName(l string) bool {
+ return model.LabelName(l).IsValid() && !strings.HasPrefix(l, reservedLabelPrefix)
+}
diff --git a/vendor/github.com/prometheus/client_golang/prometheus/metric.go b/vendor/github.com/prometheus/client_golang/prometheus/metric.go
new file mode 100644
index 0000000..55e6d86
--- /dev/null
+++ b/vendor/github.com/prometheus/client_golang/prometheus/metric.go
@@ -0,0 +1,174 @@
+// Copyright 2014 The Prometheus Authors
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package prometheus
+
+import (
+ "strings"
+ "time"
+
+ "github.com/golang/protobuf/proto"
+
+ dto "github.com/prometheus/client_model/go"
+)
+
+const separatorByte byte = 255
+
+// A Metric models a single sample value with its meta data being exported to
+// Prometheus. Implementations of Metric in this package are Gauge, Counter,
+// Histogram, Summary, and Untyped.
+type Metric interface {
+ // Desc returns the descriptor for the Metric. This method idempotently
+ // returns the same descriptor throughout the lifetime of the
+ // Metric. The returned descriptor is immutable by contract. A Metric
+ // unable to describe itself must return an invalid descriptor (created
+ // with NewInvalidDesc).
+ Desc() *Desc
+ // Write encodes the Metric into a "Metric" Protocol Buffer data
+ // transmission object.
+ //
+ // Metric implementations must observe concurrency safety as reads of
+ // this metric may occur at any time, and any blocking occurs at the
+ // expense of total performance of rendering all registered
+ // metrics. Ideally, Metric implementations should support concurrent
+ // readers.
+ //
+ // While populating dto.Metric, it is the responsibility of the
+ // implementation to ensure validity of the Metric protobuf (like valid
+ // UTF-8 strings or syntactically valid metric and label names). It is
+ // recommended to sort labels lexicographically. Callers of Write should
+ // still make sure of sorting if they depend on it.
+ Write(*dto.Metric) error
+ // TODO(beorn7): The original rationale of passing in a pre-allocated
+ // dto.Metric protobuf to save allocations has disappeared. The
+ // signature of this method should be changed to "Write() (*dto.Metric,
+ // error)".
+}
+
+// Opts bundles the options for creating most Metric types. Each metric
+// implementation XXX has its own XXXOpts type, but in most cases, it is just be
+// an alias of this type (which might change when the requirement arises.)
+//
+// It is mandatory to set Name to a non-empty string. All other fields are
+// optional and can safely be left at their zero value, although it is strongly
+// encouraged to set a Help string.
+type Opts struct {
+ // Namespace, Subsystem, and Name are components of the fully-qualified
+ // name of the Metric (created by joining these components with
+ // "_"). Only Name is mandatory, the others merely help structuring the
+ // name. Note that the fully-qualified name of the metric must be a
+ // valid Prometheus metric name.
+ Namespace string
+ Subsystem string
+ Name string
+
+ // Help provides information about this metric.
+ //
+ // Metrics with the same fully-qualified name must have the same Help
+ // string.
+ Help string
+
+ // ConstLabels are used to attach fixed labels to this metric. Metrics
+ // with the same fully-qualified name must have the same label names in
+ // their ConstLabels.
+ //
+ // ConstLabels are only used rarely. In particular, do not use them to
+ // attach the same labels to all your metrics. Those use cases are
+ // better covered by target labels set by the scraping Prometheus
+ // server, or by one specific metric (e.g. a build_info or a
+ // machine_role metric). See also
+ // https://prometheus.io/docs/instrumenting/writing_exporters/#target-labels,-not-static-scraped-labels
+ ConstLabels Labels
+}
+
+// BuildFQName joins the given three name components by "_". Empty name
+// components are ignored. If the name parameter itself is empty, an empty
+// string is returned, no matter what. Metric implementations included in this
+// library use this function internally to generate the fully-qualified metric
+// name from the name component in their Opts. Users of the library will only
+// need this function if they implement their own Metric or instantiate a Desc
+// (with NewDesc) directly.
+func BuildFQName(namespace, subsystem, name string) string {
+ if name == "" {
+ return ""
+ }
+ switch {
+ case namespace != "" && subsystem != "":
+ return strings.Join([]string{namespace, subsystem, name}, "_")
+ case namespace != "":
+ return strings.Join([]string{namespace, name}, "_")
+ case subsystem != "":
+ return strings.Join([]string{subsystem, name}, "_")
+ }
+ return name
+}
+
+// labelPairSorter implements sort.Interface. It is used to sort a slice of
+// dto.LabelPair pointers.
+type labelPairSorter []*dto.LabelPair
+
+func (s labelPairSorter) Len() int {
+ return len(s)
+}
+
+func (s labelPairSorter) Swap(i, j int) {
+ s[i], s[j] = s[j], s[i]
+}
+
+func (s labelPairSorter) Less(i, j int) bool {
+ return s[i].GetName() < s[j].GetName()
+}
+
+type invalidMetric struct {
+ desc *Desc
+ err error
+}
+
+// NewInvalidMetric returns a metric whose Write method always returns the
+// provided error. It is useful if a Collector finds itself unable to collect
+// a metric and wishes to report an error to the registry.
+func NewInvalidMetric(desc *Desc, err error) Metric {
+ return &invalidMetric{desc, err}
+}
+
+func (m *invalidMetric) Desc() *Desc { return m.desc }
+
+func (m *invalidMetric) Write(*dto.Metric) error { return m.err }
+
+type timestampedMetric struct {
+ Metric
+ t time.Time
+}
+
+func (m timestampedMetric) Write(pb *dto.Metric) error {
+ e := m.Metric.Write(pb)
+ pb.TimestampMs = proto.Int64(m.t.Unix()*1000 + int64(m.t.Nanosecond()/1000000))
+ return e
+}
+
+// NewMetricWithTimestamp returns a new Metric wrapping the provided Metric in a
+// way that it has an explicit timestamp set to the provided Time. This is only
+// useful in rare cases as the timestamp of a Prometheus metric should usually
+// be set by the Prometheus server during scraping. Exceptions include mirroring
+// metrics with given timestamps from other metric
+// sources.
+//
+// NewMetricWithTimestamp works best with MustNewConstMetric,
+// MustNewConstHistogram, and MustNewConstSummary, see example.
+//
+// Currently, the exposition formats used by Prometheus are limited to
+// millisecond resolution. Thus, the provided time will be rounded down to the
+// next full millisecond value.
+func NewMetricWithTimestamp(t time.Time, m Metric) Metric {
+ return timestampedMetric{Metric: m, t: t}
+}
diff --git a/vendor/github.com/prometheus/client_golang/prometheus/observer.go b/vendor/github.com/prometheus/client_golang/prometheus/observer.go
new file mode 100644
index 0000000..5806cd0
--- /dev/null
+++ b/vendor/github.com/prometheus/client_golang/prometheus/observer.go
@@ -0,0 +1,52 @@
+// Copyright 2017 The Prometheus Authors
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package prometheus
+
+// Observer is the interface that wraps the Observe method, which is used by
+// Histogram and Summary to add observations.
+type Observer interface {
+ Observe(float64)
+}
+
+// The ObserverFunc type is an adapter to allow the use of ordinary
+// functions as Observers. If f is a function with the appropriate
+// signature, ObserverFunc(f) is an Observer that calls f.
+//
+// This adapter is usually used in connection with the Timer type, and there are
+// two general use cases:
+//
+// The most common one is to use a Gauge as the Observer for a Timer.
+// See the "Gauge" Timer example.
+//
+// The more advanced use case is to create a function that dynamically decides
+// which Observer to use for observing the duration. See the "Complex" Timer
+// example.
+type ObserverFunc func(float64)
+
+// Observe calls f(value). It implements Observer.
+func (f ObserverFunc) Observe(value float64) {
+ f(value)
+}
+
+// ObserverVec is an interface implemented by `HistogramVec` and `SummaryVec`.
+type ObserverVec interface {
+ GetMetricWith(Labels) (Observer, error)
+ GetMetricWithLabelValues(lvs ...string) (Observer, error)
+ With(Labels) Observer
+ WithLabelValues(...string) Observer
+ CurryWith(Labels) (ObserverVec, error)
+ MustCurryWith(Labels) ObserverVec
+
+ Collector
+}
diff --git a/vendor/github.com/prometheus/client_golang/prometheus/process_collector.go b/vendor/github.com/prometheus/client_golang/prometheus/process_collector.go
new file mode 100644
index 0000000..9b80979
--- /dev/null
+++ b/vendor/github.com/prometheus/client_golang/prometheus/process_collector.go
@@ -0,0 +1,151 @@
+// Copyright 2015 The Prometheus Authors
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package prometheus
+
+import (
+ "errors"
+ "os"
+)
+
+type processCollector struct {
+ collectFn func(chan<- Metric)
+ pidFn func() (int, error)
+ reportErrors bool
+ cpuTotal *Desc
+ openFDs, maxFDs *Desc
+ vsize, maxVsize *Desc
+ rss *Desc
+ startTime *Desc
+}
+
+// ProcessCollectorOpts defines the behavior of a process metrics collector
+// created with NewProcessCollector.
+type ProcessCollectorOpts struct {
+ // PidFn returns the PID of the process the collector collects metrics
+ // for. It is called upon each collection. By default, the PID of the
+ // current process is used, as determined on construction time by
+ // calling os.Getpid().
+ PidFn func() (int, error)
+ // If non-empty, each of the collected metrics is prefixed by the
+ // provided string and an underscore ("_").
+ Namespace string
+ // If true, any error encountered during collection is reported as an
+ // invalid metric (see NewInvalidMetric). Otherwise, errors are ignored
+ // and the collected metrics will be incomplete. (Possibly, no metrics
+ // will be collected at all.) While that's usually not desired, it is
+ // appropriate for the common "mix-in" of process metrics, where process
+ // metrics are nice to have, but failing to collect them should not
+ // disrupt the collection of the remaining metrics.
+ ReportErrors bool
+}
+
+// NewProcessCollector returns a collector which exports the current state of
+// process metrics including CPU, memory and file descriptor usage as well as
+// the process start time. The detailed behavior is defined by the provided
+// ProcessCollectorOpts. The zero value of ProcessCollectorOpts creates a
+// collector for the current process with an empty namespace string and no error
+// reporting.
+//
+// The collector only works on operating systems with a Linux-style proc
+// filesystem and on Microsoft Windows. On other operating systems, it will not
+// collect any metrics.
+func NewProcessCollector(opts ProcessCollectorOpts) Collector {
+ ns := ""
+ if len(opts.Namespace) > 0 {
+ ns = opts.Namespace + "_"
+ }
+
+ c := &processCollector{
+ reportErrors: opts.ReportErrors,
+ cpuTotal: NewDesc(
+ ns+"process_cpu_seconds_total",
+ "Total user and system CPU time spent in seconds.",
+ nil, nil,
+ ),
+ openFDs: NewDesc(
+ ns+"process_open_fds",
+ "Number of open file descriptors.",
+ nil, nil,
+ ),
+ maxFDs: NewDesc(
+ ns+"process_max_fds",
+ "Maximum number of open file descriptors.",
+ nil, nil,
+ ),
+ vsize: NewDesc(
+ ns+"process_virtual_memory_bytes",
+ "Virtual memory size in bytes.",
+ nil, nil,
+ ),
+ maxVsize: NewDesc(
+ ns+"process_virtual_memory_max_bytes",
+ "Maximum amount of virtual memory available in bytes.",
+ nil, nil,
+ ),
+ rss: NewDesc(
+ ns+"process_resident_memory_bytes",
+ "Resident memory size in bytes.",
+ nil, nil,
+ ),
+ startTime: NewDesc(
+ ns+"process_start_time_seconds",
+ "Start time of the process since unix epoch in seconds.",
+ nil, nil,
+ ),
+ }
+
+ if opts.PidFn == nil {
+ pid := os.Getpid()
+ c.pidFn = func() (int, error) { return pid, nil }
+ } else {
+ c.pidFn = opts.PidFn
+ }
+
+ // Set up process metric collection if supported by the runtime.
+ if canCollectProcess() {
+ c.collectFn = c.processCollect
+ } else {
+ c.collectFn = func(ch chan<- Metric) {
+ c.reportError(ch, nil, errors.New("process metrics not supported on this platform"))
+ }
+ }
+
+ return c
+}
+
+// Describe returns all descriptions of the collector.
+func (c *processCollector) Describe(ch chan<- *Desc) {
+ ch <- c.cpuTotal
+ ch <- c.openFDs
+ ch <- c.maxFDs
+ ch <- c.vsize
+ ch <- c.maxVsize
+ ch <- c.rss
+ ch <- c.startTime
+}
+
+// Collect returns the current state of all metrics of the collector.
+func (c *processCollector) Collect(ch chan<- Metric) {
+ c.collectFn(ch)
+}
+
+func (c *processCollector) reportError(ch chan<- Metric, desc *Desc, err error) {
+ if !c.reportErrors {
+ return
+ }
+ if desc == nil {
+ desc = NewInvalidDesc(err)
+ }
+ ch <- NewInvalidMetric(desc, err)
+}
diff --git a/vendor/github.com/prometheus/client_golang/prometheus/process_collector_other.go b/vendor/github.com/prometheus/client_golang/prometheus/process_collector_other.go
new file mode 100644
index 0000000..3117461
--- /dev/null
+++ b/vendor/github.com/prometheus/client_golang/prometheus/process_collector_other.go
@@ -0,0 +1,65 @@
+// Copyright 2019 The Prometheus Authors
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// +build !windows
+
+package prometheus
+
+import (
+ "github.com/prometheus/procfs"
+)
+
+func canCollectProcess() bool {
+ _, err := procfs.NewDefaultFS()
+ return err == nil
+}
+
+func (c *processCollector) processCollect(ch chan<- Metric) {
+ pid, err := c.pidFn()
+ if err != nil {
+ c.reportError(ch, nil, err)
+ return
+ }
+
+ p, err := procfs.NewProc(pid)
+ if err != nil {
+ c.reportError(ch, nil, err)
+ return
+ }
+
+ if stat, err := p.Stat(); err == nil {
+ ch <- MustNewConstMetric(c.cpuTotal, CounterValue, stat.CPUTime())
+ ch <- MustNewConstMetric(c.vsize, GaugeValue, float64(stat.VirtualMemory()))
+ ch <- MustNewConstMetric(c.rss, GaugeValue, float64(stat.ResidentMemory()))
+ if startTime, err := stat.StartTime(); err == nil {
+ ch <- MustNewConstMetric(c.startTime, GaugeValue, startTime)
+ } else {
+ c.reportError(ch, c.startTime, err)
+ }
+ } else {
+ c.reportError(ch, nil, err)
+ }
+
+ if fds, err := p.FileDescriptorsLen(); err == nil {
+ ch <- MustNewConstMetric(c.openFDs, GaugeValue, float64(fds))
+ } else {
+ c.reportError(ch, c.openFDs, err)
+ }
+
+ if limits, err := p.Limits(); err == nil {
+ ch <- MustNewConstMetric(c.maxFDs, GaugeValue, float64(limits.OpenFiles))
+ ch <- MustNewConstMetric(c.maxVsize, GaugeValue, float64(limits.AddressSpace))
+ } else {
+ c.reportError(ch, nil, err)
+ }
+}
diff --git a/vendor/github.com/prometheus/client_golang/prometheus/process_collector_windows.go b/vendor/github.com/prometheus/client_golang/prometheus/process_collector_windows.go
new file mode 100644
index 0000000..e0b935d
--- /dev/null
+++ b/vendor/github.com/prometheus/client_golang/prometheus/process_collector_windows.go
@@ -0,0 +1,112 @@
+// Copyright 2019 The Prometheus Authors
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package prometheus
+
+import (
+ "syscall"
+ "unsafe"
+
+ "golang.org/x/sys/windows"
+)
+
+func canCollectProcess() bool {
+ return true
+}
+
+var (
+ modpsapi = syscall.NewLazyDLL("psapi.dll")
+ modkernel32 = syscall.NewLazyDLL("kernel32.dll")
+
+ procGetProcessMemoryInfo = modpsapi.NewProc("GetProcessMemoryInfo")
+ procGetProcessHandleCount = modkernel32.NewProc("GetProcessHandleCount")
+)
+
+type processMemoryCounters struct {
+ // https://docs.microsoft.com/en-us/windows/desktop/api/psapi/ns-psapi-_process_memory_counters_ex
+ _ uint32
+ PageFaultCount uint32
+ PeakWorkingSetSize uint64
+ WorkingSetSize uint64
+ QuotaPeakPagedPoolUsage uint64
+ QuotaPagedPoolUsage uint64
+ QuotaPeakNonPagedPoolUsage uint64
+ QuotaNonPagedPoolUsage uint64
+ PagefileUsage uint64
+ PeakPagefileUsage uint64
+ PrivateUsage uint64
+}
+
+func getProcessMemoryInfo(handle windows.Handle) (processMemoryCounters, error) {
+ mem := processMemoryCounters{}
+ r1, _, err := procGetProcessMemoryInfo.Call(
+ uintptr(handle),
+ uintptr(unsafe.Pointer(&mem)),
+ uintptr(unsafe.Sizeof(mem)),
+ )
+ if r1 != 1 {
+ return mem, err
+ } else {
+ return mem, nil
+ }
+}
+
+func getProcessHandleCount(handle windows.Handle) (uint32, error) {
+ var count uint32
+ r1, _, err := procGetProcessHandleCount.Call(
+ uintptr(handle),
+ uintptr(unsafe.Pointer(&count)),
+ )
+ if r1 != 1 {
+ return 0, err
+ } else {
+ return count, nil
+ }
+}
+
+func (c *processCollector) processCollect(ch chan<- Metric) {
+ h, err := windows.GetCurrentProcess()
+ if err != nil {
+ c.reportError(ch, nil, err)
+ return
+ }
+
+ var startTime, exitTime, kernelTime, userTime windows.Filetime
+ err = windows.GetProcessTimes(h, &startTime, &exitTime, &kernelTime, &userTime)
+ if err != nil {
+ c.reportError(ch, nil, err)
+ return
+ }
+ ch <- MustNewConstMetric(c.startTime, GaugeValue, float64(startTime.Nanoseconds()/1e9))
+ ch <- MustNewConstMetric(c.cpuTotal, CounterValue, fileTimeToSeconds(kernelTime)+fileTimeToSeconds(userTime))
+
+ mem, err := getProcessMemoryInfo(h)
+ if err != nil {
+ c.reportError(ch, nil, err)
+ return
+ }
+ ch <- MustNewConstMetric(c.vsize, GaugeValue, float64(mem.PrivateUsage))
+ ch <- MustNewConstMetric(c.rss, GaugeValue, float64(mem.WorkingSetSize))
+
+ handles, err := getProcessHandleCount(h)
+ if err != nil {
+ c.reportError(ch, nil, err)
+ return
+ }
+ ch <- MustNewConstMetric(c.openFDs, GaugeValue, float64(handles))
+ ch <- MustNewConstMetric(c.maxFDs, GaugeValue, float64(16*1024*1024)) // Windows has a hard-coded max limit, not per-process.
+}
+
+func fileTimeToSeconds(ft windows.Filetime) float64 {
+ return float64(uint64(ft.HighDateTime)<<32+uint64(ft.LowDateTime)) / 1e7
+}
diff --git a/vendor/github.com/prometheus/client_golang/prometheus/promauto/auto.go b/vendor/github.com/prometheus/client_golang/prometheus/promauto/auto.go
new file mode 100644
index 0000000..a00ba1e
--- /dev/null
+++ b/vendor/github.com/prometheus/client_golang/prometheus/promauto/auto.go
@@ -0,0 +1,223 @@
+// Copyright 2018 The Prometheus Authors
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Package promauto provides constructors for the usual Prometheus metrics that
+// return them already registered with the global registry
+// (prometheus.DefaultRegisterer). This allows very compact code, avoiding any
+// references to the registry altogether, but all the constructors in this
+// package will panic if the registration fails.
+//
+// The following example is a complete program to create a histogram of normally
+// distributed random numbers from the math/rand package:
+//
+// package main
+//
+// import (
+// "math/rand"
+// "net/http"
+//
+// "github.com/prometheus/client_golang/prometheus"
+// "github.com/prometheus/client_golang/prometheus/promauto"
+// "github.com/prometheus/client_golang/prometheus/promhttp"
+// )
+//
+// var histogram = promauto.NewHistogram(prometheus.HistogramOpts{
+// Name: "random_numbers",
+// Help: "A histogram of normally distributed random numbers.",
+// Buckets: prometheus.LinearBuckets(-3, .1, 61),
+// })
+//
+// func Random() {
+// for {
+// histogram.Observe(rand.NormFloat64())
+// }
+// }
+//
+// func main() {
+// go Random()
+// http.Handle("/metrics", promhttp.Handler())
+// http.ListenAndServe(":1971", nil)
+// }
+//
+// Prometheus's version of a minimal hello-world program:
+//
+// package main
+//
+// import (
+// "fmt"
+// "net/http"
+//
+// "github.com/prometheus/client_golang/prometheus"
+// "github.com/prometheus/client_golang/prometheus/promauto"
+// "github.com/prometheus/client_golang/prometheus/promhttp"
+// )
+//
+// func main() {
+// http.Handle("/", promhttp.InstrumentHandlerCounter(
+// promauto.NewCounterVec(
+// prometheus.CounterOpts{
+// Name: "hello_requests_total",
+// Help: "Total number of hello-world requests by HTTP code.",
+// },
+// []string{"code"},
+// ),
+// http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+// fmt.Fprint(w, "Hello, world!")
+// }),
+// ))
+// http.Handle("/metrics", promhttp.Handler())
+// http.ListenAndServe(":1971", nil)
+// }
+//
+// This appears very handy. So why are these constructors locked away in a
+// separate package? There are two caveats:
+//
+// First, in more complex programs, global state is often quite problematic.
+// That's the reason why the metrics constructors in the prometheus package do
+// not interact with the global prometheus.DefaultRegisterer on their own. You
+// are free to use the Register or MustRegister functions to register them with
+// the global prometheus.DefaultRegisterer, but you could as well choose a local
+// Registerer (usually created with prometheus.NewRegistry, but there are other
+// scenarios, e.g. testing).
+//
+// The second issue is that registration may fail, e.g. if a metric inconsistent
+// with the newly to be registered one is already registered. But how to signal
+// and handle a panic in the automatic registration with the default registry?
+// The only way is panicking. While panicking on invalid input provided by the
+// programmer is certainly fine, things are a bit more subtle in this case: You
+// might just add another package to the program, and that package (in its init
+// function) happens to register a metric with the same name as your code. Now,
+// all of a sudden, either your code or the code of the newly imported package
+// panics, depending on initialization order, without any opportunity to handle
+// the case gracefully. Even worse is a scenario where registration happens
+// later during the runtime (e.g. upon loading some kind of plugin), where the
+// panic could be triggered long after the code has been deployed to
+// production. A possibility to panic should be explicitly called out by the
+// Must… idiom, cf. prometheus.MustRegister. But adding a separate set of
+// constructors in the prometheus package called MustRegisterNewCounterVec or
+// similar would be quite unwieldy. Adding an extra MustRegister method to each
+// metric, returning the registered metric, would result in nice code for those
+// using the method, but would pollute every single metric interface for
+// everybody avoiding the global registry.
+//
+// To address both issues, the problematic auto-registering and possibly
+// panicking constructors are all in this package with a clear warning
+// ahead. And whoever cares about avoiding global state and possibly panicking
+// function calls can simply ignore the existence of the promauto package
+// altogether.
+//
+// A final note: There is a similar case in the net/http package of the standard
+// library. It has DefaultServeMux as a global instance of ServeMux, and the
+// Handle function acts on it, panicking if a handler for the same pattern has
+// already been registered. However, one might argue that the whole HTTP routing
+// is usually set up closely together in the same package or file, while
+// Prometheus metrics tend to be spread widely over the codebase, increasing the
+// chance of surprising registration failures. Furthermore, the use of global
+// state in net/http has been criticized widely, and some avoid it altogether.
+package promauto
+
+import "github.com/prometheus/client_golang/prometheus"
+
+// NewCounter works like the function of the same name in the prometheus package
+// but it automatically registers the Counter with the
+// prometheus.DefaultRegisterer. If the registration fails, NewCounter panics.
+func NewCounter(opts prometheus.CounterOpts) prometheus.Counter {
+ c := prometheus.NewCounter(opts)
+ prometheus.MustRegister(c)
+ return c
+}
+
+// NewCounterVec works like the function of the same name in the prometheus
+// package but it automatically registers the CounterVec with the
+// prometheus.DefaultRegisterer. If the registration fails, NewCounterVec
+// panics.
+func NewCounterVec(opts prometheus.CounterOpts, labelNames []string) *prometheus.CounterVec {
+ c := prometheus.NewCounterVec(opts, labelNames)
+ prometheus.MustRegister(c)
+ return c
+}
+
+// NewCounterFunc works like the function of the same name in the prometheus
+// package but it automatically registers the CounterFunc with the
+// prometheus.DefaultRegisterer. If the registration fails, NewCounterFunc
+// panics.
+func NewCounterFunc(opts prometheus.CounterOpts, function func() float64) prometheus.CounterFunc {
+ g := prometheus.NewCounterFunc(opts, function)
+ prometheus.MustRegister(g)
+ return g
+}
+
+// NewGauge works like the function of the same name in the prometheus package
+// but it automatically registers the Gauge with the
+// prometheus.DefaultRegisterer. If the registration fails, NewGauge panics.
+func NewGauge(opts prometheus.GaugeOpts) prometheus.Gauge {
+ g := prometheus.NewGauge(opts)
+ prometheus.MustRegister(g)
+ return g
+}
+
+// NewGaugeVec works like the function of the same name in the prometheus
+// package but it automatically registers the GaugeVec with the
+// prometheus.DefaultRegisterer. If the registration fails, NewGaugeVec panics.
+func NewGaugeVec(opts prometheus.GaugeOpts, labelNames []string) *prometheus.GaugeVec {
+ g := prometheus.NewGaugeVec(opts, labelNames)
+ prometheus.MustRegister(g)
+ return g
+}
+
+// NewGaugeFunc works like the function of the same name in the prometheus
+// package but it automatically registers the GaugeFunc with the
+// prometheus.DefaultRegisterer. If the registration fails, NewGaugeFunc panics.
+func NewGaugeFunc(opts prometheus.GaugeOpts, function func() float64) prometheus.GaugeFunc {
+ g := prometheus.NewGaugeFunc(opts, function)
+ prometheus.MustRegister(g)
+ return g
+}
+
+// NewSummary works like the function of the same name in the prometheus package
+// but it automatically registers the Summary with the
+// prometheus.DefaultRegisterer. If the registration fails, NewSummary panics.
+func NewSummary(opts prometheus.SummaryOpts) prometheus.Summary {
+ s := prometheus.NewSummary(opts)
+ prometheus.MustRegister(s)
+ return s
+}
+
+// NewSummaryVec works like the function of the same name in the prometheus
+// package but it automatically registers the SummaryVec with the
+// prometheus.DefaultRegisterer. If the registration fails, NewSummaryVec
+// panics.
+func NewSummaryVec(opts prometheus.SummaryOpts, labelNames []string) *prometheus.SummaryVec {
+ s := prometheus.NewSummaryVec(opts, labelNames)
+ prometheus.MustRegister(s)
+ return s
+}
+
+// NewHistogram works like the function of the same name in the prometheus
+// package but it automatically registers the Histogram with the
+// prometheus.DefaultRegisterer. If the registration fails, NewHistogram panics.
+func NewHistogram(opts prometheus.HistogramOpts) prometheus.Histogram {
+ h := prometheus.NewHistogram(opts)
+ prometheus.MustRegister(h)
+ return h
+}
+
+// NewHistogramVec works like the function of the same name in the prometheus
+// package but it automatically registers the HistogramVec with the
+// prometheus.DefaultRegisterer. If the registration fails, NewHistogramVec
+// panics.
+func NewHistogramVec(opts prometheus.HistogramOpts, labelNames []string) *prometheus.HistogramVec {
+ h := prometheus.NewHistogramVec(opts, labelNames)
+ prometheus.MustRegister(h)
+ return h
+}
diff --git a/vendor/github.com/prometheus/client_golang/prometheus/promhttp/delegator.go b/vendor/github.com/prometheus/client_golang/prometheus/promhttp/delegator.go
new file mode 100644
index 0000000..fa53568
--- /dev/null
+++ b/vendor/github.com/prometheus/client_golang/prometheus/promhttp/delegator.go
@@ -0,0 +1,357 @@
+// Copyright 2017 The Prometheus Authors
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package promhttp
+
+import (
+ "bufio"
+ "io"
+ "net"
+ "net/http"
+)
+
+const (
+ closeNotifier = 1 << iota
+ flusher
+ hijacker
+ readerFrom
+ pusher
+)
+
+type delegator interface {
+ http.ResponseWriter
+
+ Status() int
+ Written() int64
+}
+
+type responseWriterDelegator struct {
+ http.ResponseWriter
+
+ status int
+ written int64
+ wroteHeader bool
+ observeWriteHeader func(int)
+}
+
+func (r *responseWriterDelegator) Status() int {
+ return r.status
+}
+
+func (r *responseWriterDelegator) Written() int64 {
+ return r.written
+}
+
+func (r *responseWriterDelegator) WriteHeader(code int) {
+ r.status = code
+ r.wroteHeader = true
+ r.ResponseWriter.WriteHeader(code)
+ if r.observeWriteHeader != nil {
+ r.observeWriteHeader(code)
+ }
+}
+
+func (r *responseWriterDelegator) Write(b []byte) (int, error) {
+ if !r.wroteHeader {
+ r.WriteHeader(http.StatusOK)
+ }
+ n, err := r.ResponseWriter.Write(b)
+ r.written += int64(n)
+ return n, err
+}
+
+type closeNotifierDelegator struct{ *responseWriterDelegator }
+type flusherDelegator struct{ *responseWriterDelegator }
+type hijackerDelegator struct{ *responseWriterDelegator }
+type readerFromDelegator struct{ *responseWriterDelegator }
+type pusherDelegator struct{ *responseWriterDelegator }
+
+func (d closeNotifierDelegator) CloseNotify() <-chan bool {
+ //lint:ignore SA1019 http.CloseNotifier is deprecated but we don't want to
+ //remove support from client_golang yet.
+ return d.ResponseWriter.(http.CloseNotifier).CloseNotify()
+}
+func (d flusherDelegator) Flush() {
+ d.ResponseWriter.(http.Flusher).Flush()
+}
+func (d hijackerDelegator) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return d.ResponseWriter.(http.Hijacker).Hijack()
+}
+func (d readerFromDelegator) ReadFrom(re io.Reader) (int64, error) {
+ if !d.wroteHeader {
+ d.WriteHeader(http.StatusOK)
+ }
+ n, err := d.ResponseWriter.(io.ReaderFrom).ReadFrom(re)
+ d.written += n
+ return n, err
+}
+func (d pusherDelegator) Push(target string, opts *http.PushOptions) error {
+ return d.ResponseWriter.(http.Pusher).Push(target, opts)
+}
+
+var pickDelegator = make([]func(*responseWriterDelegator) delegator, 32)
+
+func init() {
+ // TODO(beorn7): Code generation would help here.
+ pickDelegator[0] = func(d *responseWriterDelegator) delegator { // 0
+ return d
+ }
+ pickDelegator[closeNotifier] = func(d *responseWriterDelegator) delegator { // 1
+ return closeNotifierDelegator{d}
+ }
+ pickDelegator[flusher] = func(d *responseWriterDelegator) delegator { // 2
+ return flusherDelegator{d}
+ }
+ pickDelegator[flusher+closeNotifier] = func(d *responseWriterDelegator) delegator { // 3
+ return struct {
+ *responseWriterDelegator
+ http.Flusher
+ http.CloseNotifier
+ }{d, flusherDelegator{d}, closeNotifierDelegator{d}}
+ }
+ pickDelegator[hijacker] = func(d *responseWriterDelegator) delegator { // 4
+ return hijackerDelegator{d}
+ }
+ pickDelegator[hijacker+closeNotifier] = func(d *responseWriterDelegator) delegator { // 5
+ return struct {
+ *responseWriterDelegator
+ http.Hijacker
+ http.CloseNotifier
+ }{d, hijackerDelegator{d}, closeNotifierDelegator{d}}
+ }
+ pickDelegator[hijacker+flusher] = func(d *responseWriterDelegator) delegator { // 6
+ return struct {
+ *responseWriterDelegator
+ http.Hijacker
+ http.Flusher
+ }{d, hijackerDelegator{d}, flusherDelegator{d}}
+ }
+ pickDelegator[hijacker+flusher+closeNotifier] = func(d *responseWriterDelegator) delegator { // 7
+ return struct {
+ *responseWriterDelegator
+ http.Hijacker
+ http.Flusher
+ http.CloseNotifier
+ }{d, hijackerDelegator{d}, flusherDelegator{d}, closeNotifierDelegator{d}}
+ }
+ pickDelegator[readerFrom] = func(d *responseWriterDelegator) delegator { // 8
+ return readerFromDelegator{d}
+ }
+ pickDelegator[readerFrom+closeNotifier] = func(d *responseWriterDelegator) delegator { // 9
+ return struct {
+ *responseWriterDelegator
+ io.ReaderFrom
+ http.CloseNotifier
+ }{d, readerFromDelegator{d}, closeNotifierDelegator{d}}
+ }
+ pickDelegator[readerFrom+flusher] = func(d *responseWriterDelegator) delegator { // 10
+ return struct {
+ *responseWriterDelegator
+ io.ReaderFrom
+ http.Flusher
+ }{d, readerFromDelegator{d}, flusherDelegator{d}}
+ }
+ pickDelegator[readerFrom+flusher+closeNotifier] = func(d *responseWriterDelegator) delegator { // 11
+ return struct {
+ *responseWriterDelegator
+ io.ReaderFrom
+ http.Flusher
+ http.CloseNotifier
+ }{d, readerFromDelegator{d}, flusherDelegator{d}, closeNotifierDelegator{d}}
+ }
+ pickDelegator[readerFrom+hijacker] = func(d *responseWriterDelegator) delegator { // 12
+ return struct {
+ *responseWriterDelegator
+ io.ReaderFrom
+ http.Hijacker
+ }{d, readerFromDelegator{d}, hijackerDelegator{d}}
+ }
+ pickDelegator[readerFrom+hijacker+closeNotifier] = func(d *responseWriterDelegator) delegator { // 13
+ return struct {
+ *responseWriterDelegator
+ io.ReaderFrom
+ http.Hijacker
+ http.CloseNotifier
+ }{d, readerFromDelegator{d}, hijackerDelegator{d}, closeNotifierDelegator{d}}
+ }
+ pickDelegator[readerFrom+hijacker+flusher] = func(d *responseWriterDelegator) delegator { // 14
+ return struct {
+ *responseWriterDelegator
+ io.ReaderFrom
+ http.Hijacker
+ http.Flusher
+ }{d, readerFromDelegator{d}, hijackerDelegator{d}, flusherDelegator{d}}
+ }
+ pickDelegator[readerFrom+hijacker+flusher+closeNotifier] = func(d *responseWriterDelegator) delegator { // 15
+ return struct {
+ *responseWriterDelegator
+ io.ReaderFrom
+ http.Hijacker
+ http.Flusher
+ http.CloseNotifier
+ }{d, readerFromDelegator{d}, hijackerDelegator{d}, flusherDelegator{d}, closeNotifierDelegator{d}}
+ }
+ pickDelegator[pusher] = func(d *responseWriterDelegator) delegator { // 16
+ return pusherDelegator{d}
+ }
+ pickDelegator[pusher+closeNotifier] = func(d *responseWriterDelegator) delegator { // 17
+ return struct {
+ *responseWriterDelegator
+ http.Pusher
+ http.CloseNotifier
+ }{d, pusherDelegator{d}, closeNotifierDelegator{d}}
+ }
+ pickDelegator[pusher+flusher] = func(d *responseWriterDelegator) delegator { // 18
+ return struct {
+ *responseWriterDelegator
+ http.Pusher
+ http.Flusher
+ }{d, pusherDelegator{d}, flusherDelegator{d}}
+ }
+ pickDelegator[pusher+flusher+closeNotifier] = func(d *responseWriterDelegator) delegator { // 19
+ return struct {
+ *responseWriterDelegator
+ http.Pusher
+ http.Flusher
+ http.CloseNotifier
+ }{d, pusherDelegator{d}, flusherDelegator{d}, closeNotifierDelegator{d}}
+ }
+ pickDelegator[pusher+hijacker] = func(d *responseWriterDelegator) delegator { // 20
+ return struct {
+ *responseWriterDelegator
+ http.Pusher
+ http.Hijacker
+ }{d, pusherDelegator{d}, hijackerDelegator{d}}
+ }
+ pickDelegator[pusher+hijacker+closeNotifier] = func(d *responseWriterDelegator) delegator { // 21
+ return struct {
+ *responseWriterDelegator
+ http.Pusher
+ http.Hijacker
+ http.CloseNotifier
+ }{d, pusherDelegator{d}, hijackerDelegator{d}, closeNotifierDelegator{d}}
+ }
+ pickDelegator[pusher+hijacker+flusher] = func(d *responseWriterDelegator) delegator { // 22
+ return struct {
+ *responseWriterDelegator
+ http.Pusher
+ http.Hijacker
+ http.Flusher
+ }{d, pusherDelegator{d}, hijackerDelegator{d}, flusherDelegator{d}}
+ }
+ pickDelegator[pusher+hijacker+flusher+closeNotifier] = func(d *responseWriterDelegator) delegator { //23
+ return struct {
+ *responseWriterDelegator
+ http.Pusher
+ http.Hijacker
+ http.Flusher
+ http.CloseNotifier
+ }{d, pusherDelegator{d}, hijackerDelegator{d}, flusherDelegator{d}, closeNotifierDelegator{d}}
+ }
+ pickDelegator[pusher+readerFrom] = func(d *responseWriterDelegator) delegator { // 24
+ return struct {
+ *responseWriterDelegator
+ http.Pusher
+ io.ReaderFrom
+ }{d, pusherDelegator{d}, readerFromDelegator{d}}
+ }
+ pickDelegator[pusher+readerFrom+closeNotifier] = func(d *responseWriterDelegator) delegator { // 25
+ return struct {
+ *responseWriterDelegator
+ http.Pusher
+ io.ReaderFrom
+ http.CloseNotifier
+ }{d, pusherDelegator{d}, readerFromDelegator{d}, closeNotifierDelegator{d}}
+ }
+ pickDelegator[pusher+readerFrom+flusher] = func(d *responseWriterDelegator) delegator { // 26
+ return struct {
+ *responseWriterDelegator
+ http.Pusher
+ io.ReaderFrom
+ http.Flusher
+ }{d, pusherDelegator{d}, readerFromDelegator{d}, flusherDelegator{d}}
+ }
+ pickDelegator[pusher+readerFrom+flusher+closeNotifier] = func(d *responseWriterDelegator) delegator { // 27
+ return struct {
+ *responseWriterDelegator
+ http.Pusher
+ io.ReaderFrom
+ http.Flusher
+ http.CloseNotifier
+ }{d, pusherDelegator{d}, readerFromDelegator{d}, flusherDelegator{d}, closeNotifierDelegator{d}}
+ }
+ pickDelegator[pusher+readerFrom+hijacker] = func(d *responseWriterDelegator) delegator { // 28
+ return struct {
+ *responseWriterDelegator
+ http.Pusher
+ io.ReaderFrom
+ http.Hijacker
+ }{d, pusherDelegator{d}, readerFromDelegator{d}, hijackerDelegator{d}}
+ }
+ pickDelegator[pusher+readerFrom+hijacker+closeNotifier] = func(d *responseWriterDelegator) delegator { // 29
+ return struct {
+ *responseWriterDelegator
+ http.Pusher
+ io.ReaderFrom
+ http.Hijacker
+ http.CloseNotifier
+ }{d, pusherDelegator{d}, readerFromDelegator{d}, hijackerDelegator{d}, closeNotifierDelegator{d}}
+ }
+ pickDelegator[pusher+readerFrom+hijacker+flusher] = func(d *responseWriterDelegator) delegator { // 30
+ return struct {
+ *responseWriterDelegator
+ http.Pusher
+ io.ReaderFrom
+ http.Hijacker
+ http.Flusher
+ }{d, pusherDelegator{d}, readerFromDelegator{d}, hijackerDelegator{d}, flusherDelegator{d}}
+ }
+ pickDelegator[pusher+readerFrom+hijacker+flusher+closeNotifier] = func(d *responseWriterDelegator) delegator { // 31
+ return struct {
+ *responseWriterDelegator
+ http.Pusher
+ io.ReaderFrom
+ http.Hijacker
+ http.Flusher
+ http.CloseNotifier
+ }{d, pusherDelegator{d}, readerFromDelegator{d}, hijackerDelegator{d}, flusherDelegator{d}, closeNotifierDelegator{d}}
+ }
+}
+
+func newDelegator(w http.ResponseWriter, observeWriteHeaderFunc func(int)) delegator {
+ d := &responseWriterDelegator{
+ ResponseWriter: w,
+ observeWriteHeader: observeWriteHeaderFunc,
+ }
+
+ id := 0
+ //lint:ignore SA1019 http.CloseNotifier is deprecated but we don't want to
+ //remove support from client_golang yet.
+ if _, ok := w.(http.CloseNotifier); ok {
+ id += closeNotifier
+ }
+ if _, ok := w.(http.Flusher); ok {
+ id += flusher
+ }
+ if _, ok := w.(http.Hijacker); ok {
+ id += hijacker
+ }
+ if _, ok := w.(io.ReaderFrom); ok {
+ id += readerFrom
+ }
+ if _, ok := w.(http.Pusher); ok {
+ id += pusher
+ }
+
+ return pickDelegator[id](d)
+}
diff --git a/vendor/github.com/prometheus/client_golang/prometheus/promhttp/http.go b/vendor/github.com/prometheus/client_golang/prometheus/promhttp/http.go
new file mode 100644
index 0000000..cea5a90
--- /dev/null
+++ b/vendor/github.com/prometheus/client_golang/prometheus/promhttp/http.go
@@ -0,0 +1,349 @@
+// Copyright 2016 The Prometheus Authors
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Package promhttp provides tooling around HTTP servers and clients.
+//
+// First, the package allows the creation of http.Handler instances to expose
+// Prometheus metrics via HTTP. promhttp.Handler acts on the
+// prometheus.DefaultGatherer. With HandlerFor, you can create a handler for a
+// custom registry or anything that implements the Gatherer interface. It also
+// allows the creation of handlers that act differently on errors or allow to
+// log errors.
+//
+// Second, the package provides tooling to instrument instances of http.Handler
+// via middleware. Middleware wrappers follow the naming scheme
+// InstrumentHandlerX, where X describes the intended use of the middleware.
+// See each function's doc comment for specific details.
+//
+// Finally, the package allows for an http.RoundTripper to be instrumented via
+// middleware. Middleware wrappers follow the naming scheme
+// InstrumentRoundTripperX, where X describes the intended use of the
+// middleware. See each function's doc comment for specific details.
+package promhttp
+
+import (
+ "compress/gzip"
+ "fmt"
+ "io"
+ "net/http"
+ "strings"
+ "sync"
+ "time"
+
+ "github.com/prometheus/common/expfmt"
+
+ "github.com/prometheus/client_golang/prometheus"
+)
+
+const (
+ contentTypeHeader = "Content-Type"
+ contentEncodingHeader = "Content-Encoding"
+ acceptEncodingHeader = "Accept-Encoding"
+)
+
+var gzipPool = sync.Pool{
+ New: func() interface{} {
+ return gzip.NewWriter(nil)
+ },
+}
+
+// Handler returns an http.Handler for the prometheus.DefaultGatherer, using
+// default HandlerOpts, i.e. it reports the first error as an HTTP error, it has
+// no error logging, and it applies compression if requested by the client.
+//
+// The returned http.Handler is already instrumented using the
+// InstrumentMetricHandler function and the prometheus.DefaultRegisterer. If you
+// create multiple http.Handlers by separate calls of the Handler function, the
+// metrics used for instrumentation will be shared between them, providing
+// global scrape counts.
+//
+// This function is meant to cover the bulk of basic use cases. If you are doing
+// anything that requires more customization (including using a non-default
+// Gatherer, different instrumentation, and non-default HandlerOpts), use the
+// HandlerFor function. See there for details.
+func Handler() http.Handler {
+ return InstrumentMetricHandler(
+ prometheus.DefaultRegisterer, HandlerFor(prometheus.DefaultGatherer, HandlerOpts{}),
+ )
+}
+
+// HandlerFor returns an uninstrumented http.Handler for the provided
+// Gatherer. The behavior of the Handler is defined by the provided
+// HandlerOpts. Thus, HandlerFor is useful to create http.Handlers for custom
+// Gatherers, with non-default HandlerOpts, and/or with custom (or no)
+// instrumentation. Use the InstrumentMetricHandler function to apply the same
+// kind of instrumentation as it is used by the Handler function.
+func HandlerFor(reg prometheus.Gatherer, opts HandlerOpts) http.Handler {
+ var (
+ inFlightSem chan struct{}
+ errCnt = prometheus.NewCounterVec(
+ prometheus.CounterOpts{
+ Name: "promhttp_metric_handler_errors_total",
+ Help: "Total number of internal errors encountered by the promhttp metric handler.",
+ },
+ []string{"cause"},
+ )
+ )
+
+ if opts.MaxRequestsInFlight > 0 {
+ inFlightSem = make(chan struct{}, opts.MaxRequestsInFlight)
+ }
+ if opts.Registry != nil {
+ // Initialize all possibilites that can occur below.
+ errCnt.WithLabelValues("gathering")
+ errCnt.WithLabelValues("encoding")
+ if err := opts.Registry.Register(errCnt); err != nil {
+ if are, ok := err.(prometheus.AlreadyRegisteredError); ok {
+ errCnt = are.ExistingCollector.(*prometheus.CounterVec)
+ } else {
+ panic(err)
+ }
+ }
+ }
+
+ h := http.HandlerFunc(func(rsp http.ResponseWriter, req *http.Request) {
+ if inFlightSem != nil {
+ select {
+ case inFlightSem <- struct{}{}: // All good, carry on.
+ defer func() { <-inFlightSem }()
+ default:
+ http.Error(rsp, fmt.Sprintf(
+ "Limit of concurrent requests reached (%d), try again later.", opts.MaxRequestsInFlight,
+ ), http.StatusServiceUnavailable)
+ return
+ }
+ }
+ mfs, err := reg.Gather()
+ if err != nil {
+ if opts.ErrorLog != nil {
+ opts.ErrorLog.Println("error gathering metrics:", err)
+ }
+ errCnt.WithLabelValues("gathering").Inc()
+ switch opts.ErrorHandling {
+ case PanicOnError:
+ panic(err)
+ case ContinueOnError:
+ if len(mfs) == 0 {
+ // Still report the error if no metrics have been gathered.
+ httpError(rsp, err)
+ return
+ }
+ case HTTPErrorOnError:
+ httpError(rsp, err)
+ return
+ }
+ }
+
+ contentType := expfmt.Negotiate(req.Header)
+ header := rsp.Header()
+ header.Set(contentTypeHeader, string(contentType))
+
+ w := io.Writer(rsp)
+ if !opts.DisableCompression && gzipAccepted(req.Header) {
+ header.Set(contentEncodingHeader, "gzip")
+ gz := gzipPool.Get().(*gzip.Writer)
+ defer gzipPool.Put(gz)
+
+ gz.Reset(w)
+ defer gz.Close()
+
+ w = gz
+ }
+
+ enc := expfmt.NewEncoder(w, contentType)
+
+ var lastErr error
+ for _, mf := range mfs {
+ if err := enc.Encode(mf); err != nil {
+ lastErr = err
+ if opts.ErrorLog != nil {
+ opts.ErrorLog.Println("error encoding and sending metric family:", err)
+ }
+ errCnt.WithLabelValues("encoding").Inc()
+ switch opts.ErrorHandling {
+ case PanicOnError:
+ panic(err)
+ case ContinueOnError:
+ // Handled later.
+ case HTTPErrorOnError:
+ httpError(rsp, err)
+ return
+ }
+ }
+ }
+
+ if lastErr != nil {
+ httpError(rsp, lastErr)
+ }
+ })
+
+ if opts.Timeout <= 0 {
+ return h
+ }
+ return http.TimeoutHandler(h, opts.Timeout, fmt.Sprintf(
+ "Exceeded configured timeout of %v.\n",
+ opts.Timeout,
+ ))
+}
+
+// InstrumentMetricHandler is usually used with an http.Handler returned by the
+// HandlerFor function. It instruments the provided http.Handler with two
+// metrics: A counter vector "promhttp_metric_handler_requests_total" to count
+// scrapes partitioned by HTTP status code, and a gauge
+// "promhttp_metric_handler_requests_in_flight" to track the number of
+// simultaneous scrapes. This function idempotently registers collectors for
+// both metrics with the provided Registerer. It panics if the registration
+// fails. The provided metrics are useful to see how many scrapes hit the
+// monitored target (which could be from different Prometheus servers or other
+// scrapers), and how often they overlap (which would result in more than one
+// scrape in flight at the same time). Note that the scrapes-in-flight gauge
+// will contain the scrape by which it is exposed, while the scrape counter will
+// only get incremented after the scrape is complete (as only then the status
+// code is known). For tracking scrape durations, use the
+// "scrape_duration_seconds" gauge created by the Prometheus server upon each
+// scrape.
+func InstrumentMetricHandler(reg prometheus.Registerer, handler http.Handler) http.Handler {
+ cnt := prometheus.NewCounterVec(
+ prometheus.CounterOpts{
+ Name: "promhttp_metric_handler_requests_total",
+ Help: "Total number of scrapes by HTTP status code.",
+ },
+ []string{"code"},
+ )
+ // Initialize the most likely HTTP status codes.
+ cnt.WithLabelValues("200")
+ cnt.WithLabelValues("500")
+ cnt.WithLabelValues("503")
+ if err := reg.Register(cnt); err != nil {
+ if are, ok := err.(prometheus.AlreadyRegisteredError); ok {
+ cnt = are.ExistingCollector.(*prometheus.CounterVec)
+ } else {
+ panic(err)
+ }
+ }
+
+ gge := prometheus.NewGauge(prometheus.GaugeOpts{
+ Name: "promhttp_metric_handler_requests_in_flight",
+ Help: "Current number of scrapes being served.",
+ })
+ if err := reg.Register(gge); err != nil {
+ if are, ok := err.(prometheus.AlreadyRegisteredError); ok {
+ gge = are.ExistingCollector.(prometheus.Gauge)
+ } else {
+ panic(err)
+ }
+ }
+
+ return InstrumentHandlerCounter(cnt, InstrumentHandlerInFlight(gge, handler))
+}
+
+// HandlerErrorHandling defines how a Handler serving metrics will handle
+// errors.
+type HandlerErrorHandling int
+
+// These constants cause handlers serving metrics to behave as described if
+// errors are encountered.
+const (
+ // Serve an HTTP status code 500 upon the first error
+ // encountered. Report the error message in the body.
+ HTTPErrorOnError HandlerErrorHandling = iota
+ // Ignore errors and try to serve as many metrics as possible. However,
+ // if no metrics can be served, serve an HTTP status code 500 and the
+ // last error message in the body. Only use this in deliberate "best
+ // effort" metrics collection scenarios. In this case, it is highly
+ // recommended to provide other means of detecting errors: By setting an
+ // ErrorLog in HandlerOpts, the errors are logged. By providing a
+ // Registry in HandlerOpts, the exposed metrics include an error counter
+ // "promhttp_metric_handler_errors_total", which can be used for
+ // alerts.
+ ContinueOnError
+ // Panic upon the first error encountered (useful for "crash only" apps).
+ PanicOnError
+)
+
+// Logger is the minimal interface HandlerOpts needs for logging. Note that
+// log.Logger from the standard library implements this interface, and it is
+// easy to implement by custom loggers, if they don't do so already anyway.
+type Logger interface {
+ Println(v ...interface{})
+}
+
+// HandlerOpts specifies options how to serve metrics via an http.Handler. The
+// zero value of HandlerOpts is a reasonable default.
+type HandlerOpts struct {
+ // ErrorLog specifies an optional logger for errors collecting and
+ // serving metrics. If nil, errors are not logged at all.
+ ErrorLog Logger
+ // ErrorHandling defines how errors are handled. Note that errors are
+ // logged regardless of the configured ErrorHandling provided ErrorLog
+ // is not nil.
+ ErrorHandling HandlerErrorHandling
+ // If Registry is not nil, it is used to register a metric
+ // "promhttp_metric_handler_errors_total", partitioned by "cause". A
+ // failed registration causes a panic. Note that this error counter is
+ // different from the instrumentation you get from the various
+ // InstrumentHandler... helpers. It counts errors that don't necessarily
+ // result in a non-2xx HTTP status code. There are two typical cases:
+ // (1) Encoding errors that only happen after streaming of the HTTP body
+ // has already started (and the status code 200 has been sent). This
+ // should only happen with custom collectors. (2) Collection errors with
+ // no effect on the HTTP status code because ErrorHandling is set to
+ // ContinueOnError.
+ Registry prometheus.Registerer
+ // If DisableCompression is true, the handler will never compress the
+ // response, even if requested by the client.
+ DisableCompression bool
+ // The number of concurrent HTTP requests is limited to
+ // MaxRequestsInFlight. Additional requests are responded to with 503
+ // Service Unavailable and a suitable message in the body. If
+ // MaxRequestsInFlight is 0 or negative, no limit is applied.
+ MaxRequestsInFlight int
+ // If handling a request takes longer than Timeout, it is responded to
+ // with 503 ServiceUnavailable and a suitable Message. No timeout is
+ // applied if Timeout is 0 or negative. Note that with the current
+ // implementation, reaching the timeout simply ends the HTTP requests as
+ // described above (and even that only if sending of the body hasn't
+ // started yet), while the bulk work of gathering all the metrics keeps
+ // running in the background (with the eventual result to be thrown
+ // away). Until the implementation is improved, it is recommended to
+ // implement a separate timeout in potentially slow Collectors.
+ Timeout time.Duration
+}
+
+// gzipAccepted returns whether the client will accept gzip-encoded content.
+func gzipAccepted(header http.Header) bool {
+ a := header.Get(acceptEncodingHeader)
+ parts := strings.Split(a, ",")
+ for _, part := range parts {
+ part = strings.TrimSpace(part)
+ if part == "gzip" || strings.HasPrefix(part, "gzip;") {
+ return true
+ }
+ }
+ return false
+}
+
+// httpError removes any content-encoding header and then calls http.Error with
+// the provided error and http.StatusInternalServerErrer. Error contents is
+// supposed to be uncompressed plain text. However, same as with a plain
+// http.Error, any header settings will be void if the header has already been
+// sent. The error message will still be written to the writer, but it will
+// probably be of limited use.
+func httpError(rsp http.ResponseWriter, err error) {
+ rsp.Header().Del(contentEncodingHeader)
+ http.Error(
+ rsp,
+ "An error has occurred while serving metrics:\n\n"+err.Error(),
+ http.StatusInternalServerError,
+ )
+}
diff --git a/vendor/github.com/prometheus/client_golang/prometheus/promhttp/instrument_client.go b/vendor/github.com/prometheus/client_golang/prometheus/promhttp/instrument_client.go
new file mode 100644
index 0000000..83c49b6
--- /dev/null
+++ b/vendor/github.com/prometheus/client_golang/prometheus/promhttp/instrument_client.go
@@ -0,0 +1,219 @@
+// Copyright 2017 The Prometheus Authors
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package promhttp
+
+import (
+ "crypto/tls"
+ "net/http"
+ "net/http/httptrace"
+ "time"
+
+ "github.com/prometheus/client_golang/prometheus"
+)
+
+// The RoundTripperFunc type is an adapter to allow the use of ordinary
+// functions as RoundTrippers. If f is a function with the appropriate
+// signature, RountTripperFunc(f) is a RoundTripper that calls f.
+type RoundTripperFunc func(req *http.Request) (*http.Response, error)
+
+// RoundTrip implements the RoundTripper interface.
+func (rt RoundTripperFunc) RoundTrip(r *http.Request) (*http.Response, error) {
+ return rt(r)
+}
+
+// InstrumentRoundTripperInFlight is a middleware that wraps the provided
+// http.RoundTripper. It sets the provided prometheus.Gauge to the number of
+// requests currently handled by the wrapped http.RoundTripper.
+//
+// See the example for ExampleInstrumentRoundTripperDuration for example usage.
+func InstrumentRoundTripperInFlight(gauge prometheus.Gauge, next http.RoundTripper) RoundTripperFunc {
+ return RoundTripperFunc(func(r *http.Request) (*http.Response, error) {
+ gauge.Inc()
+ defer gauge.Dec()
+ return next.RoundTrip(r)
+ })
+}
+
+// InstrumentRoundTripperCounter is a middleware that wraps the provided
+// http.RoundTripper to observe the request result with the provided CounterVec.
+// The CounterVec must have zero, one, or two non-const non-curried labels. For
+// those, the only allowed label names are "code" and "method". The function
+// panics otherwise. Partitioning of the CounterVec happens by HTTP status code
+// and/or HTTP method if the respective instance label names are present in the
+// CounterVec. For unpartitioned counting, use a CounterVec with zero labels.
+//
+// If the wrapped RoundTripper panics or returns a non-nil error, the Counter
+// is not incremented.
+//
+// See the example for ExampleInstrumentRoundTripperDuration for example usage.
+func InstrumentRoundTripperCounter(counter *prometheus.CounterVec, next http.RoundTripper) RoundTripperFunc {
+ code, method := checkLabels(counter)
+
+ return RoundTripperFunc(func(r *http.Request) (*http.Response, error) {
+ resp, err := next.RoundTrip(r)
+ if err == nil {
+ counter.With(labels(code, method, r.Method, resp.StatusCode)).Inc()
+ }
+ return resp, err
+ })
+}
+
+// InstrumentRoundTripperDuration is a middleware that wraps the provided
+// http.RoundTripper to observe the request duration with the provided
+// ObserverVec. The ObserverVec must have zero, one, or two non-const
+// non-curried labels. For those, the only allowed label names are "code" and
+// "method". The function panics otherwise. The Observe method of the Observer
+// in the ObserverVec is called with the request duration in
+// seconds. Partitioning happens by HTTP status code and/or HTTP method if the
+// respective instance label names are present in the ObserverVec. For
+// unpartitioned observations, use an ObserverVec with zero labels. Note that
+// partitioning of Histograms is expensive and should be used judiciously.
+//
+// If the wrapped RoundTripper panics or returns a non-nil error, no values are
+// reported.
+//
+// Note that this method is only guaranteed to never observe negative durations
+// if used with Go1.9+.
+func InstrumentRoundTripperDuration(obs prometheus.ObserverVec, next http.RoundTripper) RoundTripperFunc {
+ code, method := checkLabels(obs)
+
+ return RoundTripperFunc(func(r *http.Request) (*http.Response, error) {
+ start := time.Now()
+ resp, err := next.RoundTrip(r)
+ if err == nil {
+ obs.With(labels(code, method, r.Method, resp.StatusCode)).Observe(time.Since(start).Seconds())
+ }
+ return resp, err
+ })
+}
+
+// InstrumentTrace is used to offer flexibility in instrumenting the available
+// httptrace.ClientTrace hook functions. Each function is passed a float64
+// representing the time in seconds since the start of the http request. A user
+// may choose to use separately buckets Histograms, or implement custom
+// instance labels on a per function basis.
+type InstrumentTrace struct {
+ GotConn func(float64)
+ PutIdleConn func(float64)
+ GotFirstResponseByte func(float64)
+ Got100Continue func(float64)
+ DNSStart func(float64)
+ DNSDone func(float64)
+ ConnectStart func(float64)
+ ConnectDone func(float64)
+ TLSHandshakeStart func(float64)
+ TLSHandshakeDone func(float64)
+ WroteHeaders func(float64)
+ Wait100Continue func(float64)
+ WroteRequest func(float64)
+}
+
+// InstrumentRoundTripperTrace is a middleware that wraps the provided
+// RoundTripper and reports times to hook functions provided in the
+// InstrumentTrace struct. Hook functions that are not present in the provided
+// InstrumentTrace struct are ignored. Times reported to the hook functions are
+// time since the start of the request. Only with Go1.9+, those times are
+// guaranteed to never be negative. (Earlier Go versions are not using a
+// monotonic clock.) Note that partitioning of Histograms is expensive and
+// should be used judiciously.
+//
+// For hook functions that receive an error as an argument, no observations are
+// made in the event of a non-nil error value.
+//
+// See the example for ExampleInstrumentRoundTripperDuration for example usage.
+func InstrumentRoundTripperTrace(it *InstrumentTrace, next http.RoundTripper) RoundTripperFunc {
+ return RoundTripperFunc(func(r *http.Request) (*http.Response, error) {
+ start := time.Now()
+
+ trace := &httptrace.ClientTrace{
+ GotConn: func(_ httptrace.GotConnInfo) {
+ if it.GotConn != nil {
+ it.GotConn(time.Since(start).Seconds())
+ }
+ },
+ PutIdleConn: func(err error) {
+ if err != nil {
+ return
+ }
+ if it.PutIdleConn != nil {
+ it.PutIdleConn(time.Since(start).Seconds())
+ }
+ },
+ DNSStart: func(_ httptrace.DNSStartInfo) {
+ if it.DNSStart != nil {
+ it.DNSStart(time.Since(start).Seconds())
+ }
+ },
+ DNSDone: func(_ httptrace.DNSDoneInfo) {
+ if it.DNSDone != nil {
+ it.DNSDone(time.Since(start).Seconds())
+ }
+ },
+ ConnectStart: func(_, _ string) {
+ if it.ConnectStart != nil {
+ it.ConnectStart(time.Since(start).Seconds())
+ }
+ },
+ ConnectDone: func(_, _ string, err error) {
+ if err != nil {
+ return
+ }
+ if it.ConnectDone != nil {
+ it.ConnectDone(time.Since(start).Seconds())
+ }
+ },
+ GotFirstResponseByte: func() {
+ if it.GotFirstResponseByte != nil {
+ it.GotFirstResponseByte(time.Since(start).Seconds())
+ }
+ },
+ Got100Continue: func() {
+ if it.Got100Continue != nil {
+ it.Got100Continue(time.Since(start).Seconds())
+ }
+ },
+ TLSHandshakeStart: func() {
+ if it.TLSHandshakeStart != nil {
+ it.TLSHandshakeStart(time.Since(start).Seconds())
+ }
+ },
+ TLSHandshakeDone: func(_ tls.ConnectionState, err error) {
+ if err != nil {
+ return
+ }
+ if it.TLSHandshakeDone != nil {
+ it.TLSHandshakeDone(time.Since(start).Seconds())
+ }
+ },
+ WroteHeaders: func() {
+ if it.WroteHeaders != nil {
+ it.WroteHeaders(time.Since(start).Seconds())
+ }
+ },
+ Wait100Continue: func() {
+ if it.Wait100Continue != nil {
+ it.Wait100Continue(time.Since(start).Seconds())
+ }
+ },
+ WroteRequest: func(_ httptrace.WroteRequestInfo) {
+ if it.WroteRequest != nil {
+ it.WroteRequest(time.Since(start).Seconds())
+ }
+ },
+ }
+ r = r.WithContext(httptrace.WithClientTrace(r.Context(), trace))
+
+ return next.RoundTrip(r)
+ })
+}
diff --git a/vendor/github.com/prometheus/client_golang/prometheus/promhttp/instrument_server.go b/vendor/github.com/prometheus/client_golang/prometheus/promhttp/instrument_server.go
new file mode 100644
index 0000000..9db2438
--- /dev/null
+++ b/vendor/github.com/prometheus/client_golang/prometheus/promhttp/instrument_server.go
@@ -0,0 +1,447 @@
+// Copyright 2017 The Prometheus Authors
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package promhttp
+
+import (
+ "errors"
+ "net/http"
+ "strconv"
+ "strings"
+ "time"
+
+ dto "github.com/prometheus/client_model/go"
+
+ "github.com/prometheus/client_golang/prometheus"
+)
+
+// magicString is used for the hacky label test in checkLabels. Remove once fixed.
+const magicString = "zZgWfBxLqvG8kc8IMv3POi2Bb0tZI3vAnBx+gBaFi9FyPzB/CzKUer1yufDa"
+
+// InstrumentHandlerInFlight is a middleware that wraps the provided
+// http.Handler. It sets the provided prometheus.Gauge to the number of
+// requests currently handled by the wrapped http.Handler.
+//
+// See the example for InstrumentHandlerDuration for example usage.
+func InstrumentHandlerInFlight(g prometheus.Gauge, next http.Handler) http.Handler {
+ return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ g.Inc()
+ defer g.Dec()
+ next.ServeHTTP(w, r)
+ })
+}
+
+// InstrumentHandlerDuration is a middleware that wraps the provided
+// http.Handler to observe the request duration with the provided ObserverVec.
+// The ObserverVec must have zero, one, or two non-const non-curried labels. For
+// those, the only allowed label names are "code" and "method". The function
+// panics otherwise. The Observe method of the Observer in the ObserverVec is
+// called with the request duration in seconds. Partitioning happens by HTTP
+// status code and/or HTTP method if the respective instance label names are
+// present in the ObserverVec. For unpartitioned observations, use an
+// ObserverVec with zero labels. Note that partitioning of Histograms is
+// expensive and should be used judiciously.
+//
+// If the wrapped Handler does not set a status code, a status code of 200 is assumed.
+//
+// If the wrapped Handler panics, no values are reported.
+//
+// Note that this method is only guaranteed to never observe negative durations
+// if used with Go1.9+.
+func InstrumentHandlerDuration(obs prometheus.ObserverVec, next http.Handler) http.HandlerFunc {
+ code, method := checkLabels(obs)
+
+ if code {
+ return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ now := time.Now()
+ d := newDelegator(w, nil)
+ next.ServeHTTP(d, r)
+
+ obs.With(labels(code, method, r.Method, d.Status())).Observe(time.Since(now).Seconds())
+ })
+ }
+
+ return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ now := time.Now()
+ next.ServeHTTP(w, r)
+ obs.With(labels(code, method, r.Method, 0)).Observe(time.Since(now).Seconds())
+ })
+}
+
+// InstrumentHandlerCounter is a middleware that wraps the provided http.Handler
+// to observe the request result with the provided CounterVec. The CounterVec
+// must have zero, one, or two non-const non-curried labels. For those, the only
+// allowed label names are "code" and "method". The function panics
+// otherwise. Partitioning of the CounterVec happens by HTTP status code and/or
+// HTTP method if the respective instance label names are present in the
+// CounterVec. For unpartitioned counting, use a CounterVec with zero labels.
+//
+// If the wrapped Handler does not set a status code, a status code of 200 is assumed.
+//
+// If the wrapped Handler panics, the Counter is not incremented.
+//
+// See the example for InstrumentHandlerDuration for example usage.
+func InstrumentHandlerCounter(counter *prometheus.CounterVec, next http.Handler) http.HandlerFunc {
+ code, method := checkLabels(counter)
+
+ if code {
+ return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ d := newDelegator(w, nil)
+ next.ServeHTTP(d, r)
+ counter.With(labels(code, method, r.Method, d.Status())).Inc()
+ })
+ }
+
+ return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ next.ServeHTTP(w, r)
+ counter.With(labels(code, method, r.Method, 0)).Inc()
+ })
+}
+
+// InstrumentHandlerTimeToWriteHeader is a middleware that wraps the provided
+// http.Handler to observe with the provided ObserverVec the request duration
+// until the response headers are written. The ObserverVec must have zero, one,
+// or two non-const non-curried labels. For those, the only allowed label names
+// are "code" and "method". The function panics otherwise. The Observe method of
+// the Observer in the ObserverVec is called with the request duration in
+// seconds. Partitioning happens by HTTP status code and/or HTTP method if the
+// respective instance label names are present in the ObserverVec. For
+// unpartitioned observations, use an ObserverVec with zero labels. Note that
+// partitioning of Histograms is expensive and should be used judiciously.
+//
+// If the wrapped Handler panics before calling WriteHeader, no value is
+// reported.
+//
+// Note that this method is only guaranteed to never observe negative durations
+// if used with Go1.9+.
+//
+// See the example for InstrumentHandlerDuration for example usage.
+func InstrumentHandlerTimeToWriteHeader(obs prometheus.ObserverVec, next http.Handler) http.HandlerFunc {
+ code, method := checkLabels(obs)
+
+ return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ now := time.Now()
+ d := newDelegator(w, func(status int) {
+ obs.With(labels(code, method, r.Method, status)).Observe(time.Since(now).Seconds())
+ })
+ next.ServeHTTP(d, r)
+ })
+}
+
+// InstrumentHandlerRequestSize is a middleware that wraps the provided
+// http.Handler to observe the request size with the provided ObserverVec. The
+// ObserverVec must have zero, one, or two non-const non-curried labels. For
+// those, the only allowed label names are "code" and "method". The function
+// panics otherwise. The Observe method of the Observer in the ObserverVec is
+// called with the request size in bytes. Partitioning happens by HTTP status
+// code and/or HTTP method if the respective instance label names are present in
+// the ObserverVec. For unpartitioned observations, use an ObserverVec with zero
+// labels. Note that partitioning of Histograms is expensive and should be used
+// judiciously.
+//
+// If the wrapped Handler does not set a status code, a status code of 200 is assumed.
+//
+// If the wrapped Handler panics, no values are reported.
+//
+// See the example for InstrumentHandlerDuration for example usage.
+func InstrumentHandlerRequestSize(obs prometheus.ObserverVec, next http.Handler) http.HandlerFunc {
+ code, method := checkLabels(obs)
+
+ if code {
+ return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ d := newDelegator(w, nil)
+ next.ServeHTTP(d, r)
+ size := computeApproximateRequestSize(r)
+ obs.With(labels(code, method, r.Method, d.Status())).Observe(float64(size))
+ })
+ }
+
+ return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ next.ServeHTTP(w, r)
+ size := computeApproximateRequestSize(r)
+ obs.With(labels(code, method, r.Method, 0)).Observe(float64(size))
+ })
+}
+
+// InstrumentHandlerResponseSize is a middleware that wraps the provided
+// http.Handler to observe the response size with the provided ObserverVec. The
+// ObserverVec must have zero, one, or two non-const non-curried labels. For
+// those, the only allowed label names are "code" and "method". The function
+// panics otherwise. The Observe method of the Observer in the ObserverVec is
+// called with the response size in bytes. Partitioning happens by HTTP status
+// code and/or HTTP method if the respective instance label names are present in
+// the ObserverVec. For unpartitioned observations, use an ObserverVec with zero
+// labels. Note that partitioning of Histograms is expensive and should be used
+// judiciously.
+//
+// If the wrapped Handler does not set a status code, a status code of 200 is assumed.
+//
+// If the wrapped Handler panics, no values are reported.
+//
+// See the example for InstrumentHandlerDuration for example usage.
+func InstrumentHandlerResponseSize(obs prometheus.ObserverVec, next http.Handler) http.Handler {
+ code, method := checkLabels(obs)
+ return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ d := newDelegator(w, nil)
+ next.ServeHTTP(d, r)
+ obs.With(labels(code, method, r.Method, d.Status())).Observe(float64(d.Written()))
+ })
+}
+
+func checkLabels(c prometheus.Collector) (code bool, method bool) {
+ // TODO(beorn7): Remove this hacky way to check for instance labels
+ // once Descriptors can have their dimensionality queried.
+ var (
+ desc *prometheus.Desc
+ m prometheus.Metric
+ pm dto.Metric
+ lvs []string
+ )
+
+ // Get the Desc from the Collector.
+ descc := make(chan *prometheus.Desc, 1)
+ c.Describe(descc)
+
+ select {
+ case desc = <-descc:
+ default:
+ panic("no description provided by collector")
+ }
+ select {
+ case <-descc:
+ panic("more than one description provided by collector")
+ default:
+ }
+
+ close(descc)
+
+ // Create a ConstMetric with the Desc. Since we don't know how many
+ // variable labels there are, try for as long as it needs.
+ for err := errors.New("dummy"); err != nil; lvs = append(lvs, magicString) {
+ m, err = prometheus.NewConstMetric(desc, prometheus.UntypedValue, 0, lvs...)
+ }
+
+ // Write out the metric into a proto message and look at the labels.
+ // If the value is not the magicString, it is a constLabel, which doesn't interest us.
+ // If the label is curried, it doesn't interest us.
+ // In all other cases, only "code" or "method" is allowed.
+ if err := m.Write(&pm); err != nil {
+ panic("error checking metric for labels")
+ }
+ for _, label := range pm.Label {
+ name, value := label.GetName(), label.GetValue()
+ if value != magicString || isLabelCurried(c, name) {
+ continue
+ }
+ switch name {
+ case "code":
+ code = true
+ case "method":
+ method = true
+ default:
+ panic("metric partitioned with non-supported labels")
+ }
+ }
+ return
+}
+
+func isLabelCurried(c prometheus.Collector, label string) bool {
+ // This is even hackier than the label test above.
+ // We essentially try to curry again and see if it works.
+ // But for that, we need to type-convert to the two
+ // types we use here, ObserverVec or *CounterVec.
+ switch v := c.(type) {
+ case *prometheus.CounterVec:
+ if _, err := v.CurryWith(prometheus.Labels{label: "dummy"}); err == nil {
+ return false
+ }
+ case prometheus.ObserverVec:
+ if _, err := v.CurryWith(prometheus.Labels{label: "dummy"}); err == nil {
+ return false
+ }
+ default:
+ panic("unsupported metric vec type")
+ }
+ return true
+}
+
+// emptyLabels is a one-time allocation for non-partitioned metrics to avoid
+// unnecessary allocations on each request.
+var emptyLabels = prometheus.Labels{}
+
+func labels(code, method bool, reqMethod string, status int) prometheus.Labels {
+ if !(code || method) {
+ return emptyLabels
+ }
+ labels := prometheus.Labels{}
+
+ if code {
+ labels["code"] = sanitizeCode(status)
+ }
+ if method {
+ labels["method"] = sanitizeMethod(reqMethod)
+ }
+
+ return labels
+}
+
+func computeApproximateRequestSize(r *http.Request) int {
+ s := 0
+ if r.URL != nil {
+ s += len(r.URL.String())
+ }
+
+ s += len(r.Method)
+ s += len(r.Proto)
+ for name, values := range r.Header {
+ s += len(name)
+ for _, value := range values {
+ s += len(value)
+ }
+ }
+ s += len(r.Host)
+
+ // N.B. r.Form and r.MultipartForm are assumed to be included in r.URL.
+
+ if r.ContentLength != -1 {
+ s += int(r.ContentLength)
+ }
+ return s
+}
+
+func sanitizeMethod(m string) string {
+ switch m {
+ case "GET", "get":
+ return "get"
+ case "PUT", "put":
+ return "put"
+ case "HEAD", "head":
+ return "head"
+ case "POST", "post":
+ return "post"
+ case "DELETE", "delete":
+ return "delete"
+ case "CONNECT", "connect":
+ return "connect"
+ case "OPTIONS", "options":
+ return "options"
+ case "NOTIFY", "notify":
+ return "notify"
+ default:
+ return strings.ToLower(m)
+ }
+}
+
+// If the wrapped http.Handler has not set a status code, i.e. the value is
+// currently 0, santizeCode will return 200, for consistency with behavior in
+// the stdlib.
+func sanitizeCode(s int) string {
+ switch s {
+ case 100:
+ return "100"
+ case 101:
+ return "101"
+
+ case 200, 0:
+ return "200"
+ case 201:
+ return "201"
+ case 202:
+ return "202"
+ case 203:
+ return "203"
+ case 204:
+ return "204"
+ case 205:
+ return "205"
+ case 206:
+ return "206"
+
+ case 300:
+ return "300"
+ case 301:
+ return "301"
+ case 302:
+ return "302"
+ case 304:
+ return "304"
+ case 305:
+ return "305"
+ case 307:
+ return "307"
+
+ case 400:
+ return "400"
+ case 401:
+ return "401"
+ case 402:
+ return "402"
+ case 403:
+ return "403"
+ case 404:
+ return "404"
+ case 405:
+ return "405"
+ case 406:
+ return "406"
+ case 407:
+ return "407"
+ case 408:
+ return "408"
+ case 409:
+ return "409"
+ case 410:
+ return "410"
+ case 411:
+ return "411"
+ case 412:
+ return "412"
+ case 413:
+ return "413"
+ case 414:
+ return "414"
+ case 415:
+ return "415"
+ case 416:
+ return "416"
+ case 417:
+ return "417"
+ case 418:
+ return "418"
+
+ case 500:
+ return "500"
+ case 501:
+ return "501"
+ case 502:
+ return "502"
+ case 503:
+ return "503"
+ case 504:
+ return "504"
+ case 505:
+ return "505"
+
+ case 428:
+ return "428"
+ case 429:
+ return "429"
+ case 431:
+ return "431"
+ case 511:
+ return "511"
+
+ default:
+ return strconv.Itoa(s)
+ }
+}
diff --git a/vendor/github.com/prometheus/client_golang/prometheus/registry.go b/vendor/github.com/prometheus/client_golang/prometheus/registry.go
new file mode 100644
index 0000000..6c32516
--- /dev/null
+++ b/vendor/github.com/prometheus/client_golang/prometheus/registry.go
@@ -0,0 +1,945 @@
+// Copyright 2014 The Prometheus Authors
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package prometheus
+
+import (
+ "bytes"
+ "fmt"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "runtime"
+ "sort"
+ "strings"
+ "sync"
+ "unicode/utf8"
+
+ "github.com/golang/protobuf/proto"
+ "github.com/prometheus/common/expfmt"
+
+ dto "github.com/prometheus/client_model/go"
+
+ "github.com/prometheus/client_golang/prometheus/internal"
+)
+
+const (
+ // Capacity for the channel to collect metrics and descriptors.
+ capMetricChan = 1000
+ capDescChan = 10
+)
+
+// DefaultRegisterer and DefaultGatherer are the implementations of the
+// Registerer and Gatherer interface a number of convenience functions in this
+// package act on. Initially, both variables point to the same Registry, which
+// has a process collector (currently on Linux only, see NewProcessCollector)
+// and a Go collector (see NewGoCollector, in particular the note about
+// stop-the-world implication with Go versions older than 1.9) already
+// registered. This approach to keep default instances as global state mirrors
+// the approach of other packages in the Go standard library. Note that there
+// are caveats. Change the variables with caution and only if you understand the
+// consequences. Users who want to avoid global state altogether should not use
+// the convenience functions and act on custom instances instead.
+var (
+ defaultRegistry = NewRegistry()
+ DefaultRegisterer Registerer = defaultRegistry
+ DefaultGatherer Gatherer = defaultRegistry
+)
+
+func init() {
+ MustRegister(NewProcessCollector(ProcessCollectorOpts{}))
+ MustRegister(NewGoCollector())
+}
+
+// NewRegistry creates a new vanilla Registry without any Collectors
+// pre-registered.
+func NewRegistry() *Registry {
+ return &Registry{
+ collectorsByID: map[uint64]Collector{},
+ descIDs: map[uint64]struct{}{},
+ dimHashesByName: map[string]uint64{},
+ }
+}
+
+// NewPedanticRegistry returns a registry that checks during collection if each
+// collected Metric is consistent with its reported Desc, and if the Desc has
+// actually been registered with the registry. Unchecked Collectors (those whose
+// Describe methed does not yield any descriptors) are excluded from the check.
+//
+// Usually, a Registry will be happy as long as the union of all collected
+// Metrics is consistent and valid even if some metrics are not consistent with
+// their own Desc or a Desc provided by their registered Collector. Well-behaved
+// Collectors and Metrics will only provide consistent Descs. This Registry is
+// useful to test the implementation of Collectors and Metrics.
+func NewPedanticRegistry() *Registry {
+ r := NewRegistry()
+ r.pedanticChecksEnabled = true
+ return r
+}
+
+// Registerer is the interface for the part of a registry in charge of
+// registering and unregistering. Users of custom registries should use
+// Registerer as type for registration purposes (rather than the Registry type
+// directly). In that way, they are free to use custom Registerer implementation
+// (e.g. for testing purposes).
+type Registerer interface {
+ // Register registers a new Collector to be included in metrics
+ // collection. It returns an error if the descriptors provided by the
+ // Collector are invalid or if they — in combination with descriptors of
+ // already registered Collectors — do not fulfill the consistency and
+ // uniqueness criteria described in the documentation of metric.Desc.
+ //
+ // If the provided Collector is equal to a Collector already registered
+ // (which includes the case of re-registering the same Collector), the
+ // returned error is an instance of AlreadyRegisteredError, which
+ // contains the previously registered Collector.
+ //
+ // A Collector whose Describe method does not yield any Desc is treated
+ // as unchecked. Registration will always succeed. No check for
+ // re-registering (see previous paragraph) is performed. Thus, the
+ // caller is responsible for not double-registering the same unchecked
+ // Collector, and for providing a Collector that will not cause
+ // inconsistent metrics on collection. (This would lead to scrape
+ // errors.)
+ Register(Collector) error
+ // MustRegister works like Register but registers any number of
+ // Collectors and panics upon the first registration that causes an
+ // error.
+ MustRegister(...Collector)
+ // Unregister unregisters the Collector that equals the Collector passed
+ // in as an argument. (Two Collectors are considered equal if their
+ // Describe method yields the same set of descriptors.) The function
+ // returns whether a Collector was unregistered. Note that an unchecked
+ // Collector cannot be unregistered (as its Describe method does not
+ // yield any descriptor).
+ //
+ // Note that even after unregistering, it will not be possible to
+ // register a new Collector that is inconsistent with the unregistered
+ // Collector, e.g. a Collector collecting metrics with the same name but
+ // a different help string. The rationale here is that the same registry
+ // instance must only collect consistent metrics throughout its
+ // lifetime.
+ Unregister(Collector) bool
+}
+
+// Gatherer is the interface for the part of a registry in charge of gathering
+// the collected metrics into a number of MetricFamilies. The Gatherer interface
+// comes with the same general implication as described for the Registerer
+// interface.
+type Gatherer interface {
+ // Gather calls the Collect method of the registered Collectors and then
+ // gathers the collected metrics into a lexicographically sorted slice
+ // of uniquely named MetricFamily protobufs. Gather ensures that the
+ // returned slice is valid and self-consistent so that it can be used
+ // for valid exposition. As an exception to the strict consistency
+ // requirements described for metric.Desc, Gather will tolerate
+ // different sets of label names for metrics of the same metric family.
+ //
+ // Even if an error occurs, Gather attempts to gather as many metrics as
+ // possible. Hence, if a non-nil error is returned, the returned
+ // MetricFamily slice could be nil (in case of a fatal error that
+ // prevented any meaningful metric collection) or contain a number of
+ // MetricFamily protobufs, some of which might be incomplete, and some
+ // might be missing altogether. The returned error (which might be a
+ // MultiError) explains the details. Note that this is mostly useful for
+ // debugging purposes. If the gathered protobufs are to be used for
+ // exposition in actual monitoring, it is almost always better to not
+ // expose an incomplete result and instead disregard the returned
+ // MetricFamily protobufs in case the returned error is non-nil.
+ Gather() ([]*dto.MetricFamily, error)
+}
+
+// Register registers the provided Collector with the DefaultRegisterer.
+//
+// Register is a shortcut for DefaultRegisterer.Register(c). See there for more
+// details.
+func Register(c Collector) error {
+ return DefaultRegisterer.Register(c)
+}
+
+// MustRegister registers the provided Collectors with the DefaultRegisterer and
+// panics if any error occurs.
+//
+// MustRegister is a shortcut for DefaultRegisterer.MustRegister(cs...). See
+// there for more details.
+func MustRegister(cs ...Collector) {
+ DefaultRegisterer.MustRegister(cs...)
+}
+
+// Unregister removes the registration of the provided Collector from the
+// DefaultRegisterer.
+//
+// Unregister is a shortcut for DefaultRegisterer.Unregister(c). See there for
+// more details.
+func Unregister(c Collector) bool {
+ return DefaultRegisterer.Unregister(c)
+}
+
+// GathererFunc turns a function into a Gatherer.
+type GathererFunc func() ([]*dto.MetricFamily, error)
+
+// Gather implements Gatherer.
+func (gf GathererFunc) Gather() ([]*dto.MetricFamily, error) {
+ return gf()
+}
+
+// AlreadyRegisteredError is returned by the Register method if the Collector to
+// be registered has already been registered before, or a different Collector
+// that collects the same metrics has been registered before. Registration fails
+// in that case, but you can detect from the kind of error what has
+// happened. The error contains fields for the existing Collector and the
+// (rejected) new Collector that equals the existing one. This can be used to
+// find out if an equal Collector has been registered before and switch over to
+// using the old one, as demonstrated in the example.
+type AlreadyRegisteredError struct {
+ ExistingCollector, NewCollector Collector
+}
+
+func (err AlreadyRegisteredError) Error() string {
+ return "duplicate metrics collector registration attempted"
+}
+
+// MultiError is a slice of errors implementing the error interface. It is used
+// by a Gatherer to report multiple errors during MetricFamily gathering.
+type MultiError []error
+
+func (errs MultiError) Error() string {
+ if len(errs) == 0 {
+ return ""
+ }
+ buf := &bytes.Buffer{}
+ fmt.Fprintf(buf, "%d error(s) occurred:", len(errs))
+ for _, err := range errs {
+ fmt.Fprintf(buf, "\n* %s", err)
+ }
+ return buf.String()
+}
+
+// Append appends the provided error if it is not nil.
+func (errs *MultiError) Append(err error) {
+ if err != nil {
+ *errs = append(*errs, err)
+ }
+}
+
+// MaybeUnwrap returns nil if len(errs) is 0. It returns the first and only
+// contained error as error if len(errs is 1). In all other cases, it returns
+// the MultiError directly. This is helpful for returning a MultiError in a way
+// that only uses the MultiError if needed.
+func (errs MultiError) MaybeUnwrap() error {
+ switch len(errs) {
+ case 0:
+ return nil
+ case 1:
+ return errs[0]
+ default:
+ return errs
+ }
+}
+
+// Registry registers Prometheus collectors, collects their metrics, and gathers
+// them into MetricFamilies for exposition. It implements both Registerer and
+// Gatherer. The zero value is not usable. Create instances with NewRegistry or
+// NewPedanticRegistry.
+type Registry struct {
+ mtx sync.RWMutex
+ collectorsByID map[uint64]Collector // ID is a hash of the descIDs.
+ descIDs map[uint64]struct{}
+ dimHashesByName map[string]uint64
+ uncheckedCollectors []Collector
+ pedanticChecksEnabled bool
+}
+
+// Register implements Registerer.
+func (r *Registry) Register(c Collector) error {
+ var (
+ descChan = make(chan *Desc, capDescChan)
+ newDescIDs = map[uint64]struct{}{}
+ newDimHashesByName = map[string]uint64{}
+ collectorID uint64 // Just a sum of all desc IDs.
+ duplicateDescErr error
+ )
+ go func() {
+ c.Describe(descChan)
+ close(descChan)
+ }()
+ r.mtx.Lock()
+ defer func() {
+ // Drain channel in case of premature return to not leak a goroutine.
+ for range descChan {
+ }
+ r.mtx.Unlock()
+ }()
+ // Conduct various tests...
+ for desc := range descChan {
+
+ // Is the descriptor valid at all?
+ if desc.err != nil {
+ return fmt.Errorf("descriptor %s is invalid: %s", desc, desc.err)
+ }
+
+ // Is the descID unique?
+ // (In other words: Is the fqName + constLabel combination unique?)
+ if _, exists := r.descIDs[desc.id]; exists {
+ duplicateDescErr = fmt.Errorf("descriptor %s already exists with the same fully-qualified name and const label values", desc)
+ }
+ // If it is not a duplicate desc in this collector, add it to
+ // the collectorID. (We allow duplicate descs within the same
+ // collector, but their existence must be a no-op.)
+ if _, exists := newDescIDs[desc.id]; !exists {
+ newDescIDs[desc.id] = struct{}{}
+ collectorID += desc.id
+ }
+
+ // Are all the label names and the help string consistent with
+ // previous descriptors of the same name?
+ // First check existing descriptors...
+ if dimHash, exists := r.dimHashesByName[desc.fqName]; exists {
+ if dimHash != desc.dimHash {
+ return fmt.Errorf("a previously registered descriptor with the same fully-qualified name as %s has different label names or a different help string", desc)
+ }
+ } else {
+ // ...then check the new descriptors already seen.
+ if dimHash, exists := newDimHashesByName[desc.fqName]; exists {
+ if dimHash != desc.dimHash {
+ return fmt.Errorf("descriptors reported by collector have inconsistent label names or help strings for the same fully-qualified name, offender is %s", desc)
+ }
+ } else {
+ newDimHashesByName[desc.fqName] = desc.dimHash
+ }
+ }
+ }
+ // A Collector yielding no Desc at all is considered unchecked.
+ if len(newDescIDs) == 0 {
+ r.uncheckedCollectors = append(r.uncheckedCollectors, c)
+ return nil
+ }
+ if existing, exists := r.collectorsByID[collectorID]; exists {
+ switch e := existing.(type) {
+ case *wrappingCollector:
+ return AlreadyRegisteredError{
+ ExistingCollector: e.unwrapRecursively(),
+ NewCollector: c,
+ }
+ default:
+ return AlreadyRegisteredError{
+ ExistingCollector: e,
+ NewCollector: c,
+ }
+ }
+ }
+ // If the collectorID is new, but at least one of the descs existed
+ // before, we are in trouble.
+ if duplicateDescErr != nil {
+ return duplicateDescErr
+ }
+
+ // Only after all tests have passed, actually register.
+ r.collectorsByID[collectorID] = c
+ for hash := range newDescIDs {
+ r.descIDs[hash] = struct{}{}
+ }
+ for name, dimHash := range newDimHashesByName {
+ r.dimHashesByName[name] = dimHash
+ }
+ return nil
+}
+
+// Unregister implements Registerer.
+func (r *Registry) Unregister(c Collector) bool {
+ var (
+ descChan = make(chan *Desc, capDescChan)
+ descIDs = map[uint64]struct{}{}
+ collectorID uint64 // Just a sum of the desc IDs.
+ )
+ go func() {
+ c.Describe(descChan)
+ close(descChan)
+ }()
+ for desc := range descChan {
+ if _, exists := descIDs[desc.id]; !exists {
+ collectorID += desc.id
+ descIDs[desc.id] = struct{}{}
+ }
+ }
+
+ r.mtx.RLock()
+ if _, exists := r.collectorsByID[collectorID]; !exists {
+ r.mtx.RUnlock()
+ return false
+ }
+ r.mtx.RUnlock()
+
+ r.mtx.Lock()
+ defer r.mtx.Unlock()
+
+ delete(r.collectorsByID, collectorID)
+ for id := range descIDs {
+ delete(r.descIDs, id)
+ }
+ // dimHashesByName is left untouched as those must be consistent
+ // throughout the lifetime of a program.
+ return true
+}
+
+// MustRegister implements Registerer.
+func (r *Registry) MustRegister(cs ...Collector) {
+ for _, c := range cs {
+ if err := r.Register(c); err != nil {
+ panic(err)
+ }
+ }
+}
+
+// Gather implements Gatherer.
+func (r *Registry) Gather() ([]*dto.MetricFamily, error) {
+ var (
+ checkedMetricChan = make(chan Metric, capMetricChan)
+ uncheckedMetricChan = make(chan Metric, capMetricChan)
+ metricHashes = map[uint64]struct{}{}
+ wg sync.WaitGroup
+ errs MultiError // The collected errors to return in the end.
+ registeredDescIDs map[uint64]struct{} // Only used for pedantic checks
+ )
+
+ r.mtx.RLock()
+ goroutineBudget := len(r.collectorsByID) + len(r.uncheckedCollectors)
+ metricFamiliesByName := make(map[string]*dto.MetricFamily, len(r.dimHashesByName))
+ checkedCollectors := make(chan Collector, len(r.collectorsByID))
+ uncheckedCollectors := make(chan Collector, len(r.uncheckedCollectors))
+ for _, collector := range r.collectorsByID {
+ checkedCollectors <- collector
+ }
+ for _, collector := range r.uncheckedCollectors {
+ uncheckedCollectors <- collector
+ }
+ // In case pedantic checks are enabled, we have to copy the map before
+ // giving up the RLock.
+ if r.pedanticChecksEnabled {
+ registeredDescIDs = make(map[uint64]struct{}, len(r.descIDs))
+ for id := range r.descIDs {
+ registeredDescIDs[id] = struct{}{}
+ }
+ }
+ r.mtx.RUnlock()
+
+ wg.Add(goroutineBudget)
+
+ collectWorker := func() {
+ for {
+ select {
+ case collector := <-checkedCollectors:
+ collector.Collect(checkedMetricChan)
+ case collector := <-uncheckedCollectors:
+ collector.Collect(uncheckedMetricChan)
+ default:
+ return
+ }
+ wg.Done()
+ }
+ }
+
+ // Start the first worker now to make sure at least one is running.
+ go collectWorker()
+ goroutineBudget--
+
+ // Close checkedMetricChan and uncheckedMetricChan once all collectors
+ // are collected.
+ go func() {
+ wg.Wait()
+ close(checkedMetricChan)
+ close(uncheckedMetricChan)
+ }()
+
+ // Drain checkedMetricChan and uncheckedMetricChan in case of premature return.
+ defer func() {
+ if checkedMetricChan != nil {
+ for range checkedMetricChan {
+ }
+ }
+ if uncheckedMetricChan != nil {
+ for range uncheckedMetricChan {
+ }
+ }
+ }()
+
+ // Copy the channel references so we can nil them out later to remove
+ // them from the select statements below.
+ cmc := checkedMetricChan
+ umc := uncheckedMetricChan
+
+ for {
+ select {
+ case metric, ok := <-cmc:
+ if !ok {
+ cmc = nil
+ break
+ }
+ errs.Append(processMetric(
+ metric, metricFamiliesByName,
+ metricHashes,
+ registeredDescIDs,
+ ))
+ case metric, ok := <-umc:
+ if !ok {
+ umc = nil
+ break
+ }
+ errs.Append(processMetric(
+ metric, metricFamiliesByName,
+ metricHashes,
+ nil,
+ ))
+ default:
+ if goroutineBudget <= 0 || len(checkedCollectors)+len(uncheckedCollectors) == 0 {
+ // All collectors are already being worked on or
+ // we have already as many goroutines started as
+ // there are collectors. Do the same as above,
+ // just without the default.
+ select {
+ case metric, ok := <-cmc:
+ if !ok {
+ cmc = nil
+ break
+ }
+ errs.Append(processMetric(
+ metric, metricFamiliesByName,
+ metricHashes,
+ registeredDescIDs,
+ ))
+ case metric, ok := <-umc:
+ if !ok {
+ umc = nil
+ break
+ }
+ errs.Append(processMetric(
+ metric, metricFamiliesByName,
+ metricHashes,
+ nil,
+ ))
+ }
+ break
+ }
+ // Start more workers.
+ go collectWorker()
+ goroutineBudget--
+ runtime.Gosched()
+ }
+ // Once both checkedMetricChan and uncheckdMetricChan are closed
+ // and drained, the contraption above will nil out cmc and umc,
+ // and then we can leave the collect loop here.
+ if cmc == nil && umc == nil {
+ break
+ }
+ }
+ return internal.NormalizeMetricFamilies(metricFamiliesByName), errs.MaybeUnwrap()
+}
+
+// WriteToTextfile calls Gather on the provided Gatherer, encodes the result in the
+// Prometheus text format, and writes it to a temporary file. Upon success, the
+// temporary file is renamed to the provided filename.
+//
+// This is intended for use with the textfile collector of the node exporter.
+// Note that the node exporter expects the filename to be suffixed with ".prom".
+func WriteToTextfile(filename string, g Gatherer) error {
+ tmp, err := ioutil.TempFile(filepath.Dir(filename), filepath.Base(filename))
+ if err != nil {
+ return err
+ }
+ defer os.Remove(tmp.Name())
+
+ mfs, err := g.Gather()
+ if err != nil {
+ return err
+ }
+ for _, mf := range mfs {
+ if _, err := expfmt.MetricFamilyToText(tmp, mf); err != nil {
+ return err
+ }
+ }
+ if err := tmp.Close(); err != nil {
+ return err
+ }
+
+ if err := os.Chmod(tmp.Name(), 0644); err != nil {
+ return err
+ }
+ return os.Rename(tmp.Name(), filename)
+}
+
+// processMetric is an internal helper method only used by the Gather method.
+func processMetric(
+ metric Metric,
+ metricFamiliesByName map[string]*dto.MetricFamily,
+ metricHashes map[uint64]struct{},
+ registeredDescIDs map[uint64]struct{},
+) error {
+ desc := metric.Desc()
+ // Wrapped metrics collected by an unchecked Collector can have an
+ // invalid Desc.
+ if desc.err != nil {
+ return desc.err
+ }
+ dtoMetric := &dto.Metric{}
+ if err := metric.Write(dtoMetric); err != nil {
+ return fmt.Errorf("error collecting metric %v: %s", desc, err)
+ }
+ metricFamily, ok := metricFamiliesByName[desc.fqName]
+ if ok { // Existing name.
+ if metricFamily.GetHelp() != desc.help {
+ return fmt.Errorf(
+ "collected metric %s %s has help %q but should have %q",
+ desc.fqName, dtoMetric, desc.help, metricFamily.GetHelp(),
+ )
+ }
+ // TODO(beorn7): Simplify switch once Desc has type.
+ switch metricFamily.GetType() {
+ case dto.MetricType_COUNTER:
+ if dtoMetric.Counter == nil {
+ return fmt.Errorf(
+ "collected metric %s %s should be a Counter",
+ desc.fqName, dtoMetric,
+ )
+ }
+ case dto.MetricType_GAUGE:
+ if dtoMetric.Gauge == nil {
+ return fmt.Errorf(
+ "collected metric %s %s should be a Gauge",
+ desc.fqName, dtoMetric,
+ )
+ }
+ case dto.MetricType_SUMMARY:
+ if dtoMetric.Summary == nil {
+ return fmt.Errorf(
+ "collected metric %s %s should be a Summary",
+ desc.fqName, dtoMetric,
+ )
+ }
+ case dto.MetricType_UNTYPED:
+ if dtoMetric.Untyped == nil {
+ return fmt.Errorf(
+ "collected metric %s %s should be Untyped",
+ desc.fqName, dtoMetric,
+ )
+ }
+ case dto.MetricType_HISTOGRAM:
+ if dtoMetric.Histogram == nil {
+ return fmt.Errorf(
+ "collected metric %s %s should be a Histogram",
+ desc.fqName, dtoMetric,
+ )
+ }
+ default:
+ panic("encountered MetricFamily with invalid type")
+ }
+ } else { // New name.
+ metricFamily = &dto.MetricFamily{}
+ metricFamily.Name = proto.String(desc.fqName)
+ metricFamily.Help = proto.String(desc.help)
+ // TODO(beorn7): Simplify switch once Desc has type.
+ switch {
+ case dtoMetric.Gauge != nil:
+ metricFamily.Type = dto.MetricType_GAUGE.Enum()
+ case dtoMetric.Counter != nil:
+ metricFamily.Type = dto.MetricType_COUNTER.Enum()
+ case dtoMetric.Summary != nil:
+ metricFamily.Type = dto.MetricType_SUMMARY.Enum()
+ case dtoMetric.Untyped != nil:
+ metricFamily.Type = dto.MetricType_UNTYPED.Enum()
+ case dtoMetric.Histogram != nil:
+ metricFamily.Type = dto.MetricType_HISTOGRAM.Enum()
+ default:
+ return fmt.Errorf("empty metric collected: %s", dtoMetric)
+ }
+ if err := checkSuffixCollisions(metricFamily, metricFamiliesByName); err != nil {
+ return err
+ }
+ metricFamiliesByName[desc.fqName] = metricFamily
+ }
+ if err := checkMetricConsistency(metricFamily, dtoMetric, metricHashes); err != nil {
+ return err
+ }
+ if registeredDescIDs != nil {
+ // Is the desc registered at all?
+ if _, exist := registeredDescIDs[desc.id]; !exist {
+ return fmt.Errorf(
+ "collected metric %s %s with unregistered descriptor %s",
+ metricFamily.GetName(), dtoMetric, desc,
+ )
+ }
+ if err := checkDescConsistency(metricFamily, dtoMetric, desc); err != nil {
+ return err
+ }
+ }
+ metricFamily.Metric = append(metricFamily.Metric, dtoMetric)
+ return nil
+}
+
+// Gatherers is a slice of Gatherer instances that implements the Gatherer
+// interface itself. Its Gather method calls Gather on all Gatherers in the
+// slice in order and returns the merged results. Errors returned from the
+// Gather calls are all returned in a flattened MultiError. Duplicate and
+// inconsistent Metrics are skipped (first occurrence in slice order wins) and
+// reported in the returned error.
+//
+// Gatherers can be used to merge the Gather results from multiple
+// Registries. It also provides a way to directly inject existing MetricFamily
+// protobufs into the gathering by creating a custom Gatherer with a Gather
+// method that simply returns the existing MetricFamily protobufs. Note that no
+// registration is involved (in contrast to Collector registration), so
+// obviously registration-time checks cannot happen. Any inconsistencies between
+// the gathered MetricFamilies are reported as errors by the Gather method, and
+// inconsistent Metrics are dropped. Invalid parts of the MetricFamilies
+// (e.g. syntactically invalid metric or label names) will go undetected.
+type Gatherers []Gatherer
+
+// Gather implements Gatherer.
+func (gs Gatherers) Gather() ([]*dto.MetricFamily, error) {
+ var (
+ metricFamiliesByName = map[string]*dto.MetricFamily{}
+ metricHashes = map[uint64]struct{}{}
+ errs MultiError // The collected errors to return in the end.
+ )
+
+ for i, g := range gs {
+ mfs, err := g.Gather()
+ if err != nil {
+ if multiErr, ok := err.(MultiError); ok {
+ for _, err := range multiErr {
+ errs = append(errs, fmt.Errorf("[from Gatherer #%d] %s", i+1, err))
+ }
+ } else {
+ errs = append(errs, fmt.Errorf("[from Gatherer #%d] %s", i+1, err))
+ }
+ }
+ for _, mf := range mfs {
+ existingMF, exists := metricFamiliesByName[mf.GetName()]
+ if exists {
+ if existingMF.GetHelp() != mf.GetHelp() {
+ errs = append(errs, fmt.Errorf(
+ "gathered metric family %s has help %q but should have %q",
+ mf.GetName(), mf.GetHelp(), existingMF.GetHelp(),
+ ))
+ continue
+ }
+ if existingMF.GetType() != mf.GetType() {
+ errs = append(errs, fmt.Errorf(
+ "gathered metric family %s has type %s but should have %s",
+ mf.GetName(), mf.GetType(), existingMF.GetType(),
+ ))
+ continue
+ }
+ } else {
+ existingMF = &dto.MetricFamily{}
+ existingMF.Name = mf.Name
+ existingMF.Help = mf.Help
+ existingMF.Type = mf.Type
+ if err := checkSuffixCollisions(existingMF, metricFamiliesByName); err != nil {
+ errs = append(errs, err)
+ continue
+ }
+ metricFamiliesByName[mf.GetName()] = existingMF
+ }
+ for _, m := range mf.Metric {
+ if err := checkMetricConsistency(existingMF, m, metricHashes); err != nil {
+ errs = append(errs, err)
+ continue
+ }
+ existingMF.Metric = append(existingMF.Metric, m)
+ }
+ }
+ }
+ return internal.NormalizeMetricFamilies(metricFamiliesByName), errs.MaybeUnwrap()
+}
+
+// checkSuffixCollisions checks for collisions with the “magic” suffixes the
+// Prometheus text format and the internal metric representation of the
+// Prometheus server add while flattening Summaries and Histograms.
+func checkSuffixCollisions(mf *dto.MetricFamily, mfs map[string]*dto.MetricFamily) error {
+ var (
+ newName = mf.GetName()
+ newType = mf.GetType()
+ newNameWithoutSuffix = ""
+ )
+ switch {
+ case strings.HasSuffix(newName, "_count"):
+ newNameWithoutSuffix = newName[:len(newName)-6]
+ case strings.HasSuffix(newName, "_sum"):
+ newNameWithoutSuffix = newName[:len(newName)-4]
+ case strings.HasSuffix(newName, "_bucket"):
+ newNameWithoutSuffix = newName[:len(newName)-7]
+ }
+ if newNameWithoutSuffix != "" {
+ if existingMF, ok := mfs[newNameWithoutSuffix]; ok {
+ switch existingMF.GetType() {
+ case dto.MetricType_SUMMARY:
+ if !strings.HasSuffix(newName, "_bucket") {
+ return fmt.Errorf(
+ "collected metric named %q collides with previously collected summary named %q",
+ newName, newNameWithoutSuffix,
+ )
+ }
+ case dto.MetricType_HISTOGRAM:
+ return fmt.Errorf(
+ "collected metric named %q collides with previously collected histogram named %q",
+ newName, newNameWithoutSuffix,
+ )
+ }
+ }
+ }
+ if newType == dto.MetricType_SUMMARY || newType == dto.MetricType_HISTOGRAM {
+ if _, ok := mfs[newName+"_count"]; ok {
+ return fmt.Errorf(
+ "collected histogram or summary named %q collides with previously collected metric named %q",
+ newName, newName+"_count",
+ )
+ }
+ if _, ok := mfs[newName+"_sum"]; ok {
+ return fmt.Errorf(
+ "collected histogram or summary named %q collides with previously collected metric named %q",
+ newName, newName+"_sum",
+ )
+ }
+ }
+ if newType == dto.MetricType_HISTOGRAM {
+ if _, ok := mfs[newName+"_bucket"]; ok {
+ return fmt.Errorf(
+ "collected histogram named %q collides with previously collected metric named %q",
+ newName, newName+"_bucket",
+ )
+ }
+ }
+ return nil
+}
+
+// checkMetricConsistency checks if the provided Metric is consistent with the
+// provided MetricFamily. It also hashes the Metric labels and the MetricFamily
+// name. If the resulting hash is already in the provided metricHashes, an error
+// is returned. If not, it is added to metricHashes.
+func checkMetricConsistency(
+ metricFamily *dto.MetricFamily,
+ dtoMetric *dto.Metric,
+ metricHashes map[uint64]struct{},
+) error {
+ name := metricFamily.GetName()
+
+ // Type consistency with metric family.
+ if metricFamily.GetType() == dto.MetricType_GAUGE && dtoMetric.Gauge == nil ||
+ metricFamily.GetType() == dto.MetricType_COUNTER && dtoMetric.Counter == nil ||
+ metricFamily.GetType() == dto.MetricType_SUMMARY && dtoMetric.Summary == nil ||
+ metricFamily.GetType() == dto.MetricType_HISTOGRAM && dtoMetric.Histogram == nil ||
+ metricFamily.GetType() == dto.MetricType_UNTYPED && dtoMetric.Untyped == nil {
+ return fmt.Errorf(
+ "collected metric %q { %s} is not a %s",
+ name, dtoMetric, metricFamily.GetType(),
+ )
+ }
+
+ previousLabelName := ""
+ for _, labelPair := range dtoMetric.GetLabel() {
+ labelName := labelPair.GetName()
+ if labelName == previousLabelName {
+ return fmt.Errorf(
+ "collected metric %q { %s} has two or more labels with the same name: %s",
+ name, dtoMetric, labelName,
+ )
+ }
+ if !checkLabelName(labelName) {
+ return fmt.Errorf(
+ "collected metric %q { %s} has a label with an invalid name: %s",
+ name, dtoMetric, labelName,
+ )
+ }
+ if dtoMetric.Summary != nil && labelName == quantileLabel {
+ return fmt.Errorf(
+ "collected metric %q { %s} must not have an explicit %q label",
+ name, dtoMetric, quantileLabel,
+ )
+ }
+ if !utf8.ValidString(labelPair.GetValue()) {
+ return fmt.Errorf(
+ "collected metric %q { %s} has a label named %q whose value is not utf8: %#v",
+ name, dtoMetric, labelName, labelPair.GetValue())
+ }
+ previousLabelName = labelName
+ }
+
+ // Is the metric unique (i.e. no other metric with the same name and the same labels)?
+ h := hashNew()
+ h = hashAdd(h, name)
+ h = hashAddByte(h, separatorByte)
+ // Make sure label pairs are sorted. We depend on it for the consistency
+ // check.
+ if !sort.IsSorted(labelPairSorter(dtoMetric.Label)) {
+ // We cannot sort dtoMetric.Label in place as it is immutable by contract.
+ copiedLabels := make([]*dto.LabelPair, len(dtoMetric.Label))
+ copy(copiedLabels, dtoMetric.Label)
+ sort.Sort(labelPairSorter(copiedLabels))
+ dtoMetric.Label = copiedLabels
+ }
+ for _, lp := range dtoMetric.Label {
+ h = hashAdd(h, lp.GetName())
+ h = hashAddByte(h, separatorByte)
+ h = hashAdd(h, lp.GetValue())
+ h = hashAddByte(h, separatorByte)
+ }
+ if _, exists := metricHashes[h]; exists {
+ return fmt.Errorf(
+ "collected metric %q { %s} was collected before with the same name and label values",
+ name, dtoMetric,
+ )
+ }
+ metricHashes[h] = struct{}{}
+ return nil
+}
+
+func checkDescConsistency(
+ metricFamily *dto.MetricFamily,
+ dtoMetric *dto.Metric,
+ desc *Desc,
+) error {
+ // Desc help consistency with metric family help.
+ if metricFamily.GetHelp() != desc.help {
+ return fmt.Errorf(
+ "collected metric %s %s has help %q but should have %q",
+ metricFamily.GetName(), dtoMetric, metricFamily.GetHelp(), desc.help,
+ )
+ }
+
+ // Is the desc consistent with the content of the metric?
+ lpsFromDesc := make([]*dto.LabelPair, len(desc.constLabelPairs), len(dtoMetric.Label))
+ copy(lpsFromDesc, desc.constLabelPairs)
+ for _, l := range desc.variableLabels {
+ lpsFromDesc = append(lpsFromDesc, &dto.LabelPair{
+ Name: proto.String(l),
+ })
+ }
+ if len(lpsFromDesc) != len(dtoMetric.Label) {
+ return fmt.Errorf(
+ "labels in collected metric %s %s are inconsistent with descriptor %s",
+ metricFamily.GetName(), dtoMetric, desc,
+ )
+ }
+ sort.Sort(labelPairSorter(lpsFromDesc))
+ for i, lpFromDesc := range lpsFromDesc {
+ lpFromMetric := dtoMetric.Label[i]
+ if lpFromDesc.GetName() != lpFromMetric.GetName() ||
+ lpFromDesc.Value != nil && lpFromDesc.GetValue() != lpFromMetric.GetValue() {
+ return fmt.Errorf(
+ "labels in collected metric %s %s are inconsistent with descriptor %s",
+ metricFamily.GetName(), dtoMetric, desc,
+ )
+ }
+ }
+ return nil
+}
diff --git a/vendor/github.com/prometheus/client_golang/prometheus/summary.go b/vendor/github.com/prometheus/client_golang/prometheus/summary.go
new file mode 100644
index 0000000..c970fde
--- /dev/null
+++ b/vendor/github.com/prometheus/client_golang/prometheus/summary.go
@@ -0,0 +1,736 @@
+// Copyright 2014 The Prometheus Authors
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package prometheus
+
+import (
+ "fmt"
+ "math"
+ "runtime"
+ "sort"
+ "sync"
+ "sync/atomic"
+ "time"
+
+ "github.com/beorn7/perks/quantile"
+ "github.com/golang/protobuf/proto"
+
+ dto "github.com/prometheus/client_model/go"
+)
+
+// quantileLabel is used for the label that defines the quantile in a
+// summary.
+const quantileLabel = "quantile"
+
+// A Summary captures individual observations from an event or sample stream and
+// summarizes them in a manner similar to traditional summary statistics: 1. sum
+// of observations, 2. observation count, 3. rank estimations.
+//
+// A typical use-case is the observation of request latencies. By default, a
+// Summary provides the median, the 90th and the 99th percentile of the latency
+// as rank estimations. However, the default behavior will change in the
+// upcoming v1.0.0 of the library. There will be no rank estimations at all by
+// default. For a sane transition, it is recommended to set the desired rank
+// estimations explicitly.
+//
+// Note that the rank estimations cannot be aggregated in a meaningful way with
+// the Prometheus query language (i.e. you cannot average or add them). If you
+// need aggregatable quantiles (e.g. you want the 99th percentile latency of all
+// queries served across all instances of a service), consider the Histogram
+// metric type. See the Prometheus documentation for more details.
+//
+// To create Summary instances, use NewSummary.
+type Summary interface {
+ Metric
+ Collector
+
+ // Observe adds a single observation to the summary.
+ Observe(float64)
+}
+
+var errQuantileLabelNotAllowed = fmt.Errorf(
+ "%q is not allowed as label name in summaries", quantileLabel,
+)
+
+// Default values for SummaryOpts.
+const (
+ // DefMaxAge is the default duration for which observations stay
+ // relevant.
+ DefMaxAge time.Duration = 10 * time.Minute
+ // DefAgeBuckets is the default number of buckets used to calculate the
+ // age of observations.
+ DefAgeBuckets = 5
+ // DefBufCap is the standard buffer size for collecting Summary observations.
+ DefBufCap = 500
+)
+
+// SummaryOpts bundles the options for creating a Summary metric. It is
+// mandatory to set Name to a non-empty string. While all other fields are
+// optional and can safely be left at their zero value, it is recommended to set
+// a help string and to explicitly set the Objectives field to the desired value
+// as the default value will change in the upcoming v1.0.0 of the library.
+type SummaryOpts struct {
+ // Namespace, Subsystem, and Name are components of the fully-qualified
+ // name of the Summary (created by joining these components with
+ // "_"). Only Name is mandatory, the others merely help structuring the
+ // name. Note that the fully-qualified name of the Summary must be a
+ // valid Prometheus metric name.
+ Namespace string
+ Subsystem string
+ Name string
+
+ // Help provides information about this Summary.
+ //
+ // Metrics with the same fully-qualified name must have the same Help
+ // string.
+ Help string
+
+ // ConstLabels are used to attach fixed labels to this metric. Metrics
+ // with the same fully-qualified name must have the same label names in
+ // their ConstLabels.
+ //
+ // Due to the way a Summary is represented in the Prometheus text format
+ // and how it is handled by the Prometheus server internally, “quantile”
+ // is an illegal label name. Construction of a Summary or SummaryVec
+ // will panic if this label name is used in ConstLabels.
+ //
+ // ConstLabels are only used rarely. In particular, do not use them to
+ // attach the same labels to all your metrics. Those use cases are
+ // better covered by target labels set by the scraping Prometheus
+ // server, or by one specific metric (e.g. a build_info or a
+ // machine_role metric). See also
+ // https://prometheus.io/docs/instrumenting/writing_exporters/#target-labels,-not-static-scraped-labels
+ ConstLabels Labels
+
+ // Objectives defines the quantile rank estimates with their respective
+ // absolute error. If Objectives[q] = e, then the value reported for q
+ // will be the φ-quantile value for some φ between q-e and q+e. The
+ // default value is an empty map, resulting in a summary without
+ // quantiles.
+ Objectives map[float64]float64
+
+ // MaxAge defines the duration for which an observation stays relevant
+ // for the summary. Must be positive. The default value is DefMaxAge.
+ MaxAge time.Duration
+
+ // AgeBuckets is the number of buckets used to exclude observations that
+ // are older than MaxAge from the summary. A higher number has a
+ // resource penalty, so only increase it if the higher resolution is
+ // really required. For very high observation rates, you might want to
+ // reduce the number of age buckets. With only one age bucket, you will
+ // effectively see a complete reset of the summary each time MaxAge has
+ // passed. The default value is DefAgeBuckets.
+ AgeBuckets uint32
+
+ // BufCap defines the default sample stream buffer size. The default
+ // value of DefBufCap should suffice for most uses. If there is a need
+ // to increase the value, a multiple of 500 is recommended (because that
+ // is the internal buffer size of the underlying package
+ // "github.com/bmizerany/perks/quantile").
+ BufCap uint32
+}
+
+// Problem with the sliding-window decay algorithm... The Merge method of
+// perk/quantile is actually not working as advertised - and it might be
+// unfixable, as the underlying algorithm is apparently not capable of merging
+// summaries in the first place. To avoid using Merge, we are currently adding
+// observations to _each_ age bucket, i.e. the effort to add a sample is
+// essentially multiplied by the number of age buckets. When rotating age
+// buckets, we empty the previous head stream. On scrape time, we simply take
+// the quantiles from the head stream (no merging required). Result: More effort
+// on observation time, less effort on scrape time, which is exactly the
+// opposite of what we try to accomplish, but at least the results are correct.
+//
+// The quite elegant previous contraption to merge the age buckets efficiently
+// on scrape time (see code up commit 6b9530d72ea715f0ba612c0120e6e09fbf1d49d0)
+// can't be used anymore.
+
+// NewSummary creates a new Summary based on the provided SummaryOpts.
+func NewSummary(opts SummaryOpts) Summary {
+ return newSummary(
+ NewDesc(
+ BuildFQName(opts.Namespace, opts.Subsystem, opts.Name),
+ opts.Help,
+ nil,
+ opts.ConstLabels,
+ ),
+ opts,
+ )
+}
+
+func newSummary(desc *Desc, opts SummaryOpts, labelValues ...string) Summary {
+ if len(desc.variableLabels) != len(labelValues) {
+ panic(makeInconsistentCardinalityError(desc.fqName, desc.variableLabels, labelValues))
+ }
+
+ for _, n := range desc.variableLabels {
+ if n == quantileLabel {
+ panic(errQuantileLabelNotAllowed)
+ }
+ }
+ for _, lp := range desc.constLabelPairs {
+ if lp.GetName() == quantileLabel {
+ panic(errQuantileLabelNotAllowed)
+ }
+ }
+
+ if opts.Objectives == nil {
+ opts.Objectives = map[float64]float64{}
+ }
+
+ if opts.MaxAge < 0 {
+ panic(fmt.Errorf("illegal max age MaxAge=%v", opts.MaxAge))
+ }
+ if opts.MaxAge == 0 {
+ opts.MaxAge = DefMaxAge
+ }
+
+ if opts.AgeBuckets == 0 {
+ opts.AgeBuckets = DefAgeBuckets
+ }
+
+ if opts.BufCap == 0 {
+ opts.BufCap = DefBufCap
+ }
+
+ if len(opts.Objectives) == 0 {
+ // Use the lock-free implementation of a Summary without objectives.
+ s := &noObjectivesSummary{
+ desc: desc,
+ labelPairs: makeLabelPairs(desc, labelValues),
+ counts: [2]*summaryCounts{&summaryCounts{}, &summaryCounts{}},
+ }
+ s.init(s) // Init self-collection.
+ return s
+ }
+
+ s := &summary{
+ desc: desc,
+
+ objectives: opts.Objectives,
+ sortedObjectives: make([]float64, 0, len(opts.Objectives)),
+
+ labelPairs: makeLabelPairs(desc, labelValues),
+
+ hotBuf: make([]float64, 0, opts.BufCap),
+ coldBuf: make([]float64, 0, opts.BufCap),
+ streamDuration: opts.MaxAge / time.Duration(opts.AgeBuckets),
+ }
+ s.headStreamExpTime = time.Now().Add(s.streamDuration)
+ s.hotBufExpTime = s.headStreamExpTime
+
+ for i := uint32(0); i < opts.AgeBuckets; i++ {
+ s.streams = append(s.streams, s.newStream())
+ }
+ s.headStream = s.streams[0]
+
+ for qu := range s.objectives {
+ s.sortedObjectives = append(s.sortedObjectives, qu)
+ }
+ sort.Float64s(s.sortedObjectives)
+
+ s.init(s) // Init self-collection.
+ return s
+}
+
+type summary struct {
+ selfCollector
+
+ bufMtx sync.Mutex // Protects hotBuf and hotBufExpTime.
+ mtx sync.Mutex // Protects every other moving part.
+ // Lock bufMtx before mtx if both are needed.
+
+ desc *Desc
+
+ objectives map[float64]float64
+ sortedObjectives []float64
+
+ labelPairs []*dto.LabelPair
+
+ sum float64
+ cnt uint64
+
+ hotBuf, coldBuf []float64
+
+ streams []*quantile.Stream
+ streamDuration time.Duration
+ headStream *quantile.Stream
+ headStreamIdx int
+ headStreamExpTime, hotBufExpTime time.Time
+}
+
+func (s *summary) Desc() *Desc {
+ return s.desc
+}
+
+func (s *summary) Observe(v float64) {
+ s.bufMtx.Lock()
+ defer s.bufMtx.Unlock()
+
+ now := time.Now()
+ if now.After(s.hotBufExpTime) {
+ s.asyncFlush(now)
+ }
+ s.hotBuf = append(s.hotBuf, v)
+ if len(s.hotBuf) == cap(s.hotBuf) {
+ s.asyncFlush(now)
+ }
+}
+
+func (s *summary) Write(out *dto.Metric) error {
+ sum := &dto.Summary{}
+ qs := make([]*dto.Quantile, 0, len(s.objectives))
+
+ s.bufMtx.Lock()
+ s.mtx.Lock()
+ // Swap bufs even if hotBuf is empty to set new hotBufExpTime.
+ s.swapBufs(time.Now())
+ s.bufMtx.Unlock()
+
+ s.flushColdBuf()
+ sum.SampleCount = proto.Uint64(s.cnt)
+ sum.SampleSum = proto.Float64(s.sum)
+
+ for _, rank := range s.sortedObjectives {
+ var q float64
+ if s.headStream.Count() == 0 {
+ q = math.NaN()
+ } else {
+ q = s.headStream.Query(rank)
+ }
+ qs = append(qs, &dto.Quantile{
+ Quantile: proto.Float64(rank),
+ Value: proto.Float64(q),
+ })
+ }
+
+ s.mtx.Unlock()
+
+ if len(qs) > 0 {
+ sort.Sort(quantSort(qs))
+ }
+ sum.Quantile = qs
+
+ out.Summary = sum
+ out.Label = s.labelPairs
+ return nil
+}
+
+func (s *summary) newStream() *quantile.Stream {
+ return quantile.NewTargeted(s.objectives)
+}
+
+// asyncFlush needs bufMtx locked.
+func (s *summary) asyncFlush(now time.Time) {
+ s.mtx.Lock()
+ s.swapBufs(now)
+
+ // Unblock the original goroutine that was responsible for the mutation
+ // that triggered the compaction. But hold onto the global non-buffer
+ // state mutex until the operation finishes.
+ go func() {
+ s.flushColdBuf()
+ s.mtx.Unlock()
+ }()
+}
+
+// rotateStreams needs mtx AND bufMtx locked.
+func (s *summary) maybeRotateStreams() {
+ for !s.hotBufExpTime.Equal(s.headStreamExpTime) {
+ s.headStream.Reset()
+ s.headStreamIdx++
+ if s.headStreamIdx >= len(s.streams) {
+ s.headStreamIdx = 0
+ }
+ s.headStream = s.streams[s.headStreamIdx]
+ s.headStreamExpTime = s.headStreamExpTime.Add(s.streamDuration)
+ }
+}
+
+// flushColdBuf needs mtx locked.
+func (s *summary) flushColdBuf() {
+ for _, v := range s.coldBuf {
+ for _, stream := range s.streams {
+ stream.Insert(v)
+ }
+ s.cnt++
+ s.sum += v
+ }
+ s.coldBuf = s.coldBuf[0:0]
+ s.maybeRotateStreams()
+}
+
+// swapBufs needs mtx AND bufMtx locked, coldBuf must be empty.
+func (s *summary) swapBufs(now time.Time) {
+ if len(s.coldBuf) != 0 {
+ panic("coldBuf is not empty")
+ }
+ s.hotBuf, s.coldBuf = s.coldBuf, s.hotBuf
+ // hotBuf is now empty and gets new expiration set.
+ for now.After(s.hotBufExpTime) {
+ s.hotBufExpTime = s.hotBufExpTime.Add(s.streamDuration)
+ }
+}
+
+type summaryCounts struct {
+ // sumBits contains the bits of the float64 representing the sum of all
+ // observations. sumBits and count have to go first in the struct to
+ // guarantee alignment for atomic operations.
+ // http://golang.org/pkg/sync/atomic/#pkg-note-BUG
+ sumBits uint64
+ count uint64
+}
+
+type noObjectivesSummary struct {
+ // countAndHotIdx enables lock-free writes with use of atomic updates.
+ // The most significant bit is the hot index [0 or 1] of the count field
+ // below. Observe calls update the hot one. All remaining bits count the
+ // number of Observe calls. Observe starts by incrementing this counter,
+ // and finish by incrementing the count field in the respective
+ // summaryCounts, as a marker for completion.
+ //
+ // Calls of the Write method (which are non-mutating reads from the
+ // perspective of the summary) swap the hot–cold under the writeMtx
+ // lock. A cooldown is awaited (while locked) by comparing the number of
+ // observations with the initiation count. Once they match, then the
+ // last observation on the now cool one has completed. All cool fields must
+ // be merged into the new hot before releasing writeMtx.
+
+ // Fields with atomic access first! See alignment constraint:
+ // http://golang.org/pkg/sync/atomic/#pkg-note-BUG
+ countAndHotIdx uint64
+
+ selfCollector
+ desc *Desc
+ writeMtx sync.Mutex // Only used in the Write method.
+
+ // Two counts, one is "hot" for lock-free observations, the other is
+ // "cold" for writing out a dto.Metric. It has to be an array of
+ // pointers to guarantee 64bit alignment of the histogramCounts, see
+ // http://golang.org/pkg/sync/atomic/#pkg-note-BUG.
+ counts [2]*summaryCounts
+
+ labelPairs []*dto.LabelPair
+}
+
+func (s *noObjectivesSummary) Desc() *Desc {
+ return s.desc
+}
+
+func (s *noObjectivesSummary) Observe(v float64) {
+ // We increment h.countAndHotIdx so that the counter in the lower
+ // 63 bits gets incremented. At the same time, we get the new value
+ // back, which we can use to find the currently-hot counts.
+ n := atomic.AddUint64(&s.countAndHotIdx, 1)
+ hotCounts := s.counts[n>>63]
+
+ for {
+ oldBits := atomic.LoadUint64(&hotCounts.sumBits)
+ newBits := math.Float64bits(math.Float64frombits(oldBits) + v)
+ if atomic.CompareAndSwapUint64(&hotCounts.sumBits, oldBits, newBits) {
+ break
+ }
+ }
+ // Increment count last as we take it as a signal that the observation
+ // is complete.
+ atomic.AddUint64(&hotCounts.count, 1)
+}
+
+func (s *noObjectivesSummary) Write(out *dto.Metric) error {
+ // For simplicity, we protect this whole method by a mutex. It is not in
+ // the hot path, i.e. Observe is called much more often than Write. The
+ // complication of making Write lock-free isn't worth it, if possible at
+ // all.
+ s.writeMtx.Lock()
+ defer s.writeMtx.Unlock()
+
+ // Adding 1<<63 switches the hot index (from 0 to 1 or from 1 to 0)
+ // without touching the count bits. See the struct comments for a full
+ // description of the algorithm.
+ n := atomic.AddUint64(&s.countAndHotIdx, 1<<63)
+ // count is contained unchanged in the lower 63 bits.
+ count := n & ((1 << 63) - 1)
+ // The most significant bit tells us which counts is hot. The complement
+ // is thus the cold one.
+ hotCounts := s.counts[n>>63]
+ coldCounts := s.counts[(^n)>>63]
+
+ // Await cooldown.
+ for count != atomic.LoadUint64(&coldCounts.count) {
+ runtime.Gosched() // Let observations get work done.
+ }
+
+ sum := &dto.Summary{
+ SampleCount: proto.Uint64(count),
+ SampleSum: proto.Float64(math.Float64frombits(atomic.LoadUint64(&coldCounts.sumBits))),
+ }
+
+ out.Summary = sum
+ out.Label = s.labelPairs
+
+ // Finally add all the cold counts to the new hot counts and reset the cold counts.
+ atomic.AddUint64(&hotCounts.count, count)
+ atomic.StoreUint64(&coldCounts.count, 0)
+ for {
+ oldBits := atomic.LoadUint64(&hotCounts.sumBits)
+ newBits := math.Float64bits(math.Float64frombits(oldBits) + sum.GetSampleSum())
+ if atomic.CompareAndSwapUint64(&hotCounts.sumBits, oldBits, newBits) {
+ atomic.StoreUint64(&coldCounts.sumBits, 0)
+ break
+ }
+ }
+ return nil
+}
+
+type quantSort []*dto.Quantile
+
+func (s quantSort) Len() int {
+ return len(s)
+}
+
+func (s quantSort) Swap(i, j int) {
+ s[i], s[j] = s[j], s[i]
+}
+
+func (s quantSort) Less(i, j int) bool {
+ return s[i].GetQuantile() < s[j].GetQuantile()
+}
+
+// SummaryVec is a Collector that bundles a set of Summaries that all share the
+// same Desc, but have different values for their variable labels. This is used
+// if you want to count the same thing partitioned by various dimensions
+// (e.g. HTTP request latencies, partitioned by status code and method). Create
+// instances with NewSummaryVec.
+type SummaryVec struct {
+ *metricVec
+}
+
+// NewSummaryVec creates a new SummaryVec based on the provided SummaryOpts and
+// partitioned by the given label names.
+//
+// Due to the way a Summary is represented in the Prometheus text format and how
+// it is handled by the Prometheus server internally, “quantile” is an illegal
+// label name. NewSummaryVec will panic if this label name is used.
+func NewSummaryVec(opts SummaryOpts, labelNames []string) *SummaryVec {
+ for _, ln := range labelNames {
+ if ln == quantileLabel {
+ panic(errQuantileLabelNotAllowed)
+ }
+ }
+ desc := NewDesc(
+ BuildFQName(opts.Namespace, opts.Subsystem, opts.Name),
+ opts.Help,
+ labelNames,
+ opts.ConstLabels,
+ )
+ return &SummaryVec{
+ metricVec: newMetricVec(desc, func(lvs ...string) Metric {
+ return newSummary(desc, opts, lvs...)
+ }),
+ }
+}
+
+// GetMetricWithLabelValues returns the Summary for the given slice of label
+// values (same order as the VariableLabels in Desc). If that combination of
+// label values is accessed for the first time, a new Summary is created.
+//
+// It is possible to call this method without using the returned Summary to only
+// create the new Summary but leave it at its starting value, a Summary without
+// any observations.
+//
+// Keeping the Summary for later use is possible (and should be considered if
+// performance is critical), but keep in mind that Reset, DeleteLabelValues and
+// Delete can be used to delete the Summary from the SummaryVec. In that case,
+// the Summary will still exist, but it will not be exported anymore, even if a
+// Summary with the same label values is created later. See also the CounterVec
+// example.
+//
+// An error is returned if the number of label values is not the same as the
+// number of VariableLabels in Desc (minus any curried labels).
+//
+// Note that for more than one label value, this method is prone to mistakes
+// caused by an incorrect order of arguments. Consider GetMetricWith(Labels) as
+// an alternative to avoid that type of mistake. For higher label numbers, the
+// latter has a much more readable (albeit more verbose) syntax, but it comes
+// with a performance overhead (for creating and processing the Labels map).
+// See also the GaugeVec example.
+func (v *SummaryVec) GetMetricWithLabelValues(lvs ...string) (Observer, error) {
+ metric, err := v.metricVec.getMetricWithLabelValues(lvs...)
+ if metric != nil {
+ return metric.(Observer), err
+ }
+ return nil, err
+}
+
+// GetMetricWith returns the Summary for the given Labels map (the label names
+// must match those of the VariableLabels in Desc). If that label map is
+// accessed for the first time, a new Summary is created. Implications of
+// creating a Summary without using it and keeping the Summary for later use are
+// the same as for GetMetricWithLabelValues.
+//
+// An error is returned if the number and names of the Labels are inconsistent
+// with those of the VariableLabels in Desc (minus any curried labels).
+//
+// This method is used for the same purpose as
+// GetMetricWithLabelValues(...string). See there for pros and cons of the two
+// methods.
+func (v *SummaryVec) GetMetricWith(labels Labels) (Observer, error) {
+ metric, err := v.metricVec.getMetricWith(labels)
+ if metric != nil {
+ return metric.(Observer), err
+ }
+ return nil, err
+}
+
+// WithLabelValues works as GetMetricWithLabelValues, but panics where
+// GetMetricWithLabelValues would have returned an error. Not returning an
+// error allows shortcuts like
+// myVec.WithLabelValues("404", "GET").Observe(42.21)
+func (v *SummaryVec) WithLabelValues(lvs ...string) Observer {
+ s, err := v.GetMetricWithLabelValues(lvs...)
+ if err != nil {
+ panic(err)
+ }
+ return s
+}
+
+// With works as GetMetricWith, but panics where GetMetricWithLabels would have
+// returned an error. Not returning an error allows shortcuts like
+// myVec.With(prometheus.Labels{"code": "404", "method": "GET"}).Observe(42.21)
+func (v *SummaryVec) With(labels Labels) Observer {
+ s, err := v.GetMetricWith(labels)
+ if err != nil {
+ panic(err)
+ }
+ return s
+}
+
+// CurryWith returns a vector curried with the provided labels, i.e. the
+// returned vector has those labels pre-set for all labeled operations performed
+// on it. The cardinality of the curried vector is reduced accordingly. The
+// order of the remaining labels stays the same (just with the curried labels
+// taken out of the sequence – which is relevant for the
+// (GetMetric)WithLabelValues methods). It is possible to curry a curried
+// vector, but only with labels not yet used for currying before.
+//
+// The metrics contained in the SummaryVec are shared between the curried and
+// uncurried vectors. They are just accessed differently. Curried and uncurried
+// vectors behave identically in terms of collection. Only one must be
+// registered with a given registry (usually the uncurried version). The Reset
+// method deletes all metrics, even if called on a curried vector.
+func (v *SummaryVec) CurryWith(labels Labels) (ObserverVec, error) {
+ vec, err := v.curryWith(labels)
+ if vec != nil {
+ return &SummaryVec{vec}, err
+ }
+ return nil, err
+}
+
+// MustCurryWith works as CurryWith but panics where CurryWith would have
+// returned an error.
+func (v *SummaryVec) MustCurryWith(labels Labels) ObserverVec {
+ vec, err := v.CurryWith(labels)
+ if err != nil {
+ panic(err)
+ }
+ return vec
+}
+
+type constSummary struct {
+ desc *Desc
+ count uint64
+ sum float64
+ quantiles map[float64]float64
+ labelPairs []*dto.LabelPair
+}
+
+func (s *constSummary) Desc() *Desc {
+ return s.desc
+}
+
+func (s *constSummary) Write(out *dto.Metric) error {
+ sum := &dto.Summary{}
+ qs := make([]*dto.Quantile, 0, len(s.quantiles))
+
+ sum.SampleCount = proto.Uint64(s.count)
+ sum.SampleSum = proto.Float64(s.sum)
+
+ for rank, q := range s.quantiles {
+ qs = append(qs, &dto.Quantile{
+ Quantile: proto.Float64(rank),
+ Value: proto.Float64(q),
+ })
+ }
+
+ if len(qs) > 0 {
+ sort.Sort(quantSort(qs))
+ }
+ sum.Quantile = qs
+
+ out.Summary = sum
+ out.Label = s.labelPairs
+
+ return nil
+}
+
+// NewConstSummary returns a metric representing a Prometheus summary with fixed
+// values for the count, sum, and quantiles. As those parameters cannot be
+// changed, the returned value does not implement the Summary interface (but
+// only the Metric interface). Users of this package will not have much use for
+// it in regular operations. However, when implementing custom Collectors, it is
+// useful as a throw-away metric that is generated on the fly to send it to
+// Prometheus in the Collect method.
+//
+// quantiles maps ranks to quantile values. For example, a median latency of
+// 0.23s and a 99th percentile latency of 0.56s would be expressed as:
+// map[float64]float64{0.5: 0.23, 0.99: 0.56}
+//
+// NewConstSummary returns an error if the length of labelValues is not
+// consistent with the variable labels in Desc or if Desc is invalid.
+func NewConstSummary(
+ desc *Desc,
+ count uint64,
+ sum float64,
+ quantiles map[float64]float64,
+ labelValues ...string,
+) (Metric, error) {
+ if desc.err != nil {
+ return nil, desc.err
+ }
+ if err := validateLabelValues(labelValues, len(desc.variableLabels)); err != nil {
+ return nil, err
+ }
+ return &constSummary{
+ desc: desc,
+ count: count,
+ sum: sum,
+ quantiles: quantiles,
+ labelPairs: makeLabelPairs(desc, labelValues),
+ }, nil
+}
+
+// MustNewConstSummary is a version of NewConstSummary that panics where
+// NewConstMetric would have returned an error.
+func MustNewConstSummary(
+ desc *Desc,
+ count uint64,
+ sum float64,
+ quantiles map[float64]float64,
+ labelValues ...string,
+) Metric {
+ m, err := NewConstSummary(desc, count, sum, quantiles, labelValues...)
+ if err != nil {
+ panic(err)
+ }
+ return m
+}
diff --git a/vendor/github.com/prometheus/client_golang/prometheus/timer.go b/vendor/github.com/prometheus/client_golang/prometheus/timer.go
new file mode 100644
index 0000000..8d5f105
--- /dev/null
+++ b/vendor/github.com/prometheus/client_golang/prometheus/timer.go
@@ -0,0 +1,54 @@
+// Copyright 2016 The Prometheus Authors
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package prometheus
+
+import "time"
+
+// Timer is a helper type to time functions. Use NewTimer to create new
+// instances.
+type Timer struct {
+ begin time.Time
+ observer Observer
+}
+
+// NewTimer creates a new Timer. The provided Observer is used to observe a
+// duration in seconds. Timer is usually used to time a function call in the
+// following way:
+// func TimeMe() {
+// timer := NewTimer(myHistogram)
+// defer timer.ObserveDuration()
+// // Do actual work.
+// }
+func NewTimer(o Observer) *Timer {
+ return &Timer{
+ begin: time.Now(),
+ observer: o,
+ }
+}
+
+// ObserveDuration records the duration passed since the Timer was created with
+// NewTimer. It calls the Observe method of the Observer provided during
+// construction with the duration in seconds as an argument. The observed
+// duration is also returned. ObserveDuration is usually called with a defer
+// statement.
+//
+// Note that this method is only guaranteed to never observe negative durations
+// if used with Go1.9+.
+func (t *Timer) ObserveDuration() time.Duration {
+ d := time.Since(t.begin)
+ if t.observer != nil {
+ t.observer.Observe(d.Seconds())
+ }
+ return d
+}
diff --git a/vendor/github.com/prometheus/client_golang/prometheus/untyped.go b/vendor/github.com/prometheus/client_golang/prometheus/untyped.go
new file mode 100644
index 0000000..0f9ce63
--- /dev/null
+++ b/vendor/github.com/prometheus/client_golang/prometheus/untyped.go
@@ -0,0 +1,42 @@
+// Copyright 2014 The Prometheus Authors
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package prometheus
+
+// UntypedOpts is an alias for Opts. See there for doc comments.
+type UntypedOpts Opts
+
+// UntypedFunc works like GaugeFunc but the collected metric is of type
+// "Untyped". UntypedFunc is useful to mirror an external metric of unknown
+// type.
+//
+// To create UntypedFunc instances, use NewUntypedFunc.
+type UntypedFunc interface {
+ Metric
+ Collector
+}
+
+// NewUntypedFunc creates a new UntypedFunc based on the provided
+// UntypedOpts. The value reported is determined by calling the given function
+// from within the Write method. Take into account that metric collection may
+// happen concurrently. If that results in concurrent calls to Write, like in
+// the case where an UntypedFunc is directly registered with Prometheus, the
+// provided function must be concurrency-safe.
+func NewUntypedFunc(opts UntypedOpts, function func() float64) UntypedFunc {
+ return newValueFunc(NewDesc(
+ BuildFQName(opts.Namespace, opts.Subsystem, opts.Name),
+ opts.Help,
+ nil,
+ opts.ConstLabels,
+ ), UntypedValue, function)
+}
diff --git a/vendor/github.com/prometheus/client_golang/prometheus/value.go b/vendor/github.com/prometheus/client_golang/prometheus/value.go
new file mode 100644
index 0000000..eb248f1
--- /dev/null
+++ b/vendor/github.com/prometheus/client_golang/prometheus/value.go
@@ -0,0 +1,162 @@
+// Copyright 2014 The Prometheus Authors
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package prometheus
+
+import (
+ "fmt"
+ "sort"
+
+ "github.com/golang/protobuf/proto"
+
+ dto "github.com/prometheus/client_model/go"
+)
+
+// ValueType is an enumeration of metric types that represent a simple value.
+type ValueType int
+
+// Possible values for the ValueType enum.
+const (
+ _ ValueType = iota
+ CounterValue
+ GaugeValue
+ UntypedValue
+)
+
+// valueFunc is a generic metric for simple values retrieved on collect time
+// from a function. It implements Metric and Collector. Its effective type is
+// determined by ValueType. This is a low-level building block used by the
+// library to back the implementations of CounterFunc, GaugeFunc, and
+// UntypedFunc.
+type valueFunc struct {
+ selfCollector
+
+ desc *Desc
+ valType ValueType
+ function func() float64
+ labelPairs []*dto.LabelPair
+}
+
+// newValueFunc returns a newly allocated valueFunc with the given Desc and
+// ValueType. The value reported is determined by calling the given function
+// from within the Write method. Take into account that metric collection may
+// happen concurrently. If that results in concurrent calls to Write, like in
+// the case where a valueFunc is directly registered with Prometheus, the
+// provided function must be concurrency-safe.
+func newValueFunc(desc *Desc, valueType ValueType, function func() float64) *valueFunc {
+ result := &valueFunc{
+ desc: desc,
+ valType: valueType,
+ function: function,
+ labelPairs: makeLabelPairs(desc, nil),
+ }
+ result.init(result)
+ return result
+}
+
+func (v *valueFunc) Desc() *Desc {
+ return v.desc
+}
+
+func (v *valueFunc) Write(out *dto.Metric) error {
+ return populateMetric(v.valType, v.function(), v.labelPairs, out)
+}
+
+// NewConstMetric returns a metric with one fixed value that cannot be
+// changed. Users of this package will not have much use for it in regular
+// operations. However, when implementing custom Collectors, it is useful as a
+// throw-away metric that is generated on the fly to send it to Prometheus in
+// the Collect method. NewConstMetric returns an error if the length of
+// labelValues is not consistent with the variable labels in Desc or if Desc is
+// invalid.
+func NewConstMetric(desc *Desc, valueType ValueType, value float64, labelValues ...string) (Metric, error) {
+ if desc.err != nil {
+ return nil, desc.err
+ }
+ if err := validateLabelValues(labelValues, len(desc.variableLabels)); err != nil {
+ return nil, err
+ }
+ return &constMetric{
+ desc: desc,
+ valType: valueType,
+ val: value,
+ labelPairs: makeLabelPairs(desc, labelValues),
+ }, nil
+}
+
+// MustNewConstMetric is a version of NewConstMetric that panics where
+// NewConstMetric would have returned an error.
+func MustNewConstMetric(desc *Desc, valueType ValueType, value float64, labelValues ...string) Metric {
+ m, err := NewConstMetric(desc, valueType, value, labelValues...)
+ if err != nil {
+ panic(err)
+ }
+ return m
+}
+
+type constMetric struct {
+ desc *Desc
+ valType ValueType
+ val float64
+ labelPairs []*dto.LabelPair
+}
+
+func (m *constMetric) Desc() *Desc {
+ return m.desc
+}
+
+func (m *constMetric) Write(out *dto.Metric) error {
+ return populateMetric(m.valType, m.val, m.labelPairs, out)
+}
+
+func populateMetric(
+ t ValueType,
+ v float64,
+ labelPairs []*dto.LabelPair,
+ m *dto.Metric,
+) error {
+ m.Label = labelPairs
+ switch t {
+ case CounterValue:
+ m.Counter = &dto.Counter{Value: proto.Float64(v)}
+ case GaugeValue:
+ m.Gauge = &dto.Gauge{Value: proto.Float64(v)}
+ case UntypedValue:
+ m.Untyped = &dto.Untyped{Value: proto.Float64(v)}
+ default:
+ return fmt.Errorf("encountered unknown type %v", t)
+ }
+ return nil
+}
+
+func makeLabelPairs(desc *Desc, labelValues []string) []*dto.LabelPair {
+ totalLen := len(desc.variableLabels) + len(desc.constLabelPairs)
+ if totalLen == 0 {
+ // Super fast path.
+ return nil
+ }
+ if len(desc.variableLabels) == 0 {
+ // Moderately fast path.
+ return desc.constLabelPairs
+ }
+ labelPairs := make([]*dto.LabelPair, 0, totalLen)
+ for i, n := range desc.variableLabels {
+ labelPairs = append(labelPairs, &dto.LabelPair{
+ Name: proto.String(n),
+ Value: proto.String(labelValues[i]),
+ })
+ }
+ labelPairs = append(labelPairs, desc.constLabelPairs...)
+ sort.Sort(labelPairSorter(labelPairs))
+ return labelPairs
+}
diff --git a/vendor/github.com/prometheus/client_golang/prometheus/vec.go b/vendor/github.com/prometheus/client_golang/prometheus/vec.go
new file mode 100644
index 0000000..14ed9e8
--- /dev/null
+++ b/vendor/github.com/prometheus/client_golang/prometheus/vec.go
@@ -0,0 +1,472 @@
+// Copyright 2014 The Prometheus Authors
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package prometheus
+
+import (
+ "fmt"
+ "sync"
+
+ "github.com/prometheus/common/model"
+)
+
+// metricVec is a Collector to bundle metrics of the same name that differ in
+// their label values. metricVec is not used directly (and therefore
+// unexported). It is used as a building block for implementations of vectors of
+// a given metric type, like GaugeVec, CounterVec, SummaryVec, and HistogramVec.
+// It also handles label currying. It uses basicMetricVec internally.
+type metricVec struct {
+ *metricMap
+
+ curry []curriedLabelValue
+
+ // hashAdd and hashAddByte can be replaced for testing collision handling.
+ hashAdd func(h uint64, s string) uint64
+ hashAddByte func(h uint64, b byte) uint64
+}
+
+// newMetricVec returns an initialized metricVec.
+func newMetricVec(desc *Desc, newMetric func(lvs ...string) Metric) *metricVec {
+ return &metricVec{
+ metricMap: &metricMap{
+ metrics: map[uint64][]metricWithLabelValues{},
+ desc: desc,
+ newMetric: newMetric,
+ },
+ hashAdd: hashAdd,
+ hashAddByte: hashAddByte,
+ }
+}
+
+// DeleteLabelValues removes the metric where the variable labels are the same
+// as those passed in as labels (same order as the VariableLabels in Desc). It
+// returns true if a metric was deleted.
+//
+// It is not an error if the number of label values is not the same as the
+// number of VariableLabels in Desc. However, such inconsistent label count can
+// never match an actual metric, so the method will always return false in that
+// case.
+//
+// Note that for more than one label value, this method is prone to mistakes
+// caused by an incorrect order of arguments. Consider Delete(Labels) as an
+// alternative to avoid that type of mistake. For higher label numbers, the
+// latter has a much more readable (albeit more verbose) syntax, but it comes
+// with a performance overhead (for creating and processing the Labels map).
+// See also the CounterVec example.
+func (m *metricVec) DeleteLabelValues(lvs ...string) bool {
+ h, err := m.hashLabelValues(lvs)
+ if err != nil {
+ return false
+ }
+
+ return m.metricMap.deleteByHashWithLabelValues(h, lvs, m.curry)
+}
+
+// Delete deletes the metric where the variable labels are the same as those
+// passed in as labels. It returns true if a metric was deleted.
+//
+// It is not an error if the number and names of the Labels are inconsistent
+// with those of the VariableLabels in Desc. However, such inconsistent Labels
+// can never match an actual metric, so the method will always return false in
+// that case.
+//
+// This method is used for the same purpose as DeleteLabelValues(...string). See
+// there for pros and cons of the two methods.
+func (m *metricVec) Delete(labels Labels) bool {
+ h, err := m.hashLabels(labels)
+ if err != nil {
+ return false
+ }
+
+ return m.metricMap.deleteByHashWithLabels(h, labels, m.curry)
+}
+
+func (m *metricVec) curryWith(labels Labels) (*metricVec, error) {
+ var (
+ newCurry []curriedLabelValue
+ oldCurry = m.curry
+ iCurry int
+ )
+ for i, label := range m.desc.variableLabels {
+ val, ok := labels[label]
+ if iCurry < len(oldCurry) && oldCurry[iCurry].index == i {
+ if ok {
+ return nil, fmt.Errorf("label name %q is already curried", label)
+ }
+ newCurry = append(newCurry, oldCurry[iCurry])
+ iCurry++
+ } else {
+ if !ok {
+ continue // Label stays uncurried.
+ }
+ newCurry = append(newCurry, curriedLabelValue{i, val})
+ }
+ }
+ if l := len(oldCurry) + len(labels) - len(newCurry); l > 0 {
+ return nil, fmt.Errorf("%d unknown label(s) found during currying", l)
+ }
+
+ return &metricVec{
+ metricMap: m.metricMap,
+ curry: newCurry,
+ hashAdd: m.hashAdd,
+ hashAddByte: m.hashAddByte,
+ }, nil
+}
+
+func (m *metricVec) getMetricWithLabelValues(lvs ...string) (Metric, error) {
+ h, err := m.hashLabelValues(lvs)
+ if err != nil {
+ return nil, err
+ }
+
+ return m.metricMap.getOrCreateMetricWithLabelValues(h, lvs, m.curry), nil
+}
+
+func (m *metricVec) getMetricWith(labels Labels) (Metric, error) {
+ h, err := m.hashLabels(labels)
+ if err != nil {
+ return nil, err
+ }
+
+ return m.metricMap.getOrCreateMetricWithLabels(h, labels, m.curry), nil
+}
+
+func (m *metricVec) hashLabelValues(vals []string) (uint64, error) {
+ if err := validateLabelValues(vals, len(m.desc.variableLabels)-len(m.curry)); err != nil {
+ return 0, err
+ }
+
+ var (
+ h = hashNew()
+ curry = m.curry
+ iVals, iCurry int
+ )
+ for i := 0; i < len(m.desc.variableLabels); i++ {
+ if iCurry < len(curry) && curry[iCurry].index == i {
+ h = m.hashAdd(h, curry[iCurry].value)
+ iCurry++
+ } else {
+ h = m.hashAdd(h, vals[iVals])
+ iVals++
+ }
+ h = m.hashAddByte(h, model.SeparatorByte)
+ }
+ return h, nil
+}
+
+func (m *metricVec) hashLabels(labels Labels) (uint64, error) {
+ if err := validateValuesInLabels(labels, len(m.desc.variableLabels)-len(m.curry)); err != nil {
+ return 0, err
+ }
+
+ var (
+ h = hashNew()
+ curry = m.curry
+ iCurry int
+ )
+ for i, label := range m.desc.variableLabels {
+ val, ok := labels[label]
+ if iCurry < len(curry) && curry[iCurry].index == i {
+ if ok {
+ return 0, fmt.Errorf("label name %q is already curried", label)
+ }
+ h = m.hashAdd(h, curry[iCurry].value)
+ iCurry++
+ } else {
+ if !ok {
+ return 0, fmt.Errorf("label name %q missing in label map", label)
+ }
+ h = m.hashAdd(h, val)
+ }
+ h = m.hashAddByte(h, model.SeparatorByte)
+ }
+ return h, nil
+}
+
+// metricWithLabelValues provides the metric and its label values for
+// disambiguation on hash collision.
+type metricWithLabelValues struct {
+ values []string
+ metric Metric
+}
+
+// curriedLabelValue sets the curried value for a label at the given index.
+type curriedLabelValue struct {
+ index int
+ value string
+}
+
+// metricMap is a helper for metricVec and shared between differently curried
+// metricVecs.
+type metricMap struct {
+ mtx sync.RWMutex // Protects metrics.
+ metrics map[uint64][]metricWithLabelValues
+ desc *Desc
+ newMetric func(labelValues ...string) Metric
+}
+
+// Describe implements Collector. It will send exactly one Desc to the provided
+// channel.
+func (m *metricMap) Describe(ch chan<- *Desc) {
+ ch <- m.desc
+}
+
+// Collect implements Collector.
+func (m *metricMap) Collect(ch chan<- Metric) {
+ m.mtx.RLock()
+ defer m.mtx.RUnlock()
+
+ for _, metrics := range m.metrics {
+ for _, metric := range metrics {
+ ch <- metric.metric
+ }
+ }
+}
+
+// Reset deletes all metrics in this vector.
+func (m *metricMap) Reset() {
+ m.mtx.Lock()
+ defer m.mtx.Unlock()
+
+ for h := range m.metrics {
+ delete(m.metrics, h)
+ }
+}
+
+// deleteByHashWithLabelValues removes the metric from the hash bucket h. If
+// there are multiple matches in the bucket, use lvs to select a metric and
+// remove only that metric.
+func (m *metricMap) deleteByHashWithLabelValues(
+ h uint64, lvs []string, curry []curriedLabelValue,
+) bool {
+ m.mtx.Lock()
+ defer m.mtx.Unlock()
+
+ metrics, ok := m.metrics[h]
+ if !ok {
+ return false
+ }
+
+ i := findMetricWithLabelValues(metrics, lvs, curry)
+ if i >= len(metrics) {
+ return false
+ }
+
+ if len(metrics) > 1 {
+ m.metrics[h] = append(metrics[:i], metrics[i+1:]...)
+ } else {
+ delete(m.metrics, h)
+ }
+ return true
+}
+
+// deleteByHashWithLabels removes the metric from the hash bucket h. If there
+// are multiple matches in the bucket, use lvs to select a metric and remove
+// only that metric.
+func (m *metricMap) deleteByHashWithLabels(
+ h uint64, labels Labels, curry []curriedLabelValue,
+) bool {
+ m.mtx.Lock()
+ defer m.mtx.Unlock()
+
+ metrics, ok := m.metrics[h]
+ if !ok {
+ return false
+ }
+ i := findMetricWithLabels(m.desc, metrics, labels, curry)
+ if i >= len(metrics) {
+ return false
+ }
+
+ if len(metrics) > 1 {
+ m.metrics[h] = append(metrics[:i], metrics[i+1:]...)
+ } else {
+ delete(m.metrics, h)
+ }
+ return true
+}
+
+// getOrCreateMetricWithLabelValues retrieves the metric by hash and label value
+// or creates it and returns the new one.
+//
+// This function holds the mutex.
+func (m *metricMap) getOrCreateMetricWithLabelValues(
+ hash uint64, lvs []string, curry []curriedLabelValue,
+) Metric {
+ m.mtx.RLock()
+ metric, ok := m.getMetricWithHashAndLabelValues(hash, lvs, curry)
+ m.mtx.RUnlock()
+ if ok {
+ return metric
+ }
+
+ m.mtx.Lock()
+ defer m.mtx.Unlock()
+ metric, ok = m.getMetricWithHashAndLabelValues(hash, lvs, curry)
+ if !ok {
+ inlinedLVs := inlineLabelValues(lvs, curry)
+ metric = m.newMetric(inlinedLVs...)
+ m.metrics[hash] = append(m.metrics[hash], metricWithLabelValues{values: inlinedLVs, metric: metric})
+ }
+ return metric
+}
+
+// getOrCreateMetricWithLabelValues retrieves the metric by hash and label value
+// or creates it and returns the new one.
+//
+// This function holds the mutex.
+func (m *metricMap) getOrCreateMetricWithLabels(
+ hash uint64, labels Labels, curry []curriedLabelValue,
+) Metric {
+ m.mtx.RLock()
+ metric, ok := m.getMetricWithHashAndLabels(hash, labels, curry)
+ m.mtx.RUnlock()
+ if ok {
+ return metric
+ }
+
+ m.mtx.Lock()
+ defer m.mtx.Unlock()
+ metric, ok = m.getMetricWithHashAndLabels(hash, labels, curry)
+ if !ok {
+ lvs := extractLabelValues(m.desc, labels, curry)
+ metric = m.newMetric(lvs...)
+ m.metrics[hash] = append(m.metrics[hash], metricWithLabelValues{values: lvs, metric: metric})
+ }
+ return metric
+}
+
+// getMetricWithHashAndLabelValues gets a metric while handling possible
+// collisions in the hash space. Must be called while holding the read mutex.
+func (m *metricMap) getMetricWithHashAndLabelValues(
+ h uint64, lvs []string, curry []curriedLabelValue,
+) (Metric, bool) {
+ metrics, ok := m.metrics[h]
+ if ok {
+ if i := findMetricWithLabelValues(metrics, lvs, curry); i < len(metrics) {
+ return metrics[i].metric, true
+ }
+ }
+ return nil, false
+}
+
+// getMetricWithHashAndLabels gets a metric while handling possible collisions in
+// the hash space. Must be called while holding read mutex.
+func (m *metricMap) getMetricWithHashAndLabels(
+ h uint64, labels Labels, curry []curriedLabelValue,
+) (Metric, bool) {
+ metrics, ok := m.metrics[h]
+ if ok {
+ if i := findMetricWithLabels(m.desc, metrics, labels, curry); i < len(metrics) {
+ return metrics[i].metric, true
+ }
+ }
+ return nil, false
+}
+
+// findMetricWithLabelValues returns the index of the matching metric or
+// len(metrics) if not found.
+func findMetricWithLabelValues(
+ metrics []metricWithLabelValues, lvs []string, curry []curriedLabelValue,
+) int {
+ for i, metric := range metrics {
+ if matchLabelValues(metric.values, lvs, curry) {
+ return i
+ }
+ }
+ return len(metrics)
+}
+
+// findMetricWithLabels returns the index of the matching metric or len(metrics)
+// if not found.
+func findMetricWithLabels(
+ desc *Desc, metrics []metricWithLabelValues, labels Labels, curry []curriedLabelValue,
+) int {
+ for i, metric := range metrics {
+ if matchLabels(desc, metric.values, labels, curry) {
+ return i
+ }
+ }
+ return len(metrics)
+}
+
+func matchLabelValues(values []string, lvs []string, curry []curriedLabelValue) bool {
+ if len(values) != len(lvs)+len(curry) {
+ return false
+ }
+ var iLVs, iCurry int
+ for i, v := range values {
+ if iCurry < len(curry) && curry[iCurry].index == i {
+ if v != curry[iCurry].value {
+ return false
+ }
+ iCurry++
+ continue
+ }
+ if v != lvs[iLVs] {
+ return false
+ }
+ iLVs++
+ }
+ return true
+}
+
+func matchLabels(desc *Desc, values []string, labels Labels, curry []curriedLabelValue) bool {
+ if len(values) != len(labels)+len(curry) {
+ return false
+ }
+ iCurry := 0
+ for i, k := range desc.variableLabels {
+ if iCurry < len(curry) && curry[iCurry].index == i {
+ if values[i] != curry[iCurry].value {
+ return false
+ }
+ iCurry++
+ continue
+ }
+ if values[i] != labels[k] {
+ return false
+ }
+ }
+ return true
+}
+
+func extractLabelValues(desc *Desc, labels Labels, curry []curriedLabelValue) []string {
+ labelValues := make([]string, len(labels)+len(curry))
+ iCurry := 0
+ for i, k := range desc.variableLabels {
+ if iCurry < len(curry) && curry[iCurry].index == i {
+ labelValues[i] = curry[iCurry].value
+ iCurry++
+ continue
+ }
+ labelValues[i] = labels[k]
+ }
+ return labelValues
+}
+
+func inlineLabelValues(lvs []string, curry []curriedLabelValue) []string {
+ labelValues := make([]string, len(lvs)+len(curry))
+ var iCurry, iLVs int
+ for i := range labelValues {
+ if iCurry < len(curry) && curry[iCurry].index == i {
+ labelValues[i] = curry[iCurry].value
+ iCurry++
+ continue
+ }
+ labelValues[i] = lvs[iLVs]
+ iLVs++
+ }
+ return labelValues
+}
diff --git a/vendor/github.com/prometheus/client_golang/prometheus/wrap.go b/vendor/github.com/prometheus/client_golang/prometheus/wrap.go
new file mode 100644
index 0000000..e303eef
--- /dev/null
+++ b/vendor/github.com/prometheus/client_golang/prometheus/wrap.go
@@ -0,0 +1,200 @@
+// Copyright 2018 The Prometheus Authors
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package prometheus
+
+import (
+ "fmt"
+ "sort"
+
+ "github.com/golang/protobuf/proto"
+
+ dto "github.com/prometheus/client_model/go"
+)
+
+// WrapRegistererWith returns a Registerer wrapping the provided
+// Registerer. Collectors registered with the returned Registerer will be
+// registered with the wrapped Registerer in a modified way. The modified
+// Collector adds the provided Labels to all Metrics it collects (as
+// ConstLabels). The Metrics collected by the unmodified Collector must not
+// duplicate any of those labels.
+//
+// WrapRegistererWith provides a way to add fixed labels to a subset of
+// Collectors. It should not be used to add fixed labels to all metrics exposed.
+//
+// Conflicts between Collectors registered through the original Registerer with
+// Collectors registered through the wrapping Registerer will still be
+// detected. Any AlreadyRegisteredError returned by the Register method of
+// either Registerer will contain the ExistingCollector in the form it was
+// provided to the respective registry.
+//
+// The Collector example demonstrates a use of WrapRegistererWith.
+func WrapRegistererWith(labels Labels, reg Registerer) Registerer {
+ return &wrappingRegisterer{
+ wrappedRegisterer: reg,
+ labels: labels,
+ }
+}
+
+// WrapRegistererWithPrefix returns a Registerer wrapping the provided
+// Registerer. Collectors registered with the returned Registerer will be
+// registered with the wrapped Registerer in a modified way. The modified
+// Collector adds the provided prefix to the name of all Metrics it collects.
+//
+// WrapRegistererWithPrefix is useful to have one place to prefix all metrics of
+// a sub-system. To make this work, register metrics of the sub-system with the
+// wrapping Registerer returned by WrapRegistererWithPrefix. It is rarely useful
+// to use the same prefix for all metrics exposed. In particular, do not prefix
+// metric names that are standardized across applications, as that would break
+// horizontal monitoring, for example the metrics provided by the Go collector
+// (see NewGoCollector) and the process collector (see NewProcessCollector). (In
+// fact, those metrics are already prefixed with “go_” or “process_”,
+// respectively.)
+//
+// Conflicts between Collectors registered through the original Registerer with
+// Collectors registered through the wrapping Registerer will still be
+// detected. Any AlreadyRegisteredError returned by the Register method of
+// either Registerer will contain the ExistingCollector in the form it was
+// provided to the respective registry.
+func WrapRegistererWithPrefix(prefix string, reg Registerer) Registerer {
+ return &wrappingRegisterer{
+ wrappedRegisterer: reg,
+ prefix: prefix,
+ }
+}
+
+type wrappingRegisterer struct {
+ wrappedRegisterer Registerer
+ prefix string
+ labels Labels
+}
+
+func (r *wrappingRegisterer) Register(c Collector) error {
+ return r.wrappedRegisterer.Register(&wrappingCollector{
+ wrappedCollector: c,
+ prefix: r.prefix,
+ labels: r.labels,
+ })
+}
+
+func (r *wrappingRegisterer) MustRegister(cs ...Collector) {
+ for _, c := range cs {
+ if err := r.Register(c); err != nil {
+ panic(err)
+ }
+ }
+}
+
+func (r *wrappingRegisterer) Unregister(c Collector) bool {
+ return r.wrappedRegisterer.Unregister(&wrappingCollector{
+ wrappedCollector: c,
+ prefix: r.prefix,
+ labels: r.labels,
+ })
+}
+
+type wrappingCollector struct {
+ wrappedCollector Collector
+ prefix string
+ labels Labels
+}
+
+func (c *wrappingCollector) Collect(ch chan<- Metric) {
+ wrappedCh := make(chan Metric)
+ go func() {
+ c.wrappedCollector.Collect(wrappedCh)
+ close(wrappedCh)
+ }()
+ for m := range wrappedCh {
+ ch <- &wrappingMetric{
+ wrappedMetric: m,
+ prefix: c.prefix,
+ labels: c.labels,
+ }
+ }
+}
+
+func (c *wrappingCollector) Describe(ch chan<- *Desc) {
+ wrappedCh := make(chan *Desc)
+ go func() {
+ c.wrappedCollector.Describe(wrappedCh)
+ close(wrappedCh)
+ }()
+ for desc := range wrappedCh {
+ ch <- wrapDesc(desc, c.prefix, c.labels)
+ }
+}
+
+func (c *wrappingCollector) unwrapRecursively() Collector {
+ switch wc := c.wrappedCollector.(type) {
+ case *wrappingCollector:
+ return wc.unwrapRecursively()
+ default:
+ return wc
+ }
+}
+
+type wrappingMetric struct {
+ wrappedMetric Metric
+ prefix string
+ labels Labels
+}
+
+func (m *wrappingMetric) Desc() *Desc {
+ return wrapDesc(m.wrappedMetric.Desc(), m.prefix, m.labels)
+}
+
+func (m *wrappingMetric) Write(out *dto.Metric) error {
+ if err := m.wrappedMetric.Write(out); err != nil {
+ return err
+ }
+ if len(m.labels) == 0 {
+ // No wrapping labels.
+ return nil
+ }
+ for ln, lv := range m.labels {
+ out.Label = append(out.Label, &dto.LabelPair{
+ Name: proto.String(ln),
+ Value: proto.String(lv),
+ })
+ }
+ sort.Sort(labelPairSorter(out.Label))
+ return nil
+}
+
+func wrapDesc(desc *Desc, prefix string, labels Labels) *Desc {
+ constLabels := Labels{}
+ for _, lp := range desc.constLabelPairs {
+ constLabels[*lp.Name] = *lp.Value
+ }
+ for ln, lv := range labels {
+ if _, alreadyUsed := constLabels[ln]; alreadyUsed {
+ return &Desc{
+ fqName: desc.fqName,
+ help: desc.help,
+ variableLabels: desc.variableLabels,
+ constLabelPairs: desc.constLabelPairs,
+ err: fmt.Errorf("attempted wrapping with already existing label name %q", ln),
+ }
+ }
+ constLabels[ln] = lv
+ }
+ // NewDesc will do remaining validations.
+ newDesc := NewDesc(prefix+desc.fqName, desc.help, desc.variableLabels, constLabels)
+ // Propagate errors if there was any. This will override any errer
+ // created by NewDesc above, i.e. earlier errors get precedence.
+ if desc.err != nil {
+ newDesc.err = desc.err
+ }
+ return newDesc
+}
diff --git a/vendor/github.com/prometheus/client_model/LICENSE b/vendor/github.com/prometheus/client_model/LICENSE
new file mode 100644
index 0000000..261eeb9
--- /dev/null
+++ b/vendor/github.com/prometheus/client_model/LICENSE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/vendor/github.com/prometheus/client_model/NOTICE b/vendor/github.com/prometheus/client_model/NOTICE
new file mode 100644
index 0000000..20110e4
--- /dev/null
+++ b/vendor/github.com/prometheus/client_model/NOTICE
@@ -0,0 +1,5 @@
+Data model artifacts for Prometheus.
+Copyright 2012-2015 The Prometheus Authors
+
+This product includes software developed at
+SoundCloud Ltd. (http://soundcloud.com/).
diff --git a/vendor/github.com/prometheus/client_model/go/metrics.pb.go b/vendor/github.com/prometheus/client_model/go/metrics.pb.go
new file mode 100644
index 0000000..9805432
--- /dev/null
+++ b/vendor/github.com/prometheus/client_model/go/metrics.pb.go
@@ -0,0 +1,629 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// source: metrics.proto
+
+package io_prometheus_client // import "github.com/prometheus/client_model/go"
+
+import proto "github.com/golang/protobuf/proto"
+import fmt "fmt"
+import math "math"
+
+// Reference imports to suppress errors if they are not otherwise used.
+var _ = proto.Marshal
+var _ = fmt.Errorf
+var _ = math.Inf
+
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the proto package it is being compiled against.
+// A compilation error at this line likely means your copy of the
+// proto package needs to be updated.
+const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
+
+type MetricType int32
+
+const (
+ MetricType_COUNTER MetricType = 0
+ MetricType_GAUGE MetricType = 1
+ MetricType_SUMMARY MetricType = 2
+ MetricType_UNTYPED MetricType = 3
+ MetricType_HISTOGRAM MetricType = 4
+)
+
+var MetricType_name = map[int32]string{
+ 0: "COUNTER",
+ 1: "GAUGE",
+ 2: "SUMMARY",
+ 3: "UNTYPED",
+ 4: "HISTOGRAM",
+}
+var MetricType_value = map[string]int32{
+ "COUNTER": 0,
+ "GAUGE": 1,
+ "SUMMARY": 2,
+ "UNTYPED": 3,
+ "HISTOGRAM": 4,
+}
+
+func (x MetricType) Enum() *MetricType {
+ p := new(MetricType)
+ *p = x
+ return p
+}
+func (x MetricType) String() string {
+ return proto.EnumName(MetricType_name, int32(x))
+}
+func (x *MetricType) UnmarshalJSON(data []byte) error {
+ value, err := proto.UnmarshalJSONEnum(MetricType_value, data, "MetricType")
+ if err != nil {
+ return err
+ }
+ *x = MetricType(value)
+ return nil
+}
+func (MetricType) EnumDescriptor() ([]byte, []int) {
+ return fileDescriptor_metrics_c97c9a2b9560cb8f, []int{0}
+}
+
+type LabelPair struct {
+ Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"`
+ Value *string `protobuf:"bytes,2,opt,name=value" json:"value,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *LabelPair) Reset() { *m = LabelPair{} }
+func (m *LabelPair) String() string { return proto.CompactTextString(m) }
+func (*LabelPair) ProtoMessage() {}
+func (*LabelPair) Descriptor() ([]byte, []int) {
+ return fileDescriptor_metrics_c97c9a2b9560cb8f, []int{0}
+}
+func (m *LabelPair) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_LabelPair.Unmarshal(m, b)
+}
+func (m *LabelPair) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_LabelPair.Marshal(b, m, deterministic)
+}
+func (dst *LabelPair) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_LabelPair.Merge(dst, src)
+}
+func (m *LabelPair) XXX_Size() int {
+ return xxx_messageInfo_LabelPair.Size(m)
+}
+func (m *LabelPair) XXX_DiscardUnknown() {
+ xxx_messageInfo_LabelPair.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_LabelPair proto.InternalMessageInfo
+
+func (m *LabelPair) GetName() string {
+ if m != nil && m.Name != nil {
+ return *m.Name
+ }
+ return ""
+}
+
+func (m *LabelPair) GetValue() string {
+ if m != nil && m.Value != nil {
+ return *m.Value
+ }
+ return ""
+}
+
+type Gauge struct {
+ Value *float64 `protobuf:"fixed64,1,opt,name=value" json:"value,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *Gauge) Reset() { *m = Gauge{} }
+func (m *Gauge) String() string { return proto.CompactTextString(m) }
+func (*Gauge) ProtoMessage() {}
+func (*Gauge) Descriptor() ([]byte, []int) {
+ return fileDescriptor_metrics_c97c9a2b9560cb8f, []int{1}
+}
+func (m *Gauge) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_Gauge.Unmarshal(m, b)
+}
+func (m *Gauge) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_Gauge.Marshal(b, m, deterministic)
+}
+func (dst *Gauge) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_Gauge.Merge(dst, src)
+}
+func (m *Gauge) XXX_Size() int {
+ return xxx_messageInfo_Gauge.Size(m)
+}
+func (m *Gauge) XXX_DiscardUnknown() {
+ xxx_messageInfo_Gauge.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_Gauge proto.InternalMessageInfo
+
+func (m *Gauge) GetValue() float64 {
+ if m != nil && m.Value != nil {
+ return *m.Value
+ }
+ return 0
+}
+
+type Counter struct {
+ Value *float64 `protobuf:"fixed64,1,opt,name=value" json:"value,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *Counter) Reset() { *m = Counter{} }
+func (m *Counter) String() string { return proto.CompactTextString(m) }
+func (*Counter) ProtoMessage() {}
+func (*Counter) Descriptor() ([]byte, []int) {
+ return fileDescriptor_metrics_c97c9a2b9560cb8f, []int{2}
+}
+func (m *Counter) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_Counter.Unmarshal(m, b)
+}
+func (m *Counter) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_Counter.Marshal(b, m, deterministic)
+}
+func (dst *Counter) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_Counter.Merge(dst, src)
+}
+func (m *Counter) XXX_Size() int {
+ return xxx_messageInfo_Counter.Size(m)
+}
+func (m *Counter) XXX_DiscardUnknown() {
+ xxx_messageInfo_Counter.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_Counter proto.InternalMessageInfo
+
+func (m *Counter) GetValue() float64 {
+ if m != nil && m.Value != nil {
+ return *m.Value
+ }
+ return 0
+}
+
+type Quantile struct {
+ Quantile *float64 `protobuf:"fixed64,1,opt,name=quantile" json:"quantile,omitempty"`
+ Value *float64 `protobuf:"fixed64,2,opt,name=value" json:"value,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *Quantile) Reset() { *m = Quantile{} }
+func (m *Quantile) String() string { return proto.CompactTextString(m) }
+func (*Quantile) ProtoMessage() {}
+func (*Quantile) Descriptor() ([]byte, []int) {
+ return fileDescriptor_metrics_c97c9a2b9560cb8f, []int{3}
+}
+func (m *Quantile) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_Quantile.Unmarshal(m, b)
+}
+func (m *Quantile) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_Quantile.Marshal(b, m, deterministic)
+}
+func (dst *Quantile) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_Quantile.Merge(dst, src)
+}
+func (m *Quantile) XXX_Size() int {
+ return xxx_messageInfo_Quantile.Size(m)
+}
+func (m *Quantile) XXX_DiscardUnknown() {
+ xxx_messageInfo_Quantile.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_Quantile proto.InternalMessageInfo
+
+func (m *Quantile) GetQuantile() float64 {
+ if m != nil && m.Quantile != nil {
+ return *m.Quantile
+ }
+ return 0
+}
+
+func (m *Quantile) GetValue() float64 {
+ if m != nil && m.Value != nil {
+ return *m.Value
+ }
+ return 0
+}
+
+type Summary struct {
+ SampleCount *uint64 `protobuf:"varint,1,opt,name=sample_count,json=sampleCount" json:"sample_count,omitempty"`
+ SampleSum *float64 `protobuf:"fixed64,2,opt,name=sample_sum,json=sampleSum" json:"sample_sum,omitempty"`
+ Quantile []*Quantile `protobuf:"bytes,3,rep,name=quantile" json:"quantile,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *Summary) Reset() { *m = Summary{} }
+func (m *Summary) String() string { return proto.CompactTextString(m) }
+func (*Summary) ProtoMessage() {}
+func (*Summary) Descriptor() ([]byte, []int) {
+ return fileDescriptor_metrics_c97c9a2b9560cb8f, []int{4}
+}
+func (m *Summary) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_Summary.Unmarshal(m, b)
+}
+func (m *Summary) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_Summary.Marshal(b, m, deterministic)
+}
+func (dst *Summary) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_Summary.Merge(dst, src)
+}
+func (m *Summary) XXX_Size() int {
+ return xxx_messageInfo_Summary.Size(m)
+}
+func (m *Summary) XXX_DiscardUnknown() {
+ xxx_messageInfo_Summary.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_Summary proto.InternalMessageInfo
+
+func (m *Summary) GetSampleCount() uint64 {
+ if m != nil && m.SampleCount != nil {
+ return *m.SampleCount
+ }
+ return 0
+}
+
+func (m *Summary) GetSampleSum() float64 {
+ if m != nil && m.SampleSum != nil {
+ return *m.SampleSum
+ }
+ return 0
+}
+
+func (m *Summary) GetQuantile() []*Quantile {
+ if m != nil {
+ return m.Quantile
+ }
+ return nil
+}
+
+type Untyped struct {
+ Value *float64 `protobuf:"fixed64,1,opt,name=value" json:"value,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *Untyped) Reset() { *m = Untyped{} }
+func (m *Untyped) String() string { return proto.CompactTextString(m) }
+func (*Untyped) ProtoMessage() {}
+func (*Untyped) Descriptor() ([]byte, []int) {
+ return fileDescriptor_metrics_c97c9a2b9560cb8f, []int{5}
+}
+func (m *Untyped) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_Untyped.Unmarshal(m, b)
+}
+func (m *Untyped) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_Untyped.Marshal(b, m, deterministic)
+}
+func (dst *Untyped) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_Untyped.Merge(dst, src)
+}
+func (m *Untyped) XXX_Size() int {
+ return xxx_messageInfo_Untyped.Size(m)
+}
+func (m *Untyped) XXX_DiscardUnknown() {
+ xxx_messageInfo_Untyped.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_Untyped proto.InternalMessageInfo
+
+func (m *Untyped) GetValue() float64 {
+ if m != nil && m.Value != nil {
+ return *m.Value
+ }
+ return 0
+}
+
+type Histogram struct {
+ SampleCount *uint64 `protobuf:"varint,1,opt,name=sample_count,json=sampleCount" json:"sample_count,omitempty"`
+ SampleSum *float64 `protobuf:"fixed64,2,opt,name=sample_sum,json=sampleSum" json:"sample_sum,omitempty"`
+ Bucket []*Bucket `protobuf:"bytes,3,rep,name=bucket" json:"bucket,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *Histogram) Reset() { *m = Histogram{} }
+func (m *Histogram) String() string { return proto.CompactTextString(m) }
+func (*Histogram) ProtoMessage() {}
+func (*Histogram) Descriptor() ([]byte, []int) {
+ return fileDescriptor_metrics_c97c9a2b9560cb8f, []int{6}
+}
+func (m *Histogram) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_Histogram.Unmarshal(m, b)
+}
+func (m *Histogram) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_Histogram.Marshal(b, m, deterministic)
+}
+func (dst *Histogram) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_Histogram.Merge(dst, src)
+}
+func (m *Histogram) XXX_Size() int {
+ return xxx_messageInfo_Histogram.Size(m)
+}
+func (m *Histogram) XXX_DiscardUnknown() {
+ xxx_messageInfo_Histogram.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_Histogram proto.InternalMessageInfo
+
+func (m *Histogram) GetSampleCount() uint64 {
+ if m != nil && m.SampleCount != nil {
+ return *m.SampleCount
+ }
+ return 0
+}
+
+func (m *Histogram) GetSampleSum() float64 {
+ if m != nil && m.SampleSum != nil {
+ return *m.SampleSum
+ }
+ return 0
+}
+
+func (m *Histogram) GetBucket() []*Bucket {
+ if m != nil {
+ return m.Bucket
+ }
+ return nil
+}
+
+type Bucket struct {
+ CumulativeCount *uint64 `protobuf:"varint,1,opt,name=cumulative_count,json=cumulativeCount" json:"cumulative_count,omitempty"`
+ UpperBound *float64 `protobuf:"fixed64,2,opt,name=upper_bound,json=upperBound" json:"upper_bound,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *Bucket) Reset() { *m = Bucket{} }
+func (m *Bucket) String() string { return proto.CompactTextString(m) }
+func (*Bucket) ProtoMessage() {}
+func (*Bucket) Descriptor() ([]byte, []int) {
+ return fileDescriptor_metrics_c97c9a2b9560cb8f, []int{7}
+}
+func (m *Bucket) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_Bucket.Unmarshal(m, b)
+}
+func (m *Bucket) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_Bucket.Marshal(b, m, deterministic)
+}
+func (dst *Bucket) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_Bucket.Merge(dst, src)
+}
+func (m *Bucket) XXX_Size() int {
+ return xxx_messageInfo_Bucket.Size(m)
+}
+func (m *Bucket) XXX_DiscardUnknown() {
+ xxx_messageInfo_Bucket.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_Bucket proto.InternalMessageInfo
+
+func (m *Bucket) GetCumulativeCount() uint64 {
+ if m != nil && m.CumulativeCount != nil {
+ return *m.CumulativeCount
+ }
+ return 0
+}
+
+func (m *Bucket) GetUpperBound() float64 {
+ if m != nil && m.UpperBound != nil {
+ return *m.UpperBound
+ }
+ return 0
+}
+
+type Metric struct {
+ Label []*LabelPair `protobuf:"bytes,1,rep,name=label" json:"label,omitempty"`
+ Gauge *Gauge `protobuf:"bytes,2,opt,name=gauge" json:"gauge,omitempty"`
+ Counter *Counter `protobuf:"bytes,3,opt,name=counter" json:"counter,omitempty"`
+ Summary *Summary `protobuf:"bytes,4,opt,name=summary" json:"summary,omitempty"`
+ Untyped *Untyped `protobuf:"bytes,5,opt,name=untyped" json:"untyped,omitempty"`
+ Histogram *Histogram `protobuf:"bytes,7,opt,name=histogram" json:"histogram,omitempty"`
+ TimestampMs *int64 `protobuf:"varint,6,opt,name=timestamp_ms,json=timestampMs" json:"timestamp_ms,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *Metric) Reset() { *m = Metric{} }
+func (m *Metric) String() string { return proto.CompactTextString(m) }
+func (*Metric) ProtoMessage() {}
+func (*Metric) Descriptor() ([]byte, []int) {
+ return fileDescriptor_metrics_c97c9a2b9560cb8f, []int{8}
+}
+func (m *Metric) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_Metric.Unmarshal(m, b)
+}
+func (m *Metric) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_Metric.Marshal(b, m, deterministic)
+}
+func (dst *Metric) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_Metric.Merge(dst, src)
+}
+func (m *Metric) XXX_Size() int {
+ return xxx_messageInfo_Metric.Size(m)
+}
+func (m *Metric) XXX_DiscardUnknown() {
+ xxx_messageInfo_Metric.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_Metric proto.InternalMessageInfo
+
+func (m *Metric) GetLabel() []*LabelPair {
+ if m != nil {
+ return m.Label
+ }
+ return nil
+}
+
+func (m *Metric) GetGauge() *Gauge {
+ if m != nil {
+ return m.Gauge
+ }
+ return nil
+}
+
+func (m *Metric) GetCounter() *Counter {
+ if m != nil {
+ return m.Counter
+ }
+ return nil
+}
+
+func (m *Metric) GetSummary() *Summary {
+ if m != nil {
+ return m.Summary
+ }
+ return nil
+}
+
+func (m *Metric) GetUntyped() *Untyped {
+ if m != nil {
+ return m.Untyped
+ }
+ return nil
+}
+
+func (m *Metric) GetHistogram() *Histogram {
+ if m != nil {
+ return m.Histogram
+ }
+ return nil
+}
+
+func (m *Metric) GetTimestampMs() int64 {
+ if m != nil && m.TimestampMs != nil {
+ return *m.TimestampMs
+ }
+ return 0
+}
+
+type MetricFamily struct {
+ Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"`
+ Help *string `protobuf:"bytes,2,opt,name=help" json:"help,omitempty"`
+ Type *MetricType `protobuf:"varint,3,opt,name=type,enum=io.prometheus.client.MetricType" json:"type,omitempty"`
+ Metric []*Metric `protobuf:"bytes,4,rep,name=metric" json:"metric,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *MetricFamily) Reset() { *m = MetricFamily{} }
+func (m *MetricFamily) String() string { return proto.CompactTextString(m) }
+func (*MetricFamily) ProtoMessage() {}
+func (*MetricFamily) Descriptor() ([]byte, []int) {
+ return fileDescriptor_metrics_c97c9a2b9560cb8f, []int{9}
+}
+func (m *MetricFamily) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_MetricFamily.Unmarshal(m, b)
+}
+func (m *MetricFamily) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_MetricFamily.Marshal(b, m, deterministic)
+}
+func (dst *MetricFamily) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_MetricFamily.Merge(dst, src)
+}
+func (m *MetricFamily) XXX_Size() int {
+ return xxx_messageInfo_MetricFamily.Size(m)
+}
+func (m *MetricFamily) XXX_DiscardUnknown() {
+ xxx_messageInfo_MetricFamily.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_MetricFamily proto.InternalMessageInfo
+
+func (m *MetricFamily) GetName() string {
+ if m != nil && m.Name != nil {
+ return *m.Name
+ }
+ return ""
+}
+
+func (m *MetricFamily) GetHelp() string {
+ if m != nil && m.Help != nil {
+ return *m.Help
+ }
+ return ""
+}
+
+func (m *MetricFamily) GetType() MetricType {
+ if m != nil && m.Type != nil {
+ return *m.Type
+ }
+ return MetricType_COUNTER
+}
+
+func (m *MetricFamily) GetMetric() []*Metric {
+ if m != nil {
+ return m.Metric
+ }
+ return nil
+}
+
+func init() {
+ proto.RegisterType((*LabelPair)(nil), "io.prometheus.client.LabelPair")
+ proto.RegisterType((*Gauge)(nil), "io.prometheus.client.Gauge")
+ proto.RegisterType((*Counter)(nil), "io.prometheus.client.Counter")
+ proto.RegisterType((*Quantile)(nil), "io.prometheus.client.Quantile")
+ proto.RegisterType((*Summary)(nil), "io.prometheus.client.Summary")
+ proto.RegisterType((*Untyped)(nil), "io.prometheus.client.Untyped")
+ proto.RegisterType((*Histogram)(nil), "io.prometheus.client.Histogram")
+ proto.RegisterType((*Bucket)(nil), "io.prometheus.client.Bucket")
+ proto.RegisterType((*Metric)(nil), "io.prometheus.client.Metric")
+ proto.RegisterType((*MetricFamily)(nil), "io.prometheus.client.MetricFamily")
+ proto.RegisterEnum("io.prometheus.client.MetricType", MetricType_name, MetricType_value)
+}
+
+func init() { proto.RegisterFile("metrics.proto", fileDescriptor_metrics_c97c9a2b9560cb8f) }
+
+var fileDescriptor_metrics_c97c9a2b9560cb8f = []byte{
+ // 591 bytes of a gzipped FileDescriptorProto
+ 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x54, 0x4f, 0x4f, 0xdb, 0x4e,
+ 0x14, 0xfc, 0x99, 0xd8, 0x09, 0x7e, 0x86, 0x5f, 0xad, 0x15, 0x07, 0xab, 0x2d, 0x25, 0xcd, 0x89,
+ 0xf6, 0x10, 0x54, 0x04, 0xaa, 0x44, 0xdb, 0x03, 0x50, 0x1a, 0x2a, 0xd5, 0x40, 0x37, 0xc9, 0x81,
+ 0x5e, 0xac, 0x8d, 0x59, 0x25, 0x56, 0xbd, 0xb6, 0x6b, 0xef, 0x22, 0xe5, 0xdc, 0x43, 0xbf, 0x47,
+ 0xbf, 0x68, 0xab, 0xfd, 0xe3, 0x18, 0x24, 0xc3, 0xa9, 0xb7, 0xb7, 0xf3, 0x66, 0xde, 0x8e, 0x77,
+ 0xc7, 0x0b, 0x9b, 0x8c, 0xf2, 0x32, 0x89, 0xab, 0x61, 0x51, 0xe6, 0x3c, 0x47, 0x5b, 0x49, 0x2e,
+ 0x2b, 0x46, 0xf9, 0x82, 0x8a, 0x6a, 0x18, 0xa7, 0x09, 0xcd, 0xf8, 0xe0, 0x10, 0xdc, 0x2f, 0x64,
+ 0x46, 0xd3, 0x2b, 0x92, 0x94, 0x08, 0x81, 0x9d, 0x11, 0x46, 0x03, 0xab, 0x6f, 0xed, 0xba, 0x58,
+ 0xd5, 0x68, 0x0b, 0x9c, 0x5b, 0x92, 0x0a, 0x1a, 0xac, 0x29, 0x50, 0x2f, 0x06, 0xdb, 0xe0, 0x8c,
+ 0x88, 0x98, 0xdf, 0x69, 0x4b, 0x8d, 0x55, 0xb7, 0x77, 0xa0, 0x77, 0x9a, 0x8b, 0x8c, 0xd3, 0xf2,
+ 0x01, 0xc2, 0x7b, 0x58, 0xff, 0x2a, 0x48, 0xc6, 0x93, 0x94, 0xa2, 0xa7, 0xb0, 0xfe, 0xc3, 0xd4,
+ 0x86, 0xb4, 0x5a, 0xdf, 0xdf, 0x7d, 0xa5, 0xfe, 0x65, 0x41, 0x6f, 0x2c, 0x18, 0x23, 0xe5, 0x12,
+ 0xbd, 0x84, 0x8d, 0x8a, 0xb0, 0x22, 0xa5, 0x51, 0x2c, 0x77, 0x54, 0x13, 0x6c, 0xec, 0x69, 0x4c,
+ 0x99, 0x40, 0xdb, 0x00, 0x86, 0x52, 0x09, 0x66, 0x26, 0xb9, 0x1a, 0x19, 0x0b, 0x86, 0x8e, 0xee,
+ 0xec, 0xdf, 0xe9, 0x77, 0x76, 0xbd, 0xfd, 0x17, 0xc3, 0xb6, 0xb3, 0x1a, 0xd6, 0x8e, 0x1b, 0x7f,
+ 0xf2, 0x43, 0xa7, 0x19, 0x5f, 0x16, 0xf4, 0xe6, 0x81, 0x0f, 0xfd, 0x69, 0x81, 0x7b, 0x9e, 0x54,
+ 0x3c, 0x9f, 0x97, 0x84, 0xfd, 0x03, 0xb3, 0x07, 0xd0, 0x9d, 0x89, 0xf8, 0x3b, 0xe5, 0xc6, 0xea,
+ 0xf3, 0x76, 0xab, 0x27, 0x8a, 0x83, 0x0d, 0x77, 0x30, 0x81, 0xae, 0x46, 0xd0, 0x2b, 0xf0, 0x63,
+ 0xc1, 0x44, 0x4a, 0x78, 0x72, 0x7b, 0xdf, 0xc5, 0x93, 0x06, 0xd7, 0x4e, 0x76, 0xc0, 0x13, 0x45,
+ 0x41, 0xcb, 0x68, 0x96, 0x8b, 0xec, 0xc6, 0x58, 0x01, 0x05, 0x9d, 0x48, 0x64, 0xf0, 0x67, 0x0d,
+ 0xba, 0xa1, 0xca, 0x18, 0x3a, 0x04, 0x27, 0x95, 0x31, 0x0a, 0x2c, 0xe5, 0x6a, 0xa7, 0xdd, 0xd5,
+ 0x2a, 0x69, 0x58, 0xb3, 0xd1, 0x1b, 0x70, 0xe6, 0x32, 0x46, 0x6a, 0xb8, 0xb7, 0xff, 0xac, 0x5d,
+ 0xa6, 0x92, 0x86, 0x35, 0x13, 0xbd, 0x85, 0x5e, 0xac, 0xa3, 0x15, 0x74, 0x94, 0x68, 0xbb, 0x5d,
+ 0x64, 0xf2, 0x87, 0x6b, 0xb6, 0x14, 0x56, 0x3a, 0x33, 0x81, 0xfd, 0x98, 0xd0, 0x04, 0x0b, 0xd7,
+ 0x6c, 0x29, 0x14, 0xfa, 0x8e, 0x03, 0xe7, 0x31, 0xa1, 0x09, 0x02, 0xae, 0xd9, 0xe8, 0x03, 0xb8,
+ 0x8b, 0xfa, 0xea, 0x83, 0x9e, 0x92, 0x3e, 0x70, 0x30, 0xab, 0x84, 0xe0, 0x46, 0x21, 0xc3, 0xc2,
+ 0x13, 0x46, 0x2b, 0x4e, 0x58, 0x11, 0xb1, 0x2a, 0xe8, 0xf6, 0xad, 0xdd, 0x0e, 0xf6, 0x56, 0x58,
+ 0x58, 0x0d, 0x7e, 0x5b, 0xb0, 0xa1, 0x6f, 0xe0, 0x13, 0x61, 0x49, 0xba, 0x6c, 0xfd, 0x83, 0x11,
+ 0xd8, 0x0b, 0x9a, 0x16, 0xe6, 0x07, 0x56, 0x35, 0x3a, 0x00, 0x5b, 0x7a, 0x54, 0x47, 0xf8, 0xff,
+ 0x7e, 0xbf, 0xdd, 0x95, 0x9e, 0x3c, 0x59, 0x16, 0x14, 0x2b, 0xb6, 0x0c, 0x9f, 0x7e, 0x53, 0x02,
+ 0xfb, 0xb1, 0xf0, 0x69, 0x1d, 0x36, 0xdc, 0xd7, 0x21, 0x40, 0x33, 0x09, 0x79, 0xd0, 0x3b, 0xbd,
+ 0x9c, 0x5e, 0x4c, 0xce, 0xb0, 0xff, 0x1f, 0x72, 0xc1, 0x19, 0x1d, 0x4f, 0x47, 0x67, 0xbe, 0x25,
+ 0xf1, 0xf1, 0x34, 0x0c, 0x8f, 0xf1, 0xb5, 0xbf, 0x26, 0x17, 0xd3, 0x8b, 0xc9, 0xf5, 0xd5, 0xd9,
+ 0x47, 0xbf, 0x83, 0x36, 0xc1, 0x3d, 0xff, 0x3c, 0x9e, 0x5c, 0x8e, 0xf0, 0x71, 0xe8, 0xdb, 0x27,
+ 0x18, 0x5a, 0x5f, 0xb2, 0x6f, 0x47, 0xf3, 0x84, 0x2f, 0xc4, 0x6c, 0x18, 0xe7, 0x6c, 0xaf, 0xe9,
+ 0xee, 0xe9, 0x6e, 0xc4, 0xf2, 0x1b, 0x9a, 0xee, 0xcd, 0xf3, 0x77, 0x49, 0x1e, 0x35, 0xdd, 0x48,
+ 0x77, 0xff, 0x06, 0x00, 0x00, 0xff, 0xff, 0x45, 0x21, 0x7f, 0x64, 0x2b, 0x05, 0x00, 0x00,
+}
diff --git a/vendor/github.com/prometheus/common/LICENSE b/vendor/github.com/prometheus/common/LICENSE
new file mode 100644
index 0000000..261eeb9
--- /dev/null
+++ b/vendor/github.com/prometheus/common/LICENSE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/vendor/github.com/prometheus/common/NOTICE b/vendor/github.com/prometheus/common/NOTICE
new file mode 100644
index 0000000..636a2c1
--- /dev/null
+++ b/vendor/github.com/prometheus/common/NOTICE
@@ -0,0 +1,5 @@
+Common libraries shared by Prometheus Go components.
+Copyright 2015 The Prometheus Authors
+
+This product includes software developed at
+SoundCloud Ltd. (http://soundcloud.com/).
diff --git a/vendor/github.com/prometheus/common/expfmt/decode.go b/vendor/github.com/prometheus/common/expfmt/decode.go
new file mode 100644
index 0000000..c092723
--- /dev/null
+++ b/vendor/github.com/prometheus/common/expfmt/decode.go
@@ -0,0 +1,429 @@
+// Copyright 2015 The Prometheus Authors
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package expfmt
+
+import (
+ "fmt"
+ "io"
+ "math"
+ "mime"
+ "net/http"
+
+ dto "github.com/prometheus/client_model/go"
+
+ "github.com/matttproud/golang_protobuf_extensions/pbutil"
+ "github.com/prometheus/common/model"
+)
+
+// Decoder types decode an input stream into metric families.
+type Decoder interface {
+ Decode(*dto.MetricFamily) error
+}
+
+// DecodeOptions contains options used by the Decoder and in sample extraction.
+type DecodeOptions struct {
+ // Timestamp is added to each value from the stream that has no explicit timestamp set.
+ Timestamp model.Time
+}
+
+// ResponseFormat extracts the correct format from a HTTP response header.
+// If no matching format can be found FormatUnknown is returned.
+func ResponseFormat(h http.Header) Format {
+ ct := h.Get(hdrContentType)
+
+ mediatype, params, err := mime.ParseMediaType(ct)
+ if err != nil {
+ return FmtUnknown
+ }
+
+ const textType = "text/plain"
+
+ switch mediatype {
+ case ProtoType:
+ if p, ok := params["proto"]; ok && p != ProtoProtocol {
+ return FmtUnknown
+ }
+ if e, ok := params["encoding"]; ok && e != "delimited" {
+ return FmtUnknown
+ }
+ return FmtProtoDelim
+
+ case textType:
+ if v, ok := params["version"]; ok && v != TextVersion {
+ return FmtUnknown
+ }
+ return FmtText
+ }
+
+ return FmtUnknown
+}
+
+// NewDecoder returns a new decoder based on the given input format.
+// If the input format does not imply otherwise, a text format decoder is returned.
+func NewDecoder(r io.Reader, format Format) Decoder {
+ switch format {
+ case FmtProtoDelim:
+ return &protoDecoder{r: r}
+ }
+ return &textDecoder{r: r}
+}
+
+// protoDecoder implements the Decoder interface for protocol buffers.
+type protoDecoder struct {
+ r io.Reader
+}
+
+// Decode implements the Decoder interface.
+func (d *protoDecoder) Decode(v *dto.MetricFamily) error {
+ _, err := pbutil.ReadDelimited(d.r, v)
+ if err != nil {
+ return err
+ }
+ if !model.IsValidMetricName(model.LabelValue(v.GetName())) {
+ return fmt.Errorf("invalid metric name %q", v.GetName())
+ }
+ for _, m := range v.GetMetric() {
+ if m == nil {
+ continue
+ }
+ for _, l := range m.GetLabel() {
+ if l == nil {
+ continue
+ }
+ if !model.LabelValue(l.GetValue()).IsValid() {
+ return fmt.Errorf("invalid label value %q", l.GetValue())
+ }
+ if !model.LabelName(l.GetName()).IsValid() {
+ return fmt.Errorf("invalid label name %q", l.GetName())
+ }
+ }
+ }
+ return nil
+}
+
+// textDecoder implements the Decoder interface for the text protocol.
+type textDecoder struct {
+ r io.Reader
+ p TextParser
+ fams []*dto.MetricFamily
+}
+
+// Decode implements the Decoder interface.
+func (d *textDecoder) Decode(v *dto.MetricFamily) error {
+ // TODO(fabxc): Wrap this as a line reader to make streaming safer.
+ if len(d.fams) == 0 {
+ // No cached metric families, read everything and parse metrics.
+ fams, err := d.p.TextToMetricFamilies(d.r)
+ if err != nil {
+ return err
+ }
+ if len(fams) == 0 {
+ return io.EOF
+ }
+ d.fams = make([]*dto.MetricFamily, 0, len(fams))
+ for _, f := range fams {
+ d.fams = append(d.fams, f)
+ }
+ }
+
+ *v = *d.fams[0]
+ d.fams = d.fams[1:]
+
+ return nil
+}
+
+// SampleDecoder wraps a Decoder to extract samples from the metric families
+// decoded by the wrapped Decoder.
+type SampleDecoder struct {
+ Dec Decoder
+ Opts *DecodeOptions
+
+ f dto.MetricFamily
+}
+
+// Decode calls the Decode method of the wrapped Decoder and then extracts the
+// samples from the decoded MetricFamily into the provided model.Vector.
+func (sd *SampleDecoder) Decode(s *model.Vector) error {
+ err := sd.Dec.Decode(&sd.f)
+ if err != nil {
+ return err
+ }
+ *s, err = extractSamples(&sd.f, sd.Opts)
+ return err
+}
+
+// ExtractSamples builds a slice of samples from the provided metric
+// families. If an error occurrs during sample extraction, it continues to
+// extract from the remaining metric families. The returned error is the last
+// error that has occurred.
+func ExtractSamples(o *DecodeOptions, fams ...*dto.MetricFamily) (model.Vector, error) {
+ var (
+ all model.Vector
+ lastErr error
+ )
+ for _, f := range fams {
+ some, err := extractSamples(f, o)
+ if err != nil {
+ lastErr = err
+ continue
+ }
+ all = append(all, some...)
+ }
+ return all, lastErr
+}
+
+func extractSamples(f *dto.MetricFamily, o *DecodeOptions) (model.Vector, error) {
+ switch f.GetType() {
+ case dto.MetricType_COUNTER:
+ return extractCounter(o, f), nil
+ case dto.MetricType_GAUGE:
+ return extractGauge(o, f), nil
+ case dto.MetricType_SUMMARY:
+ return extractSummary(o, f), nil
+ case dto.MetricType_UNTYPED:
+ return extractUntyped(o, f), nil
+ case dto.MetricType_HISTOGRAM:
+ return extractHistogram(o, f), nil
+ }
+ return nil, fmt.Errorf("expfmt.extractSamples: unknown metric family type %v", f.GetType())
+}
+
+func extractCounter(o *DecodeOptions, f *dto.MetricFamily) model.Vector {
+ samples := make(model.Vector, 0, len(f.Metric))
+
+ for _, m := range f.Metric {
+ if m.Counter == nil {
+ continue
+ }
+
+ lset := make(model.LabelSet, len(m.Label)+1)
+ for _, p := range m.Label {
+ lset[model.LabelName(p.GetName())] = model.LabelValue(p.GetValue())
+ }
+ lset[model.MetricNameLabel] = model.LabelValue(f.GetName())
+
+ smpl := &model.Sample{
+ Metric: model.Metric(lset),
+ Value: model.SampleValue(m.Counter.GetValue()),
+ }
+
+ if m.TimestampMs != nil {
+ smpl.Timestamp = model.TimeFromUnixNano(*m.TimestampMs * 1000000)
+ } else {
+ smpl.Timestamp = o.Timestamp
+ }
+
+ samples = append(samples, smpl)
+ }
+
+ return samples
+}
+
+func extractGauge(o *DecodeOptions, f *dto.MetricFamily) model.Vector {
+ samples := make(model.Vector, 0, len(f.Metric))
+
+ for _, m := range f.Metric {
+ if m.Gauge == nil {
+ continue
+ }
+
+ lset := make(model.LabelSet, len(m.Label)+1)
+ for _, p := range m.Label {
+ lset[model.LabelName(p.GetName())] = model.LabelValue(p.GetValue())
+ }
+ lset[model.MetricNameLabel] = model.LabelValue(f.GetName())
+
+ smpl := &model.Sample{
+ Metric: model.Metric(lset),
+ Value: model.SampleValue(m.Gauge.GetValue()),
+ }
+
+ if m.TimestampMs != nil {
+ smpl.Timestamp = model.TimeFromUnixNano(*m.TimestampMs * 1000000)
+ } else {
+ smpl.Timestamp = o.Timestamp
+ }
+
+ samples = append(samples, smpl)
+ }
+
+ return samples
+}
+
+func extractUntyped(o *DecodeOptions, f *dto.MetricFamily) model.Vector {
+ samples := make(model.Vector, 0, len(f.Metric))
+
+ for _, m := range f.Metric {
+ if m.Untyped == nil {
+ continue
+ }
+
+ lset := make(model.LabelSet, len(m.Label)+1)
+ for _, p := range m.Label {
+ lset[model.LabelName(p.GetName())] = model.LabelValue(p.GetValue())
+ }
+ lset[model.MetricNameLabel] = model.LabelValue(f.GetName())
+
+ smpl := &model.Sample{
+ Metric: model.Metric(lset),
+ Value: model.SampleValue(m.Untyped.GetValue()),
+ }
+
+ if m.TimestampMs != nil {
+ smpl.Timestamp = model.TimeFromUnixNano(*m.TimestampMs * 1000000)
+ } else {
+ smpl.Timestamp = o.Timestamp
+ }
+
+ samples = append(samples, smpl)
+ }
+
+ return samples
+}
+
+func extractSummary(o *DecodeOptions, f *dto.MetricFamily) model.Vector {
+ samples := make(model.Vector, 0, len(f.Metric))
+
+ for _, m := range f.Metric {
+ if m.Summary == nil {
+ continue
+ }
+
+ timestamp := o.Timestamp
+ if m.TimestampMs != nil {
+ timestamp = model.TimeFromUnixNano(*m.TimestampMs * 1000000)
+ }
+
+ for _, q := range m.Summary.Quantile {
+ lset := make(model.LabelSet, len(m.Label)+2)
+ for _, p := range m.Label {
+ lset[model.LabelName(p.GetName())] = model.LabelValue(p.GetValue())
+ }
+ // BUG(matt): Update other names to "quantile".
+ lset[model.LabelName(model.QuantileLabel)] = model.LabelValue(fmt.Sprint(q.GetQuantile()))
+ lset[model.MetricNameLabel] = model.LabelValue(f.GetName())
+
+ samples = append(samples, &model.Sample{
+ Metric: model.Metric(lset),
+ Value: model.SampleValue(q.GetValue()),
+ Timestamp: timestamp,
+ })
+ }
+
+ lset := make(model.LabelSet, len(m.Label)+1)
+ for _, p := range m.Label {
+ lset[model.LabelName(p.GetName())] = model.LabelValue(p.GetValue())
+ }
+ lset[model.MetricNameLabel] = model.LabelValue(f.GetName() + "_sum")
+
+ samples = append(samples, &model.Sample{
+ Metric: model.Metric(lset),
+ Value: model.SampleValue(m.Summary.GetSampleSum()),
+ Timestamp: timestamp,
+ })
+
+ lset = make(model.LabelSet, len(m.Label)+1)
+ for _, p := range m.Label {
+ lset[model.LabelName(p.GetName())] = model.LabelValue(p.GetValue())
+ }
+ lset[model.MetricNameLabel] = model.LabelValue(f.GetName() + "_count")
+
+ samples = append(samples, &model.Sample{
+ Metric: model.Metric(lset),
+ Value: model.SampleValue(m.Summary.GetSampleCount()),
+ Timestamp: timestamp,
+ })
+ }
+
+ return samples
+}
+
+func extractHistogram(o *DecodeOptions, f *dto.MetricFamily) model.Vector {
+ samples := make(model.Vector, 0, len(f.Metric))
+
+ for _, m := range f.Metric {
+ if m.Histogram == nil {
+ continue
+ }
+
+ timestamp := o.Timestamp
+ if m.TimestampMs != nil {
+ timestamp = model.TimeFromUnixNano(*m.TimestampMs * 1000000)
+ }
+
+ infSeen := false
+
+ for _, q := range m.Histogram.Bucket {
+ lset := make(model.LabelSet, len(m.Label)+2)
+ for _, p := range m.Label {
+ lset[model.LabelName(p.GetName())] = model.LabelValue(p.GetValue())
+ }
+ lset[model.LabelName(model.BucketLabel)] = model.LabelValue(fmt.Sprint(q.GetUpperBound()))
+ lset[model.MetricNameLabel] = model.LabelValue(f.GetName() + "_bucket")
+
+ if math.IsInf(q.GetUpperBound(), +1) {
+ infSeen = true
+ }
+
+ samples = append(samples, &model.Sample{
+ Metric: model.Metric(lset),
+ Value: model.SampleValue(q.GetCumulativeCount()),
+ Timestamp: timestamp,
+ })
+ }
+
+ lset := make(model.LabelSet, len(m.Label)+1)
+ for _, p := range m.Label {
+ lset[model.LabelName(p.GetName())] = model.LabelValue(p.GetValue())
+ }
+ lset[model.MetricNameLabel] = model.LabelValue(f.GetName() + "_sum")
+
+ samples = append(samples, &model.Sample{
+ Metric: model.Metric(lset),
+ Value: model.SampleValue(m.Histogram.GetSampleSum()),
+ Timestamp: timestamp,
+ })
+
+ lset = make(model.LabelSet, len(m.Label)+1)
+ for _, p := range m.Label {
+ lset[model.LabelName(p.GetName())] = model.LabelValue(p.GetValue())
+ }
+ lset[model.MetricNameLabel] = model.LabelValue(f.GetName() + "_count")
+
+ count := &model.Sample{
+ Metric: model.Metric(lset),
+ Value: model.SampleValue(m.Histogram.GetSampleCount()),
+ Timestamp: timestamp,
+ }
+ samples = append(samples, count)
+
+ if !infSeen {
+ // Append an infinity bucket sample.
+ lset := make(model.LabelSet, len(m.Label)+2)
+ for _, p := range m.Label {
+ lset[model.LabelName(p.GetName())] = model.LabelValue(p.GetValue())
+ }
+ lset[model.LabelName(model.BucketLabel)] = model.LabelValue("+Inf")
+ lset[model.MetricNameLabel] = model.LabelValue(f.GetName() + "_bucket")
+
+ samples = append(samples, &model.Sample{
+ Metric: model.Metric(lset),
+ Value: count.Value,
+ Timestamp: timestamp,
+ })
+ }
+ }
+
+ return samples
+}
diff --git a/vendor/github.com/prometheus/common/expfmt/encode.go b/vendor/github.com/prometheus/common/expfmt/encode.go
new file mode 100644
index 0000000..11839ed
--- /dev/null
+++ b/vendor/github.com/prometheus/common/expfmt/encode.go
@@ -0,0 +1,88 @@
+// Copyright 2015 The Prometheus Authors
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package expfmt
+
+import (
+ "fmt"
+ "io"
+ "net/http"
+
+ "github.com/golang/protobuf/proto"
+ "github.com/matttproud/golang_protobuf_extensions/pbutil"
+ "github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg"
+
+ dto "github.com/prometheus/client_model/go"
+)
+
+// Encoder types encode metric families into an underlying wire protocol.
+type Encoder interface {
+ Encode(*dto.MetricFamily) error
+}
+
+type encoder func(*dto.MetricFamily) error
+
+func (e encoder) Encode(v *dto.MetricFamily) error {
+ return e(v)
+}
+
+// Negotiate returns the Content-Type based on the given Accept header.
+// If no appropriate accepted type is found, FmtText is returned.
+func Negotiate(h http.Header) Format {
+ for _, ac := range goautoneg.ParseAccept(h.Get(hdrAccept)) {
+ // Check for protocol buffer
+ if ac.Type+"/"+ac.SubType == ProtoType && ac.Params["proto"] == ProtoProtocol {
+ switch ac.Params["encoding"] {
+ case "delimited":
+ return FmtProtoDelim
+ case "text":
+ return FmtProtoText
+ case "compact-text":
+ return FmtProtoCompact
+ }
+ }
+ // Check for text format.
+ ver := ac.Params["version"]
+ if ac.Type == "text" && ac.SubType == "plain" && (ver == TextVersion || ver == "") {
+ return FmtText
+ }
+ }
+ return FmtText
+}
+
+// NewEncoder returns a new encoder based on content type negotiation.
+func NewEncoder(w io.Writer, format Format) Encoder {
+ switch format {
+ case FmtProtoDelim:
+ return encoder(func(v *dto.MetricFamily) error {
+ _, err := pbutil.WriteDelimited(w, v)
+ return err
+ })
+ case FmtProtoCompact:
+ return encoder(func(v *dto.MetricFamily) error {
+ _, err := fmt.Fprintln(w, v.String())
+ return err
+ })
+ case FmtProtoText:
+ return encoder(func(v *dto.MetricFamily) error {
+ _, err := fmt.Fprintln(w, proto.MarshalTextString(v))
+ return err
+ })
+ case FmtText:
+ return encoder(func(v *dto.MetricFamily) error {
+ _, err := MetricFamilyToText(w, v)
+ return err
+ })
+ }
+ panic("expfmt.NewEncoder: unknown format")
+}
diff --git a/vendor/github.com/prometheus/common/expfmt/expfmt.go b/vendor/github.com/prometheus/common/expfmt/expfmt.go
new file mode 100644
index 0000000..c71bcb9
--- /dev/null
+++ b/vendor/github.com/prometheus/common/expfmt/expfmt.go
@@ -0,0 +1,38 @@
+// Copyright 2015 The Prometheus Authors
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Package expfmt contains tools for reading and writing Prometheus metrics.
+package expfmt
+
+// Format specifies the HTTP content type of the different wire protocols.
+type Format string
+
+// Constants to assemble the Content-Type values for the different wire protocols.
+const (
+ TextVersion = "0.0.4"
+ ProtoType = `application/vnd.google.protobuf`
+ ProtoProtocol = `io.prometheus.client.MetricFamily`
+ ProtoFmt = ProtoType + "; proto=" + ProtoProtocol + ";"
+
+ // The Content-Type values for the different wire protocols.
+ FmtUnknown Format = ``
+ FmtText Format = `text/plain; version=` + TextVersion + `; charset=utf-8`
+ FmtProtoDelim Format = ProtoFmt + ` encoding=delimited`
+ FmtProtoText Format = ProtoFmt + ` encoding=text`
+ FmtProtoCompact Format = ProtoFmt + ` encoding=compact-text`
+)
+
+const (
+ hdrContentType = "Content-Type"
+ hdrAccept = "Accept"
+)
diff --git a/vendor/github.com/prometheus/common/expfmt/fuzz.go b/vendor/github.com/prometheus/common/expfmt/fuzz.go
new file mode 100644
index 0000000..dc2eede
--- /dev/null
+++ b/vendor/github.com/prometheus/common/expfmt/fuzz.go
@@ -0,0 +1,36 @@
+// Copyright 2014 The Prometheus Authors
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Build only when actually fuzzing
+// +build gofuzz
+
+package expfmt
+
+import "bytes"
+
+// Fuzz text metric parser with with github.com/dvyukov/go-fuzz:
+//
+// go-fuzz-build github.com/prometheus/common/expfmt
+// go-fuzz -bin expfmt-fuzz.zip -workdir fuzz
+//
+// Further input samples should go in the folder fuzz/corpus.
+func Fuzz(in []byte) int {
+ parser := TextParser{}
+ _, err := parser.TextToMetricFamilies(bytes.NewReader(in))
+
+ if err != nil {
+ return 0
+ }
+
+ return 1
+}
diff --git a/vendor/github.com/prometheus/common/expfmt/text_create.go b/vendor/github.com/prometheus/common/expfmt/text_create.go
new file mode 100644
index 0000000..8e473d0
--- /dev/null
+++ b/vendor/github.com/prometheus/common/expfmt/text_create.go
@@ -0,0 +1,468 @@
+// Copyright 2014 The Prometheus Authors
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package expfmt
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "math"
+ "strconv"
+ "strings"
+ "sync"
+
+ "github.com/prometheus/common/model"
+
+ dto "github.com/prometheus/client_model/go"
+)
+
+// enhancedWriter has all the enhanced write functions needed here. bytes.Buffer
+// implements it.
+type enhancedWriter interface {
+ io.Writer
+ WriteRune(r rune) (n int, err error)
+ WriteString(s string) (n int, err error)
+ WriteByte(c byte) error
+}
+
+const (
+ initialBufSize = 512
+ initialNumBufSize = 24
+)
+
+var (
+ bufPool = sync.Pool{
+ New: func() interface{} {
+ return bytes.NewBuffer(make([]byte, 0, initialBufSize))
+ },
+ }
+ numBufPool = sync.Pool{
+ New: func() interface{} {
+ b := make([]byte, 0, initialNumBufSize)
+ return &b
+ },
+ }
+)
+
+// MetricFamilyToText converts a MetricFamily proto message into text format and
+// writes the resulting lines to 'out'. It returns the number of bytes written
+// and any error encountered. The output will have the same order as the input,
+// no further sorting is performed. Furthermore, this function assumes the input
+// is already sanitized and does not perform any sanity checks. If the input
+// contains duplicate metrics or invalid metric or label names, the conversion
+// will result in invalid text format output.
+//
+// This method fulfills the type 'prometheus.encoder'.
+func MetricFamilyToText(out io.Writer, in *dto.MetricFamily) (written int, err error) {
+ // Fail-fast checks.
+ if len(in.Metric) == 0 {
+ return 0, fmt.Errorf("MetricFamily has no metrics: %s", in)
+ }
+ name := in.GetName()
+ if name == "" {
+ return 0, fmt.Errorf("MetricFamily has no name: %s", in)
+ }
+
+ // Try the interface upgrade. If it doesn't work, we'll use a
+ // bytes.Buffer from the sync.Pool and write out its content to out in a
+ // single go in the end.
+ w, ok := out.(enhancedWriter)
+ if !ok {
+ b := bufPool.Get().(*bytes.Buffer)
+ b.Reset()
+ w = b
+ defer func() {
+ bWritten, bErr := out.Write(b.Bytes())
+ written = bWritten
+ if err == nil {
+ err = bErr
+ }
+ bufPool.Put(b)
+ }()
+ }
+
+ var n int
+
+ // Comments, first HELP, then TYPE.
+ if in.Help != nil {
+ n, err = w.WriteString("# HELP ")
+ written += n
+ if err != nil {
+ return
+ }
+ n, err = w.WriteString(name)
+ written += n
+ if err != nil {
+ return
+ }
+ err = w.WriteByte(' ')
+ written++
+ if err != nil {
+ return
+ }
+ n, err = writeEscapedString(w, *in.Help, false)
+ written += n
+ if err != nil {
+ return
+ }
+ err = w.WriteByte('\n')
+ written++
+ if err != nil {
+ return
+ }
+ }
+ n, err = w.WriteString("# TYPE ")
+ written += n
+ if err != nil {
+ return
+ }
+ n, err = w.WriteString(name)
+ written += n
+ if err != nil {
+ return
+ }
+ metricType := in.GetType()
+ switch metricType {
+ case dto.MetricType_COUNTER:
+ n, err = w.WriteString(" counter\n")
+ case dto.MetricType_GAUGE:
+ n, err = w.WriteString(" gauge\n")
+ case dto.MetricType_SUMMARY:
+ n, err = w.WriteString(" summary\n")
+ case dto.MetricType_UNTYPED:
+ n, err = w.WriteString(" untyped\n")
+ case dto.MetricType_HISTOGRAM:
+ n, err = w.WriteString(" histogram\n")
+ default:
+ return written, fmt.Errorf("unknown metric type %s", metricType.String())
+ }
+ written += n
+ if err != nil {
+ return
+ }
+
+ // Finally the samples, one line for each.
+ for _, metric := range in.Metric {
+ switch metricType {
+ case dto.MetricType_COUNTER:
+ if metric.Counter == nil {
+ return written, fmt.Errorf(
+ "expected counter in metric %s %s", name, metric,
+ )
+ }
+ n, err = writeSample(
+ w, name, "", metric, "", 0,
+ metric.Counter.GetValue(),
+ )
+ case dto.MetricType_GAUGE:
+ if metric.Gauge == nil {
+ return written, fmt.Errorf(
+ "expected gauge in metric %s %s", name, metric,
+ )
+ }
+ n, err = writeSample(
+ w, name, "", metric, "", 0,
+ metric.Gauge.GetValue(),
+ )
+ case dto.MetricType_UNTYPED:
+ if metric.Untyped == nil {
+ return written, fmt.Errorf(
+ "expected untyped in metric %s %s", name, metric,
+ )
+ }
+ n, err = writeSample(
+ w, name, "", metric, "", 0,
+ metric.Untyped.GetValue(),
+ )
+ case dto.MetricType_SUMMARY:
+ if metric.Summary == nil {
+ return written, fmt.Errorf(
+ "expected summary in metric %s %s", name, metric,
+ )
+ }
+ for _, q := range metric.Summary.Quantile {
+ n, err = writeSample(
+ w, name, "", metric,
+ model.QuantileLabel, q.GetQuantile(),
+ q.GetValue(),
+ )
+ written += n
+ if err != nil {
+ return
+ }
+ }
+ n, err = writeSample(
+ w, name, "_sum", metric, "", 0,
+ metric.Summary.GetSampleSum(),
+ )
+ written += n
+ if err != nil {
+ return
+ }
+ n, err = writeSample(
+ w, name, "_count", metric, "", 0,
+ float64(metric.Summary.GetSampleCount()),
+ )
+ case dto.MetricType_HISTOGRAM:
+ if metric.Histogram == nil {
+ return written, fmt.Errorf(
+ "expected histogram in metric %s %s", name, metric,
+ )
+ }
+ infSeen := false
+ for _, b := range metric.Histogram.Bucket {
+ n, err = writeSample(
+ w, name, "_bucket", metric,
+ model.BucketLabel, b.GetUpperBound(),
+ float64(b.GetCumulativeCount()),
+ )
+ written += n
+ if err != nil {
+ return
+ }
+ if math.IsInf(b.GetUpperBound(), +1) {
+ infSeen = true
+ }
+ }
+ if !infSeen {
+ n, err = writeSample(
+ w, name, "_bucket", metric,
+ model.BucketLabel, math.Inf(+1),
+ float64(metric.Histogram.GetSampleCount()),
+ )
+ written += n
+ if err != nil {
+ return
+ }
+ }
+ n, err = writeSample(
+ w, name, "_sum", metric, "", 0,
+ metric.Histogram.GetSampleSum(),
+ )
+ written += n
+ if err != nil {
+ return
+ }
+ n, err = writeSample(
+ w, name, "_count", metric, "", 0,
+ float64(metric.Histogram.GetSampleCount()),
+ )
+ default:
+ return written, fmt.Errorf(
+ "unexpected type in metric %s %s", name, metric,
+ )
+ }
+ written += n
+ if err != nil {
+ return
+ }
+ }
+ return
+}
+
+// writeSample writes a single sample in text format to w, given the metric
+// name, the metric proto message itself, optionally an additional label name
+// with a float64 value (use empty string as label name if not required), and
+// the value. The function returns the number of bytes written and any error
+// encountered.
+func writeSample(
+ w enhancedWriter,
+ name, suffix string,
+ metric *dto.Metric,
+ additionalLabelName string, additionalLabelValue float64,
+ value float64,
+) (int, error) {
+ var written int
+ n, err := w.WriteString(name)
+ written += n
+ if err != nil {
+ return written, err
+ }
+ if suffix != "" {
+ n, err = w.WriteString(suffix)
+ written += n
+ if err != nil {
+ return written, err
+ }
+ }
+ n, err = writeLabelPairs(
+ w, metric.Label, additionalLabelName, additionalLabelValue,
+ )
+ written += n
+ if err != nil {
+ return written, err
+ }
+ err = w.WriteByte(' ')
+ written++
+ if err != nil {
+ return written, err
+ }
+ n, err = writeFloat(w, value)
+ written += n
+ if err != nil {
+ return written, err
+ }
+ if metric.TimestampMs != nil {
+ err = w.WriteByte(' ')
+ written++
+ if err != nil {
+ return written, err
+ }
+ n, err = writeInt(w, *metric.TimestampMs)
+ written += n
+ if err != nil {
+ return written, err
+ }
+ }
+ err = w.WriteByte('\n')
+ written++
+ if err != nil {
+ return written, err
+ }
+ return written, nil
+}
+
+// writeLabelPairs converts a slice of LabelPair proto messages plus the
+// explicitly given additional label pair into text formatted as required by the
+// text format and writes it to 'w'. An empty slice in combination with an empty
+// string 'additionalLabelName' results in nothing being written. Otherwise, the
+// label pairs are written, escaped as required by the text format, and enclosed
+// in '{...}'. The function returns the number of bytes written and any error
+// encountered.
+func writeLabelPairs(
+ w enhancedWriter,
+ in []*dto.LabelPair,
+ additionalLabelName string, additionalLabelValue float64,
+) (int, error) {
+ if len(in) == 0 && additionalLabelName == "" {
+ return 0, nil
+ }
+ var (
+ written int
+ separator byte = '{'
+ )
+ for _, lp := range in {
+ err := w.WriteByte(separator)
+ written++
+ if err != nil {
+ return written, err
+ }
+ n, err := w.WriteString(lp.GetName())
+ written += n
+ if err != nil {
+ return written, err
+ }
+ n, err = w.WriteString(`="`)
+ written += n
+ if err != nil {
+ return written, err
+ }
+ n, err = writeEscapedString(w, lp.GetValue(), true)
+ written += n
+ if err != nil {
+ return written, err
+ }
+ err = w.WriteByte('"')
+ written++
+ if err != nil {
+ return written, err
+ }
+ separator = ','
+ }
+ if additionalLabelName != "" {
+ err := w.WriteByte(separator)
+ written++
+ if err != nil {
+ return written, err
+ }
+ n, err := w.WriteString(additionalLabelName)
+ written += n
+ if err != nil {
+ return written, err
+ }
+ n, err = w.WriteString(`="`)
+ written += n
+ if err != nil {
+ return written, err
+ }
+ n, err = writeFloat(w, additionalLabelValue)
+ written += n
+ if err != nil {
+ return written, err
+ }
+ err = w.WriteByte('"')
+ written++
+ if err != nil {
+ return written, err
+ }
+ }
+ err := w.WriteByte('}')
+ written++
+ if err != nil {
+ return written, err
+ }
+ return written, nil
+}
+
+// writeEscapedString replaces '\' by '\\', new line character by '\n', and - if
+// includeDoubleQuote is true - '"' by '\"'.
+var (
+ escaper = strings.NewReplacer("\\", `\\`, "\n", `\n`)
+ quotedEscaper = strings.NewReplacer("\\", `\\`, "\n", `\n`, "\"", `\"`)
+)
+
+func writeEscapedString(w enhancedWriter, v string, includeDoubleQuote bool) (int, error) {
+ if includeDoubleQuote {
+ return quotedEscaper.WriteString(w, v)
+ } else {
+ return escaper.WriteString(w, v)
+ }
+}
+
+// writeFloat is equivalent to fmt.Fprint with a float64 argument but hardcodes
+// a few common cases for increased efficiency. For non-hardcoded cases, it uses
+// strconv.AppendFloat to avoid allocations, similar to writeInt.
+func writeFloat(w enhancedWriter, f float64) (int, error) {
+ switch {
+ case f == 1:
+ return 1, w.WriteByte('1')
+ case f == 0:
+ return 1, w.WriteByte('0')
+ case f == -1:
+ return w.WriteString("-1")
+ case math.IsNaN(f):
+ return w.WriteString("NaN")
+ case math.IsInf(f, +1):
+ return w.WriteString("+Inf")
+ case math.IsInf(f, -1):
+ return w.WriteString("-Inf")
+ default:
+ bp := numBufPool.Get().(*[]byte)
+ *bp = strconv.AppendFloat((*bp)[:0], f, 'g', -1, 64)
+ written, err := w.Write(*bp)
+ numBufPool.Put(bp)
+ return written, err
+ }
+}
+
+// writeInt is equivalent to fmt.Fprint with an int64 argument but uses
+// strconv.AppendInt with a byte slice taken from a sync.Pool to avoid
+// allocations.
+func writeInt(w enhancedWriter, i int64) (int, error) {
+ bp := numBufPool.Get().(*[]byte)
+ *bp = strconv.AppendInt((*bp)[:0], i, 10)
+ written, err := w.Write(*bp)
+ numBufPool.Put(bp)
+ return written, err
+}
diff --git a/vendor/github.com/prometheus/common/expfmt/text_parse.go b/vendor/github.com/prometheus/common/expfmt/text_parse.go
new file mode 100644
index 0000000..ec3d86b
--- /dev/null
+++ b/vendor/github.com/prometheus/common/expfmt/text_parse.go
@@ -0,0 +1,757 @@
+// Copyright 2014 The Prometheus Authors
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package expfmt
+
+import (
+ "bufio"
+ "bytes"
+ "fmt"
+ "io"
+ "math"
+ "strconv"
+ "strings"
+
+ dto "github.com/prometheus/client_model/go"
+
+ "github.com/golang/protobuf/proto"
+ "github.com/prometheus/common/model"
+)
+
+// A stateFn is a function that represents a state in a state machine. By
+// executing it, the state is progressed to the next state. The stateFn returns
+// another stateFn, which represents the new state. The end state is represented
+// by nil.
+type stateFn func() stateFn
+
+// ParseError signals errors while parsing the simple and flat text-based
+// exchange format.
+type ParseError struct {
+ Line int
+ Msg string
+}
+
+// Error implements the error interface.
+func (e ParseError) Error() string {
+ return fmt.Sprintf("text format parsing error in line %d: %s", e.Line, e.Msg)
+}
+
+// TextParser is used to parse the simple and flat text-based exchange format. Its
+// zero value is ready to use.
+type TextParser struct {
+ metricFamiliesByName map[string]*dto.MetricFamily
+ buf *bufio.Reader // Where the parsed input is read through.
+ err error // Most recent error.
+ lineCount int // Tracks the line count for error messages.
+ currentByte byte // The most recent byte read.
+ currentToken bytes.Buffer // Re-used each time a token has to be gathered from multiple bytes.
+ currentMF *dto.MetricFamily
+ currentMetric *dto.Metric
+ currentLabelPair *dto.LabelPair
+
+ // The remaining member variables are only used for summaries/histograms.
+ currentLabels map[string]string // All labels including '__name__' but excluding 'quantile'/'le'
+ // Summary specific.
+ summaries map[uint64]*dto.Metric // Key is created with LabelsToSignature.
+ currentQuantile float64
+ // Histogram specific.
+ histograms map[uint64]*dto.Metric // Key is created with LabelsToSignature.
+ currentBucket float64
+ // These tell us if the currently processed line ends on '_count' or
+ // '_sum' respectively and belong to a summary/histogram, representing the sample
+ // count and sum of that summary/histogram.
+ currentIsSummaryCount, currentIsSummarySum bool
+ currentIsHistogramCount, currentIsHistogramSum bool
+}
+
+// TextToMetricFamilies reads 'in' as the simple and flat text-based exchange
+// format and creates MetricFamily proto messages. It returns the MetricFamily
+// proto messages in a map where the metric names are the keys, along with any
+// error encountered.
+//
+// If the input contains duplicate metrics (i.e. lines with the same metric name
+// and exactly the same label set), the resulting MetricFamily will contain
+// duplicate Metric proto messages. Similar is true for duplicate label
+// names. Checks for duplicates have to be performed separately, if required.
+// Also note that neither the metrics within each MetricFamily are sorted nor
+// the label pairs within each Metric. Sorting is not required for the most
+// frequent use of this method, which is sample ingestion in the Prometheus
+// server. However, for presentation purposes, you might want to sort the
+// metrics, and in some cases, you must sort the labels, e.g. for consumption by
+// the metric family injection hook of the Prometheus registry.
+//
+// Summaries and histograms are rather special beasts. You would probably not
+// use them in the simple text format anyway. This method can deal with
+// summaries and histograms if they are presented in exactly the way the
+// text.Create function creates them.
+//
+// This method must not be called concurrently. If you want to parse different
+// input concurrently, instantiate a separate Parser for each goroutine.
+func (p *TextParser) TextToMetricFamilies(in io.Reader) (map[string]*dto.MetricFamily, error) {
+ p.reset(in)
+ for nextState := p.startOfLine; nextState != nil; nextState = nextState() {
+ // Magic happens here...
+ }
+ // Get rid of empty metric families.
+ for k, mf := range p.metricFamiliesByName {
+ if len(mf.GetMetric()) == 0 {
+ delete(p.metricFamiliesByName, k)
+ }
+ }
+ // If p.err is io.EOF now, we have run into a premature end of the input
+ // stream. Turn this error into something nicer and more
+ // meaningful. (io.EOF is often used as a signal for the legitimate end
+ // of an input stream.)
+ if p.err == io.EOF {
+ p.parseError("unexpected end of input stream")
+ }
+ return p.metricFamiliesByName, p.err
+}
+
+func (p *TextParser) reset(in io.Reader) {
+ p.metricFamiliesByName = map[string]*dto.MetricFamily{}
+ if p.buf == nil {
+ p.buf = bufio.NewReader(in)
+ } else {
+ p.buf.Reset(in)
+ }
+ p.err = nil
+ p.lineCount = 0
+ if p.summaries == nil || len(p.summaries) > 0 {
+ p.summaries = map[uint64]*dto.Metric{}
+ }
+ if p.histograms == nil || len(p.histograms) > 0 {
+ p.histograms = map[uint64]*dto.Metric{}
+ }
+ p.currentQuantile = math.NaN()
+ p.currentBucket = math.NaN()
+}
+
+// startOfLine represents the state where the next byte read from p.buf is the
+// start of a line (or whitespace leading up to it).
+func (p *TextParser) startOfLine() stateFn {
+ p.lineCount++
+ if p.skipBlankTab(); p.err != nil {
+ // End of input reached. This is the only case where
+ // that is not an error but a signal that we are done.
+ p.err = nil
+ return nil
+ }
+ switch p.currentByte {
+ case '#':
+ return p.startComment
+ case '\n':
+ return p.startOfLine // Empty line, start the next one.
+ }
+ return p.readingMetricName
+}
+
+// startComment represents the state where the next byte read from p.buf is the
+// start of a comment (or whitespace leading up to it).
+func (p *TextParser) startComment() stateFn {
+ if p.skipBlankTab(); p.err != nil {
+ return nil // Unexpected end of input.
+ }
+ if p.currentByte == '\n' {
+ return p.startOfLine
+ }
+ if p.readTokenUntilWhitespace(); p.err != nil {
+ return nil // Unexpected end of input.
+ }
+ // If we have hit the end of line already, there is nothing left
+ // to do. This is not considered a syntax error.
+ if p.currentByte == '\n' {
+ return p.startOfLine
+ }
+ keyword := p.currentToken.String()
+ if keyword != "HELP" && keyword != "TYPE" {
+ // Generic comment, ignore by fast forwarding to end of line.
+ for p.currentByte != '\n' {
+ if p.currentByte, p.err = p.buf.ReadByte(); p.err != nil {
+ return nil // Unexpected end of input.
+ }
+ }
+ return p.startOfLine
+ }
+ // There is something. Next has to be a metric name.
+ if p.skipBlankTab(); p.err != nil {
+ return nil // Unexpected end of input.
+ }
+ if p.readTokenAsMetricName(); p.err != nil {
+ return nil // Unexpected end of input.
+ }
+ if p.currentByte == '\n' {
+ // At the end of the line already.
+ // Again, this is not considered a syntax error.
+ return p.startOfLine
+ }
+ if !isBlankOrTab(p.currentByte) {
+ p.parseError("invalid metric name in comment")
+ return nil
+ }
+ p.setOrCreateCurrentMF()
+ if p.skipBlankTab(); p.err != nil {
+ return nil // Unexpected end of input.
+ }
+ if p.currentByte == '\n' {
+ // At the end of the line already.
+ // Again, this is not considered a syntax error.
+ return p.startOfLine
+ }
+ switch keyword {
+ case "HELP":
+ return p.readingHelp
+ case "TYPE":
+ return p.readingType
+ }
+ panic(fmt.Sprintf("code error: unexpected keyword %q", keyword))
+}
+
+// readingMetricName represents the state where the last byte read (now in
+// p.currentByte) is the first byte of a metric name.
+func (p *TextParser) readingMetricName() stateFn {
+ if p.readTokenAsMetricName(); p.err != nil {
+ return nil
+ }
+ if p.currentToken.Len() == 0 {
+ p.parseError("invalid metric name")
+ return nil
+ }
+ p.setOrCreateCurrentMF()
+ // Now is the time to fix the type if it hasn't happened yet.
+ if p.currentMF.Type == nil {
+ p.currentMF.Type = dto.MetricType_UNTYPED.Enum()
+ }
+ p.currentMetric = &dto.Metric{}
+ // Do not append the newly created currentMetric to
+ // currentMF.Metric right now. First wait if this is a summary,
+ // and the metric exists already, which we can only know after
+ // having read all the labels.
+ if p.skipBlankTabIfCurrentBlankTab(); p.err != nil {
+ return nil // Unexpected end of input.
+ }
+ return p.readingLabels
+}
+
+// readingLabels represents the state where the last byte read (now in
+// p.currentByte) is either the first byte of the label set (i.e. a '{'), or the
+// first byte of the value (otherwise).
+func (p *TextParser) readingLabels() stateFn {
+ // Summaries/histograms are special. We have to reset the
+ // currentLabels map, currentQuantile and currentBucket before starting to
+ // read labels.
+ if p.currentMF.GetType() == dto.MetricType_SUMMARY || p.currentMF.GetType() == dto.MetricType_HISTOGRAM {
+ p.currentLabels = map[string]string{}
+ p.currentLabels[string(model.MetricNameLabel)] = p.currentMF.GetName()
+ p.currentQuantile = math.NaN()
+ p.currentBucket = math.NaN()
+ }
+ if p.currentByte != '{' {
+ return p.readingValue
+ }
+ return p.startLabelName
+}
+
+// startLabelName represents the state where the next byte read from p.buf is
+// the start of a label name (or whitespace leading up to it).
+func (p *TextParser) startLabelName() stateFn {
+ if p.skipBlankTab(); p.err != nil {
+ return nil // Unexpected end of input.
+ }
+ if p.currentByte == '}' {
+ if p.skipBlankTab(); p.err != nil {
+ return nil // Unexpected end of input.
+ }
+ return p.readingValue
+ }
+ if p.readTokenAsLabelName(); p.err != nil {
+ return nil // Unexpected end of input.
+ }
+ if p.currentToken.Len() == 0 {
+ p.parseError(fmt.Sprintf("invalid label name for metric %q", p.currentMF.GetName()))
+ return nil
+ }
+ p.currentLabelPair = &dto.LabelPair{Name: proto.String(p.currentToken.String())}
+ if p.currentLabelPair.GetName() == string(model.MetricNameLabel) {
+ p.parseError(fmt.Sprintf("label name %q is reserved", model.MetricNameLabel))
+ return nil
+ }
+ // Special summary/histogram treatment. Don't add 'quantile' and 'le'
+ // labels to 'real' labels.
+ if !(p.currentMF.GetType() == dto.MetricType_SUMMARY && p.currentLabelPair.GetName() == model.QuantileLabel) &&
+ !(p.currentMF.GetType() == dto.MetricType_HISTOGRAM && p.currentLabelPair.GetName() == model.BucketLabel) {
+ p.currentMetric.Label = append(p.currentMetric.Label, p.currentLabelPair)
+ }
+ if p.skipBlankTabIfCurrentBlankTab(); p.err != nil {
+ return nil // Unexpected end of input.
+ }
+ if p.currentByte != '=' {
+ p.parseError(fmt.Sprintf("expected '=' after label name, found %q", p.currentByte))
+ return nil
+ }
+ return p.startLabelValue
+}
+
+// startLabelValue represents the state where the next byte read from p.buf is
+// the start of a (quoted) label value (or whitespace leading up to it).
+func (p *TextParser) startLabelValue() stateFn {
+ if p.skipBlankTab(); p.err != nil {
+ return nil // Unexpected end of input.
+ }
+ if p.currentByte != '"' {
+ p.parseError(fmt.Sprintf("expected '\"' at start of label value, found %q", p.currentByte))
+ return nil
+ }
+ if p.readTokenAsLabelValue(); p.err != nil {
+ return nil
+ }
+ if !model.LabelValue(p.currentToken.String()).IsValid() {
+ p.parseError(fmt.Sprintf("invalid label value %q", p.currentToken.String()))
+ return nil
+ }
+ p.currentLabelPair.Value = proto.String(p.currentToken.String())
+ // Special treatment of summaries:
+ // - Quantile labels are special, will result in dto.Quantile later.
+ // - Other labels have to be added to currentLabels for signature calculation.
+ if p.currentMF.GetType() == dto.MetricType_SUMMARY {
+ if p.currentLabelPair.GetName() == model.QuantileLabel {
+ if p.currentQuantile, p.err = strconv.ParseFloat(p.currentLabelPair.GetValue(), 64); p.err != nil {
+ // Create a more helpful error message.
+ p.parseError(fmt.Sprintf("expected float as value for 'quantile' label, got %q", p.currentLabelPair.GetValue()))
+ return nil
+ }
+ } else {
+ p.currentLabels[p.currentLabelPair.GetName()] = p.currentLabelPair.GetValue()
+ }
+ }
+ // Similar special treatment of histograms.
+ if p.currentMF.GetType() == dto.MetricType_HISTOGRAM {
+ if p.currentLabelPair.GetName() == model.BucketLabel {
+ if p.currentBucket, p.err = strconv.ParseFloat(p.currentLabelPair.GetValue(), 64); p.err != nil {
+ // Create a more helpful error message.
+ p.parseError(fmt.Sprintf("expected float as value for 'le' label, got %q", p.currentLabelPair.GetValue()))
+ return nil
+ }
+ } else {
+ p.currentLabels[p.currentLabelPair.GetName()] = p.currentLabelPair.GetValue()
+ }
+ }
+ if p.skipBlankTab(); p.err != nil {
+ return nil // Unexpected end of input.
+ }
+ switch p.currentByte {
+ case ',':
+ return p.startLabelName
+
+ case '}':
+ if p.skipBlankTab(); p.err != nil {
+ return nil // Unexpected end of input.
+ }
+ return p.readingValue
+ default:
+ p.parseError(fmt.Sprintf("unexpected end of label value %q", p.currentLabelPair.GetValue()))
+ return nil
+ }
+}
+
+// readingValue represents the state where the last byte read (now in
+// p.currentByte) is the first byte of the sample value (i.e. a float).
+func (p *TextParser) readingValue() stateFn {
+ // When we are here, we have read all the labels, so for the
+ // special case of a summary/histogram, we can finally find out
+ // if the metric already exists.
+ if p.currentMF.GetType() == dto.MetricType_SUMMARY {
+ signature := model.LabelsToSignature(p.currentLabels)
+ if summary := p.summaries[signature]; summary != nil {
+ p.currentMetric = summary
+ } else {
+ p.summaries[signature] = p.currentMetric
+ p.currentMF.Metric = append(p.currentMF.Metric, p.currentMetric)
+ }
+ } else if p.currentMF.GetType() == dto.MetricType_HISTOGRAM {
+ signature := model.LabelsToSignature(p.currentLabels)
+ if histogram := p.histograms[signature]; histogram != nil {
+ p.currentMetric = histogram
+ } else {
+ p.histograms[signature] = p.currentMetric
+ p.currentMF.Metric = append(p.currentMF.Metric, p.currentMetric)
+ }
+ } else {
+ p.currentMF.Metric = append(p.currentMF.Metric, p.currentMetric)
+ }
+ if p.readTokenUntilWhitespace(); p.err != nil {
+ return nil // Unexpected end of input.
+ }
+ value, err := strconv.ParseFloat(p.currentToken.String(), 64)
+ if err != nil {
+ // Create a more helpful error message.
+ p.parseError(fmt.Sprintf("expected float as value, got %q", p.currentToken.String()))
+ return nil
+ }
+ switch p.currentMF.GetType() {
+ case dto.MetricType_COUNTER:
+ p.currentMetric.Counter = &dto.Counter{Value: proto.Float64(value)}
+ case dto.MetricType_GAUGE:
+ p.currentMetric.Gauge = &dto.Gauge{Value: proto.Float64(value)}
+ case dto.MetricType_UNTYPED:
+ p.currentMetric.Untyped = &dto.Untyped{Value: proto.Float64(value)}
+ case dto.MetricType_SUMMARY:
+ // *sigh*
+ if p.currentMetric.Summary == nil {
+ p.currentMetric.Summary = &dto.Summary{}
+ }
+ switch {
+ case p.currentIsSummaryCount:
+ p.currentMetric.Summary.SampleCount = proto.Uint64(uint64(value))
+ case p.currentIsSummarySum:
+ p.currentMetric.Summary.SampleSum = proto.Float64(value)
+ case !math.IsNaN(p.currentQuantile):
+ p.currentMetric.Summary.Quantile = append(
+ p.currentMetric.Summary.Quantile,
+ &dto.Quantile{
+ Quantile: proto.Float64(p.currentQuantile),
+ Value: proto.Float64(value),
+ },
+ )
+ }
+ case dto.MetricType_HISTOGRAM:
+ // *sigh*
+ if p.currentMetric.Histogram == nil {
+ p.currentMetric.Histogram = &dto.Histogram{}
+ }
+ switch {
+ case p.currentIsHistogramCount:
+ p.currentMetric.Histogram.SampleCount = proto.Uint64(uint64(value))
+ case p.currentIsHistogramSum:
+ p.currentMetric.Histogram.SampleSum = proto.Float64(value)
+ case !math.IsNaN(p.currentBucket):
+ p.currentMetric.Histogram.Bucket = append(
+ p.currentMetric.Histogram.Bucket,
+ &dto.Bucket{
+ UpperBound: proto.Float64(p.currentBucket),
+ CumulativeCount: proto.Uint64(uint64(value)),
+ },
+ )
+ }
+ default:
+ p.err = fmt.Errorf("unexpected type for metric name %q", p.currentMF.GetName())
+ }
+ if p.currentByte == '\n' {
+ return p.startOfLine
+ }
+ return p.startTimestamp
+}
+
+// startTimestamp represents the state where the next byte read from p.buf is
+// the start of the timestamp (or whitespace leading up to it).
+func (p *TextParser) startTimestamp() stateFn {
+ if p.skipBlankTab(); p.err != nil {
+ return nil // Unexpected end of input.
+ }
+ if p.readTokenUntilWhitespace(); p.err != nil {
+ return nil // Unexpected end of input.
+ }
+ timestamp, err := strconv.ParseInt(p.currentToken.String(), 10, 64)
+ if err != nil {
+ // Create a more helpful error message.
+ p.parseError(fmt.Sprintf("expected integer as timestamp, got %q", p.currentToken.String()))
+ return nil
+ }
+ p.currentMetric.TimestampMs = proto.Int64(timestamp)
+ if p.readTokenUntilNewline(false); p.err != nil {
+ return nil // Unexpected end of input.
+ }
+ if p.currentToken.Len() > 0 {
+ p.parseError(fmt.Sprintf("spurious string after timestamp: %q", p.currentToken.String()))
+ return nil
+ }
+ return p.startOfLine
+}
+
+// readingHelp represents the state where the last byte read (now in
+// p.currentByte) is the first byte of the docstring after 'HELP'.
+func (p *TextParser) readingHelp() stateFn {
+ if p.currentMF.Help != nil {
+ p.parseError(fmt.Sprintf("second HELP line for metric name %q", p.currentMF.GetName()))
+ return nil
+ }
+ // Rest of line is the docstring.
+ if p.readTokenUntilNewline(true); p.err != nil {
+ return nil // Unexpected end of input.
+ }
+ p.currentMF.Help = proto.String(p.currentToken.String())
+ return p.startOfLine
+}
+
+// readingType represents the state where the last byte read (now in
+// p.currentByte) is the first byte of the type hint after 'HELP'.
+func (p *TextParser) readingType() stateFn {
+ if p.currentMF.Type != nil {
+ p.parseError(fmt.Sprintf("second TYPE line for metric name %q, or TYPE reported after samples", p.currentMF.GetName()))
+ return nil
+ }
+ // Rest of line is the type.
+ if p.readTokenUntilNewline(false); p.err != nil {
+ return nil // Unexpected end of input.
+ }
+ metricType, ok := dto.MetricType_value[strings.ToUpper(p.currentToken.String())]
+ if !ok {
+ p.parseError(fmt.Sprintf("unknown metric type %q", p.currentToken.String()))
+ return nil
+ }
+ p.currentMF.Type = dto.MetricType(metricType).Enum()
+ return p.startOfLine
+}
+
+// parseError sets p.err to a ParseError at the current line with the given
+// message.
+func (p *TextParser) parseError(msg string) {
+ p.err = ParseError{
+ Line: p.lineCount,
+ Msg: msg,
+ }
+}
+
+// skipBlankTab reads (and discards) bytes from p.buf until it encounters a byte
+// that is neither ' ' nor '\t'. That byte is left in p.currentByte.
+func (p *TextParser) skipBlankTab() {
+ for {
+ if p.currentByte, p.err = p.buf.ReadByte(); p.err != nil || !isBlankOrTab(p.currentByte) {
+ return
+ }
+ }
+}
+
+// skipBlankTabIfCurrentBlankTab works exactly as skipBlankTab but doesn't do
+// anything if p.currentByte is neither ' ' nor '\t'.
+func (p *TextParser) skipBlankTabIfCurrentBlankTab() {
+ if isBlankOrTab(p.currentByte) {
+ p.skipBlankTab()
+ }
+}
+
+// readTokenUntilWhitespace copies bytes from p.buf into p.currentToken. The
+// first byte considered is the byte already read (now in p.currentByte). The
+// first whitespace byte encountered is still copied into p.currentByte, but not
+// into p.currentToken.
+func (p *TextParser) readTokenUntilWhitespace() {
+ p.currentToken.Reset()
+ for p.err == nil && !isBlankOrTab(p.currentByte) && p.currentByte != '\n' {
+ p.currentToken.WriteByte(p.currentByte)
+ p.currentByte, p.err = p.buf.ReadByte()
+ }
+}
+
+// readTokenUntilNewline copies bytes from p.buf into p.currentToken. The first
+// byte considered is the byte already read (now in p.currentByte). The first
+// newline byte encountered is still copied into p.currentByte, but not into
+// p.currentToken. If recognizeEscapeSequence is true, two escape sequences are
+// recognized: '\\' translates into '\', and '\n' into a line-feed character.
+// All other escape sequences are invalid and cause an error.
+func (p *TextParser) readTokenUntilNewline(recognizeEscapeSequence bool) {
+ p.currentToken.Reset()
+ escaped := false
+ for p.err == nil {
+ if recognizeEscapeSequence && escaped {
+ switch p.currentByte {
+ case '\\':
+ p.currentToken.WriteByte(p.currentByte)
+ case 'n':
+ p.currentToken.WriteByte('\n')
+ default:
+ p.parseError(fmt.Sprintf("invalid escape sequence '\\%c'", p.currentByte))
+ return
+ }
+ escaped = false
+ } else {
+ switch p.currentByte {
+ case '\n':
+ return
+ case '\\':
+ escaped = true
+ default:
+ p.currentToken.WriteByte(p.currentByte)
+ }
+ }
+ p.currentByte, p.err = p.buf.ReadByte()
+ }
+}
+
+// readTokenAsMetricName copies a metric name from p.buf into p.currentToken.
+// The first byte considered is the byte already read (now in p.currentByte).
+// The first byte not part of a metric name is still copied into p.currentByte,
+// but not into p.currentToken.
+func (p *TextParser) readTokenAsMetricName() {
+ p.currentToken.Reset()
+ if !isValidMetricNameStart(p.currentByte) {
+ return
+ }
+ for {
+ p.currentToken.WriteByte(p.currentByte)
+ p.currentByte, p.err = p.buf.ReadByte()
+ if p.err != nil || !isValidMetricNameContinuation(p.currentByte) {
+ return
+ }
+ }
+}
+
+// readTokenAsLabelName copies a label name from p.buf into p.currentToken.
+// The first byte considered is the byte already read (now in p.currentByte).
+// The first byte not part of a label name is still copied into p.currentByte,
+// but not into p.currentToken.
+func (p *TextParser) readTokenAsLabelName() {
+ p.currentToken.Reset()
+ if !isValidLabelNameStart(p.currentByte) {
+ return
+ }
+ for {
+ p.currentToken.WriteByte(p.currentByte)
+ p.currentByte, p.err = p.buf.ReadByte()
+ if p.err != nil || !isValidLabelNameContinuation(p.currentByte) {
+ return
+ }
+ }
+}
+
+// readTokenAsLabelValue copies a label value from p.buf into p.currentToken.
+// In contrast to the other 'readTokenAs...' functions, which start with the
+// last read byte in p.currentByte, this method ignores p.currentByte and starts
+// with reading a new byte from p.buf. The first byte not part of a label value
+// is still copied into p.currentByte, but not into p.currentToken.
+func (p *TextParser) readTokenAsLabelValue() {
+ p.currentToken.Reset()
+ escaped := false
+ for {
+ if p.currentByte, p.err = p.buf.ReadByte(); p.err != nil {
+ return
+ }
+ if escaped {
+ switch p.currentByte {
+ case '"', '\\':
+ p.currentToken.WriteByte(p.currentByte)
+ case 'n':
+ p.currentToken.WriteByte('\n')
+ default:
+ p.parseError(fmt.Sprintf("invalid escape sequence '\\%c'", p.currentByte))
+ return
+ }
+ escaped = false
+ continue
+ }
+ switch p.currentByte {
+ case '"':
+ return
+ case '\n':
+ p.parseError(fmt.Sprintf("label value %q contains unescaped new-line", p.currentToken.String()))
+ return
+ case '\\':
+ escaped = true
+ default:
+ p.currentToken.WriteByte(p.currentByte)
+ }
+ }
+}
+
+func (p *TextParser) setOrCreateCurrentMF() {
+ p.currentIsSummaryCount = false
+ p.currentIsSummarySum = false
+ p.currentIsHistogramCount = false
+ p.currentIsHistogramSum = false
+ name := p.currentToken.String()
+ if p.currentMF = p.metricFamiliesByName[name]; p.currentMF != nil {
+ return
+ }
+ // Try out if this is a _sum or _count for a summary/histogram.
+ summaryName := summaryMetricName(name)
+ if p.currentMF = p.metricFamiliesByName[summaryName]; p.currentMF != nil {
+ if p.currentMF.GetType() == dto.MetricType_SUMMARY {
+ if isCount(name) {
+ p.currentIsSummaryCount = true
+ }
+ if isSum(name) {
+ p.currentIsSummarySum = true
+ }
+ return
+ }
+ }
+ histogramName := histogramMetricName(name)
+ if p.currentMF = p.metricFamiliesByName[histogramName]; p.currentMF != nil {
+ if p.currentMF.GetType() == dto.MetricType_HISTOGRAM {
+ if isCount(name) {
+ p.currentIsHistogramCount = true
+ }
+ if isSum(name) {
+ p.currentIsHistogramSum = true
+ }
+ return
+ }
+ }
+ p.currentMF = &dto.MetricFamily{Name: proto.String(name)}
+ p.metricFamiliesByName[name] = p.currentMF
+}
+
+func isValidLabelNameStart(b byte) bool {
+ return (b >= 'a' && b <= 'z') || (b >= 'A' && b <= 'Z') || b == '_'
+}
+
+func isValidLabelNameContinuation(b byte) bool {
+ return isValidLabelNameStart(b) || (b >= '0' && b <= '9')
+}
+
+func isValidMetricNameStart(b byte) bool {
+ return isValidLabelNameStart(b) || b == ':'
+}
+
+func isValidMetricNameContinuation(b byte) bool {
+ return isValidLabelNameContinuation(b) || b == ':'
+}
+
+func isBlankOrTab(b byte) bool {
+ return b == ' ' || b == '\t'
+}
+
+func isCount(name string) bool {
+ return len(name) > 6 && name[len(name)-6:] == "_count"
+}
+
+func isSum(name string) bool {
+ return len(name) > 4 && name[len(name)-4:] == "_sum"
+}
+
+func isBucket(name string) bool {
+ return len(name) > 7 && name[len(name)-7:] == "_bucket"
+}
+
+func summaryMetricName(name string) string {
+ switch {
+ case isCount(name):
+ return name[:len(name)-6]
+ case isSum(name):
+ return name[:len(name)-4]
+ default:
+ return name
+ }
+}
+
+func histogramMetricName(name string) string {
+ switch {
+ case isCount(name):
+ return name[:len(name)-6]
+ case isSum(name):
+ return name[:len(name)-4]
+ case isBucket(name):
+ return name[:len(name)-7]
+ default:
+ return name
+ }
+}
diff --git a/vendor/github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg/README.txt b/vendor/github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg/README.txt
new file mode 100644
index 0000000..7723656
--- /dev/null
+++ b/vendor/github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg/README.txt
@@ -0,0 +1,67 @@
+PACKAGE
+
+package goautoneg
+import "bitbucket.org/ww/goautoneg"
+
+HTTP Content-Type Autonegotiation.
+
+The functions in this package implement the behaviour specified in
+http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html
+
+Copyright (c) 2011, Open Knowledge Foundation Ltd.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+
+ Neither the name of the Open Knowledge Foundation Ltd. nor the
+ names of its contributors may be used to endorse or promote
+ products derived from this software without specific prior written
+ permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+FUNCTIONS
+
+func Negotiate(header string, alternatives []string) (content_type string)
+Negotiate the most appropriate content_type given the accept header
+and a list of alternatives.
+
+func ParseAccept(header string) (accept []Accept)
+Parse an Accept Header string returning a sorted list
+of clauses
+
+
+TYPES
+
+type Accept struct {
+ Type, SubType string
+ Q float32
+ Params map[string]string
+}
+Structure to represent a clause in an HTTP Accept Header
+
+
+SUBDIRECTORIES
+
+ .hg
diff --git a/vendor/github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg/autoneg.go b/vendor/github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg/autoneg.go
new file mode 100644
index 0000000..26e9228
--- /dev/null
+++ b/vendor/github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg/autoneg.go
@@ -0,0 +1,162 @@
+/*
+Copyright (c) 2011, Open Knowledge Foundation Ltd.
+All rights reserved.
+
+HTTP Content-Type Autonegotiation.
+
+The functions in this package implement the behaviour specified in
+http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+
+ Neither the name of the Open Knowledge Foundation Ltd. nor the
+ names of its contributors may be used to endorse or promote
+ products derived from this software without specific prior written
+ permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+*/
+package goautoneg
+
+import (
+ "sort"
+ "strconv"
+ "strings"
+)
+
+// Structure to represent a clause in an HTTP Accept Header
+type Accept struct {
+ Type, SubType string
+ Q float64
+ Params map[string]string
+}
+
+// For internal use, so that we can use the sort interface
+type accept_slice []Accept
+
+func (accept accept_slice) Len() int {
+ slice := []Accept(accept)
+ return len(slice)
+}
+
+func (accept accept_slice) Less(i, j int) bool {
+ slice := []Accept(accept)
+ ai, aj := slice[i], slice[j]
+ if ai.Q > aj.Q {
+ return true
+ }
+ if ai.Type != "*" && aj.Type == "*" {
+ return true
+ }
+ if ai.SubType != "*" && aj.SubType == "*" {
+ return true
+ }
+ return false
+}
+
+func (accept accept_slice) Swap(i, j int) {
+ slice := []Accept(accept)
+ slice[i], slice[j] = slice[j], slice[i]
+}
+
+// Parse an Accept Header string returning a sorted list
+// of clauses
+func ParseAccept(header string) (accept []Accept) {
+ parts := strings.Split(header, ",")
+ accept = make([]Accept, 0, len(parts))
+ for _, part := range parts {
+ part := strings.Trim(part, " ")
+
+ a := Accept{}
+ a.Params = make(map[string]string)
+ a.Q = 1.0
+
+ mrp := strings.Split(part, ";")
+
+ media_range := mrp[0]
+ sp := strings.Split(media_range, "/")
+ a.Type = strings.Trim(sp[0], " ")
+
+ switch {
+ case len(sp) == 1 && a.Type == "*":
+ a.SubType = "*"
+ case len(sp) == 2:
+ a.SubType = strings.Trim(sp[1], " ")
+ default:
+ continue
+ }
+
+ if len(mrp) == 1 {
+ accept = append(accept, a)
+ continue
+ }
+
+ for _, param := range mrp[1:] {
+ sp := strings.SplitN(param, "=", 2)
+ if len(sp) != 2 {
+ continue
+ }
+ token := strings.Trim(sp[0], " ")
+ if token == "q" {
+ a.Q, _ = strconv.ParseFloat(sp[1], 32)
+ } else {
+ a.Params[token] = strings.Trim(sp[1], " ")
+ }
+ }
+
+ accept = append(accept, a)
+ }
+
+ slice := accept_slice(accept)
+ sort.Sort(slice)
+
+ return
+}
+
+// Negotiate the most appropriate content_type given the accept header
+// and a list of alternatives.
+func Negotiate(header string, alternatives []string) (content_type string) {
+ asp := make([][]string, 0, len(alternatives))
+ for _, ctype := range alternatives {
+ asp = append(asp, strings.SplitN(ctype, "/", 2))
+ }
+ for _, clause := range ParseAccept(header) {
+ for i, ctsp := range asp {
+ if clause.Type == ctsp[0] && clause.SubType == ctsp[1] {
+ content_type = alternatives[i]
+ return
+ }
+ if clause.Type == ctsp[0] && clause.SubType == "*" {
+ content_type = alternatives[i]
+ return
+ }
+ if clause.Type == "*" && clause.SubType == "*" {
+ content_type = alternatives[i]
+ return
+ }
+ }
+ }
+ return
+}
diff --git a/vendor/github.com/prometheus/common/model/alert.go b/vendor/github.com/prometheus/common/model/alert.go
new file mode 100644
index 0000000..35e739c
--- /dev/null
+++ b/vendor/github.com/prometheus/common/model/alert.go
@@ -0,0 +1,136 @@
+// Copyright 2013 The Prometheus Authors
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package model
+
+import (
+ "fmt"
+ "time"
+)
+
+type AlertStatus string
+
+const (
+ AlertFiring AlertStatus = "firing"
+ AlertResolved AlertStatus = "resolved"
+)
+
+// Alert is a generic representation of an alert in the Prometheus eco-system.
+type Alert struct {
+ // Label value pairs for purpose of aggregation, matching, and disposition
+ // dispatching. This must minimally include an "alertname" label.
+ Labels LabelSet `json:"labels"`
+
+ // Extra key/value information which does not define alert identity.
+ Annotations LabelSet `json:"annotations"`
+
+ // The known time range for this alert. Both ends are optional.
+ StartsAt time.Time `json:"startsAt,omitempty"`
+ EndsAt time.Time `json:"endsAt,omitempty"`
+ GeneratorURL string `json:"generatorURL"`
+}
+
+// Name returns the name of the alert. It is equivalent to the "alertname" label.
+func (a *Alert) Name() string {
+ return string(a.Labels[AlertNameLabel])
+}
+
+// Fingerprint returns a unique hash for the alert. It is equivalent to
+// the fingerprint of the alert's label set.
+func (a *Alert) Fingerprint() Fingerprint {
+ return a.Labels.Fingerprint()
+}
+
+func (a *Alert) String() string {
+ s := fmt.Sprintf("%s[%s]", a.Name(), a.Fingerprint().String()[:7])
+ if a.Resolved() {
+ return s + "[resolved]"
+ }
+ return s + "[active]"
+}
+
+// Resolved returns true iff the activity interval ended in the past.
+func (a *Alert) Resolved() bool {
+ return a.ResolvedAt(time.Now())
+}
+
+// ResolvedAt returns true off the activity interval ended before
+// the given timestamp.
+func (a *Alert) ResolvedAt(ts time.Time) bool {
+ if a.EndsAt.IsZero() {
+ return false
+ }
+ return !a.EndsAt.After(ts)
+}
+
+// Status returns the status of the alert.
+func (a *Alert) Status() AlertStatus {
+ if a.Resolved() {
+ return AlertResolved
+ }
+ return AlertFiring
+}
+
+// Validate checks whether the alert data is inconsistent.
+func (a *Alert) Validate() error {
+ if a.StartsAt.IsZero() {
+ return fmt.Errorf("start time missing")
+ }
+ if !a.EndsAt.IsZero() && a.EndsAt.Before(a.StartsAt) {
+ return fmt.Errorf("start time must be before end time")
+ }
+ if err := a.Labels.Validate(); err != nil {
+ return fmt.Errorf("invalid label set: %s", err)
+ }
+ if len(a.Labels) == 0 {
+ return fmt.Errorf("at least one label pair required")
+ }
+ if err := a.Annotations.Validate(); err != nil {
+ return fmt.Errorf("invalid annotations: %s", err)
+ }
+ return nil
+}
+
+// Alert is a list of alerts that can be sorted in chronological order.
+type Alerts []*Alert
+
+func (as Alerts) Len() int { return len(as) }
+func (as Alerts) Swap(i, j int) { as[i], as[j] = as[j], as[i] }
+
+func (as Alerts) Less(i, j int) bool {
+ if as[i].StartsAt.Before(as[j].StartsAt) {
+ return true
+ }
+ if as[i].EndsAt.Before(as[j].EndsAt) {
+ return true
+ }
+ return as[i].Fingerprint() < as[j].Fingerprint()
+}
+
+// HasFiring returns true iff one of the alerts is not resolved.
+func (as Alerts) HasFiring() bool {
+ for _, a := range as {
+ if !a.Resolved() {
+ return true
+ }
+ }
+ return false
+}
+
+// Status returns StatusFiring iff at least one of the alerts is firing.
+func (as Alerts) Status() AlertStatus {
+ if as.HasFiring() {
+ return AlertFiring
+ }
+ return AlertResolved
+}
diff --git a/vendor/github.com/prometheus/common/model/fingerprinting.go b/vendor/github.com/prometheus/common/model/fingerprinting.go
new file mode 100644
index 0000000..fc4de41
--- /dev/null
+++ b/vendor/github.com/prometheus/common/model/fingerprinting.go
@@ -0,0 +1,105 @@
+// Copyright 2013 The Prometheus Authors
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package model
+
+import (
+ "fmt"
+ "strconv"
+)
+
+// Fingerprint provides a hash-capable representation of a Metric.
+// For our purposes, FNV-1A 64-bit is used.
+type Fingerprint uint64
+
+// FingerprintFromString transforms a string representation into a Fingerprint.
+func FingerprintFromString(s string) (Fingerprint, error) {
+ num, err := strconv.ParseUint(s, 16, 64)
+ return Fingerprint(num), err
+}
+
+// ParseFingerprint parses the input string into a fingerprint.
+func ParseFingerprint(s string) (Fingerprint, error) {
+ num, err := strconv.ParseUint(s, 16, 64)
+ if err != nil {
+ return 0, err
+ }
+ return Fingerprint(num), nil
+}
+
+func (f Fingerprint) String() string {
+ return fmt.Sprintf("%016x", uint64(f))
+}
+
+// Fingerprints represents a collection of Fingerprint subject to a given
+// natural sorting scheme. It implements sort.Interface.
+type Fingerprints []Fingerprint
+
+// Len implements sort.Interface.
+func (f Fingerprints) Len() int {
+ return len(f)
+}
+
+// Less implements sort.Interface.
+func (f Fingerprints) Less(i, j int) bool {
+ return f[i] < f[j]
+}
+
+// Swap implements sort.Interface.
+func (f Fingerprints) Swap(i, j int) {
+ f[i], f[j] = f[j], f[i]
+}
+
+// FingerprintSet is a set of Fingerprints.
+type FingerprintSet map[Fingerprint]struct{}
+
+// Equal returns true if both sets contain the same elements (and not more).
+func (s FingerprintSet) Equal(o FingerprintSet) bool {
+ if len(s) != len(o) {
+ return false
+ }
+
+ for k := range s {
+ if _, ok := o[k]; !ok {
+ return false
+ }
+ }
+
+ return true
+}
+
+// Intersection returns the elements contained in both sets.
+func (s FingerprintSet) Intersection(o FingerprintSet) FingerprintSet {
+ myLength, otherLength := len(s), len(o)
+ if myLength == 0 || otherLength == 0 {
+ return FingerprintSet{}
+ }
+
+ subSet := s
+ superSet := o
+
+ if otherLength < myLength {
+ subSet = o
+ superSet = s
+ }
+
+ out := FingerprintSet{}
+
+ for k := range subSet {
+ if _, ok := superSet[k]; ok {
+ out[k] = struct{}{}
+ }
+ }
+
+ return out
+}
diff --git a/vendor/github.com/prometheus/common/model/fnv.go b/vendor/github.com/prometheus/common/model/fnv.go
new file mode 100644
index 0000000..038fc1c
--- /dev/null
+++ b/vendor/github.com/prometheus/common/model/fnv.go
@@ -0,0 +1,42 @@
+// Copyright 2015 The Prometheus Authors
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package model
+
+// Inline and byte-free variant of hash/fnv's fnv64a.
+
+const (
+ offset64 = 14695981039346656037
+ prime64 = 1099511628211
+)
+
+// hashNew initializies a new fnv64a hash value.
+func hashNew() uint64 {
+ return offset64
+}
+
+// hashAdd adds a string to a fnv64a hash value, returning the updated hash.
+func hashAdd(h uint64, s string) uint64 {
+ for i := 0; i < len(s); i++ {
+ h ^= uint64(s[i])
+ h *= prime64
+ }
+ return h
+}
+
+// hashAddByte adds a byte to a fnv64a hash value, returning the updated hash.
+func hashAddByte(h uint64, b byte) uint64 {
+ h ^= uint64(b)
+ h *= prime64
+ return h
+}
diff --git a/vendor/github.com/prometheus/common/model/labels.go b/vendor/github.com/prometheus/common/model/labels.go
new file mode 100644
index 0000000..41051a0
--- /dev/null
+++ b/vendor/github.com/prometheus/common/model/labels.go
@@ -0,0 +1,210 @@
+// Copyright 2013 The Prometheus Authors
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package model
+
+import (
+ "encoding/json"
+ "fmt"
+ "regexp"
+ "strings"
+ "unicode/utf8"
+)
+
+const (
+ // AlertNameLabel is the name of the label containing the an alert's name.
+ AlertNameLabel = "alertname"
+
+ // ExportedLabelPrefix is the prefix to prepend to the label names present in
+ // exported metrics if a label of the same name is added by the server.
+ ExportedLabelPrefix = "exported_"
+
+ // MetricNameLabel is the label name indicating the metric name of a
+ // timeseries.
+ MetricNameLabel = "__name__"
+
+ // SchemeLabel is the name of the label that holds the scheme on which to
+ // scrape a target.
+ SchemeLabel = "__scheme__"
+
+ // AddressLabel is the name of the label that holds the address of
+ // a scrape target.
+ AddressLabel = "__address__"
+
+ // MetricsPathLabel is the name of the label that holds the path on which to
+ // scrape a target.
+ MetricsPathLabel = "__metrics_path__"
+
+ // ReservedLabelPrefix is a prefix which is not legal in user-supplied
+ // label names.
+ ReservedLabelPrefix = "__"
+
+ // MetaLabelPrefix is a prefix for labels that provide meta information.
+ // Labels with this prefix are used for intermediate label processing and
+ // will not be attached to time series.
+ MetaLabelPrefix = "__meta_"
+
+ // TmpLabelPrefix is a prefix for temporary labels as part of relabelling.
+ // Labels with this prefix are used for intermediate label processing and
+ // will not be attached to time series. This is reserved for use in
+ // Prometheus configuration files by users.
+ TmpLabelPrefix = "__tmp_"
+
+ // ParamLabelPrefix is a prefix for labels that provide URL parameters
+ // used to scrape a target.
+ ParamLabelPrefix = "__param_"
+
+ // JobLabel is the label name indicating the job from which a timeseries
+ // was scraped.
+ JobLabel = "job"
+
+ // InstanceLabel is the label name used for the instance label.
+ InstanceLabel = "instance"
+
+ // BucketLabel is used for the label that defines the upper bound of a
+ // bucket of a histogram ("le" -> "less or equal").
+ BucketLabel = "le"
+
+ // QuantileLabel is used for the label that defines the quantile in a
+ // summary.
+ QuantileLabel = "quantile"
+)
+
+// LabelNameRE is a regular expression matching valid label names. Note that the
+// IsValid method of LabelName performs the same check but faster than a match
+// with this regular expression.
+var LabelNameRE = regexp.MustCompile("^[a-zA-Z_][a-zA-Z0-9_]*$")
+
+// A LabelName is a key for a LabelSet or Metric. It has a value associated
+// therewith.
+type LabelName string
+
+// IsValid is true iff the label name matches the pattern of LabelNameRE. This
+// method, however, does not use LabelNameRE for the check but a much faster
+// hardcoded implementation.
+func (ln LabelName) IsValid() bool {
+ if len(ln) == 0 {
+ return false
+ }
+ for i, b := range ln {
+ if !((b >= 'a' && b <= 'z') || (b >= 'A' && b <= 'Z') || b == '_' || (b >= '0' && b <= '9' && i > 0)) {
+ return false
+ }
+ }
+ return true
+}
+
+// UnmarshalYAML implements the yaml.Unmarshaler interface.
+func (ln *LabelName) UnmarshalYAML(unmarshal func(interface{}) error) error {
+ var s string
+ if err := unmarshal(&s); err != nil {
+ return err
+ }
+ if !LabelName(s).IsValid() {
+ return fmt.Errorf("%q is not a valid label name", s)
+ }
+ *ln = LabelName(s)
+ return nil
+}
+
+// UnmarshalJSON implements the json.Unmarshaler interface.
+func (ln *LabelName) UnmarshalJSON(b []byte) error {
+ var s string
+ if err := json.Unmarshal(b, &s); err != nil {
+ return err
+ }
+ if !LabelName(s).IsValid() {
+ return fmt.Errorf("%q is not a valid label name", s)
+ }
+ *ln = LabelName(s)
+ return nil
+}
+
+// LabelNames is a sortable LabelName slice. In implements sort.Interface.
+type LabelNames []LabelName
+
+func (l LabelNames) Len() int {
+ return len(l)
+}
+
+func (l LabelNames) Less(i, j int) bool {
+ return l[i] < l[j]
+}
+
+func (l LabelNames) Swap(i, j int) {
+ l[i], l[j] = l[j], l[i]
+}
+
+func (l LabelNames) String() string {
+ labelStrings := make([]string, 0, len(l))
+ for _, label := range l {
+ labelStrings = append(labelStrings, string(label))
+ }
+ return strings.Join(labelStrings, ", ")
+}
+
+// A LabelValue is an associated value for a LabelName.
+type LabelValue string
+
+// IsValid returns true iff the string is a valid UTF8.
+func (lv LabelValue) IsValid() bool {
+ return utf8.ValidString(string(lv))
+}
+
+// LabelValues is a sortable LabelValue slice. It implements sort.Interface.
+type LabelValues []LabelValue
+
+func (l LabelValues) Len() int {
+ return len(l)
+}
+
+func (l LabelValues) Less(i, j int) bool {
+ return string(l[i]) < string(l[j])
+}
+
+func (l LabelValues) Swap(i, j int) {
+ l[i], l[j] = l[j], l[i]
+}
+
+// LabelPair pairs a name with a value.
+type LabelPair struct {
+ Name LabelName
+ Value LabelValue
+}
+
+// LabelPairs is a sortable slice of LabelPair pointers. It implements
+// sort.Interface.
+type LabelPairs []*LabelPair
+
+func (l LabelPairs) Len() int {
+ return len(l)
+}
+
+func (l LabelPairs) Less(i, j int) bool {
+ switch {
+ case l[i].Name > l[j].Name:
+ return false
+ case l[i].Name < l[j].Name:
+ return true
+ case l[i].Value > l[j].Value:
+ return false
+ case l[i].Value < l[j].Value:
+ return true
+ default:
+ return false
+ }
+}
+
+func (l LabelPairs) Swap(i, j int) {
+ l[i], l[j] = l[j], l[i]
+}
diff --git a/vendor/github.com/prometheus/common/model/labelset.go b/vendor/github.com/prometheus/common/model/labelset.go
new file mode 100644
index 0000000..6eda08a
--- /dev/null
+++ b/vendor/github.com/prometheus/common/model/labelset.go
@@ -0,0 +1,169 @@
+// Copyright 2013 The Prometheus Authors
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package model
+
+import (
+ "encoding/json"
+ "fmt"
+ "sort"
+ "strings"
+)
+
+// A LabelSet is a collection of LabelName and LabelValue pairs. The LabelSet
+// may be fully-qualified down to the point where it may resolve to a single
+// Metric in the data store or not. All operations that occur within the realm
+// of a LabelSet can emit a vector of Metric entities to which the LabelSet may
+// match.
+type LabelSet map[LabelName]LabelValue
+
+// Validate checks whether all names and values in the label set
+// are valid.
+func (ls LabelSet) Validate() error {
+ for ln, lv := range ls {
+ if !ln.IsValid() {
+ return fmt.Errorf("invalid name %q", ln)
+ }
+ if !lv.IsValid() {
+ return fmt.Errorf("invalid value %q", lv)
+ }
+ }
+ return nil
+}
+
+// Equal returns true iff both label sets have exactly the same key/value pairs.
+func (ls LabelSet) Equal(o LabelSet) bool {
+ if len(ls) != len(o) {
+ return false
+ }
+ for ln, lv := range ls {
+ olv, ok := o[ln]
+ if !ok {
+ return false
+ }
+ if olv != lv {
+ return false
+ }
+ }
+ return true
+}
+
+// Before compares the metrics, using the following criteria:
+//
+// If m has fewer labels than o, it is before o. If it has more, it is not.
+//
+// If the number of labels is the same, the superset of all label names is
+// sorted alphanumerically. The first differing label pair found in that order
+// determines the outcome: If the label does not exist at all in m, then m is
+// before o, and vice versa. Otherwise the label value is compared
+// alphanumerically.
+//
+// If m and o are equal, the method returns false.
+func (ls LabelSet) Before(o LabelSet) bool {
+ if len(ls) < len(o) {
+ return true
+ }
+ if len(ls) > len(o) {
+ return false
+ }
+
+ lns := make(LabelNames, 0, len(ls)+len(o))
+ for ln := range ls {
+ lns = append(lns, ln)
+ }
+ for ln := range o {
+ lns = append(lns, ln)
+ }
+ // It's probably not worth it to de-dup lns.
+ sort.Sort(lns)
+ for _, ln := range lns {
+ mlv, ok := ls[ln]
+ if !ok {
+ return true
+ }
+ olv, ok := o[ln]
+ if !ok {
+ return false
+ }
+ if mlv < olv {
+ return true
+ }
+ if mlv > olv {
+ return false
+ }
+ }
+ return false
+}
+
+// Clone returns a copy of the label set.
+func (ls LabelSet) Clone() LabelSet {
+ lsn := make(LabelSet, len(ls))
+ for ln, lv := range ls {
+ lsn[ln] = lv
+ }
+ return lsn
+}
+
+// Merge is a helper function to non-destructively merge two label sets.
+func (l LabelSet) Merge(other LabelSet) LabelSet {
+ result := make(LabelSet, len(l))
+
+ for k, v := range l {
+ result[k] = v
+ }
+
+ for k, v := range other {
+ result[k] = v
+ }
+
+ return result
+}
+
+func (l LabelSet) String() string {
+ lstrs := make([]string, 0, len(l))
+ for l, v := range l {
+ lstrs = append(lstrs, fmt.Sprintf("%s=%q", l, v))
+ }
+
+ sort.Strings(lstrs)
+ return fmt.Sprintf("{%s}", strings.Join(lstrs, ", "))
+}
+
+// Fingerprint returns the LabelSet's fingerprint.
+func (ls LabelSet) Fingerprint() Fingerprint {
+ return labelSetToFingerprint(ls)
+}
+
+// FastFingerprint returns the LabelSet's Fingerprint calculated by a faster hashing
+// algorithm, which is, however, more susceptible to hash collisions.
+func (ls LabelSet) FastFingerprint() Fingerprint {
+ return labelSetToFastFingerprint(ls)
+}
+
+// UnmarshalJSON implements the json.Unmarshaler interface.
+func (l *LabelSet) UnmarshalJSON(b []byte) error {
+ var m map[LabelName]LabelValue
+ if err := json.Unmarshal(b, &m); err != nil {
+ return err
+ }
+ // encoding/json only unmarshals maps of the form map[string]T. It treats
+ // LabelName as a string and does not call its UnmarshalJSON method.
+ // Thus, we have to replicate the behavior here.
+ for ln := range m {
+ if !ln.IsValid() {
+ return fmt.Errorf("%q is not a valid label name", ln)
+ }
+ }
+ *l = LabelSet(m)
+ return nil
+}
diff --git a/vendor/github.com/prometheus/common/model/metric.go b/vendor/github.com/prometheus/common/model/metric.go
new file mode 100644
index 0000000..00804b7
--- /dev/null
+++ b/vendor/github.com/prometheus/common/model/metric.go
@@ -0,0 +1,102 @@
+// Copyright 2013 The Prometheus Authors
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package model
+
+import (
+ "fmt"
+ "regexp"
+ "sort"
+ "strings"
+)
+
+var (
+ // MetricNameRE is a regular expression matching valid metric
+ // names. Note that the IsValidMetricName function performs the same
+ // check but faster than a match with this regular expression.
+ MetricNameRE = regexp.MustCompile(`^[a-zA-Z_:][a-zA-Z0-9_:]*$`)
+)
+
+// A Metric is similar to a LabelSet, but the key difference is that a Metric is
+// a singleton and refers to one and only one stream of samples.
+type Metric LabelSet
+
+// Equal compares the metrics.
+func (m Metric) Equal(o Metric) bool {
+ return LabelSet(m).Equal(LabelSet(o))
+}
+
+// Before compares the metrics' underlying label sets.
+func (m Metric) Before(o Metric) bool {
+ return LabelSet(m).Before(LabelSet(o))
+}
+
+// Clone returns a copy of the Metric.
+func (m Metric) Clone() Metric {
+ clone := make(Metric, len(m))
+ for k, v := range m {
+ clone[k] = v
+ }
+ return clone
+}
+
+func (m Metric) String() string {
+ metricName, hasName := m[MetricNameLabel]
+ numLabels := len(m) - 1
+ if !hasName {
+ numLabels = len(m)
+ }
+ labelStrings := make([]string, 0, numLabels)
+ for label, value := range m {
+ if label != MetricNameLabel {
+ labelStrings = append(labelStrings, fmt.Sprintf("%s=%q", label, value))
+ }
+ }
+
+ switch numLabels {
+ case 0:
+ if hasName {
+ return string(metricName)
+ }
+ return "{}"
+ default:
+ sort.Strings(labelStrings)
+ return fmt.Sprintf("%s{%s}", metricName, strings.Join(labelStrings, ", "))
+ }
+}
+
+// Fingerprint returns a Metric's Fingerprint.
+func (m Metric) Fingerprint() Fingerprint {
+ return LabelSet(m).Fingerprint()
+}
+
+// FastFingerprint returns a Metric's Fingerprint calculated by a faster hashing
+// algorithm, which is, however, more susceptible to hash collisions.
+func (m Metric) FastFingerprint() Fingerprint {
+ return LabelSet(m).FastFingerprint()
+}
+
+// IsValidMetricName returns true iff name matches the pattern of MetricNameRE.
+// This function, however, does not use MetricNameRE for the check but a much
+// faster hardcoded implementation.
+func IsValidMetricName(n LabelValue) bool {
+ if len(n) == 0 {
+ return false
+ }
+ for i, b := range n {
+ if !((b >= 'a' && b <= 'z') || (b >= 'A' && b <= 'Z') || b == '_' || b == ':' || (b >= '0' && b <= '9' && i > 0)) {
+ return false
+ }
+ }
+ return true
+}
diff --git a/vendor/github.com/prometheus/common/model/model.go b/vendor/github.com/prometheus/common/model/model.go
new file mode 100644
index 0000000..a7b9691
--- /dev/null
+++ b/vendor/github.com/prometheus/common/model/model.go
@@ -0,0 +1,16 @@
+// Copyright 2013 The Prometheus Authors
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Package model contains common data structures that are shared across
+// Prometheus components and libraries.
+package model
diff --git a/vendor/github.com/prometheus/common/model/signature.go b/vendor/github.com/prometheus/common/model/signature.go
new file mode 100644
index 0000000..8762b13
--- /dev/null
+++ b/vendor/github.com/prometheus/common/model/signature.go
@@ -0,0 +1,144 @@
+// Copyright 2014 The Prometheus Authors
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package model
+
+import (
+ "sort"
+)
+
+// SeparatorByte is a byte that cannot occur in valid UTF-8 sequences and is
+// used to separate label names, label values, and other strings from each other
+// when calculating their combined hash value (aka signature aka fingerprint).
+const SeparatorByte byte = 255
+
+var (
+ // cache the signature of an empty label set.
+ emptyLabelSignature = hashNew()
+)
+
+// LabelsToSignature returns a quasi-unique signature (i.e., fingerprint) for a
+// given label set. (Collisions are possible but unlikely if the number of label
+// sets the function is applied to is small.)
+func LabelsToSignature(labels map[string]string) uint64 {
+ if len(labels) == 0 {
+ return emptyLabelSignature
+ }
+
+ labelNames := make([]string, 0, len(labels))
+ for labelName := range labels {
+ labelNames = append(labelNames, labelName)
+ }
+ sort.Strings(labelNames)
+
+ sum := hashNew()
+ for _, labelName := range labelNames {
+ sum = hashAdd(sum, labelName)
+ sum = hashAddByte(sum, SeparatorByte)
+ sum = hashAdd(sum, labels[labelName])
+ sum = hashAddByte(sum, SeparatorByte)
+ }
+ return sum
+}
+
+// labelSetToFingerprint works exactly as LabelsToSignature but takes a LabelSet as
+// parameter (rather than a label map) and returns a Fingerprint.
+func labelSetToFingerprint(ls LabelSet) Fingerprint {
+ if len(ls) == 0 {
+ return Fingerprint(emptyLabelSignature)
+ }
+
+ labelNames := make(LabelNames, 0, len(ls))
+ for labelName := range ls {
+ labelNames = append(labelNames, labelName)
+ }
+ sort.Sort(labelNames)
+
+ sum := hashNew()
+ for _, labelName := range labelNames {
+ sum = hashAdd(sum, string(labelName))
+ sum = hashAddByte(sum, SeparatorByte)
+ sum = hashAdd(sum, string(ls[labelName]))
+ sum = hashAddByte(sum, SeparatorByte)
+ }
+ return Fingerprint(sum)
+}
+
+// labelSetToFastFingerprint works similar to labelSetToFingerprint but uses a
+// faster and less allocation-heavy hash function, which is more susceptible to
+// create hash collisions. Therefore, collision detection should be applied.
+func labelSetToFastFingerprint(ls LabelSet) Fingerprint {
+ if len(ls) == 0 {
+ return Fingerprint(emptyLabelSignature)
+ }
+
+ var result uint64
+ for labelName, labelValue := range ls {
+ sum := hashNew()
+ sum = hashAdd(sum, string(labelName))
+ sum = hashAddByte(sum, SeparatorByte)
+ sum = hashAdd(sum, string(labelValue))
+ result ^= sum
+ }
+ return Fingerprint(result)
+}
+
+// SignatureForLabels works like LabelsToSignature but takes a Metric as
+// parameter (rather than a label map) and only includes the labels with the
+// specified LabelNames into the signature calculation. The labels passed in
+// will be sorted by this function.
+func SignatureForLabels(m Metric, labels ...LabelName) uint64 {
+ if len(labels) == 0 {
+ return emptyLabelSignature
+ }
+
+ sort.Sort(LabelNames(labels))
+
+ sum := hashNew()
+ for _, label := range labels {
+ sum = hashAdd(sum, string(label))
+ sum = hashAddByte(sum, SeparatorByte)
+ sum = hashAdd(sum, string(m[label]))
+ sum = hashAddByte(sum, SeparatorByte)
+ }
+ return sum
+}
+
+// SignatureWithoutLabels works like LabelsToSignature but takes a Metric as
+// parameter (rather than a label map) and excludes the labels with any of the
+// specified LabelNames from the signature calculation.
+func SignatureWithoutLabels(m Metric, labels map[LabelName]struct{}) uint64 {
+ if len(m) == 0 {
+ return emptyLabelSignature
+ }
+
+ labelNames := make(LabelNames, 0, len(m))
+ for labelName := range m {
+ if _, exclude := labels[labelName]; !exclude {
+ labelNames = append(labelNames, labelName)
+ }
+ }
+ if len(labelNames) == 0 {
+ return emptyLabelSignature
+ }
+ sort.Sort(labelNames)
+
+ sum := hashNew()
+ for _, labelName := range labelNames {
+ sum = hashAdd(sum, string(labelName))
+ sum = hashAddByte(sum, SeparatorByte)
+ sum = hashAdd(sum, string(m[labelName]))
+ sum = hashAddByte(sum, SeparatorByte)
+ }
+ return sum
+}
diff --git a/vendor/github.com/prometheus/common/model/silence.go b/vendor/github.com/prometheus/common/model/silence.go
new file mode 100644
index 0000000..bb99889
--- /dev/null
+++ b/vendor/github.com/prometheus/common/model/silence.go
@@ -0,0 +1,106 @@
+// Copyright 2015 The Prometheus Authors
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package model
+
+import (
+ "encoding/json"
+ "fmt"
+ "regexp"
+ "time"
+)
+
+// Matcher describes a matches the value of a given label.
+type Matcher struct {
+ Name LabelName `json:"name"`
+ Value string `json:"value"`
+ IsRegex bool `json:"isRegex"`
+}
+
+func (m *Matcher) UnmarshalJSON(b []byte) error {
+ type plain Matcher
+ if err := json.Unmarshal(b, (*plain)(m)); err != nil {
+ return err
+ }
+
+ if len(m.Name) == 0 {
+ return fmt.Errorf("label name in matcher must not be empty")
+ }
+ if m.IsRegex {
+ if _, err := regexp.Compile(m.Value); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// Validate returns true iff all fields of the matcher have valid values.
+func (m *Matcher) Validate() error {
+ if !m.Name.IsValid() {
+ return fmt.Errorf("invalid name %q", m.Name)
+ }
+ if m.IsRegex {
+ if _, err := regexp.Compile(m.Value); err != nil {
+ return fmt.Errorf("invalid regular expression %q", m.Value)
+ }
+ } else if !LabelValue(m.Value).IsValid() || len(m.Value) == 0 {
+ return fmt.Errorf("invalid value %q", m.Value)
+ }
+ return nil
+}
+
+// Silence defines the representation of a silence definition in the Prometheus
+// eco-system.
+type Silence struct {
+ ID uint64 `json:"id,omitempty"`
+
+ Matchers []*Matcher `json:"matchers"`
+
+ StartsAt time.Time `json:"startsAt"`
+ EndsAt time.Time `json:"endsAt"`
+
+ CreatedAt time.Time `json:"createdAt,omitempty"`
+ CreatedBy string `json:"createdBy"`
+ Comment string `json:"comment,omitempty"`
+}
+
+// Validate returns true iff all fields of the silence have valid values.
+func (s *Silence) Validate() error {
+ if len(s.Matchers) == 0 {
+ return fmt.Errorf("at least one matcher required")
+ }
+ for _, m := range s.Matchers {
+ if err := m.Validate(); err != nil {
+ return fmt.Errorf("invalid matcher: %s", err)
+ }
+ }
+ if s.StartsAt.IsZero() {
+ return fmt.Errorf("start time missing")
+ }
+ if s.EndsAt.IsZero() {
+ return fmt.Errorf("end time missing")
+ }
+ if s.EndsAt.Before(s.StartsAt) {
+ return fmt.Errorf("start time must be before end time")
+ }
+ if s.CreatedBy == "" {
+ return fmt.Errorf("creator information missing")
+ }
+ if s.Comment == "" {
+ return fmt.Errorf("comment missing")
+ }
+ if s.CreatedAt.IsZero() {
+ return fmt.Errorf("creation timestamp missing")
+ }
+ return nil
+}
diff --git a/vendor/github.com/prometheus/common/model/time.go b/vendor/github.com/prometheus/common/model/time.go
new file mode 100644
index 0000000..7b0064f
--- /dev/null
+++ b/vendor/github.com/prometheus/common/model/time.go
@@ -0,0 +1,270 @@
+// Copyright 2013 The Prometheus Authors
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package model
+
+import (
+ "fmt"
+ "math"
+ "regexp"
+ "strconv"
+ "strings"
+ "time"
+)
+
+const (
+ // MinimumTick is the minimum supported time resolution. This has to be
+ // at least time.Second in order for the code below to work.
+ minimumTick = time.Millisecond
+ // second is the Time duration equivalent to one second.
+ second = int64(time.Second / minimumTick)
+ // The number of nanoseconds per minimum tick.
+ nanosPerTick = int64(minimumTick / time.Nanosecond)
+
+ // Earliest is the earliest Time representable. Handy for
+ // initializing a high watermark.
+ Earliest = Time(math.MinInt64)
+ // Latest is the latest Time representable. Handy for initializing
+ // a low watermark.
+ Latest = Time(math.MaxInt64)
+)
+
+// Time is the number of milliseconds since the epoch
+// (1970-01-01 00:00 UTC) excluding leap seconds.
+type Time int64
+
+// Interval describes an interval between two timestamps.
+type Interval struct {
+ Start, End Time
+}
+
+// Now returns the current time as a Time.
+func Now() Time {
+ return TimeFromUnixNano(time.Now().UnixNano())
+}
+
+// TimeFromUnix returns the Time equivalent to the Unix Time t
+// provided in seconds.
+func TimeFromUnix(t int64) Time {
+ return Time(t * second)
+}
+
+// TimeFromUnixNano returns the Time equivalent to the Unix Time
+// t provided in nanoseconds.
+func TimeFromUnixNano(t int64) Time {
+ return Time(t / nanosPerTick)
+}
+
+// Equal reports whether two Times represent the same instant.
+func (t Time) Equal(o Time) bool {
+ return t == o
+}
+
+// Before reports whether the Time t is before o.
+func (t Time) Before(o Time) bool {
+ return t < o
+}
+
+// After reports whether the Time t is after o.
+func (t Time) After(o Time) bool {
+ return t > o
+}
+
+// Add returns the Time t + d.
+func (t Time) Add(d time.Duration) Time {
+ return t + Time(d/minimumTick)
+}
+
+// Sub returns the Duration t - o.
+func (t Time) Sub(o Time) time.Duration {
+ return time.Duration(t-o) * minimumTick
+}
+
+// Time returns the time.Time representation of t.
+func (t Time) Time() time.Time {
+ return time.Unix(int64(t)/second, (int64(t)%second)*nanosPerTick)
+}
+
+// Unix returns t as a Unix time, the number of seconds elapsed
+// since January 1, 1970 UTC.
+func (t Time) Unix() int64 {
+ return int64(t) / second
+}
+
+// UnixNano returns t as a Unix time, the number of nanoseconds elapsed
+// since January 1, 1970 UTC.
+func (t Time) UnixNano() int64 {
+ return int64(t) * nanosPerTick
+}
+
+// The number of digits after the dot.
+var dotPrecision = int(math.Log10(float64(second)))
+
+// String returns a string representation of the Time.
+func (t Time) String() string {
+ return strconv.FormatFloat(float64(t)/float64(second), 'f', -1, 64)
+}
+
+// MarshalJSON implements the json.Marshaler interface.
+func (t Time) MarshalJSON() ([]byte, error) {
+ return []byte(t.String()), nil
+}
+
+// UnmarshalJSON implements the json.Unmarshaler interface.
+func (t *Time) UnmarshalJSON(b []byte) error {
+ p := strings.Split(string(b), ".")
+ switch len(p) {
+ case 1:
+ v, err := strconv.ParseInt(string(p[0]), 10, 64)
+ if err != nil {
+ return err
+ }
+ *t = Time(v * second)
+
+ case 2:
+ v, err := strconv.ParseInt(string(p[0]), 10, 64)
+ if err != nil {
+ return err
+ }
+ v *= second
+
+ prec := dotPrecision - len(p[1])
+ if prec < 0 {
+ p[1] = p[1][:dotPrecision]
+ } else if prec > 0 {
+ p[1] = p[1] + strings.Repeat("0", prec)
+ }
+
+ va, err := strconv.ParseInt(p[1], 10, 32)
+ if err != nil {
+ return err
+ }
+
+ // If the value was something like -0.1 the negative is lost in the
+ // parsing because of the leading zero, this ensures that we capture it.
+ if len(p[0]) > 0 && p[0][0] == '-' && v+va > 0 {
+ *t = Time(v+va) * -1
+ } else {
+ *t = Time(v + va)
+ }
+
+ default:
+ return fmt.Errorf("invalid time %q", string(b))
+ }
+ return nil
+}
+
+// Duration wraps time.Duration. It is used to parse the custom duration format
+// from YAML.
+// This type should not propagate beyond the scope of input/output processing.
+type Duration time.Duration
+
+// Set implements pflag/flag.Value
+func (d *Duration) Set(s string) error {
+ var err error
+ *d, err = ParseDuration(s)
+ return err
+}
+
+// Type implements pflag.Value
+func (d *Duration) Type() string {
+ return "duration"
+}
+
+var durationRE = regexp.MustCompile("^([0-9]+)(y|w|d|h|m|s|ms)$")
+
+// ParseDuration parses a string into a time.Duration, assuming that a year
+// always has 365d, a week always has 7d, and a day always has 24h.
+func ParseDuration(durationStr string) (Duration, error) {
+ matches := durationRE.FindStringSubmatch(durationStr)
+ if len(matches) != 3 {
+ return 0, fmt.Errorf("not a valid duration string: %q", durationStr)
+ }
+ var (
+ n, _ = strconv.Atoi(matches[1])
+ dur = time.Duration(n) * time.Millisecond
+ )
+ switch unit := matches[2]; unit {
+ case "y":
+ dur *= 1000 * 60 * 60 * 24 * 365
+ case "w":
+ dur *= 1000 * 60 * 60 * 24 * 7
+ case "d":
+ dur *= 1000 * 60 * 60 * 24
+ case "h":
+ dur *= 1000 * 60 * 60
+ case "m":
+ dur *= 1000 * 60
+ case "s":
+ dur *= 1000
+ case "ms":
+ // Value already correct
+ default:
+ return 0, fmt.Errorf("invalid time unit in duration string: %q", unit)
+ }
+ return Duration(dur), nil
+}
+
+func (d Duration) String() string {
+ var (
+ ms = int64(time.Duration(d) / time.Millisecond)
+ unit = "ms"
+ )
+ if ms == 0 {
+ return "0s"
+ }
+ factors := map[string]int64{
+ "y": 1000 * 60 * 60 * 24 * 365,
+ "w": 1000 * 60 * 60 * 24 * 7,
+ "d": 1000 * 60 * 60 * 24,
+ "h": 1000 * 60 * 60,
+ "m": 1000 * 60,
+ "s": 1000,
+ "ms": 1,
+ }
+
+ switch int64(0) {
+ case ms % factors["y"]:
+ unit = "y"
+ case ms % factors["w"]:
+ unit = "w"
+ case ms % factors["d"]:
+ unit = "d"
+ case ms % factors["h"]:
+ unit = "h"
+ case ms % factors["m"]:
+ unit = "m"
+ case ms % factors["s"]:
+ unit = "s"
+ }
+ return fmt.Sprintf("%v%v", ms/factors[unit], unit)
+}
+
+// MarshalYAML implements the yaml.Marshaler interface.
+func (d Duration) MarshalYAML() (interface{}, error) {
+ return d.String(), nil
+}
+
+// UnmarshalYAML implements the yaml.Unmarshaler interface.
+func (d *Duration) UnmarshalYAML(unmarshal func(interface{}) error) error {
+ var s string
+ if err := unmarshal(&s); err != nil {
+ return err
+ }
+ dur, err := ParseDuration(s)
+ if err != nil {
+ return err
+ }
+ *d = dur
+ return nil
+}
diff --git a/vendor/github.com/prometheus/common/model/value.go b/vendor/github.com/prometheus/common/model/value.go
new file mode 100644
index 0000000..c9d8fb1
--- /dev/null
+++ b/vendor/github.com/prometheus/common/model/value.go
@@ -0,0 +1,416 @@
+// Copyright 2013 The Prometheus Authors
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package model
+
+import (
+ "encoding/json"
+ "fmt"
+ "math"
+ "sort"
+ "strconv"
+ "strings"
+)
+
+var (
+ // ZeroSamplePair is the pseudo zero-value of SamplePair used to signal a
+ // non-existing sample pair. It is a SamplePair with timestamp Earliest and
+ // value 0.0. Note that the natural zero value of SamplePair has a timestamp
+ // of 0, which is possible to appear in a real SamplePair and thus not
+ // suitable to signal a non-existing SamplePair.
+ ZeroSamplePair = SamplePair{Timestamp: Earliest}
+
+ // ZeroSample is the pseudo zero-value of Sample used to signal a
+ // non-existing sample. It is a Sample with timestamp Earliest, value 0.0,
+ // and metric nil. Note that the natural zero value of Sample has a timestamp
+ // of 0, which is possible to appear in a real Sample and thus not suitable
+ // to signal a non-existing Sample.
+ ZeroSample = Sample{Timestamp: Earliest}
+)
+
+// A SampleValue is a representation of a value for a given sample at a given
+// time.
+type SampleValue float64
+
+// MarshalJSON implements json.Marshaler.
+func (v SampleValue) MarshalJSON() ([]byte, error) {
+ return json.Marshal(v.String())
+}
+
+// UnmarshalJSON implements json.Unmarshaler.
+func (v *SampleValue) UnmarshalJSON(b []byte) error {
+ if len(b) < 2 || b[0] != '"' || b[len(b)-1] != '"' {
+ return fmt.Errorf("sample value must be a quoted string")
+ }
+ f, err := strconv.ParseFloat(string(b[1:len(b)-1]), 64)
+ if err != nil {
+ return err
+ }
+ *v = SampleValue(f)
+ return nil
+}
+
+// Equal returns true if the value of v and o is equal or if both are NaN. Note
+// that v==o is false if both are NaN. If you want the conventional float
+// behavior, use == to compare two SampleValues.
+func (v SampleValue) Equal(o SampleValue) bool {
+ if v == o {
+ return true
+ }
+ return math.IsNaN(float64(v)) && math.IsNaN(float64(o))
+}
+
+func (v SampleValue) String() string {
+ return strconv.FormatFloat(float64(v), 'f', -1, 64)
+}
+
+// SamplePair pairs a SampleValue with a Timestamp.
+type SamplePair struct {
+ Timestamp Time
+ Value SampleValue
+}
+
+// MarshalJSON implements json.Marshaler.
+func (s SamplePair) MarshalJSON() ([]byte, error) {
+ t, err := json.Marshal(s.Timestamp)
+ if err != nil {
+ return nil, err
+ }
+ v, err := json.Marshal(s.Value)
+ if err != nil {
+ return nil, err
+ }
+ return []byte(fmt.Sprintf("[%s,%s]", t, v)), nil
+}
+
+// UnmarshalJSON implements json.Unmarshaler.
+func (s *SamplePair) UnmarshalJSON(b []byte) error {
+ v := [...]json.Unmarshaler{&s.Timestamp, &s.Value}
+ return json.Unmarshal(b, &v)
+}
+
+// Equal returns true if this SamplePair and o have equal Values and equal
+// Timestamps. The semantics of Value equality is defined by SampleValue.Equal.
+func (s *SamplePair) Equal(o *SamplePair) bool {
+ return s == o || (s.Value.Equal(o.Value) && s.Timestamp.Equal(o.Timestamp))
+}
+
+func (s SamplePair) String() string {
+ return fmt.Sprintf("%s @[%s]", s.Value, s.Timestamp)
+}
+
+// Sample is a sample pair associated with a metric.
+type Sample struct {
+ Metric Metric `json:"metric"`
+ Value SampleValue `json:"value"`
+ Timestamp Time `json:"timestamp"`
+}
+
+// Equal compares first the metrics, then the timestamp, then the value. The
+// semantics of value equality is defined by SampleValue.Equal.
+func (s *Sample) Equal(o *Sample) bool {
+ if s == o {
+ return true
+ }
+
+ if !s.Metric.Equal(o.Metric) {
+ return false
+ }
+ if !s.Timestamp.Equal(o.Timestamp) {
+ return false
+ }
+
+ return s.Value.Equal(o.Value)
+}
+
+func (s Sample) String() string {
+ return fmt.Sprintf("%s => %s", s.Metric, SamplePair{
+ Timestamp: s.Timestamp,
+ Value: s.Value,
+ })
+}
+
+// MarshalJSON implements json.Marshaler.
+func (s Sample) MarshalJSON() ([]byte, error) {
+ v := struct {
+ Metric Metric `json:"metric"`
+ Value SamplePair `json:"value"`
+ }{
+ Metric: s.Metric,
+ Value: SamplePair{
+ Timestamp: s.Timestamp,
+ Value: s.Value,
+ },
+ }
+
+ return json.Marshal(&v)
+}
+
+// UnmarshalJSON implements json.Unmarshaler.
+func (s *Sample) UnmarshalJSON(b []byte) error {
+ v := struct {
+ Metric Metric `json:"metric"`
+ Value SamplePair `json:"value"`
+ }{
+ Metric: s.Metric,
+ Value: SamplePair{
+ Timestamp: s.Timestamp,
+ Value: s.Value,
+ },
+ }
+
+ if err := json.Unmarshal(b, &v); err != nil {
+ return err
+ }
+
+ s.Metric = v.Metric
+ s.Timestamp = v.Value.Timestamp
+ s.Value = v.Value.Value
+
+ return nil
+}
+
+// Samples is a sortable Sample slice. It implements sort.Interface.
+type Samples []*Sample
+
+func (s Samples) Len() int {
+ return len(s)
+}
+
+// Less compares first the metrics, then the timestamp.
+func (s Samples) Less(i, j int) bool {
+ switch {
+ case s[i].Metric.Before(s[j].Metric):
+ return true
+ case s[j].Metric.Before(s[i].Metric):
+ return false
+ case s[i].Timestamp.Before(s[j].Timestamp):
+ return true
+ default:
+ return false
+ }
+}
+
+func (s Samples) Swap(i, j int) {
+ s[i], s[j] = s[j], s[i]
+}
+
+// Equal compares two sets of samples and returns true if they are equal.
+func (s Samples) Equal(o Samples) bool {
+ if len(s) != len(o) {
+ return false
+ }
+
+ for i, sample := range s {
+ if !sample.Equal(o[i]) {
+ return false
+ }
+ }
+ return true
+}
+
+// SampleStream is a stream of Values belonging to an attached COWMetric.
+type SampleStream struct {
+ Metric Metric `json:"metric"`
+ Values []SamplePair `json:"values"`
+}
+
+func (ss SampleStream) String() string {
+ vals := make([]string, len(ss.Values))
+ for i, v := range ss.Values {
+ vals[i] = v.String()
+ }
+ return fmt.Sprintf("%s =>\n%s", ss.Metric, strings.Join(vals, "\n"))
+}
+
+// Value is a generic interface for values resulting from a query evaluation.
+type Value interface {
+ Type() ValueType
+ String() string
+}
+
+func (Matrix) Type() ValueType { return ValMatrix }
+func (Vector) Type() ValueType { return ValVector }
+func (*Scalar) Type() ValueType { return ValScalar }
+func (*String) Type() ValueType { return ValString }
+
+type ValueType int
+
+const (
+ ValNone ValueType = iota
+ ValScalar
+ ValVector
+ ValMatrix
+ ValString
+)
+
+// MarshalJSON implements json.Marshaler.
+func (et ValueType) MarshalJSON() ([]byte, error) {
+ return json.Marshal(et.String())
+}
+
+func (et *ValueType) UnmarshalJSON(b []byte) error {
+ var s string
+ if err := json.Unmarshal(b, &s); err != nil {
+ return err
+ }
+ switch s {
+ case "":
+ *et = ValNone
+ case "scalar":
+ *et = ValScalar
+ case "vector":
+ *et = ValVector
+ case "matrix":
+ *et = ValMatrix
+ case "string":
+ *et = ValString
+ default:
+ return fmt.Errorf("unknown value type %q", s)
+ }
+ return nil
+}
+
+func (e ValueType) String() string {
+ switch e {
+ case ValNone:
+ return ""
+ case ValScalar:
+ return "scalar"
+ case ValVector:
+ return "vector"
+ case ValMatrix:
+ return "matrix"
+ case ValString:
+ return "string"
+ }
+ panic("ValueType.String: unhandled value type")
+}
+
+// Scalar is a scalar value evaluated at the set timestamp.
+type Scalar struct {
+ Value SampleValue `json:"value"`
+ Timestamp Time `json:"timestamp"`
+}
+
+func (s Scalar) String() string {
+ return fmt.Sprintf("scalar: %v @[%v]", s.Value, s.Timestamp)
+}
+
+// MarshalJSON implements json.Marshaler.
+func (s Scalar) MarshalJSON() ([]byte, error) {
+ v := strconv.FormatFloat(float64(s.Value), 'f', -1, 64)
+ return json.Marshal([...]interface{}{s.Timestamp, string(v)})
+}
+
+// UnmarshalJSON implements json.Unmarshaler.
+func (s *Scalar) UnmarshalJSON(b []byte) error {
+ var f string
+ v := [...]interface{}{&s.Timestamp, &f}
+
+ if err := json.Unmarshal(b, &v); err != nil {
+ return err
+ }
+
+ value, err := strconv.ParseFloat(f, 64)
+ if err != nil {
+ return fmt.Errorf("error parsing sample value: %s", err)
+ }
+ s.Value = SampleValue(value)
+ return nil
+}
+
+// String is a string value evaluated at the set timestamp.
+type String struct {
+ Value string `json:"value"`
+ Timestamp Time `json:"timestamp"`
+}
+
+func (s *String) String() string {
+ return s.Value
+}
+
+// MarshalJSON implements json.Marshaler.
+func (s String) MarshalJSON() ([]byte, error) {
+ return json.Marshal([]interface{}{s.Timestamp, s.Value})
+}
+
+// UnmarshalJSON implements json.Unmarshaler.
+func (s *String) UnmarshalJSON(b []byte) error {
+ v := [...]interface{}{&s.Timestamp, &s.Value}
+ return json.Unmarshal(b, &v)
+}
+
+// Vector is basically only an alias for Samples, but the
+// contract is that in a Vector, all Samples have the same timestamp.
+type Vector []*Sample
+
+func (vec Vector) String() string {
+ entries := make([]string, len(vec))
+ for i, s := range vec {
+ entries[i] = s.String()
+ }
+ return strings.Join(entries, "\n")
+}
+
+func (vec Vector) Len() int { return len(vec) }
+func (vec Vector) Swap(i, j int) { vec[i], vec[j] = vec[j], vec[i] }
+
+// Less compares first the metrics, then the timestamp.
+func (vec Vector) Less(i, j int) bool {
+ switch {
+ case vec[i].Metric.Before(vec[j].Metric):
+ return true
+ case vec[j].Metric.Before(vec[i].Metric):
+ return false
+ case vec[i].Timestamp.Before(vec[j].Timestamp):
+ return true
+ default:
+ return false
+ }
+}
+
+// Equal compares two sets of samples and returns true if they are equal.
+func (vec Vector) Equal(o Vector) bool {
+ if len(vec) != len(o) {
+ return false
+ }
+
+ for i, sample := range vec {
+ if !sample.Equal(o[i]) {
+ return false
+ }
+ }
+ return true
+}
+
+// Matrix is a list of time series.
+type Matrix []*SampleStream
+
+func (m Matrix) Len() int { return len(m) }
+func (m Matrix) Less(i, j int) bool { return m[i].Metric.Before(m[j].Metric) }
+func (m Matrix) Swap(i, j int) { m[i], m[j] = m[j], m[i] }
+
+func (mat Matrix) String() string {
+ matCp := make(Matrix, len(mat))
+ copy(matCp, mat)
+ sort.Sort(matCp)
+
+ strs := make([]string, len(matCp))
+
+ for i, ss := range matCp {
+ strs[i] = ss.String()
+ }
+
+ return strings.Join(strs, "\n")
+}
diff --git a/vendor/github.com/prometheus/procfs/.gitignore b/vendor/github.com/prometheus/procfs/.gitignore
new file mode 100644
index 0000000..25e3659
--- /dev/null
+++ b/vendor/github.com/prometheus/procfs/.gitignore
@@ -0,0 +1 @@
+/fixtures/
diff --git a/vendor/github.com/prometheus/procfs/.golangci.yml b/vendor/github.com/prometheus/procfs/.golangci.yml
new file mode 100644
index 0000000..438ca92
--- /dev/null
+++ b/vendor/github.com/prometheus/procfs/.golangci.yml
@@ -0,0 +1,6 @@
+# Run only staticcheck for now. Additional linters will be enabled one-by-one.
+linters:
+ enable:
+ - staticcheck
+ - govet
+ disable-all: true
diff --git a/vendor/github.com/prometheus/procfs/CONTRIBUTING.md b/vendor/github.com/prometheus/procfs/CONTRIBUTING.md
new file mode 100644
index 0000000..40503ed
--- /dev/null
+++ b/vendor/github.com/prometheus/procfs/CONTRIBUTING.md
@@ -0,0 +1,18 @@
+# Contributing
+
+Prometheus uses GitHub to manage reviews of pull requests.
+
+* If you have a trivial fix or improvement, go ahead and create a pull request,
+ addressing (with `@...`) the maintainer of this repository (see
+ [MAINTAINERS.md](MAINTAINERS.md)) in the description of the pull request.
+
+* If you plan to do something more involved, first discuss your ideas
+ on our [mailing list](https://groups.google.com/forum/?fromgroups#!forum/prometheus-developers).
+ This will avoid unnecessary work and surely give you and us a good deal
+ of inspiration.
+
+* Relevant coding style guidelines are the [Go Code Review
+ Comments](https://code.google.com/p/go-wiki/wiki/CodeReviewComments)
+ and the _Formatting and style_ section of Peter Bourgon's [Go: Best
+ Practices for Production
+ Environments](http://peter.bourgon.org/go-in-production/#formatting-and-style).
diff --git a/vendor/github.com/prometheus/procfs/LICENSE b/vendor/github.com/prometheus/procfs/LICENSE
new file mode 100644
index 0000000..261eeb9
--- /dev/null
+++ b/vendor/github.com/prometheus/procfs/LICENSE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/vendor/github.com/prometheus/procfs/MAINTAINERS.md b/vendor/github.com/prometheus/procfs/MAINTAINERS.md
new file mode 100644
index 0000000..56ba67d
--- /dev/null
+++ b/vendor/github.com/prometheus/procfs/MAINTAINERS.md
@@ -0,0 +1,2 @@
+* Johannes 'fish' Ziemke @discordianfish
+* Paul Gier @pgier
diff --git a/vendor/github.com/prometheus/procfs/Makefile b/vendor/github.com/prometheus/procfs/Makefile
new file mode 100644
index 0000000..616a0d2
--- /dev/null
+++ b/vendor/github.com/prometheus/procfs/Makefile
@@ -0,0 +1,29 @@
+# Copyright 2018 The Prometheus Authors
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+include Makefile.common
+
+%/.unpacked: %.ttar
+ @echo ">> extracting fixtures"
+ ./ttar -C $(dir $*) -x -f $*.ttar
+ touch $@
+
+update_fixtures:
+ rm -vf fixtures/.unpacked
+ ./ttar -c -f fixtures.ttar fixtures/
+
+.PHONY: build
+build:
+
+.PHONY: test
+test: fixtures/.unpacked common-test
diff --git a/vendor/github.com/prometheus/procfs/Makefile.common b/vendor/github.com/prometheus/procfs/Makefile.common
new file mode 100644
index 0000000..d7aea1b
--- /dev/null
+++ b/vendor/github.com/prometheus/procfs/Makefile.common
@@ -0,0 +1,275 @@
+# Copyright 2018 The Prometheus Authors
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+# A common Makefile that includes rules to be reused in different prometheus projects.
+# !!! Open PRs only against the prometheus/prometheus/Makefile.common repository!
+
+# Example usage :
+# Create the main Makefile in the root project directory.
+# include Makefile.common
+# customTarget:
+# @echo ">> Running customTarget"
+#
+
+# Ensure GOBIN is not set during build so that promu is installed to the correct path
+unexport GOBIN
+
+GO ?= go
+GOFMT ?= $(GO)fmt
+FIRST_GOPATH := $(firstword $(subst :, ,$(shell $(GO) env GOPATH)))
+GOOPTS ?=
+GOHOSTOS ?= $(shell $(GO) env GOHOSTOS)
+GOHOSTARCH ?= $(shell $(GO) env GOHOSTARCH)
+
+GO_VERSION ?= $(shell $(GO) version)
+GO_VERSION_NUMBER ?= $(word 3, $(GO_VERSION))
+PRE_GO_111 ?= $(shell echo $(GO_VERSION_NUMBER) | grep -E 'go1\.(10|[0-9])\.')
+
+GOVENDOR :=
+GO111MODULE :=
+ifeq (, $(PRE_GO_111))
+ ifneq (,$(wildcard go.mod))
+ # Enforce Go modules support just in case the directory is inside GOPATH (and for Travis CI).
+ GO111MODULE := on
+
+ ifneq (,$(wildcard vendor))
+ # Always use the local vendor/ directory to satisfy the dependencies.
+ GOOPTS := $(GOOPTS) -mod=vendor
+ endif
+ endif
+else
+ ifneq (,$(wildcard go.mod))
+ ifneq (,$(wildcard vendor))
+$(warning This repository requires Go >= 1.11 because of Go modules)
+$(warning Some recipes may not work as expected as the current Go runtime is '$(GO_VERSION_NUMBER)')
+ endif
+ else
+ # This repository isn't using Go modules (yet).
+ GOVENDOR := $(FIRST_GOPATH)/bin/govendor
+ endif
+endif
+PROMU := $(FIRST_GOPATH)/bin/promu
+pkgs = ./...
+
+ifeq (arm, $(GOHOSTARCH))
+ GOHOSTARM ?= $(shell GOARM= $(GO) env GOARM)
+ GO_BUILD_PLATFORM ?= $(GOHOSTOS)-$(GOHOSTARCH)v$(GOHOSTARM)
+else
+ GO_BUILD_PLATFORM ?= $(GOHOSTOS)-$(GOHOSTARCH)
+endif
+
+PROMU_VERSION ?= 0.4.0
+PROMU_URL := https://github.com/prometheus/promu/releases/download/v$(PROMU_VERSION)/promu-$(PROMU_VERSION).$(GO_BUILD_PLATFORM).tar.gz
+
+GOLANGCI_LINT :=
+GOLANGCI_LINT_OPTS ?=
+GOLANGCI_LINT_VERSION ?= v1.16.0
+# golangci-lint only supports linux, darwin and windows platforms on i386/amd64.
+# windows isn't included here because of the path separator being different.
+ifeq ($(GOHOSTOS),$(filter $(GOHOSTOS),linux darwin))
+ ifeq ($(GOHOSTARCH),$(filter $(GOHOSTARCH),amd64 i386))
+ GOLANGCI_LINT := $(FIRST_GOPATH)/bin/golangci-lint
+ endif
+endif
+
+PREFIX ?= $(shell pwd)
+BIN_DIR ?= $(shell pwd)
+DOCKER_IMAGE_TAG ?= $(subst /,-,$(shell git rev-parse --abbrev-ref HEAD))
+DOCKERFILE_PATH ?= ./
+DOCKER_REPO ?= prom
+
+DOCKER_ARCHS ?= amd64
+
+BUILD_DOCKER_ARCHS = $(addprefix common-docker-,$(DOCKER_ARCHS))
+PUBLISH_DOCKER_ARCHS = $(addprefix common-docker-publish-,$(DOCKER_ARCHS))
+TAG_DOCKER_ARCHS = $(addprefix common-docker-tag-latest-,$(DOCKER_ARCHS))
+
+ifeq ($(GOHOSTARCH),amd64)
+ ifeq ($(GOHOSTOS),$(filter $(GOHOSTOS),linux freebsd darwin windows))
+ # Only supported on amd64
+ test-flags := -race
+ endif
+endif
+
+# This rule is used to forward a target like "build" to "common-build". This
+# allows a new "build" target to be defined in a Makefile which includes this
+# one and override "common-build" without override warnings.
+%: common-% ;
+
+.PHONY: common-all
+common-all: precheck style check_license lint unused build test
+
+.PHONY: common-style
+common-style:
+ @echo ">> checking code style"
+ @fmtRes=$$($(GOFMT) -d $$(find . -path ./vendor -prune -o -name '*.go' -print)); \
+ if [ -n "$${fmtRes}" ]; then \
+ echo "gofmt checking failed!"; echo "$${fmtRes}"; echo; \
+ echo "Please ensure you are using $$($(GO) version) for formatting code."; \
+ exit 1; \
+ fi
+
+.PHONY: common-check_license
+common-check_license:
+ @echo ">> checking license header"
+ @licRes=$$(for file in $$(find . -type f -iname '*.go' ! -path './vendor/*') ; do \
+ awk 'NR<=3' $$file | grep -Eq "(Copyright|generated|GENERATED)" || echo $$file; \
+ done); \
+ if [ -n "$${licRes}" ]; then \
+ echo "license header checking failed:"; echo "$${licRes}"; \
+ exit 1; \
+ fi
+
+.PHONY: common-deps
+common-deps:
+ @echo ">> getting dependencies"
+ifdef GO111MODULE
+ GO111MODULE=$(GO111MODULE) $(GO) mod download
+else
+ $(GO) get $(GOOPTS) -t ./...
+endif
+
+.PHONY: common-test-short
+common-test-short:
+ @echo ">> running short tests"
+ GO111MODULE=$(GO111MODULE) $(GO) test -short $(GOOPTS) $(pkgs)
+
+.PHONY: common-test
+common-test:
+ @echo ">> running all tests"
+ GO111MODULE=$(GO111MODULE) $(GO) test $(test-flags) $(GOOPTS) $(pkgs)
+
+.PHONY: common-format
+common-format:
+ @echo ">> formatting code"
+ GO111MODULE=$(GO111MODULE) $(GO) fmt $(pkgs)
+
+.PHONY: common-vet
+common-vet:
+ @echo ">> vetting code"
+ GO111MODULE=$(GO111MODULE) $(GO) vet $(GOOPTS) $(pkgs)
+
+.PHONY: common-lint
+common-lint: $(GOLANGCI_LINT)
+ifdef GOLANGCI_LINT
+ @echo ">> running golangci-lint"
+ifdef GO111MODULE
+# 'go list' needs to be executed before staticcheck to prepopulate the modules cache.
+# Otherwise staticcheck might fail randomly for some reason not yet explained.
+ GO111MODULE=$(GO111MODULE) $(GO) list -e -compiled -test=true -export=false -deps=true -find=false -tags= -- ./... > /dev/null
+ GO111MODULE=$(GO111MODULE) $(GOLANGCI_LINT) run $(GOLANGCI_LINT_OPTS) $(pkgs)
+else
+ $(GOLANGCI_LINT) run $(pkgs)
+endif
+endif
+
+# For backward-compatibility.
+.PHONY: common-staticcheck
+common-staticcheck: lint
+
+.PHONY: common-unused
+common-unused: $(GOVENDOR)
+ifdef GOVENDOR
+ @echo ">> running check for unused packages"
+ @$(GOVENDOR) list +unused | grep . && exit 1 || echo 'No unused packages'
+else
+ifdef GO111MODULE
+ @echo ">> running check for unused/missing packages in go.mod"
+ GO111MODULE=$(GO111MODULE) $(GO) mod tidy
+ifeq (,$(wildcard vendor))
+ @git diff --exit-code -- go.sum go.mod
+else
+ @echo ">> running check for unused packages in vendor/"
+ GO111MODULE=$(GO111MODULE) $(GO) mod vendor
+ @git diff --exit-code -- go.sum go.mod vendor/
+endif
+endif
+endif
+
+.PHONY: common-build
+common-build: promu
+ @echo ">> building binaries"
+ GO111MODULE=$(GO111MODULE) $(PROMU) build --prefix $(PREFIX)
+
+.PHONY: common-tarball
+common-tarball: promu
+ @echo ">> building release tarball"
+ $(PROMU) tarball --prefix $(PREFIX) $(BIN_DIR)
+
+.PHONY: common-docker $(BUILD_DOCKER_ARCHS)
+common-docker: $(BUILD_DOCKER_ARCHS)
+$(BUILD_DOCKER_ARCHS): common-docker-%:
+ docker build -t "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:$(DOCKER_IMAGE_TAG)" \
+ --build-arg ARCH="$*" \
+ --build-arg OS="linux" \
+ $(DOCKERFILE_PATH)
+
+.PHONY: common-docker-publish $(PUBLISH_DOCKER_ARCHS)
+common-docker-publish: $(PUBLISH_DOCKER_ARCHS)
+$(PUBLISH_DOCKER_ARCHS): common-docker-publish-%:
+ docker push "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:$(DOCKER_IMAGE_TAG)"
+
+.PHONY: common-docker-tag-latest $(TAG_DOCKER_ARCHS)
+common-docker-tag-latest: $(TAG_DOCKER_ARCHS)
+$(TAG_DOCKER_ARCHS): common-docker-tag-latest-%:
+ docker tag "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:$(DOCKER_IMAGE_TAG)" "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:latest"
+
+.PHONY: common-docker-manifest
+common-docker-manifest:
+ DOCKER_CLI_EXPERIMENTAL=enabled docker manifest create -a "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME):$(DOCKER_IMAGE_TAG)" $(foreach ARCH,$(DOCKER_ARCHS),$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$(ARCH):$(DOCKER_IMAGE_TAG))
+ DOCKER_CLI_EXPERIMENTAL=enabled docker manifest push "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME):$(DOCKER_IMAGE_TAG)"
+
+.PHONY: promu
+promu: $(PROMU)
+
+$(PROMU):
+ $(eval PROMU_TMP := $(shell mktemp -d))
+ curl -s -L $(PROMU_URL) | tar -xvzf - -C $(PROMU_TMP)
+ mkdir -p $(FIRST_GOPATH)/bin
+ cp $(PROMU_TMP)/promu-$(PROMU_VERSION).$(GO_BUILD_PLATFORM)/promu $(FIRST_GOPATH)/bin/promu
+ rm -r $(PROMU_TMP)
+
+.PHONY: proto
+proto:
+ @echo ">> generating code from proto files"
+ @./scripts/genproto.sh
+
+ifdef GOLANGCI_LINT
+$(GOLANGCI_LINT):
+ mkdir -p $(FIRST_GOPATH)/bin
+ curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/$(GOLANGCI_LINT_VERSION)/install.sh \
+ | sed -e '/install -d/d' \
+ | sh -s -- -b $(FIRST_GOPATH)/bin $(GOLANGCI_LINT_VERSION)
+endif
+
+ifdef GOVENDOR
+.PHONY: $(GOVENDOR)
+$(GOVENDOR):
+ GOOS= GOARCH= $(GO) get -u github.com/kardianos/govendor
+endif
+
+.PHONY: precheck
+precheck::
+
+define PRECHECK_COMMAND_template =
+precheck:: $(1)_precheck
+
+PRECHECK_COMMAND_$(1) ?= $(1) $$(strip $$(PRECHECK_OPTIONS_$(1)))
+.PHONY: $(1)_precheck
+$(1)_precheck:
+ @if ! $$(PRECHECK_COMMAND_$(1)) 1>/dev/null 2>&1; then \
+ echo "Execution of '$$(PRECHECK_COMMAND_$(1))' command failed. Is $(1) installed?"; \
+ exit 1; \
+ fi
+endef
diff --git a/vendor/github.com/prometheus/procfs/NOTICE b/vendor/github.com/prometheus/procfs/NOTICE
new file mode 100644
index 0000000..53c5e9a
--- /dev/null
+++ b/vendor/github.com/prometheus/procfs/NOTICE
@@ -0,0 +1,7 @@
+procfs provides functions to retrieve system, kernel and process
+metrics from the pseudo-filesystem proc.
+
+Copyright 2014-2015 The Prometheus Authors
+
+This product includes software developed at
+SoundCloud Ltd. (http://soundcloud.com/).
diff --git a/vendor/github.com/prometheus/procfs/README.md b/vendor/github.com/prometheus/procfs/README.md
new file mode 100644
index 0000000..6f8850f
--- /dev/null
+++ b/vendor/github.com/prometheus/procfs/README.md
@@ -0,0 +1,53 @@
+# procfs
+
+This procfs package provides functions to retrieve system, kernel and process
+metrics from the pseudo-filesystems /proc and /sys.
+
+*WARNING*: This package is a work in progress. Its API may still break in
+backwards-incompatible ways without warnings. Use it at your own risk.
+
+[![GoDoc](https://godoc.org/github.com/prometheus/procfs?status.png)](https://godoc.org/github.com/prometheus/procfs)
+[![Build Status](https://travis-ci.org/prometheus/procfs.svg?branch=master)](https://travis-ci.org/prometheus/procfs)
+[![Go Report Card](https://goreportcard.com/badge/github.com/prometheus/procfs)](https://goreportcard.com/report/github.com/prometheus/procfs)
+
+## Usage
+
+The procfs library is organized by packages based on whether the gathered data is coming from
+/proc, /sys, or both. Each package contains an `FS` type which represents the path to either /proc, /sys, or both. For example, current cpu statistics are gathered from
+`/proc/stat` and are available via the root procfs package. First, the proc filesystem mount
+point is initialized, and then the stat information is read.
+
+```go
+fs, err := procfs.NewFS("/proc")
+stats, err := fs.Stat()
+```
+
+Some sub-packages such as `blockdevice`, require access to both the proc and sys filesystems.
+
+```go
+ fs, err := blockdevice.NewFS("/proc", "/sys")
+ stats, err := fs.ProcDiskstats()
+```
+
+## Building and Testing
+
+The procfs library is normally built as part of another application. However, when making
+changes to the library, the `make test` command can be used to run the API test suite.
+
+### Updating Test Fixtures
+
+The procfs library includes a set of test fixtures which include many example files from
+the `/proc` and `/sys` filesystems. These fixtures are included as a [ttar](https://github.com/ideaship/ttar) file
+which is extracted automatically during testing. To add/update the test fixtures, first
+ensure the `fixtures` directory is up to date by removing the existing directory and then
+extracting the ttar file using `make fixtures/.unpacked` or just `make test`.
+
+```bash
+rm -rf fixtures
+make test
+```
+
+Next, make the required changes to the extracted files in the `fixtures` directory. When
+the changes are complete, run `make update_fixtures` to create a new `fixtures.ttar` file
+based on the updated `fixtures` directory. And finally, verify the changes using
+`git diff fixtures.ttar`.
diff --git a/vendor/github.com/prometheus/procfs/buddyinfo.go b/vendor/github.com/prometheus/procfs/buddyinfo.go
new file mode 100644
index 0000000..63d4229
--- /dev/null
+++ b/vendor/github.com/prometheus/procfs/buddyinfo.go
@@ -0,0 +1,85 @@
+// Copyright 2017 The Prometheus Authors
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package procfs
+
+import (
+ "bufio"
+ "fmt"
+ "io"
+ "os"
+ "strconv"
+ "strings"
+)
+
+// A BuddyInfo is the details parsed from /proc/buddyinfo.
+// The data is comprised of an array of free fragments of each size.
+// The sizes are 2^n*PAGE_SIZE, where n is the array index.
+type BuddyInfo struct {
+ Node string
+ Zone string
+ Sizes []float64
+}
+
+// NewBuddyInfo reads the buddyinfo statistics from the specified `proc` filesystem.
+func (fs FS) BuddyInfo() ([]BuddyInfo, error) {
+ file, err := os.Open(fs.proc.Path("buddyinfo"))
+ if err != nil {
+ return nil, err
+ }
+ defer file.Close()
+
+ return parseBuddyInfo(file)
+}
+
+func parseBuddyInfo(r io.Reader) ([]BuddyInfo, error) {
+ var (
+ buddyInfo = []BuddyInfo{}
+ scanner = bufio.NewScanner(r)
+ bucketCount = -1
+ )
+
+ for scanner.Scan() {
+ var err error
+ line := scanner.Text()
+ parts := strings.Fields(line)
+
+ if len(parts) < 4 {
+ return nil, fmt.Errorf("invalid number of fields when parsing buddyinfo")
+ }
+
+ node := strings.TrimRight(parts[1], ",")
+ zone := strings.TrimRight(parts[3], ",")
+ arraySize := len(parts[4:])
+
+ if bucketCount == -1 {
+ bucketCount = arraySize
+ } else {
+ if bucketCount != arraySize {
+ return nil, fmt.Errorf("mismatch in number of buddyinfo buckets, previous count %d, new count %d", bucketCount, arraySize)
+ }
+ }
+
+ sizes := make([]float64, arraySize)
+ for i := 0; i < arraySize; i++ {
+ sizes[i], err = strconv.ParseFloat(parts[i+4], 64)
+ if err != nil {
+ return nil, fmt.Errorf("invalid value in buddyinfo: %s", err)
+ }
+ }
+
+ buddyInfo = append(buddyInfo, BuddyInfo{node, zone, sizes})
+ }
+
+ return buddyInfo, scanner.Err()
+}
diff --git a/vendor/github.com/prometheus/procfs/doc.go b/vendor/github.com/prometheus/procfs/doc.go
new file mode 100644
index 0000000..e2acd6d
--- /dev/null
+++ b/vendor/github.com/prometheus/procfs/doc.go
@@ -0,0 +1,45 @@
+// Copyright 2014 Prometheus Team
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Package procfs provides functions to retrieve system, kernel and process
+// metrics from the pseudo-filesystem proc.
+//
+// Example:
+//
+// package main
+//
+// import (
+// "fmt"
+// "log"
+//
+// "github.com/prometheus/procfs"
+// )
+//
+// func main() {
+// p, err := procfs.Self()
+// if err != nil {
+// log.Fatalf("could not get process: %s", err)
+// }
+//
+// stat, err := p.NewStat()
+// if err != nil {
+// log.Fatalf("could not get process stat: %s", err)
+// }
+//
+// fmt.Printf("command: %s\n", stat.Comm)
+// fmt.Printf("cpu time: %fs\n", stat.CPUTime())
+// fmt.Printf("vsize: %dB\n", stat.VirtualMemory())
+// fmt.Printf("rss: %dB\n", stat.ResidentMemory())
+// }
+//
+package procfs
diff --git a/vendor/github.com/prometheus/procfs/fixtures.ttar b/vendor/github.com/prometheus/procfs/fixtures.ttar
new file mode 100644
index 0000000..6b42e7b
--- /dev/null
+++ b/vendor/github.com/prometheus/procfs/fixtures.ttar
@@ -0,0 +1,2343 @@
+# Archive created by ttar -c -f fixtures.ttar fixtures/
+Directory: fixtures
+Mode: 775
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/proc
+Mode: 775
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/proc/26231
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/proc/26231/cmdline
+Lines: 1
+vimNULLBYTEtest.goNULLBYTE+10NULLBYTEEOF
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/proc/26231/comm
+Lines: 1
+vim
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/proc/26231/cwd
+SymlinkTo: /usr/bin
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/proc/26231/environ
+Lines: 1
+PATH=/go/bin:/usr/local/go/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/binNULLBYTEHOSTNAME=cd24e11f73a5NULLBYTETERM=xtermNULLBYTEGOLANG_VERSION=1.12.5NULLBYTEGOPATH=/goNULLBYTEHOME=/rootNULLBYTEEOF
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/proc/26231/exe
+SymlinkTo: /usr/bin/vim
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/proc/26231/fd
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/proc/26231/fd/0
+SymlinkTo: ../../symlinktargets/abc
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/proc/26231/fd/1
+SymlinkTo: ../../symlinktargets/def
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/proc/26231/fd/10
+SymlinkTo: ../../symlinktargets/xyz
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/proc/26231/fd/2
+SymlinkTo: ../../symlinktargets/ghi
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/proc/26231/fd/3
+SymlinkTo: ../../symlinktargets/uvw
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/proc/26231/io
+Lines: 7
+rchar: 750339
+wchar: 818609
+syscr: 7405
+syscw: 5245
+read_bytes: 1024
+write_bytes: 2048
+cancelled_write_bytes: -1024
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/proc/26231/limits
+Lines: 17
+Limit Soft Limit Hard Limit Units
+Max cpu time unlimited unlimited seconds
+Max file size unlimited unlimited bytes
+Max data size unlimited unlimited bytes
+Max stack size 8388608 unlimited bytes
+Max core file size 0 unlimited bytes
+Max resident set unlimited unlimited bytes
+Max processes 62898 62898 processes
+Max open files 2048 4096 files
+Max locked memory 65536 65536 bytes
+Max address space 8589934592 unlimited bytes
+Max file locks unlimited unlimited locks
+Max pending signals 62898 62898 signals
+Max msgqueue size 819200 819200 bytes
+Max nice priority 0 0
+Max realtime priority 0 0
+Max realtime timeout unlimited unlimited us
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/proc/26231/mountstats
+Lines: 20
+device rootfs mounted on / with fstype rootfs
+device sysfs mounted on /sys with fstype sysfs
+device proc mounted on /proc with fstype proc
+device /dev/sda1 mounted on / with fstype ext4
+device 192.168.1.1:/srv/test mounted on /mnt/nfs/test with fstype nfs4 statvers=1.1
+ opts: rw,vers=4.0,rsize=1048576,wsize=1048576,namlen=255,acregmin=3,acregmax=60,acdirmin=30,acdirmax=60,hard,proto=tcp,port=0,timeo=600,retrans=2,sec=sys,mountaddr=192.168.1.1,clientaddr=192.168.1.5,local_lock=none
+ age: 13968
+ caps: caps=0xfff7,wtmult=512,dtsize=32768,bsize=0,namlen=255
+ nfsv4: bm0=0xfdffafff,bm1=0xf9be3e,bm2=0x0,acl=0x0,pnfs=not configured
+ sec: flavor=1,pseudoflavor=1
+ events: 52 226 0 0 1 13 398 0 0 331 0 47 0 0 77 0 0 77 0 0 0 0 0 0 0 0 0
+ bytes: 1207640230 0 0 0 1210214218 0 295483 0
+ RPC iostats version: 1.0 p/v: 100003/4 (nfs)
+ xprt: tcp 832 0 1 0 11 6428 6428 0 12154 0 24 26 5726
+ per-op statistics
+ NULL: 0 0 0 0 0 0 0 0
+ READ: 1298 1298 0 207680 1210292152 6 79386 79407
+ WRITE: 0 0 0 0 0 0 0 0
+ ACCESS: 2927395007 2927394995 0 526931094212 362996810236 18446743919241604546 1667369447 1953587717
+
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/proc/26231/net
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/proc/26231/net/dev
+Lines: 4
+Inter-| Receive | Transmit
+ face |bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed
+ lo: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ eth0: 438 5 0 0 0 0 0 0 648 8 0 0 0 0 0 0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/proc/26231/ns
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/proc/26231/ns/mnt
+SymlinkTo: mnt:[4026531840]
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/proc/26231/ns/net
+SymlinkTo: net:[4026531993]
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/proc/26231/root
+SymlinkTo: /
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/proc/26231/stat
+Lines: 1
+26231 (vim) R 5392 7446 5392 34835 7446 4218880 32533 309516 26 82 1677 44 158 99 20 0 1 0 82375 56274944 1981 18446744073709551615 4194304 6294284 140736914091744 140736914087944 139965136429984 0 0 12288 1870679807 0 0 0 17 0 0 0 31 0 0 8391624 8481048 16420864 140736914093252 140736914093279 140736914093279 140736914096107 0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/proc/26231/status
+Lines: 53
+
+Name: prometheus
+Umask: 0022
+State: S (sleeping)
+Tgid: 1
+Ngid: 0
+Pid: 1
+PPid: 0
+TracerPid: 0
+Uid: 0 0 0 0
+Gid: 0 0 0 0
+FDSize: 128
+Groups:
+NStgid: 1
+NSpid: 1
+NSpgid: 1
+NSsid: 1
+VmPeak: 58472 kB
+VmSize: 58440 kB
+VmLck: 0 kB
+VmPin: 0 kB
+VmHWM: 8028 kB
+VmRSS: 6716 kB
+RssAnon: 2092 kB
+RssFile: 4624 kB
+RssShmem: 0 kB
+VmData: 2580 kB
+VmStk: 136 kB
+VmExe: 948 kB
+VmLib: 6816 kB
+VmPTE: 128 kB
+VmPMD: 12 kB
+VmSwap: 660 kB
+HugetlbPages: 0 kB
+Threads: 1
+SigQ: 8/63965
+SigPnd: 0000000000000000
+ShdPnd: 0000000000000000
+SigBlk: 7be3c0fe28014a03
+SigIgn: 0000000000001000
+SigCgt: 00000001800004ec
+CapInh: 0000000000000000
+CapPrm: 0000003fffffffff
+CapEff: 0000003fffffffff
+CapBnd: 0000003fffffffff
+CapAmb: 0000000000000000
+Seccomp: 0
+Cpus_allowed: ff
+Cpus_allowed_list: 0-7
+Mems_allowed: 00000000,00000001
+Mems_allowed_list: 0
+voluntary_ctxt_switches: 4742839
+nonvoluntary_ctxt_switches: 1727500
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/proc/26232
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/proc/26232/cmdline
+Lines: 0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/proc/26232/comm
+Lines: 1
+ata_sff
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/proc/26232/cwd
+SymlinkTo: /does/not/exist
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/proc/26232/fd
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/proc/26232/fd/0
+SymlinkTo: ../../symlinktargets/abc
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/proc/26232/fd/1
+SymlinkTo: ../../symlinktargets/def
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/proc/26232/fd/2
+SymlinkTo: ../../symlinktargets/ghi
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/proc/26232/fd/3
+SymlinkTo: ../../symlinktargets/uvw
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/proc/26232/fd/4
+SymlinkTo: ../../symlinktargets/xyz
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/proc/26232/limits
+Lines: 17
+Limit Soft Limit Hard Limit Units
+Max cpu time unlimited unlimited seconds
+Max file size unlimited unlimited bytes
+Max data size unlimited unlimited bytes
+Max stack size 8388608 unlimited bytes
+Max core file size 0 unlimited bytes
+Max resident set unlimited unlimited bytes
+Max processes 29436 29436 processes
+Max open files 1024 4096 files
+Max locked memory 65536 65536 bytes
+Max address space unlimited unlimited bytes
+Max file locks unlimited unlimited locks
+Max pending signals 29436 29436 signals
+Max msgqueue size 819200 819200 bytes
+Max nice priority 0 0
+Max realtime priority 0 0
+Max realtime timeout unlimited unlimited us
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/proc/26232/root
+SymlinkTo: /does/not/exist
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/proc/26232/stat
+Lines: 1
+33 (ata_sff) S 2 0 0 0 -1 69238880 0 0 0 0 0 0 0 0 0 -20 1 0 5 0 0 18446744073709551615 0 0 0 0 0 0 0 2147483647 0 18446744073709551615 0 0 17 1 0 0 0 0 0 0 0 0 0 0 0 0 0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/proc/26233
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/proc/26233/cmdline
+Lines: 1
+com.github.uiautomatorNULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTEEOF
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/proc/584
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/proc/584/stat
+Lines: 2
+1020 ((a b ) ( c d) ) R 28378 1020 28378 34842 1020 4218880 286 0 0 0 0 0 0 0 20 0 1 0 10839175 10395648 155 18446744073709551615 4194304 4238788 140736466511168 140736466511168 140609271124624 0 0 0 0 0 0 0 17 5 0 0 0 0 0 6336016 6337300 25579520 140736466515030 140736466515061 140736466515061 140736466518002 0
+#!/bin/cat /proc/self/stat
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/proc/buddyinfo
+Lines: 3
+Node 0, zone DMA 1 0 1 0 2 1 1 0 1 1 3
+Node 0, zone DMA32 759 572 791 475 194 45 12 0 0 0 0
+Node 0, zone Normal 4381 1093 185 1530 567 102 4 0 0 0 0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/proc/diskstats
+Lines: 49
+ 1 0 ram0 0 0 0 0 0 0 0 0 0 0 0
+ 1 1 ram1 0 0 0 0 0 0 0 0 0 0 0
+ 1 2 ram2 0 0 0 0 0 0 0 0 0 0 0
+ 1 3 ram3 0 0 0 0 0 0 0 0 0 0 0
+ 1 4 ram4 0 0 0 0 0 0 0 0 0 0 0
+ 1 5 ram5 0 0 0 0 0 0 0 0 0 0 0
+ 1 6 ram6 0 0 0 0 0 0 0 0 0 0 0
+ 1 7 ram7 0 0 0 0 0 0 0 0 0 0 0
+ 1 8 ram8 0 0 0 0 0 0 0 0 0 0 0
+ 1 9 ram9 0 0 0 0 0 0 0 0 0 0 0
+ 1 10 ram10 0 0 0 0 0 0 0 0 0 0 0
+ 1 11 ram11 0 0 0 0 0 0 0 0 0 0 0
+ 1 12 ram12 0 0 0 0 0 0 0 0 0 0 0
+ 1 13 ram13 0 0 0 0 0 0 0 0 0 0 0
+ 1 14 ram14 0 0 0 0 0 0 0 0 0 0 0
+ 1 15 ram15 0 0 0 0 0 0 0 0 0 0 0
+ 7 0 loop0 0 0 0 0 0 0 0 0 0 0 0
+ 7 1 loop1 0 0 0 0 0 0 0 0 0 0 0
+ 7 2 loop2 0 0 0 0 0 0 0 0 0 0 0
+ 7 3 loop3 0 0 0 0 0 0 0 0 0 0 0
+ 7 4 loop4 0 0 0 0 0 0 0 0 0 0 0
+ 7 5 loop5 0 0 0 0 0 0 0 0 0 0 0
+ 7 6 loop6 0 0 0 0 0 0 0 0 0 0 0
+ 7 7 loop7 0 0 0 0 0 0 0 0 0 0 0
+ 8 0 sda 25354637 34367663 1003346126 18492372 28444756 11134226 505697032 63877960 0 9653880 82621804
+ 8 1 sda1 250 0 2000 36 0 0 0 0 0 36 36
+ 8 2 sda2 246 0 1968 32 0 0 0 0 0 32 32
+ 8 3 sda3 340 13 2818 52 11 8 152 8 0 56 60
+ 8 4 sda4 25353629 34367650 1003337964 18492232 27448755 11134218 505696880 61593380 0 7576432 80332428
+ 252 0 dm-0 59910002 0 1003337218 46229572 39231014 0 505696880 1158557800 0 11325968 1206301256
+ 252 1 dm-1 388 0 3104 84 74 0 592 0 0 76 84
+ 252 2 dm-2 11571 0 308350 6536 153522 0 5093416 122884 0 65400 129416
+ 252 3 dm-3 3870 0 3870 104 0 0 0 0 0 16 104
+ 252 4 dm-4 392 0 1034 28 38 0 137 16 0 24 44
+ 252 5 dm-5 3729 0 84279 924 98918 0 1151688 104684 0 58848 105632
+ 179 0 mmcblk0 192 3 1560 156 0 0 0 0 0 136 156
+ 179 1 mmcblk0p1 17 3 160 24 0 0 0 0 0 24 24
+ 179 2 mmcblk0p2 95 0 760 68 0 0 0 0 0 68 68
+ 2 0 fd0 2 0 16 80 0 0 0 0 0 80 80
+ 254 0 vda 1775784 15386 32670882 8655768 6038856 20711856 213637440 2069221364 0 41614592 2077872228
+ 254 1 vda1 668 85 5984 956 207 4266 35784 32772 0 8808 33720
+ 254 2 vda2 1774936 15266 32663262 8654692 5991028 20707590 213601656 2069152216 0 41607628 2077801992
+ 11 0 sr0 0 0 0 0 0 0 0 0 0 0 0
+ 259 0 nvme0n1 47114 4 4643973 21650 1078320 43950 39451633 1011053 0 222766 1032546
+ 259 1 nvme0n1p1 1140 0 9370 16 1 0 1 0 0 16 16
+ 259 2 nvme0n1p2 45914 4 4631243 21626 1036885 43950 39451632 919480 0 131580 940970
+ 8 0 sdb 326552 841 9657779 84 41822 2895 1972905 5007 0 60730 67070 68851 0 1925173784 11130
+ 8 1 sdb1 231 3 34466 4 24 23 106 0 0 64 64 0 0 0 0
+ 8 2 sdb2 326310 838 9622281 67 40726 2872 1972799 4924 0 58250 64567 68851 0 1925173784 11130
+Mode: 664
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/proc/fs
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/proc/fs/xfs
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/proc/fs/xfs/stat
+Lines: 23
+extent_alloc 92447 97589 92448 93751
+abt 0 0 0 0
+blk_map 1767055 188820 184891 92447 92448 2140766 0
+bmbt 0 0 0 0
+dir 185039 92447 92444 136422
+trans 706 944304 0
+ig 185045 58807 0 126238 0 33637 22
+log 2883 113448 9 17360 739
+push_ail 945014 0 134260 15483 0 3940 464 159985 0 40
+xstrat 92447 0
+rw 107739 94045
+attr 4 0 0 0
+icluster 8677 7849 135802
+vnodes 92601 0 0 0 92444 92444 92444 0
+buf 2666287 7122 2659202 3599 2 7085 0 10297 7085
+abtb2 184941 1277345 13257 13278 0 0 0 0 0 0 0 0 0 0 2746147
+abtc2 345295 2416764 172637 172658 0 0 0 0 0 0 0 0 0 0 21406023
+bmbt2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ibt2 343004 1358467 0 0 0 0 0 0 0 0 0 0 0 0 0
+fibt2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+qm 0 0 0 0 0 0 0 0
+xpc 399724544 92823103 86219234
+debug 0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/proc/mdstat
+Lines: 56
+Personalities : [linear] [multipath] [raid0] [raid1] [raid6] [raid5] [raid4] [raid10]
+
+md3 : active raid6 sda1[8] sdh1[7] sdg1[6] sdf1[5] sde1[11] sdd1[3] sdc1[10] sdb1[9] sdd1[10](S) sdd2[11](S)
+ 5853468288 blocks super 1.2 level 6, 64k chunk, algorithm 2 [8/8] [UUUUUUUU]
+
+md127 : active raid1 sdi2[0] sdj2[1]
+ 312319552 blocks [2/2] [UU]
+
+md0 : active raid1 sdi1[0] sdj1[1]
+ 248896 blocks [2/2] [UU]
+
+md4 : inactive raid1 sda3[0](F) sdb3[1](S)
+ 4883648 blocks [2/2] [UU]
+
+md6 : active raid1 sdb2[2](F) sdc[1](S) sda2[0]
+ 195310144 blocks [2/1] [U_]
+ [=>...................] recovery = 8.5% (16775552/195310144) finish=17.0min speed=259783K/sec
+
+md8 : active raid1 sdb1[1] sda1[0] sdc[2](S) sde[3](S)
+ 195310144 blocks [2/2] [UU]
+ [=>...................] resync = 8.5% (16775552/195310144) finish=17.0min speed=259783K/sec
+
+md7 : active raid6 sdb1[0] sde1[3] sdd1[2] sdc1[1](F)
+ 7813735424 blocks super 1.2 level 6, 512k chunk, algorithm 2 [4/3] [U_UU]
+ bitmap: 0/30 pages [0KB], 65536KB chunk
+
+md9 : active raid1 sdc2[2] sdd2[3] sdb2[1] sda2[0] sde[4](F) sdf[5](F) sdg[6](S)
+ 523968 blocks super 1.2 [4/4] [UUUU]
+ resync=DELAYED
+
+md10 : active raid0 sda1[0] sdb1[1]
+ 314159265 blocks 64k chunks
+
+md11 : active (auto-read-only) raid1 sdb2[0] sdc2[1] sdc3[2](F) hda[4](S) ssdc2[3](S)
+ 4190208 blocks super 1.2 [2/2] [UU]
+ resync=PENDING
+
+md12 : active raid0 sdc2[0] sdd2[1]
+ 3886394368 blocks super 1.2 512k chunks
+
+md126 : active raid0 sdb[1] sdc[0]
+ 1855870976 blocks super external:/md127/0 128k chunks
+
+md219 : inactive sdb[2](S) sdc[1](S) sda[0](S)
+ 7932 blocks super external:imsm
+
+md00 : active raid0 xvdb[0]
+ 4186624 blocks super 1.2 256k chunks
+
+md120 : active linear sda1[1] sdb1[0]
+ 2095104 blocks super 1.2 0k rounding
+
+md101 : active (read-only) raid0 sdb[2] sdd[1] sdc[0]
+ 322560 blocks super 1.2 512k chunks
+
+unused devices:
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/proc/net
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/proc/net/dev
+Lines: 6
+Inter-| Receive | Transmit
+ face |bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed
+vethf345468: 648 8 0 0 0 0 0 0 438 5 0 0 0 0 0 0
+ lo: 1664039048 1566805 0 0 0 0 0 0 1664039048 1566805 0 0 0 0 0 0
+docker0: 2568 38 0 0 0 0 0 0 438 5 0 0 0 0 0 0
+ eth0: 874354587 1036395 0 0 0 0 0 0 563352563 732147 0 0 0 0 0 0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/proc/net/ip_vs
+Lines: 21
+IP Virtual Server version 1.2.1 (size=4096)
+Prot LocalAddress:Port Scheduler Flags
+ -> RemoteAddress:Port Forward Weight ActiveConn InActConn
+TCP C0A80016:0CEA wlc
+ -> C0A85216:0CEA Tunnel 100 248 2
+ -> C0A85318:0CEA Tunnel 100 248 2
+ -> C0A85315:0CEA Tunnel 100 248 1
+TCP C0A80039:0CEA wlc
+ -> C0A85416:0CEA Tunnel 0 0 0
+ -> C0A85215:0CEA Tunnel 100 1499 0
+ -> C0A83215:0CEA Tunnel 100 1498 0
+TCP C0A80037:0CEA wlc
+ -> C0A8321A:0CEA Tunnel 0 0 0
+ -> C0A83120:0CEA Tunnel 100 0 0
+TCP [2620:0000:0000:0000:0000:0000:0000:0001]:0050 sh
+ -> [2620:0000:0000:0000:0000:0000:0000:0002]:0050 Route 1 0 0
+ -> [2620:0000:0000:0000:0000:0000:0000:0003]:0050 Route 1 0 0
+ -> [2620:0000:0000:0000:0000:0000:0000:0004]:0050 Route 1 1 1
+FWM 10001000 wlc
+ -> C0A8321A:0CEA Route 0 0 1
+ -> C0A83215:0CEA Route 0 0 2
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/proc/net/ip_vs_stats
+Lines: 6
+ Total Incoming Outgoing Incoming Outgoing
+ Conns Packets Packets Bytes Bytes
+ 16AA370 E33656E5 0 51D8C8883AB3 0
+
+ Conns/s Pkts/s Pkts/s Bytes/s Bytes/s
+ 4 1FB3C 0 1282A8F 0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/proc/net/rpc
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/proc/net/rpc/nfs
+Lines: 5
+net 18628 0 18628 6
+rpc 4329785 0 4338291
+proc2 18 2 69 0 0 4410 0 0 0 0 0 0 0 0 0 0 0 99 2
+proc3 22 1 4084749 29200 94754 32580 186 47747 7981 8639 0 6356 0 6962 0 7958 0 0 241 4 4 2 39
+proc4 61 1 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/proc/net/rpc/nfsd
+Lines: 11
+rc 0 6 18622
+fh 0 0 0 0 0
+io 157286400 0
+th 8 0 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000
+ra 32 0 0 0 0 0 0 0 0 0 0 0
+net 18628 0 18628 6
+rpc 18628 0 0 0 0
+proc2 18 2 69 0 0 4410 0 0 0 0 0 0 0 0 0 0 0 99 2
+proc3 22 2 112 0 2719 111 0 0 0 0 0 0 0 0 0 0 0 27 216 0 2 1 0
+proc4 2 2 10853
+proc4ops 72 0 0 0 1098 2 0 0 0 0 8179 5896 0 0 0 0 5900 0 0 2 0 2 0 9609 0 2 150 1272 0 0 0 1236 0 0 0 0 3 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/proc/net/unix
+Lines: 6
+Num RefCount Protocol Flags Type St Inode Path
+0000000000000000: 00000002 00000000 00010000 0001 01 3442596 /var/run/postgresql/.s.PGSQL.5432
+0000000000000000: 0000000a 00000000 00010000 0005 01 10061 /run/udev/control
+0000000000000000: 00000007 00000000 00000000 0002 01 12392 /dev/log
+0000000000000000: 00000003 00000000 00000000 0001 03 4787297 /var/run/postgresql/.s.PGSQL.5432
+0000000000000000: 00000003 00000000 00000000 0001 03 5091797
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/proc/net/unix_without_inode
+Lines: 6
+Num RefCount Protocol Flags Type St Path
+0000000000000000: 00000002 00000000 00010000 0001 01 /var/run/postgresql/.s.PGSQL.5432
+0000000000000000: 0000000a 00000000 00010000 0005 01 /run/udev/control
+0000000000000000: 00000007 00000000 00000000 0002 01 /dev/log
+0000000000000000: 00000003 00000000 00000000 0001 03 /var/run/postgresql/.s.PGSQL.5432
+0000000000000000: 00000003 00000000 00000000 0001 03
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/proc/net/xfrm_stat
+Lines: 28
+XfrmInError 1
+XfrmInBufferError 2
+XfrmInHdrError 4
+XfrmInNoStates 3
+XfrmInStateProtoError 40
+XfrmInStateModeError 100
+XfrmInStateSeqError 6000
+XfrmInStateExpired 4
+XfrmInStateMismatch 23451
+XfrmInStateInvalid 55555
+XfrmInTmplMismatch 51
+XfrmInNoPols 65432
+XfrmInPolBlock 100
+XfrmInPolError 10000
+XfrmOutError 1000000
+XfrmOutBundleGenError 43321
+XfrmOutBundleCheckError 555
+XfrmOutNoStates 869
+XfrmOutStateProtoError 4542
+XfrmOutStateModeError 4
+XfrmOutStateSeqError 543
+XfrmOutStateExpired 565
+XfrmOutPolBlock 43456
+XfrmOutPolDead 7656
+XfrmOutPolError 1454
+XfrmFwdHdrError 6654
+XfrmOutStateInvalid 28765
+XfrmAcquireError 24532
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/proc/pressure
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/proc/pressure/cpu
+Lines: 1
+some avg10=0.10 avg60=2.00 avg300=3.85 total=15
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/proc/pressure/io
+Lines: 2
+some avg10=0.10 avg60=2.00 avg300=3.85 total=15
+full avg10=0.20 avg60=3.00 avg300=4.95 total=25
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/proc/pressure/memory
+Lines: 2
+some avg10=0.10 avg60=2.00 avg300=3.85 total=15
+full avg10=0.20 avg60=3.00 avg300=4.95 total=25
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/proc/self
+SymlinkTo: 26231
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/proc/stat
+Lines: 16
+cpu 301854 612 111922 8979004 3552 2 3944 0 0 0
+cpu0 44490 19 21045 1087069 220 1 3410 0 0 0
+cpu1 47869 23 16474 1110787 591 0 46 0 0 0
+cpu2 46504 36 15916 1112321 441 0 326 0 0 0
+cpu3 47054 102 15683 1113230 533 0 60 0 0 0
+cpu4 28413 25 10776 1140321 217 0 8 0 0 0
+cpu5 29271 101 11586 1136270 672 0 30 0 0 0
+cpu6 29152 36 10276 1139721 319 0 29 0 0 0
+cpu7 29098 268 10164 1139282 555 0 31 0 0 0
+intr 8885917 17 0 0 0 0 0 0 0 1 79281 0 0 0 0 0 0 0 231237 0 0 0 0 250586 103 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 223424 190745 13 906 1283803 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ctxt 38014093
+btime 1418183276
+processes 26442
+procs_running 2
+procs_blocked 1
+softirq 5057579 250191 1481983 1647 211099 186066 0 1783454 622196 12499 508444
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/proc/symlinktargets
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/proc/symlinktargets/README
+Lines: 2
+This directory contains some empty files that are the symlinks the files in the "fd" directory point to.
+They are otherwise ignored by the tests
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/proc/symlinktargets/abc
+Lines: 0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/proc/symlinktargets/def
+Lines: 0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/proc/symlinktargets/ghi
+Lines: 0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/proc/symlinktargets/uvw
+Lines: 0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/proc/symlinktargets/xyz
+Lines: 0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/block
+Mode: 775
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/block/dm-0
+Mode: 775
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/block/dm-0/stat
+Lines: 1
+6447303 0 710266738 1529043 953216 0 31201176 4557464 0 796160 6088971
+Mode: 664
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/block/sda
+Mode: 775
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/block/sda/stat
+Lines: 1
+9652963 396792 759304206 412943 8422549 6731723 286915323 13947418 0 5658367 19174573 1 2 3 12
+Mode: 664
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/class
+Mode: 775
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/class/infiniband
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/class/infiniband/mlx4_0
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/class/infiniband/mlx4_0/board_id
+Lines: 1
+SM_1141000001000
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/class/infiniband/mlx4_0/fw_ver
+Lines: 1
+2.31.5050
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/class/infiniband/mlx4_0/hca_type
+Lines: 1
+MT4099
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/class/infiniband/mlx4_0/ports
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/class/infiniband/mlx4_0/ports/1
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/class/infiniband/mlx4_0/ports/1/counters
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/class/infiniband/mlx4_0/ports/1/counters/excessive_buffer_overrun_errors
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/class/infiniband/mlx4_0/ports/1/counters/link_downed
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/class/infiniband/mlx4_0/ports/1/counters/link_error_recovery
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/class/infiniband/mlx4_0/ports/1/counters/local_link_integrity_errors
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/class/infiniband/mlx4_0/ports/1/counters/port_rcv_constraint_errors
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/class/infiniband/mlx4_0/ports/1/counters/port_rcv_data
+Lines: 1
+2221223609
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/class/infiniband/mlx4_0/ports/1/counters/port_rcv_errors
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/class/infiniband/mlx4_0/ports/1/counters/port_rcv_packets
+Lines: 1
+87169372
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/class/infiniband/mlx4_0/ports/1/counters/port_rcv_remote_physical_errors
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/class/infiniband/mlx4_0/ports/1/counters/port_rcv_switch_relay_errors
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/class/infiniband/mlx4_0/ports/1/counters/port_xmit_constraint_errors
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/class/infiniband/mlx4_0/ports/1/counters/port_xmit_data
+Lines: 1
+26509113295
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/class/infiniband/mlx4_0/ports/1/counters/port_xmit_discards
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/class/infiniband/mlx4_0/ports/1/counters/port_xmit_packets
+Lines: 1
+85734114
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/class/infiniband/mlx4_0/ports/1/counters/port_xmit_wait
+Lines: 1
+3599
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/class/infiniband/mlx4_0/ports/1/counters/symbol_error
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/class/infiniband/mlx4_0/ports/1/phys_state
+Lines: 1
+5: LinkUp
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/class/infiniband/mlx4_0/ports/1/rate
+Lines: 1
+40 Gb/sec (4X QDR)
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/class/infiniband/mlx4_0/ports/1/state
+Lines: 1
+4: ACTIVE
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/class/infiniband/mlx4_0/ports/2
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/class/infiniband/mlx4_0/ports/2/counters
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/class/infiniband/mlx4_0/ports/2/counters/excessive_buffer_overrun_errors
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/class/infiniband/mlx4_0/ports/2/counters/link_downed
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/class/infiniband/mlx4_0/ports/2/counters/link_error_recovery
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/class/infiniband/mlx4_0/ports/2/counters/local_link_integrity_errors
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/class/infiniband/mlx4_0/ports/2/counters/port_rcv_constraint_errors
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/class/infiniband/mlx4_0/ports/2/counters/port_rcv_data
+Lines: 1
+2460436784
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/class/infiniband/mlx4_0/ports/2/counters/port_rcv_errors
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/class/infiniband/mlx4_0/ports/2/counters/port_rcv_packets
+Lines: 1
+89332064
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/class/infiniband/mlx4_0/ports/2/counters/port_rcv_remote_physical_errors
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/class/infiniband/mlx4_0/ports/2/counters/port_rcv_switch_relay_errors
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/class/infiniband/mlx4_0/ports/2/counters/port_xmit_constraint_errors
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/class/infiniband/mlx4_0/ports/2/counters/port_xmit_data
+Lines: 1
+26540356890
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/class/infiniband/mlx4_0/ports/2/counters/port_xmit_discards
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/class/infiniband/mlx4_0/ports/2/counters/port_xmit_packets
+Lines: 1
+88622850
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/class/infiniband/mlx4_0/ports/2/counters/port_xmit_wait
+Lines: 1
+3846
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/class/infiniband/mlx4_0/ports/2/counters/symbol_error
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/class/infiniband/mlx4_0/ports/2/phys_state
+Lines: 1
+5: LinkUp
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/class/infiniband/mlx4_0/ports/2/rate
+Lines: 1
+40 Gb/sec (4X QDR)
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/class/infiniband/mlx4_0/ports/2/state
+Lines: 1
+4: ACTIVE
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/class/net
+Mode: 775
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/class/net/eth0
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/class/net/eth0/addr_assign_type
+Lines: 1
+3
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/class/net/eth0/addr_len
+Lines: 1
+6
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/class/net/eth0/address
+Lines: 1
+01:01:01:01:01:01
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/class/net/eth0/broadcast
+Lines: 1
+ff:ff:ff:ff:ff:ff
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/class/net/eth0/carrier
+Lines: 1
+1
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/class/net/eth0/carrier_changes
+Lines: 1
+2
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/class/net/eth0/carrier_down_count
+Lines: 1
+1
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/class/net/eth0/carrier_up_count
+Lines: 1
+1
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/class/net/eth0/dev_id
+Lines: 1
+0x20
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/class/net/eth0/dormant
+Lines: 1
+1
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/class/net/eth0/duplex
+Lines: 1
+full
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/class/net/eth0/flags
+Lines: 1
+0x1303
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/class/net/eth0/ifalias
+Lines: 0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/class/net/eth0/ifindex
+Lines: 1
+2
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/class/net/eth0/iflink
+Lines: 1
+2
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/class/net/eth0/link_mode
+Lines: 1
+1
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/class/net/eth0/mtu
+Lines: 1
+1500
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/class/net/eth0/name_assign_type
+Lines: 1
+2
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/class/net/eth0/netdev_group
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/class/net/eth0/operstate
+Lines: 1
+up
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/class/net/eth0/phys_port_id
+Lines: 0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/class/net/eth0/phys_port_name
+Lines: 0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/class/net/eth0/phys_switch_id
+Lines: 0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/class/net/eth0/speed
+Lines: 1
+1000
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/class/net/eth0/tx_queue_len
+Lines: 1
+1000
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/class/net/eth0/type
+Lines: 1
+1
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/class/power_supply
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/class/power_supply/AC
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/class/power_supply/AC/online
+Lines: 1
+0
+Mode: 444
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/class/power_supply/AC/type
+Lines: 1
+Mains
+Mode: 444
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/class/power_supply/AC/uevent
+Lines: 2
+POWER_SUPPLY_NAME=AC
+POWER_SUPPLY_ONLINE=0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/class/power_supply/BAT0
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/class/power_supply/BAT0/alarm
+Lines: 1
+2503000
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/class/power_supply/BAT0/capacity
+Lines: 1
+98
+Mode: 444
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/class/power_supply/BAT0/capacity_level
+Lines: 1
+Normal
+Mode: 444
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/class/power_supply/BAT0/charge_start_threshold
+Lines: 1
+95
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/class/power_supply/BAT0/charge_stop_threshold
+Lines: 1
+100
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/class/power_supply/BAT0/cycle_count
+Lines: 1
+0
+Mode: 444
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/class/power_supply/BAT0/energy_full
+Lines: 1
+50060000
+Mode: 444
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/class/power_supply/BAT0/energy_full_design
+Lines: 1
+47520000
+Mode: 444
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/class/power_supply/BAT0/energy_now
+Lines: 1
+49450000
+Mode: 444
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/class/power_supply/BAT0/manufacturer
+Lines: 1
+LGC
+Mode: 444
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/class/power_supply/BAT0/model_name
+Lines: 1
+LNV-45N1
+Mode: 444
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/class/power_supply/BAT0/power_now
+Lines: 1
+4830000
+Mode: 444
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/class/power_supply/BAT0/present
+Lines: 1
+1
+Mode: 444
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/class/power_supply/BAT0/serial_number
+Lines: 1
+38109
+Mode: 444
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/class/power_supply/BAT0/status
+Lines: 1
+Discharging
+Mode: 444
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/class/power_supply/BAT0/technology
+Lines: 1
+Li-ion
+Mode: 444
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/class/power_supply/BAT0/type
+Lines: 1
+Battery
+Mode: 444
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/class/power_supply/BAT0/uevent
+Lines: 16
+POWER_SUPPLY_NAME=BAT0
+POWER_SUPPLY_STATUS=Discharging
+POWER_SUPPLY_PRESENT=1
+POWER_SUPPLY_TECHNOLOGY=Li-ion
+POWER_SUPPLY_CYCLE_COUNT=0
+POWER_SUPPLY_VOLTAGE_MIN_DESIGN=10800000
+POWER_SUPPLY_VOLTAGE_NOW=12229000
+POWER_SUPPLY_POWER_NOW=4830000
+POWER_SUPPLY_ENERGY_FULL_DESIGN=47520000
+POWER_SUPPLY_ENERGY_FULL=50060000
+POWER_SUPPLY_ENERGY_NOW=49450000
+POWER_SUPPLY_CAPACITY=98
+POWER_SUPPLY_CAPACITY_LEVEL=Normal
+POWER_SUPPLY_MODEL_NAME=LNV-45N1
+POWER_SUPPLY_MANUFACTURER=LGC
+POWER_SUPPLY_SERIAL_NUMBER=38109
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/class/power_supply/BAT0/voltage_min_design
+Lines: 1
+10800000
+Mode: 444
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/class/power_supply/BAT0/voltage_now
+Lines: 1
+12229000
+Mode: 444
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/class/thermal
+Mode: 775
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/class/thermal/thermal_zone0
+Mode: 775
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/class/thermal/thermal_zone0/policy
+Lines: 1
+step_wise
+Mode: 664
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/class/thermal/thermal_zone0/temp
+Lines: 1
+49925
+Mode: 664
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/class/thermal/thermal_zone0/type
+Lines: 1
+bcm2835_thermal
+Mode: 664
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/class/thermal/thermal_zone1
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/class/thermal/thermal_zone1/mode
+Lines: 1
+enabled
+Mode: 664
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/class/thermal/thermal_zone1/passive
+Lines: 1
+0
+Mode: 664
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/class/thermal/thermal_zone1/policy
+Lines: 1
+step_wise
+Mode: 664
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/class/thermal/thermal_zone1/temp
+Lines: 1
+44000
+Mode: 664
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/class/thermal/thermal_zone1/type
+Lines: 1
+acpitz
+Mode: 664
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/devices
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/devices/pci0000:00
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/devices/pci0000:00/0000:00:0d.0
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/dirty_data
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_day
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_day/bypassed
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_day/cache_bypass_hits
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_day/cache_bypass_misses
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_day/cache_hit_ratio
+Lines: 1
+100
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_day/cache_hits
+Lines: 1
+289
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_day/cache_miss_collisions
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_day/cache_misses
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_day/cache_readaheads
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_five_minute
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_five_minute/bypassed
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_five_minute/cache_bypass_hits
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_five_minute/cache_bypass_misses
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_five_minute/cache_hit_ratio
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_five_minute/cache_hits
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_five_minute/cache_miss_collisions
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_five_minute/cache_misses
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_five_minute/cache_readaheads
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_hour
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_hour/bypassed
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_hour/cache_bypass_hits
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_hour/cache_bypass_misses
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_hour/cache_hit_ratio
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_hour/cache_hits
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_hour/cache_miss_collisions
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_hour/cache_misses
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_hour/cache_readaheads
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_total
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_total/bypassed
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_total/cache_bypass_hits
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_total/cache_bypass_misses
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_total/cache_hit_ratio
+Lines: 1
+100
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_total/cache_hits
+Lines: 1
+546
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_total/cache_miss_collisions
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_total/cache_misses
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_total/cache_readaheads
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata5
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata5/host4
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata5/host4/target4:0:0
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata5/host4/target4:0:0/4:0:0:0
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata5/host4/target4:0:0/4:0:0:0/block
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata5/host4/target4:0:0/4:0:0:0/block/sdc
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata5/host4/target4:0:0/4:0:0:0/block/sdc/bcache
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata5/host4/target4:0:0/4:0:0:0/block/sdc/bcache/io_errors
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata5/host4/target4:0:0/4:0:0:0/block/sdc/bcache/metadata_written
+Lines: 1
+512
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata5/host4/target4:0:0/4:0:0:0/block/sdc/bcache/priority_stats
+Lines: 5
+Unused: 99%
+Metadata: 0%
+Average: 10473
+Sectors per Q: 64
+Quantiles: [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 20946 20946 20946 20946 20946 20946 20946 20946 20946 20946 20946 20946 20946 20946 20946 20946]
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata5/host4/target4:0:0/4:0:0:0/block/sdc/bcache/written
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/devices/rbd
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/devices/rbd/0
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/devices/rbd/0/name
+Lines: 1
+demo
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/devices/rbd/0/pool
+Lines: 1
+iscsi-images
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/devices/rbd/1
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/devices/rbd/1/name
+Lines: 1
+wrong
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/devices/rbd/1/pool
+Lines: 1
+wrong-images
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/devices/system
+Mode: 775
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/devices/system/clocksource
+Mode: 775
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/devices/system/clocksource/clocksource0
+Mode: 775
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/devices/system/clocksource/clocksource0/available_clocksource
+Lines: 1
+tsc hpet acpi_pm
+Mode: 444
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/devices/system/clocksource/clocksource0/current_clocksource
+Lines: 1
+tsc
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/devices/system/cpu
+Mode: 775
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/devices/system/cpu/cpu0
+Mode: 775
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/devices/system/cpu/cpu0/cpufreq
+SymlinkTo: ../cpufreq/policy0
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/devices/system/cpu/cpu1
+Mode: 775
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/devices/system/cpu/cpu1/cpufreq
+Mode: 775
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/devices/system/cpu/cpu1/cpufreq/cpuinfo_cur_freq
+Lines: 1
+1200195
+Mode: 400
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/devices/system/cpu/cpu1/cpufreq/cpuinfo_max_freq
+Lines: 1
+3300000
+Mode: 664
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/devices/system/cpu/cpu1/cpufreq/cpuinfo_min_freq
+Lines: 1
+1200000
+Mode: 664
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/devices/system/cpu/cpu1/cpufreq/cpuinfo_transition_latency
+Lines: 1
+4294967295
+Mode: 664
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/devices/system/cpu/cpu1/cpufreq/related_cpus
+Lines: 1
+1
+Mode: 664
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/devices/system/cpu/cpu1/cpufreq/scaling_available_governors
+Lines: 1
+performance powersave
+Mode: 664
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/devices/system/cpu/cpu1/cpufreq/scaling_driver
+Lines: 1
+intel_pstate
+Mode: 664
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/devices/system/cpu/cpu1/cpufreq/scaling_governor
+Lines: 1
+powersave
+Mode: 664
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/devices/system/cpu/cpu1/cpufreq/scaling_max_freq
+Lines: 1
+3300000
+Mode: 664
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/devices/system/cpu/cpu1/cpufreq/scaling_min_freq
+Lines: 1
+1200000
+Mode: 664
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/devices/system/cpu/cpu1/cpufreq/scaling_setspeed
+Lines: 1
+
+Mode: 664
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/devices/system/cpu/cpufreq
+Mode: 775
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/devices/system/cpu/cpufreq/policy0
+Mode: 775
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/devices/system/cpu/cpufreq/policy0/affected_cpus
+Lines: 1
+0
+Mode: 444
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/devices/system/cpu/cpufreq/policy0/cpuinfo_max_freq
+Lines: 1
+2400000
+Mode: 444
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/devices/system/cpu/cpufreq/policy0/cpuinfo_min_freq
+Lines: 1
+800000
+Mode: 444
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/devices/system/cpu/cpufreq/policy0/cpuinfo_transition_latency
+Lines: 1
+0
+Mode: 444
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/devices/system/cpu/cpufreq/policy0/related_cpus
+Lines: 1
+0
+Mode: 444
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/devices/system/cpu/cpufreq/policy0/scaling_available_governors
+Lines: 1
+performance powersave
+Mode: 444
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/devices/system/cpu/cpufreq/policy0/scaling_cur_freq
+Lines: 1
+1219917
+Mode: 444
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/devices/system/cpu/cpufreq/policy0/scaling_driver
+Lines: 1
+intel_pstate
+Mode: 444
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/devices/system/cpu/cpufreq/policy0/scaling_governor
+Lines: 1
+powersave
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/devices/system/cpu/cpufreq/policy0/scaling_max_freq
+Lines: 1
+2400000
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/devices/system/cpu/cpufreq/policy0/scaling_min_freq
+Lines: 1
+800000
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/devices/system/cpu/cpufreq/policy0/scaling_setspeed
+Lines: 1
+
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/devices/system/cpu/cpufreq/policy1
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/fs
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/fs/bcache
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/average_key_size
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0
+Mode: 777
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/dirty_data
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_day
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_day/bypassed
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_day/cache_bypass_hits
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_day/cache_bypass_misses
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_day/cache_hit_ratio
+Lines: 1
+100
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_day/cache_hits
+Lines: 1
+289
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_day/cache_miss_collisions
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_day/cache_misses
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_day/cache_readaheads
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_five_minute
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_five_minute/bypassed
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_five_minute/cache_bypass_hits
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_five_minute/cache_bypass_misses
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_five_minute/cache_hit_ratio
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_five_minute/cache_hits
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_five_minute/cache_miss_collisions
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_five_minute/cache_misses
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_five_minute/cache_readaheads
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_hour
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_hour/bypassed
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_hour/cache_bypass_hits
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_hour/cache_bypass_misses
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_hour/cache_hit_ratio
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_hour/cache_hits
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_hour/cache_miss_collisions
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_hour/cache_misses
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_hour/cache_readaheads
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_total
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_total/bypassed
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_total/cache_bypass_hits
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_total/cache_bypass_misses
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_total/cache_hit_ratio
+Lines: 1
+100
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_total/cache_hits
+Lines: 1
+546
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_total/cache_miss_collisions
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_total/cache_misses
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_total/cache_readaheads
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/btree_cache_size
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/cache0
+Mode: 777
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/cache0/io_errors
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/cache0/metadata_written
+Lines: 1
+512
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/cache0/priority_stats
+Lines: 5
+Unused: 99%
+Metadata: 0%
+Average: 10473
+Sectors per Q: 64
+Quantiles: [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 20946 20946 20946 20946 20946 20946 20946 20946 20946 20946 20946 20946 20946 20946 20946 20946]
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/cache0/written
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/cache_available_percent
+Lines: 1
+100
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/congested
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/internal
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/internal/active_journal_entries
+Lines: 1
+1
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/internal/btree_nodes
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/internal/btree_read_average_duration_us
+Lines: 1
+1305
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/internal/cache_read_races
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/root_usage_percent
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_day
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_day/bypassed
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_day/cache_bypass_hits
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_day/cache_bypass_misses
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_day/cache_hit_ratio
+Lines: 1
+100
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_day/cache_hits
+Lines: 1
+289
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_day/cache_miss_collisions
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_day/cache_misses
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_day/cache_readaheads
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_five_minute
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_five_minute/bypassed
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_five_minute/cache_bypass_hits
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_five_minute/cache_bypass_misses
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_five_minute/cache_hit_ratio
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_five_minute/cache_hits
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_five_minute/cache_miss_collisions
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_five_minute/cache_misses
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_five_minute/cache_readaheads
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_hour
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_hour/bypassed
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_hour/cache_bypass_hits
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_hour/cache_bypass_misses
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_hour/cache_hit_ratio
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_hour/cache_hits
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_hour/cache_miss_collisions
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_hour/cache_misses
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_hour/cache_readaheads
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_total
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_total/bypassed
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_total/cache_bypass_hits
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_total/cache_bypass_misses
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_total/cache_hit_ratio
+Lines: 1
+100
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_total/cache_hits
+Lines: 1
+546
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_total/cache_miss_collisions
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_total/cache_misses
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_total/cache_readaheads
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/tree_depth
+Lines: 1
+0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/fs/xfs
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/fs/xfs/sda1
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/fs/xfs/sda1/stats
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/fs/xfs/sda1/stats/stats
+Lines: 1
+extent_alloc 1 0 0 0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/fs/xfs/sdb1
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/fs/xfs/sdb1/stats
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/fs/xfs/sdb1/stats/stats
+Lines: 1
+extent_alloc 2 0 0 0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/kernel
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/kernel/config
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/kernel/config/target
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/kernel/config/target/core
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/kernel/config/target/core/fileio_0
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/kernel/config/target/core/fileio_1
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/kernel/config/target/core/fileio_1/file_lio_1G
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/kernel/config/target/core/fileio_1/file_lio_1G/enable
+Lines: 1
+1
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/kernel/config/target/core/fileio_1/file_lio_1G/udev_path
+Lines: 1
+/home/iscsi/file_back_1G
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/kernel/config/target/core/iblock_0
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/kernel/config/target/core/iblock_0/block_lio_rbd1
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/kernel/config/target/core/iblock_0/block_lio_rbd1/enable
+Lines: 1
+1
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/kernel/config/target/core/iblock_0/block_lio_rbd1/udev_path
+Lines: 1
+/dev/rbd1
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/kernel/config/target/core/rbd_0
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/kernel/config/target/core/rbd_0/iscsi-images-demo
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/kernel/config/target/core/rbd_0/iscsi-images-demo/enable
+Lines: 1
+1
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/kernel/config/target/core/rbd_0/iscsi-images-demo/udev_path
+Lines: 1
+/dev/rbd/iscsi-images/demo
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/kernel/config/target/core/rd_mcp_119
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/kernel/config/target/core/rd_mcp_119/ramdisk_lio_1G
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/kernel/config/target/core/rd_mcp_119/ramdisk_lio_1G/enable
+Lines: 1
+1
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/kernel/config/target/core/rd_mcp_119/ramdisk_lio_1G/udev_path
+Lines: 0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/kernel/config/target/iscsi
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/kernel/config/target/iscsi/iqn.2003-01.org.linux-iscsi.osd1.x8664:sn.8888bbbbddd0
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/kernel/config/target/iscsi/iqn.2003-01.org.linux-iscsi.osd1.x8664:sn.8888bbbbddd0/tpgt_1
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/kernel/config/target/iscsi/iqn.2003-01.org.linux-iscsi.osd1.x8664:sn.8888bbbbddd0/tpgt_1/enable
+Lines: 1
+1
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/kernel/config/target/iscsi/iqn.2003-01.org.linux-iscsi.osd1.x8664:sn.8888bbbbddd0/tpgt_1/lun
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/kernel/config/target/iscsi/iqn.2003-01.org.linux-iscsi.osd1.x8664:sn.8888bbbbddd0/tpgt_1/lun/lun_0
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/kernel/config/target/iscsi/iqn.2003-01.org.linux-iscsi.osd1.x8664:sn.8888bbbbddd0/tpgt_1/lun/lun_0/7f4a4eb56d
+SymlinkTo: ../../../../../../target/core/rd_mcp_119/ramdisk_lio_1G
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/kernel/config/target/iscsi/iqn.2003-01.org.linux-iscsi.osd1.x8664:sn.8888bbbbddd0/tpgt_1/lun/lun_0/statistics
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/kernel/config/target/iscsi/iqn.2003-01.org.linux-iscsi.osd1.x8664:sn.8888bbbbddd0/tpgt_1/lun/lun_0/statistics/scsi_tgt_port
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/kernel/config/target/iscsi/iqn.2003-01.org.linux-iscsi.osd1.x8664:sn.8888bbbbddd0/tpgt_1/lun/lun_0/statistics/scsi_tgt_port/in_cmds
+Lines: 1
+204950
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/kernel/config/target/iscsi/iqn.2003-01.org.linux-iscsi.osd1.x8664:sn.8888bbbbddd0/tpgt_1/lun/lun_0/statistics/scsi_tgt_port/read_mbytes
+Lines: 1
+10325
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/kernel/config/target/iscsi/iqn.2003-01.org.linux-iscsi.osd1.x8664:sn.8888bbbbddd0/tpgt_1/lun/lun_0/statistics/scsi_tgt_port/write_mbytes
+Lines: 1
+40325
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/kernel/config/target/iscsi/iqn.2003-01.org.linux-iscsi.osd1.x8664:sn.abcd1abcd2ab
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/kernel/config/target/iscsi/iqn.2003-01.org.linux-iscsi.osd1.x8664:sn.abcd1abcd2ab/tpgt_1
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/kernel/config/target/iscsi/iqn.2003-01.org.linux-iscsi.osd1.x8664:sn.abcd1abcd2ab/tpgt_1/enable
+Lines: 1
+1
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/kernel/config/target/iscsi/iqn.2003-01.org.linux-iscsi.osd1.x8664:sn.abcd1abcd2ab/tpgt_1/lun
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/kernel/config/target/iscsi/iqn.2003-01.org.linux-iscsi.osd1.x8664:sn.abcd1abcd2ab/tpgt_1/lun/lun_0
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/kernel/config/target/iscsi/iqn.2003-01.org.linux-iscsi.osd1.x8664:sn.abcd1abcd2ab/tpgt_1/lun/lun_0/795b7c7026
+SymlinkTo: ../../../../../../target/core/iblock_0/block_lio_rbd1
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/kernel/config/target/iscsi/iqn.2003-01.org.linux-iscsi.osd1.x8664:sn.abcd1abcd2ab/tpgt_1/lun/lun_0/statistics
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/kernel/config/target/iscsi/iqn.2003-01.org.linux-iscsi.osd1.x8664:sn.abcd1abcd2ab/tpgt_1/lun/lun_0/statistics/scsi_tgt_port
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/kernel/config/target/iscsi/iqn.2003-01.org.linux-iscsi.osd1.x8664:sn.abcd1abcd2ab/tpgt_1/lun/lun_0/statistics/scsi_tgt_port/in_cmds
+Lines: 1
+104950
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/kernel/config/target/iscsi/iqn.2003-01.org.linux-iscsi.osd1.x8664:sn.abcd1abcd2ab/tpgt_1/lun/lun_0/statistics/scsi_tgt_port/read_mbytes
+Lines: 1
+20095
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/kernel/config/target/iscsi/iqn.2003-01.org.linux-iscsi.osd1.x8664:sn.abcd1abcd2ab/tpgt_1/lun/lun_0/statistics/scsi_tgt_port/write_mbytes
+Lines: 1
+71235
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/kernel/config/target/iscsi/iqn.2016-11.org.linux-iscsi.igw.x86:dev.rbd0
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/kernel/config/target/iscsi/iqn.2016-11.org.linux-iscsi.igw.x86:dev.rbd0/tpgt_1
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/kernel/config/target/iscsi/iqn.2016-11.org.linux-iscsi.igw.x86:dev.rbd0/tpgt_1/enable
+Lines: 1
+1
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/kernel/config/target/iscsi/iqn.2016-11.org.linux-iscsi.igw.x86:dev.rbd0/tpgt_1/lun
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/kernel/config/target/iscsi/iqn.2016-11.org.linux-iscsi.igw.x86:dev.rbd0/tpgt_1/lun/lun_0
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/kernel/config/target/iscsi/iqn.2016-11.org.linux-iscsi.igw.x86:dev.rbd0/tpgt_1/lun/lun_0/fff5e16686
+SymlinkTo: ../../../../../../target/core/fileio_1/file_lio_1G
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/kernel/config/target/iscsi/iqn.2016-11.org.linux-iscsi.igw.x86:dev.rbd0/tpgt_1/lun/lun_0/statistics
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/kernel/config/target/iscsi/iqn.2016-11.org.linux-iscsi.igw.x86:dev.rbd0/tpgt_1/lun/lun_0/statistics/scsi_tgt_port
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/kernel/config/target/iscsi/iqn.2016-11.org.linux-iscsi.igw.x86:dev.rbd0/tpgt_1/lun/lun_0/statistics/scsi_tgt_port/in_cmds
+Lines: 1
+301950
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/kernel/config/target/iscsi/iqn.2016-11.org.linux-iscsi.igw.x86:dev.rbd0/tpgt_1/lun/lun_0/statistics/scsi_tgt_port/read_mbytes
+Lines: 1
+10195
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/kernel/config/target/iscsi/iqn.2016-11.org.linux-iscsi.igw.x86:dev.rbd0/tpgt_1/lun/lun_0/statistics/scsi_tgt_port/write_mbytes
+Lines: 1
+30195
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/kernel/config/target/iscsi/iqn.2016-11.org.linux-iscsi.igw.x86:sn.ramdemo
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/kernel/config/target/iscsi/iqn.2016-11.org.linux-iscsi.igw.x86:sn.ramdemo/tpgt_1
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/kernel/config/target/iscsi/iqn.2016-11.org.linux-iscsi.igw.x86:sn.ramdemo/tpgt_1/enable
+Lines: 1
+1
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/kernel/config/target/iscsi/iqn.2016-11.org.linux-iscsi.igw.x86:sn.ramdemo/tpgt_1/lun
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/kernel/config/target/iscsi/iqn.2016-11.org.linux-iscsi.igw.x86:sn.ramdemo/tpgt_1/lun/lun_0
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/kernel/config/target/iscsi/iqn.2016-11.org.linux-iscsi.igw.x86:sn.ramdemo/tpgt_1/lun/lun_0/eba1edf893
+SymlinkTo: ../../../../../../target/core/rbd_0/iscsi-images-demo
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/kernel/config/target/iscsi/iqn.2016-11.org.linux-iscsi.igw.x86:sn.ramdemo/tpgt_1/lun/lun_0/statistics
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/sys/kernel/config/target/iscsi/iqn.2016-11.org.linux-iscsi.igw.x86:sn.ramdemo/tpgt_1/lun/lun_0/statistics/scsi_tgt_port
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/kernel/config/target/iscsi/iqn.2016-11.org.linux-iscsi.igw.x86:sn.ramdemo/tpgt_1/lun/lun_0/statistics/scsi_tgt_port/in_cmds
+Lines: 1
+1234
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/kernel/config/target/iscsi/iqn.2016-11.org.linux-iscsi.igw.x86:sn.ramdemo/tpgt_1/lun/lun_0/statistics/scsi_tgt_port/read_mbytes
+Lines: 1
+1504
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/sys/kernel/config/target/iscsi/iqn.2016-11.org.linux-iscsi.igw.x86:sn.ramdemo/tpgt_1/lun/lun_0/statistics/scsi_tgt_port/write_mbytes
+Lines: 1
+4733
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
diff --git a/vendor/github.com/prometheus/procfs/fs.go b/vendor/github.com/prometheus/procfs/fs.go
new file mode 100644
index 0000000..0102ab0
--- /dev/null
+++ b/vendor/github.com/prometheus/procfs/fs.go
@@ -0,0 +1,43 @@
+// Copyright 2018 The Prometheus Authors
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package procfs
+
+import (
+ "github.com/prometheus/procfs/internal/fs"
+)
+
+// FS represents the pseudo-filesystem sys, which provides an interface to
+// kernel data structures.
+type FS struct {
+ proc fs.FS
+}
+
+// DefaultMountPoint is the common mount point of the proc filesystem.
+const DefaultMountPoint = fs.DefaultProcMountPoint
+
+// NewDefaultFS returns a new proc FS mounted under the default proc mountPoint.
+// It will error if the mount point directory can't be read or is a file.
+func NewDefaultFS() (FS, error) {
+ return NewFS(DefaultMountPoint)
+}
+
+// NewFS returns a new proc FS mounted under the given proc mountPoint. It will error
+// if the mount point directory can't be read or is a file.
+func NewFS(mountPoint string) (FS, error) {
+ fs, err := fs.NewFS(mountPoint)
+ if err != nil {
+ return FS{}, err
+ }
+ return FS{fs}, nil
+}
diff --git a/vendor/github.com/prometheus/procfs/go.mod b/vendor/github.com/prometheus/procfs/go.mod
new file mode 100644
index 0000000..b2f8cca
--- /dev/null
+++ b/vendor/github.com/prometheus/procfs/go.mod
@@ -0,0 +1,6 @@
+module github.com/prometheus/procfs
+
+require (
+ github.com/google/go-cmp v0.3.0
+ golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4
+)
diff --git a/vendor/github.com/prometheus/procfs/go.sum b/vendor/github.com/prometheus/procfs/go.sum
new file mode 100644
index 0000000..db54133
--- /dev/null
+++ b/vendor/github.com/prometheus/procfs/go.sum
@@ -0,0 +1,4 @@
+github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY=
+github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw=
+golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
diff --git a/vendor/github.com/prometheus/procfs/internal/fs/fs.go b/vendor/github.com/prometheus/procfs/internal/fs/fs.go
new file mode 100644
index 0000000..7ddfd6b
--- /dev/null
+++ b/vendor/github.com/prometheus/procfs/internal/fs/fs.go
@@ -0,0 +1,55 @@
+// Copyright 2019 The Prometheus Authors
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package fs
+
+import (
+ "fmt"
+ "os"
+ "path/filepath"
+)
+
+const (
+ // DefaultProcMountPoint is the common mount point of the proc filesystem.
+ DefaultProcMountPoint = "/proc"
+
+ // DefaultSysMountPoint is the common mount point of the sys filesystem.
+ DefaultSysMountPoint = "/sys"
+
+ // DefaultConfigfsMountPoint is the commont mount point of the configfs
+ DefaultConfigfsMountPoint = "/sys/kernel/config"
+)
+
+// FS represents a pseudo-filesystem, normally /proc or /sys, which provides an
+// interface to kernel data structures.
+type FS string
+
+// NewFS returns a new FS mounted under the given mountPoint. It will error
+// if the mount point can't be read.
+func NewFS(mountPoint string) (FS, error) {
+ info, err := os.Stat(mountPoint)
+ if err != nil {
+ return "", fmt.Errorf("could not read %s: %s", mountPoint, err)
+ }
+ if !info.IsDir() {
+ return "", fmt.Errorf("mount point %s is not a directory", mountPoint)
+ }
+
+ return FS(mountPoint), nil
+}
+
+// Path appends the given path elements to the filesystem path, adding separators
+// as necessary.
+func (fs FS) Path(p ...string) string {
+ return filepath.Join(append([]string{string(fs)}, p...)...)
+}
diff --git a/vendor/github.com/prometheus/procfs/ipvs.go b/vendor/github.com/prometheus/procfs/ipvs.go
new file mode 100644
index 0000000..2d6cb8d
--- /dev/null
+++ b/vendor/github.com/prometheus/procfs/ipvs.go
@@ -0,0 +1,239 @@
+// Copyright 2018 The Prometheus Authors
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package procfs
+
+import (
+ "bufio"
+ "encoding/hex"
+ "errors"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "net"
+ "os"
+ "strconv"
+ "strings"
+)
+
+// IPVSStats holds IPVS statistics, as exposed by the kernel in `/proc/net/ip_vs_stats`.
+type IPVSStats struct {
+ // Total count of connections.
+ Connections uint64
+ // Total incoming packages processed.
+ IncomingPackets uint64
+ // Total outgoing packages processed.
+ OutgoingPackets uint64
+ // Total incoming traffic.
+ IncomingBytes uint64
+ // Total outgoing traffic.
+ OutgoingBytes uint64
+}
+
+// IPVSBackendStatus holds current metrics of one virtual / real address pair.
+type IPVSBackendStatus struct {
+ // The local (virtual) IP address.
+ LocalAddress net.IP
+ // The remote (real) IP address.
+ RemoteAddress net.IP
+ // The local (virtual) port.
+ LocalPort uint16
+ // The remote (real) port.
+ RemotePort uint16
+ // The local firewall mark
+ LocalMark string
+ // The transport protocol (TCP, UDP).
+ Proto string
+ // The current number of active connections for this virtual/real address pair.
+ ActiveConn uint64
+ // The current number of inactive connections for this virtual/real address pair.
+ InactConn uint64
+ // The current weight of this virtual/real address pair.
+ Weight uint64
+}
+
+// IPVSStats reads the IPVS statistics from the specified `proc` filesystem.
+func (fs FS) IPVSStats() (IPVSStats, error) {
+ file, err := os.Open(fs.proc.Path("net/ip_vs_stats"))
+ if err != nil {
+ return IPVSStats{}, err
+ }
+ defer file.Close()
+
+ return parseIPVSStats(file)
+}
+
+// parseIPVSStats performs the actual parsing of `ip_vs_stats`.
+func parseIPVSStats(file io.Reader) (IPVSStats, error) {
+ var (
+ statContent []byte
+ statLines []string
+ statFields []string
+ stats IPVSStats
+ )
+
+ statContent, err := ioutil.ReadAll(file)
+ if err != nil {
+ return IPVSStats{}, err
+ }
+
+ statLines = strings.SplitN(string(statContent), "\n", 4)
+ if len(statLines) != 4 {
+ return IPVSStats{}, errors.New("ip_vs_stats corrupt: too short")
+ }
+
+ statFields = strings.Fields(statLines[2])
+ if len(statFields) != 5 {
+ return IPVSStats{}, errors.New("ip_vs_stats corrupt: unexpected number of fields")
+ }
+
+ stats.Connections, err = strconv.ParseUint(statFields[0], 16, 64)
+ if err != nil {
+ return IPVSStats{}, err
+ }
+ stats.IncomingPackets, err = strconv.ParseUint(statFields[1], 16, 64)
+ if err != nil {
+ return IPVSStats{}, err
+ }
+ stats.OutgoingPackets, err = strconv.ParseUint(statFields[2], 16, 64)
+ if err != nil {
+ return IPVSStats{}, err
+ }
+ stats.IncomingBytes, err = strconv.ParseUint(statFields[3], 16, 64)
+ if err != nil {
+ return IPVSStats{}, err
+ }
+ stats.OutgoingBytes, err = strconv.ParseUint(statFields[4], 16, 64)
+ if err != nil {
+ return IPVSStats{}, err
+ }
+
+ return stats, nil
+}
+
+// IPVSBackendStatus reads and returns the status of all (virtual,real) server pairs from the specified `proc` filesystem.
+func (fs FS) IPVSBackendStatus() ([]IPVSBackendStatus, error) {
+ file, err := os.Open(fs.proc.Path("net/ip_vs"))
+ if err != nil {
+ return nil, err
+ }
+ defer file.Close()
+
+ return parseIPVSBackendStatus(file)
+}
+
+func parseIPVSBackendStatus(file io.Reader) ([]IPVSBackendStatus, error) {
+ var (
+ status []IPVSBackendStatus
+ scanner = bufio.NewScanner(file)
+ proto string
+ localMark string
+ localAddress net.IP
+ localPort uint16
+ err error
+ )
+
+ for scanner.Scan() {
+ fields := strings.Fields(scanner.Text())
+ if len(fields) == 0 {
+ continue
+ }
+ switch {
+ case fields[0] == "IP" || fields[0] == "Prot" || fields[1] == "RemoteAddress:Port":
+ continue
+ case fields[0] == "TCP" || fields[0] == "UDP":
+ if len(fields) < 2 {
+ continue
+ }
+ proto = fields[0]
+ localMark = ""
+ localAddress, localPort, err = parseIPPort(fields[1])
+ if err != nil {
+ return nil, err
+ }
+ case fields[0] == "FWM":
+ if len(fields) < 2 {
+ continue
+ }
+ proto = fields[0]
+ localMark = fields[1]
+ localAddress = nil
+ localPort = 0
+ case fields[0] == "->":
+ if len(fields) < 6 {
+ continue
+ }
+ remoteAddress, remotePort, err := parseIPPort(fields[1])
+ if err != nil {
+ return nil, err
+ }
+ weight, err := strconv.ParseUint(fields[3], 10, 64)
+ if err != nil {
+ return nil, err
+ }
+ activeConn, err := strconv.ParseUint(fields[4], 10, 64)
+ if err != nil {
+ return nil, err
+ }
+ inactConn, err := strconv.ParseUint(fields[5], 10, 64)
+ if err != nil {
+ return nil, err
+ }
+ status = append(status, IPVSBackendStatus{
+ LocalAddress: localAddress,
+ LocalPort: localPort,
+ LocalMark: localMark,
+ RemoteAddress: remoteAddress,
+ RemotePort: remotePort,
+ Proto: proto,
+ Weight: weight,
+ ActiveConn: activeConn,
+ InactConn: inactConn,
+ })
+ }
+ }
+ return status, nil
+}
+
+func parseIPPort(s string) (net.IP, uint16, error) {
+ var (
+ ip net.IP
+ err error
+ )
+
+ switch len(s) {
+ case 13:
+ ip, err = hex.DecodeString(s[0:8])
+ if err != nil {
+ return nil, 0, err
+ }
+ case 46:
+ ip = net.ParseIP(s[1:40])
+ if ip == nil {
+ return nil, 0, fmt.Errorf("invalid IPv6 address: %s", s[1:40])
+ }
+ default:
+ return nil, 0, fmt.Errorf("unexpected IP:Port: %s", s)
+ }
+
+ portString := s[len(s)-4:]
+ if len(portString) != 4 {
+ return nil, 0, fmt.Errorf("unexpected port string format: %s", portString)
+ }
+ port, err := strconv.ParseUint(portString, 16, 16)
+ if err != nil {
+ return nil, 0, err
+ }
+
+ return ip, uint16(port), nil
+}
diff --git a/vendor/github.com/prometheus/procfs/mdstat.go b/vendor/github.com/prometheus/procfs/mdstat.go
new file mode 100644
index 0000000..2af3ada
--- /dev/null
+++ b/vendor/github.com/prometheus/procfs/mdstat.go
@@ -0,0 +1,194 @@
+// Copyright 2018 The Prometheus Authors
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package procfs
+
+import (
+ "fmt"
+ "io/ioutil"
+ "regexp"
+ "strconv"
+ "strings"
+)
+
+var (
+ statusLineRE = regexp.MustCompile(`(\d+) blocks .*\[(\d+)/(\d+)\] \[[U_]+\]`)
+ recoveryLineRE = regexp.MustCompile(`\((\d+)/\d+\)`)
+)
+
+// MDStat holds info parsed from /proc/mdstat.
+type MDStat struct {
+ // Name of the device.
+ Name string
+ // activity-state of the device.
+ ActivityState string
+ // Number of active disks.
+ DisksActive int64
+ // Total number of disks the device requires.
+ DisksTotal int64
+ // Number of failed disks.
+ DisksFailed int64
+ // Spare disks in the device.
+ DisksSpare int64
+ // Number of blocks the device holds.
+ BlocksTotal int64
+ // Number of blocks on the device that are in sync.
+ BlocksSynced int64
+}
+
+// MDStat parses an mdstat-file (/proc/mdstat) and returns a slice of
+// structs containing the relevant info. More information available here:
+// https://raid.wiki.kernel.org/index.php/Mdstat
+func (fs FS) MDStat() ([]MDStat, error) {
+ data, err := ioutil.ReadFile(fs.proc.Path("mdstat"))
+ if err != nil {
+ return nil, fmt.Errorf("error parsing mdstat %s: %s", fs.proc.Path("mdstat"), err)
+ }
+ mdstat, err := parseMDStat(data)
+ if err != nil {
+ return nil, fmt.Errorf("error parsing mdstat %s: %s", fs.proc.Path("mdstat"), err)
+ }
+ return mdstat, nil
+}
+
+// parseMDStat parses data from mdstat file (/proc/mdstat) and returns a slice of
+// structs containing the relevant info.
+func parseMDStat(mdStatData []byte) ([]MDStat, error) {
+ mdStats := []MDStat{}
+ lines := strings.Split(string(mdStatData), "\n")
+
+ for i, line := range lines {
+ if strings.TrimSpace(line) == "" || line[0] == ' ' ||
+ strings.HasPrefix(line, "Personalities") ||
+ strings.HasPrefix(line, "unused") {
+ continue
+ }
+
+ deviceFields := strings.Fields(line)
+ if len(deviceFields) < 3 {
+ return nil, fmt.Errorf("not enough fields in mdline (expected at least 3): %s", line)
+ }
+ mdName := deviceFields[0] // mdx
+ state := deviceFields[2] // active or inactive
+
+ if len(lines) <= i+3 {
+ return nil, fmt.Errorf(
+ "error parsing %s: too few lines for md device",
+ mdName,
+ )
+ }
+
+ // Failed disks have the suffix (F) & Spare disks have the suffix (S).
+ fail := int64(strings.Count(line, "(F)"))
+ spare := int64(strings.Count(line, "(S)"))
+ active, total, size, err := evalStatusLine(lines[i], lines[i+1])
+
+ if err != nil {
+ return nil, fmt.Errorf("error parsing md device lines: %s", err)
+ }
+
+ syncLineIdx := i + 2
+ if strings.Contains(lines[i+2], "bitmap") { // skip bitmap line
+ syncLineIdx++
+ }
+
+ // If device is syncing at the moment, get the number of currently
+ // synced bytes, otherwise that number equals the size of the device.
+ syncedBlocks := size
+ recovering := strings.Contains(lines[syncLineIdx], "recovery")
+ resyncing := strings.Contains(lines[syncLineIdx], "resync")
+
+ // Append recovery and resyncing state info.
+ if recovering || resyncing {
+ if recovering {
+ state = "recovering"
+ } else {
+ state = "resyncing"
+ }
+
+ // Handle case when resync=PENDING or resync=DELAYED.
+ if strings.Contains(lines[syncLineIdx], "PENDING") ||
+ strings.Contains(lines[syncLineIdx], "DELAYED") {
+ syncedBlocks = 0
+ } else {
+ syncedBlocks, err = evalRecoveryLine(lines[syncLineIdx])
+ if err != nil {
+ return nil, fmt.Errorf("error parsing sync line in md device %s: %s", mdName, err)
+ }
+ }
+ }
+
+ mdStats = append(mdStats, MDStat{
+ Name: mdName,
+ ActivityState: state,
+ DisksActive: active,
+ DisksFailed: fail,
+ DisksSpare: spare,
+ DisksTotal: total,
+ BlocksTotal: size,
+ BlocksSynced: syncedBlocks,
+ })
+ }
+
+ return mdStats, nil
+}
+
+func evalStatusLine(deviceLine, statusLine string) (active, total, size int64, err error) {
+
+ sizeStr := strings.Fields(statusLine)[0]
+ size, err = strconv.ParseInt(sizeStr, 10, 64)
+ if err != nil {
+ return 0, 0, 0, fmt.Errorf("unexpected statusLine %s: %s", statusLine, err)
+ }
+
+ if strings.Contains(deviceLine, "raid0") || strings.Contains(deviceLine, "linear") {
+ // In the device deviceLine, only disks have a number associated with them in [].
+ total = int64(strings.Count(deviceLine, "["))
+ return total, total, size, nil
+ }
+
+ if strings.Contains(deviceLine, "inactive") {
+ return 0, 0, size, nil
+ }
+
+ matches := statusLineRE.FindStringSubmatch(statusLine)
+ if len(matches) != 4 {
+ return 0, 0, 0, fmt.Errorf("couldn't find all the substring matches: %s", statusLine)
+ }
+
+ total, err = strconv.ParseInt(matches[2], 10, 64)
+ if err != nil {
+ return 0, 0, 0, fmt.Errorf("unexpected statusLine %s: %s", statusLine, err)
+ }
+
+ active, err = strconv.ParseInt(matches[3], 10, 64)
+ if err != nil {
+ return 0, 0, 0, fmt.Errorf("unexpected statusLine %s: %s", statusLine, err)
+ }
+
+ return active, total, size, nil
+}
+
+func evalRecoveryLine(recoveryLine string) (syncedBlocks int64, err error) {
+ matches := recoveryLineRE.FindStringSubmatch(recoveryLine)
+ if len(matches) != 2 {
+ return 0, fmt.Errorf("unexpected recoveryLine: %s", recoveryLine)
+ }
+
+ syncedBlocks, err = strconv.ParseInt(matches[1], 10, 64)
+ if err != nil {
+ return 0, fmt.Errorf("%s in recoveryLine: %s", err, recoveryLine)
+ }
+
+ return syncedBlocks, nil
+}
diff --git a/vendor/github.com/prometheus/procfs/mountinfo.go b/vendor/github.com/prometheus/procfs/mountinfo.go
new file mode 100644
index 0000000..61fa618
--- /dev/null
+++ b/vendor/github.com/prometheus/procfs/mountinfo.go
@@ -0,0 +1,178 @@
+// Copyright 2019 The Prometheus Authors
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package procfs
+
+import (
+ "bufio"
+ "fmt"
+ "io"
+ "os"
+ "strconv"
+ "strings"
+)
+
+var validOptionalFields = map[string]bool{
+ "shared": true,
+ "master": true,
+ "propagate_from": true,
+ "unbindable": true,
+}
+
+// A MountInfo is a type that describes the details, options
+// for each mount, parsed from /proc/self/mountinfo.
+// The fields described in each entry of /proc/self/mountinfo
+// is described in the following man page.
+// http://man7.org/linux/man-pages/man5/proc.5.html
+type MountInfo struct {
+ // Unique Id for the mount
+ MountId int
+ // The Id of the parent mount
+ ParentId int
+ // The value of `st_dev` for the files on this FS
+ MajorMinorVer string
+ // The pathname of the directory in the FS that forms
+ // the root for this mount
+ Root string
+ // The pathname of the mount point relative to the root
+ MountPoint string
+ // Mount options
+ Options map[string]string
+ // Zero or more optional fields
+ OptionalFields map[string]string
+ // The Filesystem type
+ FSType string
+ // FS specific information or "none"
+ Source string
+ // Superblock options
+ SuperOptions map[string]string
+}
+
+// Returns part of the mountinfo line, if it exists, else an empty string.
+func getStringSliceElement(parts []string, idx int, defaultValue string) string {
+ if idx >= len(parts) {
+ return defaultValue
+ }
+ return parts[idx]
+}
+
+// Reads each line of the mountinfo file, and returns a list of formatted MountInfo structs.
+func parseMountInfo(r io.Reader) ([]*MountInfo, error) {
+ mounts := []*MountInfo{}
+ scanner := bufio.NewScanner(r)
+ for scanner.Scan() {
+ mountString := scanner.Text()
+ parsedMounts, err := parseMountInfoString(mountString)
+ if err != nil {
+ return nil, err
+ }
+ mounts = append(mounts, parsedMounts)
+ }
+
+ err := scanner.Err()
+ return mounts, err
+}
+
+// Parses a mountinfo file line, and converts it to a MountInfo struct.
+// An important check here is to see if the hyphen separator, as if it does not exist,
+// it means that the line is malformed.
+func parseMountInfoString(mountString string) (*MountInfo, error) {
+ var err error
+
+ // OptionalFields can be zero, hence these checks to ensure we do not populate the wrong values in the wrong spots
+ separatorIndex := strings.Index(mountString, "-")
+ if separatorIndex == -1 {
+ return nil, fmt.Errorf("no separator found in mountinfo string: %s", mountString)
+ }
+ beforeFields := strings.Fields(mountString[:separatorIndex])
+ afterFields := strings.Fields(mountString[separatorIndex+1:])
+ if (len(beforeFields) + len(afterFields)) < 7 {
+ return nil, fmt.Errorf("too few fields")
+ }
+
+ mount := &MountInfo{
+ MajorMinorVer: getStringSliceElement(beforeFields, 2, ""),
+ Root: getStringSliceElement(beforeFields, 3, ""),
+ MountPoint: getStringSliceElement(beforeFields, 4, ""),
+ Options: mountOptionsParser(getStringSliceElement(beforeFields, 5, "")),
+ OptionalFields: nil,
+ FSType: getStringSliceElement(afterFields, 0, ""),
+ Source: getStringSliceElement(afterFields, 1, ""),
+ SuperOptions: mountOptionsParser(getStringSliceElement(afterFields, 2, "")),
+ }
+
+ mount.MountId, err = strconv.Atoi(getStringSliceElement(beforeFields, 0, ""))
+ if err != nil {
+ return nil, fmt.Errorf("failed to parse mount ID")
+ }
+ mount.ParentId, err = strconv.Atoi(getStringSliceElement(beforeFields, 1, ""))
+ if err != nil {
+ return nil, fmt.Errorf("failed to parse parent ID")
+ }
+ // Has optional fields, which is a space separated list of values.
+ // Example: shared:2 master:7
+ if len(beforeFields) > 6 {
+ mount.OptionalFields = make(map[string]string)
+ optionalFields := beforeFields[6:]
+ for _, field := range optionalFields {
+ optionSplit := strings.Split(field, ":")
+ target, value := optionSplit[0], ""
+ if len(optionSplit) == 2 {
+ value = optionSplit[1]
+ }
+ // Checks if the 'keys' in the optional fields in the mountinfo line are acceptable.
+ // Allowed 'keys' are shared, master, propagate_from, unbindable.
+ if _, ok := validOptionalFields[target]; ok {
+ mount.OptionalFields[target] = value
+ }
+ }
+ }
+ return mount, nil
+}
+
+// Parses the mount options, superblock options.
+func mountOptionsParser(mountOptions string) map[string]string {
+ opts := make(map[string]string)
+ options := strings.Split(mountOptions, ",")
+ for _, opt := range options {
+ splitOption := strings.Split(opt, "=")
+ if len(splitOption) < 2 {
+ key := splitOption[0]
+ opts[key] = ""
+ } else {
+ key, value := splitOption[0], splitOption[1]
+ opts[key] = value
+ }
+ }
+ return opts
+}
+
+// Retrieves mountinfo information from `/proc/self/mountinfo`.
+func GetMounts() ([]*MountInfo, error) {
+ f, err := os.Open("/proc/self/mountinfo")
+ if err != nil {
+ return nil, err
+ }
+ defer f.Close()
+ return parseMountInfo(f)
+}
+
+// Retrieves mountinfo information from a processes' `/proc//mountinfo`.
+func GetProcMounts(pid int) ([]*MountInfo, error) {
+ f, err := os.Open(fmt.Sprintf("/proc/%d/mountinfo", pid))
+ if err != nil {
+ return nil, err
+ }
+ defer f.Close()
+ return parseMountInfo(f)
+}
diff --git a/vendor/github.com/prometheus/procfs/mountstats.go b/vendor/github.com/prometheus/procfs/mountstats.go
new file mode 100644
index 0000000..35b2ef3
--- /dev/null
+++ b/vendor/github.com/prometheus/procfs/mountstats.go
@@ -0,0 +1,621 @@
+// Copyright 2018 The Prometheus Authors
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package procfs
+
+// While implementing parsing of /proc/[pid]/mountstats, this blog was used
+// heavily as a reference:
+// https://utcc.utoronto.ca/~cks/space/blog/linux/NFSMountstatsIndex
+//
+// Special thanks to Chris Siebenmann for all of his posts explaining the
+// various statistics available for NFS.
+
+import (
+ "bufio"
+ "fmt"
+ "io"
+ "strconv"
+ "strings"
+ "time"
+)
+
+// Constants shared between multiple functions.
+const (
+ deviceEntryLen = 8
+
+ fieldBytesLen = 8
+ fieldEventsLen = 27
+
+ statVersion10 = "1.0"
+ statVersion11 = "1.1"
+
+ fieldTransport10TCPLen = 10
+ fieldTransport10UDPLen = 7
+
+ fieldTransport11TCPLen = 13
+ fieldTransport11UDPLen = 10
+)
+
+// A Mount is a device mount parsed from /proc/[pid]/mountstats.
+type Mount struct {
+ // Name of the device.
+ Device string
+ // The mount point of the device.
+ Mount string
+ // The filesystem type used by the device.
+ Type string
+ // If available additional statistics related to this Mount.
+ // Use a type assertion to determine if additional statistics are available.
+ Stats MountStats
+}
+
+// A MountStats is a type which contains detailed statistics for a specific
+// type of Mount.
+type MountStats interface {
+ mountStats()
+}
+
+// A MountStatsNFS is a MountStats implementation for NFSv3 and v4 mounts.
+type MountStatsNFS struct {
+ // The version of statistics provided.
+ StatVersion string
+ // The mount options of the NFS mount.
+ Opts map[string]string
+ // The age of the NFS mount.
+ Age time.Duration
+ // Statistics related to byte counters for various operations.
+ Bytes NFSBytesStats
+ // Statistics related to various NFS event occurrences.
+ Events NFSEventsStats
+ // Statistics broken down by filesystem operation.
+ Operations []NFSOperationStats
+ // Statistics about the NFS RPC transport.
+ Transport NFSTransportStats
+}
+
+// mountStats implements MountStats.
+func (m MountStatsNFS) mountStats() {}
+
+// A NFSBytesStats contains statistics about the number of bytes read and written
+// by an NFS client to and from an NFS server.
+type NFSBytesStats struct {
+ // Number of bytes read using the read() syscall.
+ Read uint64
+ // Number of bytes written using the write() syscall.
+ Write uint64
+ // Number of bytes read using the read() syscall in O_DIRECT mode.
+ DirectRead uint64
+ // Number of bytes written using the write() syscall in O_DIRECT mode.
+ DirectWrite uint64
+ // Number of bytes read from the NFS server, in total.
+ ReadTotal uint64
+ // Number of bytes written to the NFS server, in total.
+ WriteTotal uint64
+ // Number of pages read directly via mmap()'d files.
+ ReadPages uint64
+ // Number of pages written directly via mmap()'d files.
+ WritePages uint64
+}
+
+// A NFSEventsStats contains statistics about NFS event occurrences.
+type NFSEventsStats struct {
+ // Number of times cached inode attributes are re-validated from the server.
+ InodeRevalidate uint64
+ // Number of times cached dentry nodes are re-validated from the server.
+ DnodeRevalidate uint64
+ // Number of times an inode cache is cleared.
+ DataInvalidate uint64
+ // Number of times cached inode attributes are invalidated.
+ AttributeInvalidate uint64
+ // Number of times files or directories have been open()'d.
+ VFSOpen uint64
+ // Number of times a directory lookup has occurred.
+ VFSLookup uint64
+ // Number of times permissions have been checked.
+ VFSAccess uint64
+ // Number of updates (and potential writes) to pages.
+ VFSUpdatePage uint64
+ // Number of pages read directly via mmap()'d files.
+ VFSReadPage uint64
+ // Number of times a group of pages have been read.
+ VFSReadPages uint64
+ // Number of pages written directly via mmap()'d files.
+ VFSWritePage uint64
+ // Number of times a group of pages have been written.
+ VFSWritePages uint64
+ // Number of times directory entries have been read with getdents().
+ VFSGetdents uint64
+ // Number of times attributes have been set on inodes.
+ VFSSetattr uint64
+ // Number of pending writes that have been forcefully flushed to the server.
+ VFSFlush uint64
+ // Number of times fsync() has been called on directories and files.
+ VFSFsync uint64
+ // Number of times locking has been attempted on a file.
+ VFSLock uint64
+ // Number of times files have been closed and released.
+ VFSFileRelease uint64
+ // Unknown. Possibly unused.
+ CongestionWait uint64
+ // Number of times files have been truncated.
+ Truncation uint64
+ // Number of times a file has been grown due to writes beyond its existing end.
+ WriteExtension uint64
+ // Number of times a file was removed while still open by another process.
+ SillyRename uint64
+ // Number of times the NFS server gave less data than expected while reading.
+ ShortRead uint64
+ // Number of times the NFS server wrote less data than expected while writing.
+ ShortWrite uint64
+ // Number of times the NFS server indicated EJUKEBOX; retrieving data from
+ // offline storage.
+ JukeboxDelay uint64
+ // Number of NFS v4.1+ pNFS reads.
+ PNFSRead uint64
+ // Number of NFS v4.1+ pNFS writes.
+ PNFSWrite uint64
+}
+
+// A NFSOperationStats contains statistics for a single operation.
+type NFSOperationStats struct {
+ // The name of the operation.
+ Operation string
+ // Number of requests performed for this operation.
+ Requests uint64
+ // Number of times an actual RPC request has been transmitted for this operation.
+ Transmissions uint64
+ // Number of times a request has had a major timeout.
+ MajorTimeouts uint64
+ // Number of bytes sent for this operation, including RPC headers and payload.
+ BytesSent uint64
+ // Number of bytes received for this operation, including RPC headers and payload.
+ BytesReceived uint64
+ // Duration all requests spent queued for transmission before they were sent.
+ CumulativeQueueMilliseconds uint64
+ // Duration it took to get a reply back after the request was transmitted.
+ CumulativeTotalResponseMilliseconds uint64
+ // Duration from when a request was enqueued to when it was completely handled.
+ CumulativeTotalRequestMilliseconds uint64
+}
+
+// A NFSTransportStats contains statistics for the NFS mount RPC requests and
+// responses.
+type NFSTransportStats struct {
+ // The transport protocol used for the NFS mount.
+ Protocol string
+ // The local port used for the NFS mount.
+ Port uint64
+ // Number of times the client has had to establish a connection from scratch
+ // to the NFS server.
+ Bind uint64
+ // Number of times the client has made a TCP connection to the NFS server.
+ Connect uint64
+ // Duration (in jiffies, a kernel internal unit of time) the NFS mount has
+ // spent waiting for connections to the server to be established.
+ ConnectIdleTime uint64
+ // Duration since the NFS mount last saw any RPC traffic.
+ IdleTimeSeconds uint64
+ // Number of RPC requests for this mount sent to the NFS server.
+ Sends uint64
+ // Number of RPC responses for this mount received from the NFS server.
+ Receives uint64
+ // Number of times the NFS server sent a response with a transaction ID
+ // unknown to this client.
+ BadTransactionIDs uint64
+ // A running counter, incremented on each request as the current difference
+ // ebetween sends and receives.
+ CumulativeActiveRequests uint64
+ // A running counter, incremented on each request by the current backlog
+ // queue size.
+ CumulativeBacklog uint64
+
+ // Stats below only available with stat version 1.1.
+
+ // Maximum number of simultaneously active RPC requests ever used.
+ MaximumRPCSlotsUsed uint64
+ // A running counter, incremented on each request as the current size of the
+ // sending queue.
+ CumulativeSendingQueue uint64
+ // A running counter, incremented on each request as the current size of the
+ // pending queue.
+ CumulativePendingQueue uint64
+}
+
+// parseMountStats parses a /proc/[pid]/mountstats file and returns a slice
+// of Mount structures containing detailed information about each mount.
+// If available, statistics for each mount are parsed as well.
+func parseMountStats(r io.Reader) ([]*Mount, error) {
+ const (
+ device = "device"
+ statVersionPrefix = "statvers="
+
+ nfs3Type = "nfs"
+ nfs4Type = "nfs4"
+ )
+
+ var mounts []*Mount
+
+ s := bufio.NewScanner(r)
+ for s.Scan() {
+ // Only look for device entries in this function
+ ss := strings.Fields(string(s.Bytes()))
+ if len(ss) == 0 || ss[0] != device {
+ continue
+ }
+
+ m, err := parseMount(ss)
+ if err != nil {
+ return nil, err
+ }
+
+ // Does this mount also possess statistics information?
+ if len(ss) > deviceEntryLen {
+ // Only NFSv3 and v4 are supported for parsing statistics
+ if m.Type != nfs3Type && m.Type != nfs4Type {
+ return nil, fmt.Errorf("cannot parse MountStats for fstype %q", m.Type)
+ }
+
+ statVersion := strings.TrimPrefix(ss[8], statVersionPrefix)
+
+ stats, err := parseMountStatsNFS(s, statVersion)
+ if err != nil {
+ return nil, err
+ }
+
+ m.Stats = stats
+ }
+
+ mounts = append(mounts, m)
+ }
+
+ return mounts, s.Err()
+}
+
+// parseMount parses an entry in /proc/[pid]/mountstats in the format:
+// device [device] mounted on [mount] with fstype [type]
+func parseMount(ss []string) (*Mount, error) {
+ if len(ss) < deviceEntryLen {
+ return nil, fmt.Errorf("invalid device entry: %v", ss)
+ }
+
+ // Check for specific words appearing at specific indices to ensure
+ // the format is consistent with what we expect
+ format := []struct {
+ i int
+ s string
+ }{
+ {i: 0, s: "device"},
+ {i: 2, s: "mounted"},
+ {i: 3, s: "on"},
+ {i: 5, s: "with"},
+ {i: 6, s: "fstype"},
+ }
+
+ for _, f := range format {
+ if ss[f.i] != f.s {
+ return nil, fmt.Errorf("invalid device entry: %v", ss)
+ }
+ }
+
+ return &Mount{
+ Device: ss[1],
+ Mount: ss[4],
+ Type: ss[7],
+ }, nil
+}
+
+// parseMountStatsNFS parses a MountStatsNFS by scanning additional information
+// related to NFS statistics.
+func parseMountStatsNFS(s *bufio.Scanner, statVersion string) (*MountStatsNFS, error) {
+ // Field indicators for parsing specific types of data
+ const (
+ fieldOpts = "opts:"
+ fieldAge = "age:"
+ fieldBytes = "bytes:"
+ fieldEvents = "events:"
+ fieldPerOpStats = "per-op"
+ fieldTransport = "xprt:"
+ )
+
+ stats := &MountStatsNFS{
+ StatVersion: statVersion,
+ }
+
+ for s.Scan() {
+ ss := strings.Fields(string(s.Bytes()))
+ if len(ss) == 0 {
+ break
+ }
+ if len(ss) < 2 {
+ return nil, fmt.Errorf("not enough information for NFS stats: %v", ss)
+ }
+
+ switch ss[0] {
+ case fieldOpts:
+ if stats.Opts == nil {
+ stats.Opts = map[string]string{}
+ }
+ for _, opt := range strings.Split(ss[1], ",") {
+ split := strings.Split(opt, "=")
+ if len(split) == 2 {
+ stats.Opts[split[0]] = split[1]
+ } else {
+ stats.Opts[opt] = ""
+ }
+ }
+ case fieldAge:
+ // Age integer is in seconds
+ d, err := time.ParseDuration(ss[1] + "s")
+ if err != nil {
+ return nil, err
+ }
+
+ stats.Age = d
+ case fieldBytes:
+ bstats, err := parseNFSBytesStats(ss[1:])
+ if err != nil {
+ return nil, err
+ }
+
+ stats.Bytes = *bstats
+ case fieldEvents:
+ estats, err := parseNFSEventsStats(ss[1:])
+ if err != nil {
+ return nil, err
+ }
+
+ stats.Events = *estats
+ case fieldTransport:
+ if len(ss) < 3 {
+ return nil, fmt.Errorf("not enough information for NFS transport stats: %v", ss)
+ }
+
+ tstats, err := parseNFSTransportStats(ss[1:], statVersion)
+ if err != nil {
+ return nil, err
+ }
+
+ stats.Transport = *tstats
+ }
+
+ // When encountering "per-operation statistics", we must break this
+ // loop and parse them separately to ensure we can terminate parsing
+ // before reaching another device entry; hence why this 'if' statement
+ // is not just another switch case
+ if ss[0] == fieldPerOpStats {
+ break
+ }
+ }
+
+ if err := s.Err(); err != nil {
+ return nil, err
+ }
+
+ // NFS per-operation stats appear last before the next device entry
+ perOpStats, err := parseNFSOperationStats(s)
+ if err != nil {
+ return nil, err
+ }
+
+ stats.Operations = perOpStats
+
+ return stats, nil
+}
+
+// parseNFSBytesStats parses a NFSBytesStats line using an input set of
+// integer fields.
+func parseNFSBytesStats(ss []string) (*NFSBytesStats, error) {
+ if len(ss) != fieldBytesLen {
+ return nil, fmt.Errorf("invalid NFS bytes stats: %v", ss)
+ }
+
+ ns := make([]uint64, 0, fieldBytesLen)
+ for _, s := range ss {
+ n, err := strconv.ParseUint(s, 10, 64)
+ if err != nil {
+ return nil, err
+ }
+
+ ns = append(ns, n)
+ }
+
+ return &NFSBytesStats{
+ Read: ns[0],
+ Write: ns[1],
+ DirectRead: ns[2],
+ DirectWrite: ns[3],
+ ReadTotal: ns[4],
+ WriteTotal: ns[5],
+ ReadPages: ns[6],
+ WritePages: ns[7],
+ }, nil
+}
+
+// parseNFSEventsStats parses a NFSEventsStats line using an input set of
+// integer fields.
+func parseNFSEventsStats(ss []string) (*NFSEventsStats, error) {
+ if len(ss) != fieldEventsLen {
+ return nil, fmt.Errorf("invalid NFS events stats: %v", ss)
+ }
+
+ ns := make([]uint64, 0, fieldEventsLen)
+ for _, s := range ss {
+ n, err := strconv.ParseUint(s, 10, 64)
+ if err != nil {
+ return nil, err
+ }
+
+ ns = append(ns, n)
+ }
+
+ return &NFSEventsStats{
+ InodeRevalidate: ns[0],
+ DnodeRevalidate: ns[1],
+ DataInvalidate: ns[2],
+ AttributeInvalidate: ns[3],
+ VFSOpen: ns[4],
+ VFSLookup: ns[5],
+ VFSAccess: ns[6],
+ VFSUpdatePage: ns[7],
+ VFSReadPage: ns[8],
+ VFSReadPages: ns[9],
+ VFSWritePage: ns[10],
+ VFSWritePages: ns[11],
+ VFSGetdents: ns[12],
+ VFSSetattr: ns[13],
+ VFSFlush: ns[14],
+ VFSFsync: ns[15],
+ VFSLock: ns[16],
+ VFSFileRelease: ns[17],
+ CongestionWait: ns[18],
+ Truncation: ns[19],
+ WriteExtension: ns[20],
+ SillyRename: ns[21],
+ ShortRead: ns[22],
+ ShortWrite: ns[23],
+ JukeboxDelay: ns[24],
+ PNFSRead: ns[25],
+ PNFSWrite: ns[26],
+ }, nil
+}
+
+// parseNFSOperationStats parses a slice of NFSOperationStats by scanning
+// additional information about per-operation statistics until an empty
+// line is reached.
+func parseNFSOperationStats(s *bufio.Scanner) ([]NFSOperationStats, error) {
+ const (
+ // Number of expected fields in each per-operation statistics set
+ numFields = 9
+ )
+
+ var ops []NFSOperationStats
+
+ for s.Scan() {
+ ss := strings.Fields(string(s.Bytes()))
+ if len(ss) == 0 {
+ // Must break when reading a blank line after per-operation stats to
+ // enable top-level function to parse the next device entry
+ break
+ }
+
+ if len(ss) != numFields {
+ return nil, fmt.Errorf("invalid NFS per-operations stats: %v", ss)
+ }
+
+ // Skip string operation name for integers
+ ns := make([]uint64, 0, numFields-1)
+ for _, st := range ss[1:] {
+ n, err := strconv.ParseUint(st, 10, 64)
+ if err != nil {
+ return nil, err
+ }
+
+ ns = append(ns, n)
+ }
+
+ ops = append(ops, NFSOperationStats{
+ Operation: strings.TrimSuffix(ss[0], ":"),
+ Requests: ns[0],
+ Transmissions: ns[1],
+ MajorTimeouts: ns[2],
+ BytesSent: ns[3],
+ BytesReceived: ns[4],
+ CumulativeQueueMilliseconds: ns[5],
+ CumulativeTotalResponseMilliseconds: ns[6],
+ CumulativeTotalRequestMilliseconds: ns[7],
+ })
+ }
+
+ return ops, s.Err()
+}
+
+// parseNFSTransportStats parses a NFSTransportStats line using an input set of
+// integer fields matched to a specific stats version.
+func parseNFSTransportStats(ss []string, statVersion string) (*NFSTransportStats, error) {
+ // Extract the protocol field. It is the only string value in the line
+ protocol := ss[0]
+ ss = ss[1:]
+
+ switch statVersion {
+ case statVersion10:
+ var expectedLength int
+ if protocol == "tcp" {
+ expectedLength = fieldTransport10TCPLen
+ } else if protocol == "udp" {
+ expectedLength = fieldTransport10UDPLen
+ } else {
+ return nil, fmt.Errorf("invalid NFS protocol \"%s\" in stats 1.0 statement: %v", protocol, ss)
+ }
+ if len(ss) != expectedLength {
+ return nil, fmt.Errorf("invalid NFS transport stats 1.0 statement: %v", ss)
+ }
+ case statVersion11:
+ var expectedLength int
+ if protocol == "tcp" {
+ expectedLength = fieldTransport11TCPLen
+ } else if protocol == "udp" {
+ expectedLength = fieldTransport11UDPLen
+ } else {
+ return nil, fmt.Errorf("invalid NFS protocol \"%s\" in stats 1.1 statement: %v", protocol, ss)
+ }
+ if len(ss) != expectedLength {
+ return nil, fmt.Errorf("invalid NFS transport stats 1.1 statement: %v", ss)
+ }
+ default:
+ return nil, fmt.Errorf("unrecognized NFS transport stats version: %q", statVersion)
+ }
+
+ // Allocate enough for v1.1 stats since zero value for v1.1 stats will be okay
+ // in a v1.0 response. Since the stat length is bigger for TCP stats, we use
+ // the TCP length here.
+ //
+ // Note: slice length must be set to length of v1.1 stats to avoid a panic when
+ // only v1.0 stats are present.
+ // See: https://github.com/prometheus/node_exporter/issues/571.
+ ns := make([]uint64, fieldTransport11TCPLen)
+ for i, s := range ss {
+ n, err := strconv.ParseUint(s, 10, 64)
+ if err != nil {
+ return nil, err
+ }
+
+ ns[i] = n
+ }
+
+ // The fields differ depending on the transport protocol (TCP or UDP)
+ // From https://utcc.utoronto.ca/%7Ecks/space/blog/linux/NFSMountstatsXprt
+ //
+ // For the udp RPC transport there is no connection count, connect idle time,
+ // or idle time (fields #3, #4, and #5); all other fields are the same. So
+ // we set them to 0 here.
+ if protocol == "udp" {
+ ns = append(ns[:2], append(make([]uint64, 3), ns[2:]...)...)
+ }
+
+ return &NFSTransportStats{
+ Protocol: protocol,
+ Port: ns[0],
+ Bind: ns[1],
+ Connect: ns[2],
+ ConnectIdleTime: ns[3],
+ IdleTimeSeconds: ns[4],
+ Sends: ns[5],
+ Receives: ns[6],
+ BadTransactionIDs: ns[7],
+ CumulativeActiveRequests: ns[8],
+ CumulativeBacklog: ns[9],
+ MaximumRPCSlotsUsed: ns[10],
+ CumulativeSendingQueue: ns[11],
+ CumulativePendingQueue: ns[12],
+ }, nil
+}
diff --git a/vendor/github.com/prometheus/procfs/net_dev.go b/vendor/github.com/prometheus/procfs/net_dev.go
new file mode 100644
index 0000000..a0b7a01
--- /dev/null
+++ b/vendor/github.com/prometheus/procfs/net_dev.go
@@ -0,0 +1,206 @@
+// Copyright 2018 The Prometheus Authors
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package procfs
+
+import (
+ "bufio"
+ "errors"
+ "os"
+ "sort"
+ "strconv"
+ "strings"
+)
+
+// NetDevLine is single line parsed from /proc/net/dev or /proc/[pid]/net/dev.
+type NetDevLine struct {
+ Name string `json:"name"` // The name of the interface.
+ RxBytes uint64 `json:"rx_bytes"` // Cumulative count of bytes received.
+ RxPackets uint64 `json:"rx_packets"` // Cumulative count of packets received.
+ RxErrors uint64 `json:"rx_errors"` // Cumulative count of receive errors encountered.
+ RxDropped uint64 `json:"rx_dropped"` // Cumulative count of packets dropped while receiving.
+ RxFIFO uint64 `json:"rx_fifo"` // Cumulative count of FIFO buffer errors.
+ RxFrame uint64 `json:"rx_frame"` // Cumulative count of packet framing errors.
+ RxCompressed uint64 `json:"rx_compressed"` // Cumulative count of compressed packets received by the device driver.
+ RxMulticast uint64 `json:"rx_multicast"` // Cumulative count of multicast frames received by the device driver.
+ TxBytes uint64 `json:"tx_bytes"` // Cumulative count of bytes transmitted.
+ TxPackets uint64 `json:"tx_packets"` // Cumulative count of packets transmitted.
+ TxErrors uint64 `json:"tx_errors"` // Cumulative count of transmit errors encountered.
+ TxDropped uint64 `json:"tx_dropped"` // Cumulative count of packets dropped while transmitting.
+ TxFIFO uint64 `json:"tx_fifo"` // Cumulative count of FIFO buffer errors.
+ TxCollisions uint64 `json:"tx_collisions"` // Cumulative count of collisions detected on the interface.
+ TxCarrier uint64 `json:"tx_carrier"` // Cumulative count of carrier losses detected by the device driver.
+ TxCompressed uint64 `json:"tx_compressed"` // Cumulative count of compressed packets transmitted by the device driver.
+}
+
+// NetDev is parsed from /proc/net/dev or /proc/[pid]/net/dev. The map keys
+// are interface names.
+type NetDev map[string]NetDevLine
+
+// NetDev returns kernel/system statistics read from /proc/net/dev.
+func (fs FS) NetDev() (NetDev, error) {
+ return newNetDev(fs.proc.Path("net/dev"))
+}
+
+// NetDev returns kernel/system statistics read from /proc/[pid]/net/dev.
+func (p Proc) NetDev() (NetDev, error) {
+ return newNetDev(p.path("net/dev"))
+}
+
+// newNetDev creates a new NetDev from the contents of the given file.
+func newNetDev(file string) (NetDev, error) {
+ f, err := os.Open(file)
+ if err != nil {
+ return NetDev{}, err
+ }
+ defer f.Close()
+
+ netDev := NetDev{}
+ s := bufio.NewScanner(f)
+ for n := 0; s.Scan(); n++ {
+ // Skip the 2 header lines.
+ if n < 2 {
+ continue
+ }
+
+ line, err := netDev.parseLine(s.Text())
+ if err != nil {
+ return netDev, err
+ }
+
+ netDev[line.Name] = *line
+ }
+
+ return netDev, s.Err()
+}
+
+// parseLine parses a single line from the /proc/net/dev file. Header lines
+// must be filtered prior to calling this method.
+func (netDev NetDev) parseLine(rawLine string) (*NetDevLine, error) {
+ parts := strings.SplitN(rawLine, ":", 2)
+ if len(parts) != 2 {
+ return nil, errors.New("invalid net/dev line, missing colon")
+ }
+ fields := strings.Fields(strings.TrimSpace(parts[1]))
+
+ var err error
+ line := &NetDevLine{}
+
+ // Interface Name
+ line.Name = strings.TrimSpace(parts[0])
+ if line.Name == "" {
+ return nil, errors.New("invalid net/dev line, empty interface name")
+ }
+
+ // RX
+ line.RxBytes, err = strconv.ParseUint(fields[0], 10, 64)
+ if err != nil {
+ return nil, err
+ }
+ line.RxPackets, err = strconv.ParseUint(fields[1], 10, 64)
+ if err != nil {
+ return nil, err
+ }
+ line.RxErrors, err = strconv.ParseUint(fields[2], 10, 64)
+ if err != nil {
+ return nil, err
+ }
+ line.RxDropped, err = strconv.ParseUint(fields[3], 10, 64)
+ if err != nil {
+ return nil, err
+ }
+ line.RxFIFO, err = strconv.ParseUint(fields[4], 10, 64)
+ if err != nil {
+ return nil, err
+ }
+ line.RxFrame, err = strconv.ParseUint(fields[5], 10, 64)
+ if err != nil {
+ return nil, err
+ }
+ line.RxCompressed, err = strconv.ParseUint(fields[6], 10, 64)
+ if err != nil {
+ return nil, err
+ }
+ line.RxMulticast, err = strconv.ParseUint(fields[7], 10, 64)
+ if err != nil {
+ return nil, err
+ }
+
+ // TX
+ line.TxBytes, err = strconv.ParseUint(fields[8], 10, 64)
+ if err != nil {
+ return nil, err
+ }
+ line.TxPackets, err = strconv.ParseUint(fields[9], 10, 64)
+ if err != nil {
+ return nil, err
+ }
+ line.TxErrors, err = strconv.ParseUint(fields[10], 10, 64)
+ if err != nil {
+ return nil, err
+ }
+ line.TxDropped, err = strconv.ParseUint(fields[11], 10, 64)
+ if err != nil {
+ return nil, err
+ }
+ line.TxFIFO, err = strconv.ParseUint(fields[12], 10, 64)
+ if err != nil {
+ return nil, err
+ }
+ line.TxCollisions, err = strconv.ParseUint(fields[13], 10, 64)
+ if err != nil {
+ return nil, err
+ }
+ line.TxCarrier, err = strconv.ParseUint(fields[14], 10, 64)
+ if err != nil {
+ return nil, err
+ }
+ line.TxCompressed, err = strconv.ParseUint(fields[15], 10, 64)
+ if err != nil {
+ return nil, err
+ }
+
+ return line, nil
+}
+
+// Total aggregates the values across interfaces and returns a new NetDevLine.
+// The Name field will be a sorted comma separated list of interface names.
+func (netDev NetDev) Total() NetDevLine {
+ total := NetDevLine{}
+
+ names := make([]string, 0, len(netDev))
+ for _, ifc := range netDev {
+ names = append(names, ifc.Name)
+ total.RxBytes += ifc.RxBytes
+ total.RxPackets += ifc.RxPackets
+ total.RxPackets += ifc.RxPackets
+ total.RxErrors += ifc.RxErrors
+ total.RxDropped += ifc.RxDropped
+ total.RxFIFO += ifc.RxFIFO
+ total.RxFrame += ifc.RxFrame
+ total.RxCompressed += ifc.RxCompressed
+ total.RxMulticast += ifc.RxMulticast
+ total.TxBytes += ifc.TxBytes
+ total.TxPackets += ifc.TxPackets
+ total.TxErrors += ifc.TxErrors
+ total.TxDropped += ifc.TxDropped
+ total.TxFIFO += ifc.TxFIFO
+ total.TxCollisions += ifc.TxCollisions
+ total.TxCarrier += ifc.TxCarrier
+ total.TxCompressed += ifc.TxCompressed
+ }
+ sort.Strings(names)
+ total.Name = strings.Join(names, ", ")
+
+ return total
+}
diff --git a/vendor/github.com/prometheus/procfs/net_unix.go b/vendor/github.com/prometheus/procfs/net_unix.go
new file mode 100644
index 0000000..240340a
--- /dev/null
+++ b/vendor/github.com/prometheus/procfs/net_unix.go
@@ -0,0 +1,275 @@
+// Copyright 2018 The Prometheus Authors
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package procfs
+
+import (
+ "bufio"
+ "errors"
+ "fmt"
+ "io"
+ "os"
+ "strconv"
+ "strings"
+)
+
+// For the proc file format details,
+// see https://elixir.bootlin.com/linux/v4.17/source/net/unix/af_unix.c#L2815
+// and https://elixir.bootlin.com/linux/latest/source/include/uapi/linux/net.h#L48.
+
+const (
+ netUnixKernelPtrIdx = iota
+ netUnixRefCountIdx
+ _
+ netUnixFlagsIdx
+ netUnixTypeIdx
+ netUnixStateIdx
+ netUnixInodeIdx
+
+ // Inode and Path are optional.
+ netUnixStaticFieldsCnt = 6
+)
+
+const (
+ netUnixTypeStream = 1
+ netUnixTypeDgram = 2
+ netUnixTypeSeqpacket = 5
+
+ netUnixFlagListen = 1 << 16
+
+ netUnixStateUnconnected = 1
+ netUnixStateConnecting = 2
+ netUnixStateConnected = 3
+ netUnixStateDisconnected = 4
+)
+
+var errInvalidKernelPtrFmt = errors.New("Invalid Num(the kernel table slot number) format")
+
+// NetUnixType is the type of the type field.
+type NetUnixType uint64
+
+// NetUnixFlags is the type of the flags field.
+type NetUnixFlags uint64
+
+// NetUnixState is the type of the state field.
+type NetUnixState uint64
+
+// NetUnixLine represents a line of /proc/net/unix.
+type NetUnixLine struct {
+ KernelPtr string
+ RefCount uint64
+ Protocol uint64
+ Flags NetUnixFlags
+ Type NetUnixType
+ State NetUnixState
+ Inode uint64
+ Path string
+}
+
+// NetUnix holds the data read from /proc/net/unix.
+type NetUnix struct {
+ Rows []*NetUnixLine
+}
+
+// NewNetUnix returns data read from /proc/net/unix.
+func NewNetUnix() (*NetUnix, error) {
+ fs, err := NewFS(DefaultMountPoint)
+ if err != nil {
+ return nil, err
+ }
+
+ return fs.NewNetUnix()
+}
+
+// NewNetUnix returns data read from /proc/net/unix.
+func (fs FS) NewNetUnix() (*NetUnix, error) {
+ return NewNetUnixByPath(fs.proc.Path("net/unix"))
+}
+
+// NewNetUnixByPath returns data read from /proc/net/unix by file path.
+// It might returns an error with partial parsed data, if an error occur after some data parsed.
+func NewNetUnixByPath(path string) (*NetUnix, error) {
+ f, err := os.Open(path)
+ if err != nil {
+ return nil, err
+ }
+ defer f.Close()
+ return NewNetUnixByReader(f)
+}
+
+// NewNetUnixByReader returns data read from /proc/net/unix by a reader.
+// It might returns an error with partial parsed data, if an error occur after some data parsed.
+func NewNetUnixByReader(reader io.Reader) (*NetUnix, error) {
+ nu := &NetUnix{
+ Rows: make([]*NetUnixLine, 0, 32),
+ }
+ scanner := bufio.NewScanner(reader)
+ // Omit the header line.
+ scanner.Scan()
+ header := scanner.Text()
+ // From the man page of proc(5), it does not contain an Inode field,
+ // but in actually it exists.
+ // This code works for both cases.
+ hasInode := strings.Contains(header, "Inode")
+
+ minFieldsCnt := netUnixStaticFieldsCnt
+ if hasInode {
+ minFieldsCnt++
+ }
+ for scanner.Scan() {
+ line := scanner.Text()
+ item, err := nu.parseLine(line, hasInode, minFieldsCnt)
+ if err != nil {
+ return nu, err
+ }
+ nu.Rows = append(nu.Rows, item)
+ }
+
+ return nu, scanner.Err()
+}
+
+func (u *NetUnix) parseLine(line string, hasInode bool, minFieldsCnt int) (*NetUnixLine, error) {
+ fields := strings.Fields(line)
+ fieldsLen := len(fields)
+ if fieldsLen < minFieldsCnt {
+ return nil, fmt.Errorf(
+ "Parse Unix domain failed: expect at least %d fields but got %d",
+ minFieldsCnt, fieldsLen)
+ }
+ kernelPtr, err := u.parseKernelPtr(fields[netUnixKernelPtrIdx])
+ if err != nil {
+ return nil, fmt.Errorf("Parse Unix domain num(%s) failed: %s", fields[netUnixKernelPtrIdx], err)
+ }
+ users, err := u.parseUsers(fields[netUnixRefCountIdx])
+ if err != nil {
+ return nil, fmt.Errorf("Parse Unix domain ref count(%s) failed: %s", fields[netUnixRefCountIdx], err)
+ }
+ flags, err := u.parseFlags(fields[netUnixFlagsIdx])
+ if err != nil {
+ return nil, fmt.Errorf("Parse Unix domain flags(%s) failed: %s", fields[netUnixFlagsIdx], err)
+ }
+ typ, err := u.parseType(fields[netUnixTypeIdx])
+ if err != nil {
+ return nil, fmt.Errorf("Parse Unix domain type(%s) failed: %s", fields[netUnixTypeIdx], err)
+ }
+ state, err := u.parseState(fields[netUnixStateIdx])
+ if err != nil {
+ return nil, fmt.Errorf("Parse Unix domain state(%s) failed: %s", fields[netUnixStateIdx], err)
+ }
+ var inode uint64
+ if hasInode {
+ inodeStr := fields[netUnixInodeIdx]
+ inode, err = u.parseInode(inodeStr)
+ if err != nil {
+ return nil, fmt.Errorf("Parse Unix domain inode(%s) failed: %s", inodeStr, err)
+ }
+ }
+
+ nuLine := &NetUnixLine{
+ KernelPtr: kernelPtr,
+ RefCount: users,
+ Type: typ,
+ Flags: flags,
+ State: state,
+ Inode: inode,
+ }
+
+ // Path field is optional.
+ if fieldsLen > minFieldsCnt {
+ pathIdx := netUnixInodeIdx + 1
+ if !hasInode {
+ pathIdx--
+ }
+ nuLine.Path = fields[pathIdx]
+ }
+
+ return nuLine, nil
+}
+
+func (u NetUnix) parseKernelPtr(str string) (string, error) {
+ if !strings.HasSuffix(str, ":") {
+ return "", errInvalidKernelPtrFmt
+ }
+ return str[:len(str)-1], nil
+}
+
+func (u NetUnix) parseUsers(hexStr string) (uint64, error) {
+ return strconv.ParseUint(hexStr, 16, 32)
+}
+
+func (u NetUnix) parseProtocol(hexStr string) (uint64, error) {
+ return strconv.ParseUint(hexStr, 16, 32)
+}
+
+func (u NetUnix) parseType(hexStr string) (NetUnixType, error) {
+ typ, err := strconv.ParseUint(hexStr, 16, 16)
+ if err != nil {
+ return 0, err
+ }
+ return NetUnixType(typ), nil
+}
+
+func (u NetUnix) parseFlags(hexStr string) (NetUnixFlags, error) {
+ flags, err := strconv.ParseUint(hexStr, 16, 32)
+ if err != nil {
+ return 0, err
+ }
+ return NetUnixFlags(flags), nil
+}
+
+func (u NetUnix) parseState(hexStr string) (NetUnixState, error) {
+ st, err := strconv.ParseInt(hexStr, 16, 8)
+ if err != nil {
+ return 0, err
+ }
+ return NetUnixState(st), nil
+}
+
+func (u NetUnix) parseInode(inodeStr string) (uint64, error) {
+ return strconv.ParseUint(inodeStr, 10, 64)
+}
+
+func (t NetUnixType) String() string {
+ switch t {
+ case netUnixTypeStream:
+ return "stream"
+ case netUnixTypeDgram:
+ return "dgram"
+ case netUnixTypeSeqpacket:
+ return "seqpacket"
+ }
+ return "unknown"
+}
+
+func (f NetUnixFlags) String() string {
+ switch f {
+ case netUnixFlagListen:
+ return "listen"
+ default:
+ return "default"
+ }
+}
+
+func (s NetUnixState) String() string {
+ switch s {
+ case netUnixStateUnconnected:
+ return "unconnected"
+ case netUnixStateConnecting:
+ return "connecting"
+ case netUnixStateConnected:
+ return "connected"
+ case netUnixStateDisconnected:
+ return "disconnected"
+ }
+ return "unknown"
+}
diff --git a/vendor/github.com/prometheus/procfs/proc.go b/vendor/github.com/prometheus/procfs/proc.go
new file mode 100644
index 0000000..41c148d
--- /dev/null
+++ b/vendor/github.com/prometheus/procfs/proc.go
@@ -0,0 +1,281 @@
+// Copyright 2018 The Prometheus Authors
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package procfs
+
+import (
+ "bytes"
+ "fmt"
+ "io/ioutil"
+ "os"
+ "strconv"
+ "strings"
+
+ "github.com/prometheus/procfs/internal/fs"
+)
+
+// Proc provides information about a running process.
+type Proc struct {
+ // The process ID.
+ PID int
+
+ fs fs.FS
+}
+
+// Procs represents a list of Proc structs.
+type Procs []Proc
+
+func (p Procs) Len() int { return len(p) }
+func (p Procs) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
+func (p Procs) Less(i, j int) bool { return p[i].PID < p[j].PID }
+
+// Self returns a process for the current process read via /proc/self.
+func Self() (Proc, error) {
+ fs, err := NewFS(DefaultMountPoint)
+ if err != nil {
+ return Proc{}, err
+ }
+ return fs.Self()
+}
+
+// NewProc returns a process for the given pid under /proc.
+func NewProc(pid int) (Proc, error) {
+ fs, err := NewFS(DefaultMountPoint)
+ if err != nil {
+ return Proc{}, err
+ }
+ return fs.Proc(pid)
+}
+
+// AllProcs returns a list of all currently available processes under /proc.
+func AllProcs() (Procs, error) {
+ fs, err := NewFS(DefaultMountPoint)
+ if err != nil {
+ return Procs{}, err
+ }
+ return fs.AllProcs()
+}
+
+// Self returns a process for the current process.
+func (fs FS) Self() (Proc, error) {
+ p, err := os.Readlink(fs.proc.Path("self"))
+ if err != nil {
+ return Proc{}, err
+ }
+ pid, err := strconv.Atoi(strings.Replace(p, string(fs.proc), "", -1))
+ if err != nil {
+ return Proc{}, err
+ }
+ return fs.Proc(pid)
+}
+
+// NewProc returns a process for the given pid.
+//
+// Deprecated: use fs.Proc() instead
+func (fs FS) NewProc(pid int) (Proc, error) {
+ return fs.Proc(pid)
+}
+
+// Proc returns a process for the given pid.
+func (fs FS) Proc(pid int) (Proc, error) {
+ if _, err := os.Stat(fs.proc.Path(strconv.Itoa(pid))); err != nil {
+ return Proc{}, err
+ }
+ return Proc{PID: pid, fs: fs.proc}, nil
+}
+
+// AllProcs returns a list of all currently available processes.
+func (fs FS) AllProcs() (Procs, error) {
+ d, err := os.Open(fs.proc.Path())
+ if err != nil {
+ return Procs{}, err
+ }
+ defer d.Close()
+
+ names, err := d.Readdirnames(-1)
+ if err != nil {
+ return Procs{}, fmt.Errorf("could not read %s: %s", d.Name(), err)
+ }
+
+ p := Procs{}
+ for _, n := range names {
+ pid, err := strconv.ParseInt(n, 10, 64)
+ if err != nil {
+ continue
+ }
+ p = append(p, Proc{PID: int(pid), fs: fs.proc})
+ }
+
+ return p, nil
+}
+
+// CmdLine returns the command line of a process.
+func (p Proc) CmdLine() ([]string, error) {
+ f, err := os.Open(p.path("cmdline"))
+ if err != nil {
+ return nil, err
+ }
+ defer f.Close()
+
+ data, err := ioutil.ReadAll(f)
+ if err != nil {
+ return nil, err
+ }
+
+ if len(data) < 1 {
+ return []string{}, nil
+ }
+
+ return strings.Split(string(bytes.TrimRight(data, string("\x00"))), string(byte(0))), nil
+}
+
+// Comm returns the command name of a process.
+func (p Proc) Comm() (string, error) {
+ f, err := os.Open(p.path("comm"))
+ if err != nil {
+ return "", err
+ }
+ defer f.Close()
+
+ data, err := ioutil.ReadAll(f)
+ if err != nil {
+ return "", err
+ }
+
+ return strings.TrimSpace(string(data)), nil
+}
+
+// Executable returns the absolute path of the executable command of a process.
+func (p Proc) Executable() (string, error) {
+ exe, err := os.Readlink(p.path("exe"))
+ if os.IsNotExist(err) {
+ return "", nil
+ }
+
+ return exe, err
+}
+
+// Cwd returns the absolute path to the current working directory of the process.
+func (p Proc) Cwd() (string, error) {
+ wd, err := os.Readlink(p.path("cwd"))
+ if os.IsNotExist(err) {
+ return "", nil
+ }
+
+ return wd, err
+}
+
+// RootDir returns the absolute path to the process's root directory (as set by chroot)
+func (p Proc) RootDir() (string, error) {
+ rdir, err := os.Readlink(p.path("root"))
+ if os.IsNotExist(err) {
+ return "", nil
+ }
+
+ return rdir, err
+}
+
+// FileDescriptors returns the currently open file descriptors of a process.
+func (p Proc) FileDescriptors() ([]uintptr, error) {
+ names, err := p.fileDescriptors()
+ if err != nil {
+ return nil, err
+ }
+
+ fds := make([]uintptr, len(names))
+ for i, n := range names {
+ fd, err := strconv.ParseInt(n, 10, 32)
+ if err != nil {
+ return nil, fmt.Errorf("could not parse fd %s: %s", n, err)
+ }
+ fds[i] = uintptr(fd)
+ }
+
+ return fds, nil
+}
+
+// FileDescriptorTargets returns the targets of all file descriptors of a process.
+// If a file descriptor is not a symlink to a file (like a socket), that value will be the empty string.
+func (p Proc) FileDescriptorTargets() ([]string, error) {
+ names, err := p.fileDescriptors()
+ if err != nil {
+ return nil, err
+ }
+
+ targets := make([]string, len(names))
+
+ for i, name := range names {
+ target, err := os.Readlink(p.path("fd", name))
+ if err == nil {
+ targets[i] = target
+ }
+ }
+
+ return targets, nil
+}
+
+// FileDescriptorsLen returns the number of currently open file descriptors of
+// a process.
+func (p Proc) FileDescriptorsLen() (int, error) {
+ fds, err := p.fileDescriptors()
+ if err != nil {
+ return 0, err
+ }
+
+ return len(fds), nil
+}
+
+// MountStats retrieves statistics and configuration for mount points in a
+// process's namespace.
+func (p Proc) MountStats() ([]*Mount, error) {
+ f, err := os.Open(p.path("mountstats"))
+ if err != nil {
+ return nil, err
+ }
+ defer f.Close()
+
+ return parseMountStats(f)
+}
+
+// MountInfo retrieves mount information for mount points in a
+// process's namespace.
+// It supplies information missing in `/proc/self/mounts` and
+// fixes various other problems with that file too.
+func (p Proc) MountInfo() ([]*MountInfo, error) {
+ f, err := os.Open(p.path("mountinfo"))
+ if err != nil {
+ return nil, err
+ }
+ defer f.Close()
+
+ return parseMountInfo(f)
+}
+
+func (p Proc) fileDescriptors() ([]string, error) {
+ d, err := os.Open(p.path("fd"))
+ if err != nil {
+ return nil, err
+ }
+ defer d.Close()
+
+ names, err := d.Readdirnames(-1)
+ if err != nil {
+ return nil, fmt.Errorf("could not read %s: %s", d.Name(), err)
+ }
+
+ return names, nil
+}
+
+func (p Proc) path(pa ...string) string {
+ return p.fs.Path(append([]string{strconv.Itoa(p.PID)}, pa...)...)
+}
diff --git a/vendor/github.com/prometheus/procfs/proc_environ.go b/vendor/github.com/prometheus/procfs/proc_environ.go
new file mode 100644
index 0000000..7172bb5
--- /dev/null
+++ b/vendor/github.com/prometheus/procfs/proc_environ.go
@@ -0,0 +1,43 @@
+// Copyright 2019 The Prometheus Authors
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package procfs
+
+import (
+ "io/ioutil"
+ "os"
+ "strings"
+)
+
+// Environ reads process environments from /proc//environ
+func (p Proc) Environ() ([]string, error) {
+ environments := make([]string, 0)
+
+ f, err := os.Open(p.path("environ"))
+ if err != nil {
+ return environments, err
+ }
+ defer f.Close()
+
+ data, err := ioutil.ReadAll(f)
+ if err != nil {
+ return environments, err
+ }
+
+ environments = strings.Split(string(data), "\000")
+ if len(environments) > 0 {
+ environments = environments[:len(environments)-1]
+ }
+
+ return environments, nil
+}
diff --git a/vendor/github.com/prometheus/procfs/proc_io.go b/vendor/github.com/prometheus/procfs/proc_io.go
new file mode 100644
index 0000000..0ff89b1
--- /dev/null
+++ b/vendor/github.com/prometheus/procfs/proc_io.go
@@ -0,0 +1,65 @@
+// Copyright 2018 The Prometheus Authors
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package procfs
+
+import (
+ "fmt"
+ "io/ioutil"
+ "os"
+)
+
+// ProcIO models the content of /proc//io.
+type ProcIO struct {
+ // Chars read.
+ RChar uint64
+ // Chars written.
+ WChar uint64
+ // Read syscalls.
+ SyscR uint64
+ // Write syscalls.
+ SyscW uint64
+ // Bytes read.
+ ReadBytes uint64
+ // Bytes written.
+ WriteBytes uint64
+ // Bytes written, but taking into account truncation. See
+ // Documentation/filesystems/proc.txt in the kernel sources for
+ // detailed explanation.
+ CancelledWriteBytes int64
+}
+
+// IO creates a new ProcIO instance from a given Proc instance.
+func (p Proc) IO() (ProcIO, error) {
+ pio := ProcIO{}
+
+ f, err := os.Open(p.path("io"))
+ if err != nil {
+ return pio, err
+ }
+ defer f.Close()
+
+ data, err := ioutil.ReadAll(f)
+ if err != nil {
+ return pio, err
+ }
+
+ ioFormat := "rchar: %d\nwchar: %d\nsyscr: %d\nsyscw: %d\n" +
+ "read_bytes: %d\nwrite_bytes: %d\n" +
+ "cancelled_write_bytes: %d\n"
+
+ _, err = fmt.Sscanf(string(data), ioFormat, &pio.RChar, &pio.WChar, &pio.SyscR,
+ &pio.SyscW, &pio.ReadBytes, &pio.WriteBytes, &pio.CancelledWriteBytes)
+
+ return pio, err
+}
diff --git a/vendor/github.com/prometheus/procfs/proc_limits.go b/vendor/github.com/prometheus/procfs/proc_limits.go
new file mode 100644
index 0000000..91ee24d
--- /dev/null
+++ b/vendor/github.com/prometheus/procfs/proc_limits.go
@@ -0,0 +1,157 @@
+// Copyright 2018 The Prometheus Authors
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package procfs
+
+import (
+ "bufio"
+ "fmt"
+ "os"
+ "regexp"
+ "strconv"
+)
+
+// ProcLimits represents the soft limits for each of the process's resource
+// limits. For more information see getrlimit(2):
+// http://man7.org/linux/man-pages/man2/getrlimit.2.html.
+type ProcLimits struct {
+ // CPU time limit in seconds.
+ CPUTime int64
+ // Maximum size of files that the process may create.
+ FileSize int64
+ // Maximum size of the process's data segment (initialized data,
+ // uninitialized data, and heap).
+ DataSize int64
+ // Maximum size of the process stack in bytes.
+ StackSize int64
+ // Maximum size of a core file.
+ CoreFileSize int64
+ // Limit of the process's resident set in pages.
+ ResidentSet int64
+ // Maximum number of processes that can be created for the real user ID of
+ // the calling process.
+ Processes int64
+ // Value one greater than the maximum file descriptor number that can be
+ // opened by this process.
+ OpenFiles int64
+ // Maximum number of bytes of memory that may be locked into RAM.
+ LockedMemory int64
+ // Maximum size of the process's virtual memory address space in bytes.
+ AddressSpace int64
+ // Limit on the combined number of flock(2) locks and fcntl(2) leases that
+ // this process may establish.
+ FileLocks int64
+ // Limit of signals that may be queued for the real user ID of the calling
+ // process.
+ PendingSignals int64
+ // Limit on the number of bytes that can be allocated for POSIX message
+ // queues for the real user ID of the calling process.
+ MsqqueueSize int64
+ // Limit of the nice priority set using setpriority(2) or nice(2).
+ NicePriority int64
+ // Limit of the real-time priority set using sched_setscheduler(2) or
+ // sched_setparam(2).
+ RealtimePriority int64
+ // Limit (in microseconds) on the amount of CPU time that a process
+ // scheduled under a real-time scheduling policy may consume without making
+ // a blocking system call.
+ RealtimeTimeout int64
+}
+
+const (
+ limitsFields = 3
+ limitsUnlimited = "unlimited"
+)
+
+var (
+ limitsDelimiter = regexp.MustCompile(" +")
+)
+
+// NewLimits returns the current soft limits of the process.
+//
+// Deprecated: use p.Limits() instead
+func (p Proc) NewLimits() (ProcLimits, error) {
+ return p.Limits()
+}
+
+// Limits returns the current soft limits of the process.
+func (p Proc) Limits() (ProcLimits, error) {
+ f, err := os.Open(p.path("limits"))
+ if err != nil {
+ return ProcLimits{}, err
+ }
+ defer f.Close()
+
+ var (
+ l = ProcLimits{}
+ s = bufio.NewScanner(f)
+ )
+ for s.Scan() {
+ fields := limitsDelimiter.Split(s.Text(), limitsFields)
+ if len(fields) != limitsFields {
+ return ProcLimits{}, fmt.Errorf(
+ "couldn't parse %s line %s", f.Name(), s.Text())
+ }
+
+ switch fields[0] {
+ case "Max cpu time":
+ l.CPUTime, err = parseInt(fields[1])
+ case "Max file size":
+ l.FileSize, err = parseInt(fields[1])
+ case "Max data size":
+ l.DataSize, err = parseInt(fields[1])
+ case "Max stack size":
+ l.StackSize, err = parseInt(fields[1])
+ case "Max core file size":
+ l.CoreFileSize, err = parseInt(fields[1])
+ case "Max resident set":
+ l.ResidentSet, err = parseInt(fields[1])
+ case "Max processes":
+ l.Processes, err = parseInt(fields[1])
+ case "Max open files":
+ l.OpenFiles, err = parseInt(fields[1])
+ case "Max locked memory":
+ l.LockedMemory, err = parseInt(fields[1])
+ case "Max address space":
+ l.AddressSpace, err = parseInt(fields[1])
+ case "Max file locks":
+ l.FileLocks, err = parseInt(fields[1])
+ case "Max pending signals":
+ l.PendingSignals, err = parseInt(fields[1])
+ case "Max msgqueue size":
+ l.MsqqueueSize, err = parseInt(fields[1])
+ case "Max nice priority":
+ l.NicePriority, err = parseInt(fields[1])
+ case "Max realtime priority":
+ l.RealtimePriority, err = parseInt(fields[1])
+ case "Max realtime timeout":
+ l.RealtimeTimeout, err = parseInt(fields[1])
+ }
+ if err != nil {
+ return ProcLimits{}, err
+ }
+ }
+
+ return l, s.Err()
+}
+
+func parseInt(s string) (int64, error) {
+ if s == limitsUnlimited {
+ return -1, nil
+ }
+ i, err := strconv.ParseInt(s, 10, 64)
+ if err != nil {
+ return 0, fmt.Errorf("couldn't parse value %s: %s", s, err)
+ }
+ return i, nil
+}
diff --git a/vendor/github.com/prometheus/procfs/proc_ns.go b/vendor/github.com/prometheus/procfs/proc_ns.go
new file mode 100644
index 0000000..c66740f
--- /dev/null
+++ b/vendor/github.com/prometheus/procfs/proc_ns.go
@@ -0,0 +1,68 @@
+// Copyright 2018 The Prometheus Authors
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package procfs
+
+import (
+ "fmt"
+ "os"
+ "strconv"
+ "strings"
+)
+
+// Namespace represents a single namespace of a process.
+type Namespace struct {
+ Type string // Namespace type.
+ Inode uint32 // Inode number of the namespace. If two processes are in the same namespace their inodes will match.
+}
+
+// Namespaces contains all of the namespaces that the process is contained in.
+type Namespaces map[string]Namespace
+
+// Namespaces reads from /proc//ns/* to get the namespaces of which the
+// process is a member.
+func (p Proc) Namespaces() (Namespaces, error) {
+ d, err := os.Open(p.path("ns"))
+ if err != nil {
+ return nil, err
+ }
+ defer d.Close()
+
+ names, err := d.Readdirnames(-1)
+ if err != nil {
+ return nil, fmt.Errorf("failed to read contents of ns dir: %v", err)
+ }
+
+ ns := make(Namespaces, len(names))
+ for _, name := range names {
+ target, err := os.Readlink(p.path("ns", name))
+ if err != nil {
+ return nil, err
+ }
+
+ fields := strings.SplitN(target, ":", 2)
+ if len(fields) != 2 {
+ return nil, fmt.Errorf("failed to parse namespace type and inode from '%v'", target)
+ }
+
+ typ := fields[0]
+ inode, err := strconv.ParseUint(strings.Trim(fields[1], "[]"), 10, 32)
+ if err != nil {
+ return nil, fmt.Errorf("failed to parse inode from '%v': %v", fields[1], err)
+ }
+
+ ns[name] = Namespace{typ, uint32(inode)}
+ }
+
+ return ns, nil
+}
diff --git a/vendor/github.com/prometheus/procfs/proc_psi.go b/vendor/github.com/prometheus/procfs/proc_psi.go
new file mode 100644
index 0000000..46fe266
--- /dev/null
+++ b/vendor/github.com/prometheus/procfs/proc_psi.go
@@ -0,0 +1,101 @@
+// Copyright 2019 The Prometheus Authors
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package procfs
+
+// The PSI / pressure interface is described at
+// https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/accounting/psi.txt
+// Each resource (cpu, io, memory, ...) is exposed as a single file.
+// Each file may contain up to two lines, one for "some" pressure and one for "full" pressure.
+// Each line contains several averages (over n seconds) and a total in µs.
+//
+// Example io pressure file:
+// > some avg10=0.06 avg60=0.21 avg300=0.99 total=8537362
+// > full avg10=0.00 avg60=0.13 avg300=0.96 total=8183134
+
+import (
+ "fmt"
+ "io"
+ "io/ioutil"
+ "os"
+ "strings"
+)
+
+const lineFormat = "avg10=%f avg60=%f avg300=%f total=%d"
+
+// PSILine is a single line of values as returned by /proc/pressure/*
+// The Avg entries are averages over n seconds, as a percentage
+// The Total line is in microseconds
+type PSILine struct {
+ Avg10 float64
+ Avg60 float64
+ Avg300 float64
+ Total uint64
+}
+
+// PSIStats represent pressure stall information from /proc/pressure/*
+// Some indicates the share of time in which at least some tasks are stalled
+// Full indicates the share of time in which all non-idle tasks are stalled simultaneously
+type PSIStats struct {
+ Some *PSILine
+ Full *PSILine
+}
+
+// PSIStatsForResource reads pressure stall information for the specified
+// resource from /proc/pressure/. At time of writing this can be
+// either "cpu", "memory" or "io".
+func (fs FS) PSIStatsForResource(resource string) (PSIStats, error) {
+ file, err := os.Open(fs.proc.Path(fmt.Sprintf("%s/%s", "pressure", resource)))
+ if err != nil {
+ return PSIStats{}, fmt.Errorf("psi_stats: unavailable for %s", resource)
+ }
+
+ defer file.Close()
+ return parsePSIStats(resource, file)
+}
+
+// parsePSIStats parses the specified file for pressure stall information
+func parsePSIStats(resource string, file io.Reader) (PSIStats, error) {
+ psiStats := PSIStats{}
+ stats, err := ioutil.ReadAll(file)
+ if err != nil {
+ return psiStats, fmt.Errorf("psi_stats: unable to read data for %s", resource)
+ }
+
+ for _, l := range strings.Split(string(stats), "\n") {
+ prefix := strings.Split(l, " ")[0]
+ switch prefix {
+ case "some":
+ psi := PSILine{}
+ _, err := fmt.Sscanf(l, fmt.Sprintf("some %s", lineFormat), &psi.Avg10, &psi.Avg60, &psi.Avg300, &psi.Total)
+ if err != nil {
+ return PSIStats{}, err
+ }
+ psiStats.Some = &psi
+ case "full":
+ psi := PSILine{}
+ _, err := fmt.Sscanf(l, fmt.Sprintf("full %s", lineFormat), &psi.Avg10, &psi.Avg60, &psi.Avg300, &psi.Total)
+ if err != nil {
+ return PSIStats{}, err
+ }
+ psiStats.Full = &psi
+ default:
+ // If we encounter a line with an unknown prefix, ignore it and move on
+ // Should new measurement types be added in the future we'll simply ignore them instead
+ // of erroring on retrieval
+ continue
+ }
+ }
+
+ return psiStats, nil
+}
diff --git a/vendor/github.com/prometheus/procfs/proc_stat.go b/vendor/github.com/prometheus/procfs/proc_stat.go
new file mode 100644
index 0000000..dbde1fa
--- /dev/null
+++ b/vendor/github.com/prometheus/procfs/proc_stat.go
@@ -0,0 +1,198 @@
+// Copyright 2018 The Prometheus Authors
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package procfs
+
+import (
+ "bytes"
+ "fmt"
+ "io/ioutil"
+ "os"
+
+ "github.com/prometheus/procfs/internal/fs"
+)
+
+// Originally, this USER_HZ value was dynamically retrieved via a sysconf call
+// which required cgo. However, that caused a lot of problems regarding
+// cross-compilation. Alternatives such as running a binary to determine the
+// value, or trying to derive it in some other way were all problematic. After
+// much research it was determined that USER_HZ is actually hardcoded to 100 on
+// all Go-supported platforms as of the time of this writing. This is why we
+// decided to hardcode it here as well. It is not impossible that there could
+// be systems with exceptions, but they should be very exotic edge cases, and
+// in that case, the worst outcome will be two misreported metrics.
+//
+// See also the following discussions:
+//
+// - https://github.com/prometheus/node_exporter/issues/52
+// - https://github.com/prometheus/procfs/pull/2
+// - http://stackoverflow.com/questions/17410841/how-does-user-hz-solve-the-jiffy-scaling-issue
+const userHZ = 100
+
+// ProcStat provides status information about the process,
+// read from /proc/[pid]/stat.
+type ProcStat struct {
+ // The process ID.
+ PID int
+ // The filename of the executable.
+ Comm string
+ // The process state.
+ State string
+ // The PID of the parent of this process.
+ PPID int
+ // The process group ID of the process.
+ PGRP int
+ // The session ID of the process.
+ Session int
+ // The controlling terminal of the process.
+ TTY int
+ // The ID of the foreground process group of the controlling terminal of
+ // the process.
+ TPGID int
+ // The kernel flags word of the process.
+ Flags uint
+ // The number of minor faults the process has made which have not required
+ // loading a memory page from disk.
+ MinFlt uint
+ // The number of minor faults that the process's waited-for children have
+ // made.
+ CMinFlt uint
+ // The number of major faults the process has made which have required
+ // loading a memory page from disk.
+ MajFlt uint
+ // The number of major faults that the process's waited-for children have
+ // made.
+ CMajFlt uint
+ // Amount of time that this process has been scheduled in user mode,
+ // measured in clock ticks.
+ UTime uint
+ // Amount of time that this process has been scheduled in kernel mode,
+ // measured in clock ticks.
+ STime uint
+ // Amount of time that this process's waited-for children have been
+ // scheduled in user mode, measured in clock ticks.
+ CUTime uint
+ // Amount of time that this process's waited-for children have been
+ // scheduled in kernel mode, measured in clock ticks.
+ CSTime uint
+ // For processes running a real-time scheduling policy, this is the negated
+ // scheduling priority, minus one.
+ Priority int
+ // The nice value, a value in the range 19 (low priority) to -20 (high
+ // priority).
+ Nice int
+ // Number of threads in this process.
+ NumThreads int
+ // The time the process started after system boot, the value is expressed
+ // in clock ticks.
+ Starttime uint64
+ // Virtual memory size in bytes.
+ VSize uint
+ // Resident set size in pages.
+ RSS int
+
+ proc fs.FS
+}
+
+// NewStat returns the current status information of the process.
+//
+// Deprecated: use p.Stat() instead
+func (p Proc) NewStat() (ProcStat, error) {
+ return p.Stat()
+}
+
+// Stat returns the current status information of the process.
+func (p Proc) Stat() (ProcStat, error) {
+ f, err := os.Open(p.path("stat"))
+ if err != nil {
+ return ProcStat{}, err
+ }
+ defer f.Close()
+
+ data, err := ioutil.ReadAll(f)
+ if err != nil {
+ return ProcStat{}, err
+ }
+
+ var (
+ ignore int
+
+ s = ProcStat{PID: p.PID, proc: p.fs}
+ l = bytes.Index(data, []byte("("))
+ r = bytes.LastIndex(data, []byte(")"))
+ )
+
+ if l < 0 || r < 0 {
+ return ProcStat{}, fmt.Errorf(
+ "unexpected format, couldn't extract comm: %s",
+ data,
+ )
+ }
+
+ s.Comm = string(data[l+1 : r])
+ _, err = fmt.Fscan(
+ bytes.NewBuffer(data[r+2:]),
+ &s.State,
+ &s.PPID,
+ &s.PGRP,
+ &s.Session,
+ &s.TTY,
+ &s.TPGID,
+ &s.Flags,
+ &s.MinFlt,
+ &s.CMinFlt,
+ &s.MajFlt,
+ &s.CMajFlt,
+ &s.UTime,
+ &s.STime,
+ &s.CUTime,
+ &s.CSTime,
+ &s.Priority,
+ &s.Nice,
+ &s.NumThreads,
+ &ignore,
+ &s.Starttime,
+ &s.VSize,
+ &s.RSS,
+ )
+ if err != nil {
+ return ProcStat{}, err
+ }
+
+ return s, nil
+}
+
+// VirtualMemory returns the virtual memory size in bytes.
+func (s ProcStat) VirtualMemory() uint {
+ return s.VSize
+}
+
+// ResidentMemory returns the resident memory size in bytes.
+func (s ProcStat) ResidentMemory() int {
+ return s.RSS * os.Getpagesize()
+}
+
+// StartTime returns the unix timestamp of the process in seconds.
+func (s ProcStat) StartTime() (float64, error) {
+ fs := FS{proc: s.proc}
+ stat, err := fs.Stat()
+ if err != nil {
+ return 0, err
+ }
+ return float64(stat.BootTime) + (float64(s.Starttime) / userHZ), nil
+}
+
+// CPUTime returns the total CPU user and system time in seconds.
+func (s ProcStat) CPUTime() float64 {
+ return float64(s.UTime+s.STime) / userHZ
+}
diff --git a/vendor/github.com/prometheus/procfs/proc_status.go b/vendor/github.com/prometheus/procfs/proc_status.go
new file mode 100644
index 0000000..6b4b61f
--- /dev/null
+++ b/vendor/github.com/prometheus/procfs/proc_status.go
@@ -0,0 +1,162 @@
+// Copyright 2018 The Prometheus Authors
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package procfs
+
+import (
+ "bytes"
+ "io/ioutil"
+ "os"
+ "strconv"
+ "strings"
+)
+
+// ProcStat provides status information about the process,
+// read from /proc/[pid]/stat.
+type ProcStatus struct {
+ // The process ID.
+ PID int
+ // The process name.
+ Name string
+
+ // Peak virtual memory size.
+ VmPeak uint64
+ // Virtual memory size.
+ VmSize uint64
+ // Locked memory size.
+ VmLck uint64
+ // Pinned memory size.
+ VmPin uint64
+ // Peak resident set size.
+ VmHWM uint64
+ // Resident set size (sum of RssAnnon RssFile and RssShmem).
+ VmRSS uint64
+ // Size of resident anonymous memory.
+ RssAnon uint64
+ // Size of resident file mappings.
+ RssFile uint64
+ // Size of resident shared memory.
+ RssShmem uint64
+ // Size of data segments.
+ VmData uint64
+ // Size of stack segments.
+ VmStk uint64
+ // Size of text segments.
+ VmExe uint64
+ // Shared library code size.
+ VmLib uint64
+ // Page table entries size.
+ VmPTE uint64
+ // Size of second-level page tables.
+ VmPMD uint64
+ // Swapped-out virtual memory size by anonymous private.
+ VmSwap uint64
+ // Size of hugetlb memory portions
+ HugetlbPages uint64
+
+ // Number of voluntary context switches.
+ VoluntaryCtxtSwitches uint64
+ // Number of involuntary context switches.
+ NonVoluntaryCtxtSwitches uint64
+}
+
+// NewStatus returns the current status information of the process.
+func (p Proc) NewStatus() (ProcStatus, error) {
+ f, err := os.Open(p.path("status"))
+ if err != nil {
+ return ProcStatus{}, err
+ }
+ defer f.Close()
+
+ data, err := ioutil.ReadAll(f)
+ if err != nil {
+ return ProcStatus{}, err
+ }
+
+ s := ProcStatus{PID: p.PID}
+
+ lines := strings.Split(string(data), "\n")
+ for _, line := range lines {
+ if !bytes.Contains([]byte(line), []byte(":")) {
+ continue
+ }
+
+ kv := strings.SplitN(line, ":", 2)
+
+ // removes spaces
+ k := string(strings.TrimSpace(kv[0]))
+ v := string(strings.TrimSpace(kv[1]))
+ // removes "kB"
+ v = string(bytes.Trim([]byte(v), " kB"))
+
+ // value to int when possible
+ // we can skip error check here, 'cause vKBytes is not used when value is a string
+ vKBytes, _ := strconv.ParseUint(v, 10, 64)
+ // convert kB to B
+ vBytes := vKBytes * 1024
+
+ s.fillStatus(k, v, vKBytes, vBytes)
+ }
+
+ return s, nil
+}
+
+func (s *ProcStatus) fillStatus(k string, vString string, vUint uint64, vUintBytes uint64) {
+ switch k {
+ case "Name":
+ s.Name = vString
+ case "VmPeak":
+ s.VmPeak = vUintBytes
+ case "VmSize":
+ s.VmSize = vUintBytes
+ case "VmLck":
+ s.VmLck = vUintBytes
+ case "VmPin":
+ s.VmPin = vUintBytes
+ case "VmHWM":
+ s.VmHWM = vUintBytes
+ case "VmRSS":
+ s.VmRSS = vUintBytes
+ case "RssAnon":
+ s.RssAnon = vUintBytes
+ case "RssFile":
+ s.RssFile = vUintBytes
+ case "RssShmem":
+ s.RssShmem = vUintBytes
+ case "VmData":
+ s.VmData = vUintBytes
+ case "VmStk":
+ s.VmStk = vUintBytes
+ case "VmExe":
+ s.VmExe = vUintBytes
+ case "VmLib":
+ s.VmLib = vUintBytes
+ case "VmPTE":
+ s.VmPTE = vUintBytes
+ case "VmPMD":
+ s.VmPMD = vUintBytes
+ case "VmSwap":
+ s.VmSwap = vUintBytes
+ case "HugetlbPages":
+ s.HugetlbPages = vUintBytes
+ case "voluntary_ctxt_switches":
+ s.VoluntaryCtxtSwitches = vUint
+ case "nonvoluntary_ctxt_switches":
+ s.NonVoluntaryCtxtSwitches = vUint
+ }
+}
+
+// TotalCtxtSwitches returns the total context switch.
+func (s ProcStatus) TotalCtxtSwitches() uint64 {
+ return s.VoluntaryCtxtSwitches + s.NonVoluntaryCtxtSwitches
+}
diff --git a/vendor/github.com/prometheus/procfs/stat.go b/vendor/github.com/prometheus/procfs/stat.go
new file mode 100644
index 0000000..6661ee0
--- /dev/null
+++ b/vendor/github.com/prometheus/procfs/stat.go
@@ -0,0 +1,244 @@
+// Copyright 2018 The Prometheus Authors
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package procfs
+
+import (
+ "bufio"
+ "fmt"
+ "io"
+ "os"
+ "strconv"
+ "strings"
+
+ "github.com/prometheus/procfs/internal/fs"
+)
+
+// CPUStat shows how much time the cpu spend in various stages.
+type CPUStat struct {
+ User float64
+ Nice float64
+ System float64
+ Idle float64
+ Iowait float64
+ IRQ float64
+ SoftIRQ float64
+ Steal float64
+ Guest float64
+ GuestNice float64
+}
+
+// SoftIRQStat represent the softirq statistics as exported in the procfs stat file.
+// A nice introduction can be found at https://0xax.gitbooks.io/linux-insides/content/interrupts/interrupts-9.html
+// It is possible to get per-cpu stats by reading /proc/softirqs
+type SoftIRQStat struct {
+ Hi uint64
+ Timer uint64
+ NetTx uint64
+ NetRx uint64
+ Block uint64
+ BlockIoPoll uint64
+ Tasklet uint64
+ Sched uint64
+ Hrtimer uint64
+ Rcu uint64
+}
+
+// Stat represents kernel/system statistics.
+type Stat struct {
+ // Boot time in seconds since the Epoch.
+ BootTime uint64
+ // Summed up cpu statistics.
+ CPUTotal CPUStat
+ // Per-CPU statistics.
+ CPU []CPUStat
+ // Number of times interrupts were handled, which contains numbered and unnumbered IRQs.
+ IRQTotal uint64
+ // Number of times a numbered IRQ was triggered.
+ IRQ []uint64
+ // Number of times a context switch happened.
+ ContextSwitches uint64
+ // Number of times a process was created.
+ ProcessCreated uint64
+ // Number of processes currently running.
+ ProcessesRunning uint64
+ // Number of processes currently blocked (waiting for IO).
+ ProcessesBlocked uint64
+ // Number of times a softirq was scheduled.
+ SoftIRQTotal uint64
+ // Detailed softirq statistics.
+ SoftIRQ SoftIRQStat
+}
+
+// Parse a cpu statistics line and returns the CPUStat struct plus the cpu id (or -1 for the overall sum).
+func parseCPUStat(line string) (CPUStat, int64, error) {
+ cpuStat := CPUStat{}
+ var cpu string
+
+ count, err := fmt.Sscanf(line, "%s %f %f %f %f %f %f %f %f %f %f",
+ &cpu,
+ &cpuStat.User, &cpuStat.Nice, &cpuStat.System, &cpuStat.Idle,
+ &cpuStat.Iowait, &cpuStat.IRQ, &cpuStat.SoftIRQ, &cpuStat.Steal,
+ &cpuStat.Guest, &cpuStat.GuestNice)
+
+ if err != nil && err != io.EOF {
+ return CPUStat{}, -1, fmt.Errorf("couldn't parse %s (cpu): %s", line, err)
+ }
+ if count == 0 {
+ return CPUStat{}, -1, fmt.Errorf("couldn't parse %s (cpu): 0 elements parsed", line)
+ }
+
+ cpuStat.User /= userHZ
+ cpuStat.Nice /= userHZ
+ cpuStat.System /= userHZ
+ cpuStat.Idle /= userHZ
+ cpuStat.Iowait /= userHZ
+ cpuStat.IRQ /= userHZ
+ cpuStat.SoftIRQ /= userHZ
+ cpuStat.Steal /= userHZ
+ cpuStat.Guest /= userHZ
+ cpuStat.GuestNice /= userHZ
+
+ if cpu == "cpu" {
+ return cpuStat, -1, nil
+ }
+
+ cpuID, err := strconv.ParseInt(cpu[3:], 10, 64)
+ if err != nil {
+ return CPUStat{}, -1, fmt.Errorf("couldn't parse %s (cpu/cpuid): %s", line, err)
+ }
+
+ return cpuStat, cpuID, nil
+}
+
+// Parse a softirq line.
+func parseSoftIRQStat(line string) (SoftIRQStat, uint64, error) {
+ softIRQStat := SoftIRQStat{}
+ var total uint64
+ var prefix string
+
+ _, err := fmt.Sscanf(line, "%s %d %d %d %d %d %d %d %d %d %d %d",
+ &prefix, &total,
+ &softIRQStat.Hi, &softIRQStat.Timer, &softIRQStat.NetTx, &softIRQStat.NetRx,
+ &softIRQStat.Block, &softIRQStat.BlockIoPoll,
+ &softIRQStat.Tasklet, &softIRQStat.Sched,
+ &softIRQStat.Hrtimer, &softIRQStat.Rcu)
+
+ if err != nil {
+ return SoftIRQStat{}, 0, fmt.Errorf("couldn't parse %s (softirq): %s", line, err)
+ }
+
+ return softIRQStat, total, nil
+}
+
+// NewStat returns information about current cpu/process statistics.
+// See https://www.kernel.org/doc/Documentation/filesystems/proc.txt
+//
+// Deprecated: use fs.Stat() instead
+func NewStat() (Stat, error) {
+ fs, err := NewFS(fs.DefaultProcMountPoint)
+ if err != nil {
+ return Stat{}, err
+ }
+ return fs.Stat()
+}
+
+// NewStat returns information about current cpu/process statistics.
+// See https://www.kernel.org/doc/Documentation/filesystems/proc.txt
+//
+// Deprecated: use fs.Stat() instead
+func (fs FS) NewStat() (Stat, error) {
+ return fs.Stat()
+}
+
+// Stat returns information about current cpu/process statistics.
+// See https://www.kernel.org/doc/Documentation/filesystems/proc.txt
+func (fs FS) Stat() (Stat, error) {
+
+ f, err := os.Open(fs.proc.Path("stat"))
+ if err != nil {
+ return Stat{}, err
+ }
+ defer f.Close()
+
+ stat := Stat{}
+
+ scanner := bufio.NewScanner(f)
+ for scanner.Scan() {
+ line := scanner.Text()
+ parts := strings.Fields(scanner.Text())
+ // require at least
+ if len(parts) < 2 {
+ continue
+ }
+ switch {
+ case parts[0] == "btime":
+ if stat.BootTime, err = strconv.ParseUint(parts[1], 10, 64); err != nil {
+ return Stat{}, fmt.Errorf("couldn't parse %s (btime): %s", parts[1], err)
+ }
+ case parts[0] == "intr":
+ if stat.IRQTotal, err = strconv.ParseUint(parts[1], 10, 64); err != nil {
+ return Stat{}, fmt.Errorf("couldn't parse %s (intr): %s", parts[1], err)
+ }
+ numberedIRQs := parts[2:]
+ stat.IRQ = make([]uint64, len(numberedIRQs))
+ for i, count := range numberedIRQs {
+ if stat.IRQ[i], err = strconv.ParseUint(count, 10, 64); err != nil {
+ return Stat{}, fmt.Errorf("couldn't parse %s (intr%d): %s", count, i, err)
+ }
+ }
+ case parts[0] == "ctxt":
+ if stat.ContextSwitches, err = strconv.ParseUint(parts[1], 10, 64); err != nil {
+ return Stat{}, fmt.Errorf("couldn't parse %s (ctxt): %s", parts[1], err)
+ }
+ case parts[0] == "processes":
+ if stat.ProcessCreated, err = strconv.ParseUint(parts[1], 10, 64); err != nil {
+ return Stat{}, fmt.Errorf("couldn't parse %s (processes): %s", parts[1], err)
+ }
+ case parts[0] == "procs_running":
+ if stat.ProcessesRunning, err = strconv.ParseUint(parts[1], 10, 64); err != nil {
+ return Stat{}, fmt.Errorf("couldn't parse %s (procs_running): %s", parts[1], err)
+ }
+ case parts[0] == "procs_blocked":
+ if stat.ProcessesBlocked, err = strconv.ParseUint(parts[1], 10, 64); err != nil {
+ return Stat{}, fmt.Errorf("couldn't parse %s (procs_blocked): %s", parts[1], err)
+ }
+ case parts[0] == "softirq":
+ softIRQStats, total, err := parseSoftIRQStat(line)
+ if err != nil {
+ return Stat{}, err
+ }
+ stat.SoftIRQTotal = total
+ stat.SoftIRQ = softIRQStats
+ case strings.HasPrefix(parts[0], "cpu"):
+ cpuStat, cpuID, err := parseCPUStat(line)
+ if err != nil {
+ return Stat{}, err
+ }
+ if cpuID == -1 {
+ stat.CPUTotal = cpuStat
+ } else {
+ for int64(len(stat.CPU)) <= cpuID {
+ stat.CPU = append(stat.CPU, CPUStat{})
+ }
+ stat.CPU[cpuID] = cpuStat
+ }
+ }
+ }
+
+ if err := scanner.Err(); err != nil {
+ return Stat{}, fmt.Errorf("couldn't parse %s: %s", f.Name(), err)
+ }
+
+ return stat, nil
+}
diff --git a/vendor/github.com/prometheus/procfs/ttar b/vendor/github.com/prometheus/procfs/ttar
new file mode 100644
index 0000000..19ef02b
--- /dev/null
+++ b/vendor/github.com/prometheus/procfs/ttar
@@ -0,0 +1,413 @@
+#!/usr/bin/env bash
+
+# Purpose: plain text tar format
+# Limitations: - only suitable for text files, directories, and symlinks
+# - stores only filename, content, and mode
+# - not designed for untrusted input
+#
+# Note: must work with bash version 3.2 (macOS)
+
+# Copyright 2017 Roger Luethi
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -o errexit -o nounset
+
+# Sanitize environment (for instance, standard sorting of glob matches)
+export LC_ALL=C
+
+path=""
+CMD=""
+ARG_STRING="$*"
+
+#------------------------------------------------------------------------------
+# Not all sed implementations can work on null bytes. In order to make ttar
+# work out of the box on macOS, use Python as a stream editor.
+
+USE_PYTHON=0
+
+PYTHON_CREATE_FILTER=$(cat << 'PCF'
+#!/usr/bin/env python
+
+import re
+import sys
+
+for line in sys.stdin:
+ line = re.sub(r'EOF', r'\EOF', line)
+ line = re.sub(r'NULLBYTE', r'\NULLBYTE', line)
+ line = re.sub('\x00', r'NULLBYTE', line)
+ sys.stdout.write(line)
+PCF
+)
+
+PYTHON_EXTRACT_FILTER=$(cat << 'PEF'
+#!/usr/bin/env python
+
+import re
+import sys
+
+for line in sys.stdin:
+ line = re.sub(r'(?/dev/null; then
+ echo "ERROR Python not found. Aborting."
+ exit 2
+ fi
+ USE_PYTHON=1
+ fi
+}
+
+#------------------------------------------------------------------------------
+
+function usage {
+ bname=$(basename "$0")
+ cat << USAGE
+Usage: $bname [-C ] -c -f (create archive)
+ $bname -t -f (list archive contents)
+ $bname [-C ] -x -f (extract archive)
+
+Options:
+ -C (change directory)
+ -v (verbose)
+ --recursive-unlink (recursively delete existing directory if path
+ collides with file or directory to extract)
+
+Example: Change to sysfs directory, create ttar file from fixtures directory
+ $bname -C sysfs -c -f sysfs/fixtures.ttar fixtures/
+USAGE
+exit "$1"
+}
+
+function vecho {
+ if [ "${VERBOSE:-}" == "yes" ]; then
+ echo >&7 "$@"
+ fi
+}
+
+function set_cmd {
+ if [ -n "$CMD" ]; then
+ echo "ERROR: more than one command given"
+ echo
+ usage 2
+ fi
+ CMD=$1
+}
+
+unset VERBOSE
+unset RECURSIVE_UNLINK
+
+while getopts :cf:-:htxvC: opt; do
+ case $opt in
+ c)
+ set_cmd "create"
+ ;;
+ f)
+ ARCHIVE=$OPTARG
+ ;;
+ h)
+ usage 0
+ ;;
+ t)
+ set_cmd "list"
+ ;;
+ x)
+ set_cmd "extract"
+ ;;
+ v)
+ VERBOSE=yes
+ exec 7>&1
+ ;;
+ C)
+ CDIR=$OPTARG
+ ;;
+ -)
+ case $OPTARG in
+ recursive-unlink)
+ RECURSIVE_UNLINK="yes"
+ ;;
+ *)
+ echo -e "Error: invalid option -$OPTARG"
+ echo
+ usage 1
+ ;;
+ esac
+ ;;
+ *)
+ echo >&2 "ERROR: invalid option -$OPTARG"
+ echo
+ usage 1
+ ;;
+ esac
+done
+
+# Remove processed options from arguments
+shift $(( OPTIND - 1 ));
+
+if [ "${CMD:-}" == "" ]; then
+ echo >&2 "ERROR: no command given"
+ echo
+ usage 1
+elif [ "${ARCHIVE:-}" == "" ]; then
+ echo >&2 "ERROR: no archive name given"
+ echo
+ usage 1
+fi
+
+function list {
+ local path=""
+ local size=0
+ local line_no=0
+ local ttar_file=$1
+ if [ -n "${2:-}" ]; then
+ echo >&2 "ERROR: too many arguments."
+ echo
+ usage 1
+ fi
+ if [ ! -e "$ttar_file" ]; then
+ echo >&2 "ERROR: file not found ($ttar_file)"
+ echo
+ usage 1
+ fi
+ while read -r line; do
+ line_no=$(( line_no + 1 ))
+ if [ $size -gt 0 ]; then
+ size=$(( size - 1 ))
+ continue
+ fi
+ if [[ $line =~ ^Path:\ (.*)$ ]]; then
+ path=${BASH_REMATCH[1]}
+ elif [[ $line =~ ^Lines:\ (.*)$ ]]; then
+ size=${BASH_REMATCH[1]}
+ echo "$path"
+ elif [[ $line =~ ^Directory:\ (.*)$ ]]; then
+ path=${BASH_REMATCH[1]}
+ echo "$path/"
+ elif [[ $line =~ ^SymlinkTo:\ (.*)$ ]]; then
+ echo "$path -> ${BASH_REMATCH[1]}"
+ fi
+ done < "$ttar_file"
+}
+
+function extract {
+ local path=""
+ local size=0
+ local line_no=0
+ local ttar_file=$1
+ if [ -n "${2:-}" ]; then
+ echo >&2 "ERROR: too many arguments."
+ echo
+ usage 1
+ fi
+ if [ ! -e "$ttar_file" ]; then
+ echo >&2 "ERROR: file not found ($ttar_file)"
+ echo
+ usage 1
+ fi
+ while IFS= read -r line; do
+ line_no=$(( line_no + 1 ))
+ local eof_without_newline
+ if [ "$size" -gt 0 ]; then
+ if [[ "$line" =~ [^\\]EOF ]]; then
+ # An EOF not preceded by a backslash indicates that the line
+ # does not end with a newline
+ eof_without_newline=1
+ else
+ eof_without_newline=0
+ fi
+ # Replace NULLBYTE with null byte if at beginning of line
+ # Replace NULLBYTE with null byte unless preceded by backslash
+ # Remove one backslash in front of NULLBYTE (if any)
+ # Remove EOF unless preceded by backslash
+ # Remove one backslash in front of EOF
+ if [ $USE_PYTHON -eq 1 ]; then
+ echo -n "$line" | python -c "$PYTHON_EXTRACT_FILTER" >> "$path"
+ else
+ # The repeated pattern makes up for sed's lack of negative
+ # lookbehind assertions (for consecutive null bytes).
+ echo -n "$line" | \
+ sed -e 's/^NULLBYTE/\x0/g;
+ s/\([^\\]\)NULLBYTE/\1\x0/g;
+ s/\([^\\]\)NULLBYTE/\1\x0/g;
+ s/\\NULLBYTE/NULLBYTE/g;
+ s/\([^\\]\)EOF/\1/g;
+ s/\\EOF/EOF/g;
+ ' >> "$path"
+ fi
+ if [[ "$eof_without_newline" -eq 0 ]]; then
+ echo >> "$path"
+ fi
+ size=$(( size - 1 ))
+ continue
+ fi
+ if [[ $line =~ ^Path:\ (.*)$ ]]; then
+ path=${BASH_REMATCH[1]}
+ if [ -L "$path" ]; then
+ rm "$path"
+ elif [ -d "$path" ]; then
+ if [ "${RECURSIVE_UNLINK:-}" == "yes" ]; then
+ rm -r "$path"
+ else
+ # Safe because symlinks to directories are dealt with above
+ rmdir "$path"
+ fi
+ elif [ -e "$path" ]; then
+ rm "$path"
+ fi
+ elif [[ $line =~ ^Lines:\ (.*)$ ]]; then
+ size=${BASH_REMATCH[1]}
+ # Create file even if it is zero-length.
+ touch "$path"
+ vecho " $path"
+ elif [[ $line =~ ^Mode:\ (.*)$ ]]; then
+ mode=${BASH_REMATCH[1]}
+ chmod "$mode" "$path"
+ vecho "$mode"
+ elif [[ $line =~ ^Directory:\ (.*)$ ]]; then
+ path=${BASH_REMATCH[1]}
+ mkdir -p "$path"
+ vecho " $path/"
+ elif [[ $line =~ ^SymlinkTo:\ (.*)$ ]]; then
+ ln -s "${BASH_REMATCH[1]}" "$path"
+ vecho " $path -> ${BASH_REMATCH[1]}"
+ elif [[ $line =~ ^# ]]; then
+ # Ignore comments between files
+ continue
+ else
+ echo >&2 "ERROR: Unknown keyword on line $line_no: $line"
+ exit 1
+ fi
+ done < "$ttar_file"
+}
+
+function div {
+ echo "# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -" \
+ "- - - - - -"
+}
+
+function get_mode {
+ local mfile=$1
+ if [ -z "${STAT_OPTION:-}" ]; then
+ if stat -c '%a' "$mfile" >/dev/null 2>&1; then
+ # GNU stat
+ STAT_OPTION='-c'
+ STAT_FORMAT='%a'
+ else
+ # BSD stat
+ STAT_OPTION='-f'
+ # Octal output, user/group/other (omit file type, sticky bit)
+ STAT_FORMAT='%OLp'
+ fi
+ fi
+ stat "${STAT_OPTION}" "${STAT_FORMAT}" "$mfile"
+}
+
+function _create {
+ shopt -s nullglob
+ local mode
+ local eof_without_newline
+ while (( "$#" )); do
+ file=$1
+ if [ -L "$file" ]; then
+ echo "Path: $file"
+ symlinkTo=$(readlink "$file")
+ echo "SymlinkTo: $symlinkTo"
+ vecho " $file -> $symlinkTo"
+ div
+ elif [ -d "$file" ]; then
+ # Strip trailing slash (if there is one)
+ file=${file%/}
+ echo "Directory: $file"
+ mode=$(get_mode "$file")
+ echo "Mode: $mode"
+ vecho "$mode $file/"
+ div
+ # Find all files and dirs, including hidden/dot files
+ for x in "$file/"{*,.[^.]*}; do
+ _create "$x"
+ done
+ elif [ -f "$file" ]; then
+ echo "Path: $file"
+ lines=$(wc -l "$file"|awk '{print $1}')
+ eof_without_newline=0
+ if [[ "$(wc -c "$file"|awk '{print $1}')" -gt 0 ]] && \
+ [[ "$(tail -c 1 "$file" | wc -l)" -eq 0 ]]; then
+ eof_without_newline=1
+ lines=$((lines+1))
+ fi
+ echo "Lines: $lines"
+ # Add backslash in front of EOF
+ # Add backslash in front of NULLBYTE
+ # Replace null byte with NULLBYTE
+ if [ $USE_PYTHON -eq 1 ]; then
+ < "$file" python -c "$PYTHON_CREATE_FILTER"
+ else
+ < "$file" \
+ sed 's/EOF/\\EOF/g;
+ s/NULLBYTE/\\NULLBYTE/g;
+ s/\x0/NULLBYTE/g;
+ '
+ fi
+ if [[ "$eof_without_newline" -eq 1 ]]; then
+ # Finish line with EOF to indicate that the original line did
+ # not end with a linefeed
+ echo "EOF"
+ fi
+ mode=$(get_mode "$file")
+ echo "Mode: $mode"
+ vecho "$mode $file"
+ div
+ else
+ echo >&2 "ERROR: file not found ($file in $(pwd))"
+ exit 2
+ fi
+ shift
+ done
+}
+
+function create {
+ ttar_file=$1
+ shift
+ if [ -z "${1:-}" ]; then
+ echo >&2 "ERROR: missing arguments."
+ echo
+ usage 1
+ fi
+ if [ -e "$ttar_file" ]; then
+ rm "$ttar_file"
+ fi
+ exec > "$ttar_file"
+ echo "# Archive created by ttar $ARG_STRING"
+ _create "$@"
+}
+
+test_environment
+
+if [ -n "${CDIR:-}" ]; then
+ if [[ "$ARCHIVE" != /* ]]; then
+ # Relative path: preserve the archive's location before changing
+ # directory
+ ARCHIVE="$(pwd)/$ARCHIVE"
+ fi
+ cd "$CDIR"
+fi
+
+"$CMD" "$ARCHIVE" "$@"
diff --git a/vendor/github.com/prometheus/procfs/xfrm.go b/vendor/github.com/prometheus/procfs/xfrm.go
new file mode 100644
index 0000000..30aa417
--- /dev/null
+++ b/vendor/github.com/prometheus/procfs/xfrm.go
@@ -0,0 +1,187 @@
+// Copyright 2017 Prometheus Team
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package procfs
+
+import (
+ "bufio"
+ "fmt"
+ "os"
+ "strconv"
+ "strings"
+)
+
+// XfrmStat models the contents of /proc/net/xfrm_stat.
+type XfrmStat struct {
+ // All errors which are not matched by other
+ XfrmInError int
+ // No buffer is left
+ XfrmInBufferError int
+ // Header Error
+ XfrmInHdrError int
+ // No state found
+ // i.e. either inbound SPI, address, or IPSEC protocol at SA is wrong
+ XfrmInNoStates int
+ // Transformation protocol specific error
+ // e.g. SA Key is wrong
+ XfrmInStateProtoError int
+ // Transformation mode specific error
+ XfrmInStateModeError int
+ // Sequence error
+ // e.g. sequence number is out of window
+ XfrmInStateSeqError int
+ // State is expired
+ XfrmInStateExpired int
+ // State has mismatch option
+ // e.g. UDP encapsulation type is mismatched
+ XfrmInStateMismatch int
+ // State is invalid
+ XfrmInStateInvalid int
+ // No matching template for states
+ // e.g. Inbound SAs are correct but SP rule is wrong
+ XfrmInTmplMismatch int
+ // No policy is found for states
+ // e.g. Inbound SAs are correct but no SP is found
+ XfrmInNoPols int
+ // Policy discards
+ XfrmInPolBlock int
+ // Policy error
+ XfrmInPolError int
+ // All errors which are not matched by others
+ XfrmOutError int
+ // Bundle generation error
+ XfrmOutBundleGenError int
+ // Bundle check error
+ XfrmOutBundleCheckError int
+ // No state was found
+ XfrmOutNoStates int
+ // Transformation protocol specific error
+ XfrmOutStateProtoError int
+ // Transportation mode specific error
+ XfrmOutStateModeError int
+ // Sequence error
+ // i.e sequence number overflow
+ XfrmOutStateSeqError int
+ // State is expired
+ XfrmOutStateExpired int
+ // Policy discads
+ XfrmOutPolBlock int
+ // Policy is dead
+ XfrmOutPolDead int
+ // Policy Error
+ XfrmOutPolError int
+ XfrmFwdHdrError int
+ XfrmOutStateInvalid int
+ XfrmAcquireError int
+}
+
+// NewXfrmStat reads the xfrm_stat statistics.
+func NewXfrmStat() (XfrmStat, error) {
+ fs, err := NewFS(DefaultMountPoint)
+ if err != nil {
+ return XfrmStat{}, err
+ }
+
+ return fs.NewXfrmStat()
+}
+
+// NewXfrmStat reads the xfrm_stat statistics from the 'proc' filesystem.
+func (fs FS) NewXfrmStat() (XfrmStat, error) {
+ file, err := os.Open(fs.proc.Path("net/xfrm_stat"))
+ if err != nil {
+ return XfrmStat{}, err
+ }
+ defer file.Close()
+
+ var (
+ x = XfrmStat{}
+ s = bufio.NewScanner(file)
+ )
+
+ for s.Scan() {
+ fields := strings.Fields(s.Text())
+
+ if len(fields) != 2 {
+ return XfrmStat{}, fmt.Errorf(
+ "couldn't parse %s line %s", file.Name(), s.Text())
+ }
+
+ name := fields[0]
+ value, err := strconv.Atoi(fields[1])
+ if err != nil {
+ return XfrmStat{}, err
+ }
+
+ switch name {
+ case "XfrmInError":
+ x.XfrmInError = value
+ case "XfrmInBufferError":
+ x.XfrmInBufferError = value
+ case "XfrmInHdrError":
+ x.XfrmInHdrError = value
+ case "XfrmInNoStates":
+ x.XfrmInNoStates = value
+ case "XfrmInStateProtoError":
+ x.XfrmInStateProtoError = value
+ case "XfrmInStateModeError":
+ x.XfrmInStateModeError = value
+ case "XfrmInStateSeqError":
+ x.XfrmInStateSeqError = value
+ case "XfrmInStateExpired":
+ x.XfrmInStateExpired = value
+ case "XfrmInStateInvalid":
+ x.XfrmInStateInvalid = value
+ case "XfrmInTmplMismatch":
+ x.XfrmInTmplMismatch = value
+ case "XfrmInNoPols":
+ x.XfrmInNoPols = value
+ case "XfrmInPolBlock":
+ x.XfrmInPolBlock = value
+ case "XfrmInPolError":
+ x.XfrmInPolError = value
+ case "XfrmOutError":
+ x.XfrmOutError = value
+ case "XfrmInStateMismatch":
+ x.XfrmInStateMismatch = value
+ case "XfrmOutBundleGenError":
+ x.XfrmOutBundleGenError = value
+ case "XfrmOutBundleCheckError":
+ x.XfrmOutBundleCheckError = value
+ case "XfrmOutNoStates":
+ x.XfrmOutNoStates = value
+ case "XfrmOutStateProtoError":
+ x.XfrmOutStateProtoError = value
+ case "XfrmOutStateModeError":
+ x.XfrmOutStateModeError = value
+ case "XfrmOutStateSeqError":
+ x.XfrmOutStateSeqError = value
+ case "XfrmOutStateExpired":
+ x.XfrmOutStateExpired = value
+ case "XfrmOutPolBlock":
+ x.XfrmOutPolBlock = value
+ case "XfrmOutPolDead":
+ x.XfrmOutPolDead = value
+ case "XfrmOutPolError":
+ x.XfrmOutPolError = value
+ case "XfrmFwdHdrError":
+ x.XfrmFwdHdrError = value
+ case "XfrmOutStateInvalid":
+ x.XfrmOutStateInvalid = value
+ case "XfrmAcquireError":
+ x.XfrmAcquireError = value
+ }
+
+ }
+
+ return x, s.Err()
+}
diff --git a/vendor/github.com/shirou/gopsutil/LICENSE b/vendor/github.com/shirou/gopsutil/LICENSE
new file mode 100644
index 0000000..da71a5e
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/LICENSE
@@ -0,0 +1,61 @@
+gopsutil is distributed under BSD license reproduced below.
+
+Copyright (c) 2014, WAKAYAMA Shirou
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of the gopsutil authors nor the names of its contributors
+ may be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+-------
+internal/common/binary.go in the gopsutil is copied and modifid from golang/encoding/binary.go.
+
+
+
+Copyright (c) 2009 The Go Authors. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+ * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\ No newline at end of file
diff --git a/vendor/github.com/shirou/gopsutil/cpu/cpu.go b/vendor/github.com/shirou/gopsutil/cpu/cpu.go
new file mode 100644
index 0000000..ceaf77f
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/cpu/cpu.go
@@ -0,0 +1,189 @@
+package cpu
+
+import (
+ "context"
+ "encoding/json"
+ "fmt"
+ "runtime"
+ "strconv"
+ "strings"
+ "sync"
+ "time"
+
+ "github.com/shirou/gopsutil/internal/common"
+)
+
+// TimesStat contains the amounts of time the CPU has spent performing different
+// kinds of work. Time units are in USER_HZ or Jiffies (typically hundredths of
+// a second). It is based on linux /proc/stat file.
+type TimesStat struct {
+ CPU string `json:"cpu"`
+ User float64 `json:"user"`
+ System float64 `json:"system"`
+ Idle float64 `json:"idle"`
+ Nice float64 `json:"nice"`
+ Iowait float64 `json:"iowait"`
+ Irq float64 `json:"irq"`
+ Softirq float64 `json:"softirq"`
+ Steal float64 `json:"steal"`
+ Guest float64 `json:"guest"`
+ GuestNice float64 `json:"guestNice"`
+ Stolen float64 `json:"stolen"`
+}
+
+type InfoStat struct {
+ CPU int32 `json:"cpu"`
+ VendorID string `json:"vendorId"`
+ Family string `json:"family"`
+ Model string `json:"model"`
+ Stepping int32 `json:"stepping"`
+ PhysicalID string `json:"physicalId"`
+ CoreID string `json:"coreId"`
+ Cores int32 `json:"cores"`
+ ModelName string `json:"modelName"`
+ Mhz float64 `json:"mhz"`
+ CacheSize int32 `json:"cacheSize"`
+ Flags []string `json:"flags"`
+ Microcode string `json:"microcode"`
+}
+
+type lastPercent struct {
+ sync.Mutex
+ lastCPUTimes []TimesStat
+ lastPerCPUTimes []TimesStat
+}
+
+var lastCPUPercent lastPercent
+var invoke common.Invoker = common.Invoke{}
+
+func init() {
+ lastCPUPercent.Lock()
+ lastCPUPercent.lastCPUTimes, _ = Times(false)
+ lastCPUPercent.lastPerCPUTimes, _ = Times(true)
+ lastCPUPercent.Unlock()
+}
+
+func Counts(logical bool) (int, error) {
+ return CountsWithContext(context.Background(), logical)
+}
+
+func CountsWithContext(ctx context.Context, logical bool) (int, error) {
+ return runtime.NumCPU(), nil
+}
+
+func (c TimesStat) String() string {
+ v := []string{
+ `"cpu":"` + c.CPU + `"`,
+ `"user":` + strconv.FormatFloat(c.User, 'f', 1, 64),
+ `"system":` + strconv.FormatFloat(c.System, 'f', 1, 64),
+ `"idle":` + strconv.FormatFloat(c.Idle, 'f', 1, 64),
+ `"nice":` + strconv.FormatFloat(c.Nice, 'f', 1, 64),
+ `"iowait":` + strconv.FormatFloat(c.Iowait, 'f', 1, 64),
+ `"irq":` + strconv.FormatFloat(c.Irq, 'f', 1, 64),
+ `"softirq":` + strconv.FormatFloat(c.Softirq, 'f', 1, 64),
+ `"steal":` + strconv.FormatFloat(c.Steal, 'f', 1, 64),
+ `"guest":` + strconv.FormatFloat(c.Guest, 'f', 1, 64),
+ `"guestNice":` + strconv.FormatFloat(c.GuestNice, 'f', 1, 64),
+ `"stolen":` + strconv.FormatFloat(c.Stolen, 'f', 1, 64),
+ }
+
+ return `{` + strings.Join(v, ",") + `}`
+}
+
+// Total returns the total number of seconds in a CPUTimesStat
+func (c TimesStat) Total() float64 {
+ total := c.User + c.System + c.Nice + c.Iowait + c.Irq + c.Softirq + c.Steal +
+ c.Guest + c.GuestNice + c.Idle + c.Stolen
+ return total
+}
+
+func (c InfoStat) String() string {
+ s, _ := json.Marshal(c)
+ return string(s)
+}
+
+func getAllBusy(t TimesStat) (float64, float64) {
+ busy := t.User + t.System + t.Nice + t.Iowait + t.Irq +
+ t.Softirq + t.Steal + t.Guest + t.GuestNice + t.Stolen
+ return busy + t.Idle, busy
+}
+
+func calculateBusy(t1, t2 TimesStat) float64 {
+ t1All, t1Busy := getAllBusy(t1)
+ t2All, t2Busy := getAllBusy(t2)
+
+ if t2Busy <= t1Busy {
+ return 0
+ }
+ if t2All <= t1All {
+ return 1
+ }
+ return (t2Busy - t1Busy) / (t2All - t1All) * 100
+}
+
+func calculateAllBusy(t1, t2 []TimesStat) ([]float64, error) {
+ // Make sure the CPU measurements have the same length.
+ if len(t1) != len(t2) {
+ return nil, fmt.Errorf(
+ "received two CPU counts: %d != %d",
+ len(t1), len(t2),
+ )
+ }
+
+ ret := make([]float64, len(t1))
+ for i, t := range t2 {
+ ret[i] = calculateBusy(t1[i], t)
+ }
+ return ret, nil
+}
+
+// Percent calculates the percentage of cpu used either per CPU or combined.
+// If an interval of 0 is given it will compare the current cpu times against the last call.
+// Returns one value per cpu, or a single value if percpu is set to false.
+func Percent(interval time.Duration, percpu bool) ([]float64, error) {
+ return PercentWithContext(context.Background(), interval, percpu)
+}
+
+func PercentWithContext(ctx context.Context, interval time.Duration, percpu bool) ([]float64, error) {
+ if interval <= 0 {
+ return percentUsedFromLastCall(percpu)
+ }
+
+ // Get CPU usage at the start of the interval.
+ cpuTimes1, err := Times(percpu)
+ if err != nil {
+ return nil, err
+ }
+
+ time.Sleep(interval)
+
+ // And at the end of the interval.
+ cpuTimes2, err := Times(percpu)
+ if err != nil {
+ return nil, err
+ }
+
+ return calculateAllBusy(cpuTimes1, cpuTimes2)
+}
+
+func percentUsedFromLastCall(percpu bool) ([]float64, error) {
+ cpuTimes, err := Times(percpu)
+ if err != nil {
+ return nil, err
+ }
+ lastCPUPercent.Lock()
+ defer lastCPUPercent.Unlock()
+ var lastTimes []TimesStat
+ if percpu {
+ lastTimes = lastCPUPercent.lastPerCPUTimes
+ lastCPUPercent.lastPerCPUTimes = cpuTimes
+ } else {
+ lastTimes = lastCPUPercent.lastCPUTimes
+ lastCPUPercent.lastCPUTimes = cpuTimes
+ }
+
+ if lastTimes == nil {
+ return nil, fmt.Errorf("error getting times for cpu percent. lastTimes was nil")
+ }
+ return calculateAllBusy(lastTimes, cpuTimes)
+}
diff --git a/vendor/github.com/shirou/gopsutil/cpu/cpu_darwin.go b/vendor/github.com/shirou/gopsutil/cpu/cpu_darwin.go
new file mode 100644
index 0000000..74d2737
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/cpu/cpu_darwin.go
@@ -0,0 +1,115 @@
+// +build darwin
+
+package cpu
+
+import (
+ "context"
+ "os/exec"
+ "strconv"
+ "strings"
+)
+
+// sys/resource.h
+const (
+ CPUser = 0
+ CPNice = 1
+ CPSys = 2
+ CPIntr = 3
+ CPIdle = 4
+ CPUStates = 5
+)
+
+// default value. from time.h
+var ClocksPerSec = float64(128)
+
+func Times(percpu bool) ([]TimesStat, error) {
+ return TimesWithContext(context.Background(), percpu)
+}
+
+func TimesWithContext(ctx context.Context, percpu bool) ([]TimesStat, error) {
+ if percpu {
+ return perCPUTimes()
+ }
+
+ return allCPUTimes()
+}
+
+// Returns only one CPUInfoStat on FreeBSD
+func Info() ([]InfoStat, error) {
+ return InfoWithContext(context.Background())
+}
+
+func InfoWithContext(ctx context.Context) ([]InfoStat, error) {
+ var ret []InfoStat
+ sysctl, err := exec.LookPath("/usr/sbin/sysctl")
+ if err != nil {
+ return ret, err
+ }
+ out, err := invoke.CommandWithContext(ctx, sysctl, "machdep.cpu")
+ if err != nil {
+ return ret, err
+ }
+
+ c := InfoStat{}
+ for _, line := range strings.Split(string(out), "\n") {
+ values := strings.Fields(line)
+ if len(values) < 1 {
+ continue
+ }
+
+ t, err := strconv.ParseInt(values[1], 10, 64)
+ // err is not checked here because some value is string.
+ if strings.HasPrefix(line, "machdep.cpu.brand_string") {
+ c.ModelName = strings.Join(values[1:], " ")
+ } else if strings.HasPrefix(line, "machdep.cpu.family") {
+ c.Family = values[1]
+ } else if strings.HasPrefix(line, "machdep.cpu.model") {
+ c.Model = values[1]
+ } else if strings.HasPrefix(line, "machdep.cpu.stepping") {
+ if err != nil {
+ return ret, err
+ }
+ c.Stepping = int32(t)
+ } else if strings.HasPrefix(line, "machdep.cpu.features") {
+ for _, v := range values[1:] {
+ c.Flags = append(c.Flags, strings.ToLower(v))
+ }
+ } else if strings.HasPrefix(line, "machdep.cpu.leaf7_features") {
+ for _, v := range values[1:] {
+ c.Flags = append(c.Flags, strings.ToLower(v))
+ }
+ } else if strings.HasPrefix(line, "machdep.cpu.extfeatures") {
+ for _, v := range values[1:] {
+ c.Flags = append(c.Flags, strings.ToLower(v))
+ }
+ } else if strings.HasPrefix(line, "machdep.cpu.core_count") {
+ if err != nil {
+ return ret, err
+ }
+ c.Cores = int32(t)
+ } else if strings.HasPrefix(line, "machdep.cpu.cache.size") {
+ if err != nil {
+ return ret, err
+ }
+ c.CacheSize = int32(t)
+ } else if strings.HasPrefix(line, "machdep.cpu.vendor") {
+ c.VendorID = values[1]
+ }
+ }
+
+ // Use the rated frequency of the CPU. This is a static value and does not
+ // account for low power or Turbo Boost modes.
+ out, err = invoke.CommandWithContext(ctx, sysctl, "hw.cpufrequency")
+ if err != nil {
+ return ret, err
+ }
+
+ values := strings.Fields(string(out))
+ hz, err := strconv.ParseFloat(values[1], 64)
+ if err != nil {
+ return ret, err
+ }
+ c.Mhz = hz / 1000000.0
+
+ return append(ret, c), nil
+}
diff --git a/vendor/github.com/shirou/gopsutil/cpu/cpu_darwin_cgo.go b/vendor/github.com/shirou/gopsutil/cpu/cpu_darwin_cgo.go
new file mode 100644
index 0000000..180e0af
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/cpu/cpu_darwin_cgo.go
@@ -0,0 +1,111 @@
+// +build darwin
+// +build cgo
+
+package cpu
+
+/*
+#include
+#include
+#include
+#include
+#include
+#include
+#if TARGET_OS_MAC
+#include
+#endif
+#include
+#include
+*/
+import "C"
+
+import (
+ "bytes"
+ "encoding/binary"
+ "fmt"
+ "unsafe"
+)
+
+// these CPU times for darwin is borrowed from influxdb/telegraf.
+
+func perCPUTimes() ([]TimesStat, error) {
+ var (
+ count C.mach_msg_type_number_t
+ cpuload *C.processor_cpu_load_info_data_t
+ ncpu C.natural_t
+ )
+
+ status := C.host_processor_info(C.host_t(C.mach_host_self()),
+ C.PROCESSOR_CPU_LOAD_INFO,
+ &ncpu,
+ (*C.processor_info_array_t)(unsafe.Pointer(&cpuload)),
+ &count)
+
+ if status != C.KERN_SUCCESS {
+ return nil, fmt.Errorf("host_processor_info error=%d", status)
+ }
+
+ // jump through some cgo casting hoops and ensure we properly free
+ // the memory that cpuload points to
+ target := C.vm_map_t(C.mach_task_self_)
+ address := C.vm_address_t(uintptr(unsafe.Pointer(cpuload)))
+ defer C.vm_deallocate(target, address, C.vm_size_t(ncpu))
+
+ // the body of struct processor_cpu_load_info
+ // aka processor_cpu_load_info_data_t
+ var cpu_ticks [C.CPU_STATE_MAX]uint32
+
+ // copy the cpuload array to a []byte buffer
+ // where we can binary.Read the data
+ size := int(ncpu) * binary.Size(cpu_ticks)
+ buf := (*[1 << 30]byte)(unsafe.Pointer(cpuload))[:size:size]
+
+ bbuf := bytes.NewBuffer(buf)
+
+ var ret []TimesStat
+
+ for i := 0; i < int(ncpu); i++ {
+ err := binary.Read(bbuf, binary.LittleEndian, &cpu_ticks)
+ if err != nil {
+ return nil, err
+ }
+
+ c := TimesStat{
+ CPU: fmt.Sprintf("cpu%d", i),
+ User: float64(cpu_ticks[C.CPU_STATE_USER]) / ClocksPerSec,
+ System: float64(cpu_ticks[C.CPU_STATE_SYSTEM]) / ClocksPerSec,
+ Nice: float64(cpu_ticks[C.CPU_STATE_NICE]) / ClocksPerSec,
+ Idle: float64(cpu_ticks[C.CPU_STATE_IDLE]) / ClocksPerSec,
+ }
+
+ ret = append(ret, c)
+ }
+
+ return ret, nil
+}
+
+func allCPUTimes() ([]TimesStat, error) {
+ var count C.mach_msg_type_number_t
+ var cpuload C.host_cpu_load_info_data_t
+
+ count = C.HOST_CPU_LOAD_INFO_COUNT
+
+ status := C.host_statistics(C.host_t(C.mach_host_self()),
+ C.HOST_CPU_LOAD_INFO,
+ C.host_info_t(unsafe.Pointer(&cpuload)),
+ &count)
+
+ if status != C.KERN_SUCCESS {
+ return nil, fmt.Errorf("host_statistics error=%d", status)
+ }
+
+ c := TimesStat{
+ CPU: "cpu-total",
+ User: float64(cpuload.cpu_ticks[C.CPU_STATE_USER]) / ClocksPerSec,
+ System: float64(cpuload.cpu_ticks[C.CPU_STATE_SYSTEM]) / ClocksPerSec,
+ Nice: float64(cpuload.cpu_ticks[C.CPU_STATE_NICE]) / ClocksPerSec,
+ Idle: float64(cpuload.cpu_ticks[C.CPU_STATE_IDLE]) / ClocksPerSec,
+ }
+
+ return []TimesStat{c}, nil
+
+}
diff --git a/vendor/github.com/shirou/gopsutil/cpu/cpu_darwin_nocgo.go b/vendor/github.com/shirou/gopsutil/cpu/cpu_darwin_nocgo.go
new file mode 100644
index 0000000..242b4a8
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/cpu/cpu_darwin_nocgo.go
@@ -0,0 +1,14 @@
+// +build darwin
+// +build !cgo
+
+package cpu
+
+import "github.com/shirou/gopsutil/internal/common"
+
+func perCPUTimes() ([]TimesStat, error) {
+ return []TimesStat{}, common.ErrNotImplementedError
+}
+
+func allCPUTimes() ([]TimesStat, error) {
+ return []TimesStat{}, common.ErrNotImplementedError
+}
diff --git a/vendor/github.com/shirou/gopsutil/cpu/cpu_fallback.go b/vendor/github.com/shirou/gopsutil/cpu/cpu_fallback.go
new file mode 100644
index 0000000..e9e7ada
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/cpu/cpu_fallback.go
@@ -0,0 +1,25 @@
+// +build !darwin,!linux,!freebsd,!openbsd,!solaris,!windows
+
+package cpu
+
+import (
+ "context"
+
+ "github.com/shirou/gopsutil/internal/common"
+)
+
+func Times(percpu bool) ([]TimesStat, error) {
+ return TimesWithContext(context.Background(), percpu)
+}
+
+func TimesWithContext(ctx context.Context, percpu bool) ([]TimesStat, error) {
+ return []TimesStat{}, common.ErrNotImplementedError
+}
+
+func Info() ([]InfoStat, error) {
+ return InfoWithContext(context.Background())
+}
+
+func InfoWithContext(ctx context.Context) ([]InfoStat, error) {
+ return []InfoStat{}, common.ErrNotImplementedError
+}
diff --git a/vendor/github.com/shirou/gopsutil/cpu/cpu_freebsd.go b/vendor/github.com/shirou/gopsutil/cpu/cpu_freebsd.go
new file mode 100644
index 0000000..b6c7186
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/cpu/cpu_freebsd.go
@@ -0,0 +1,168 @@
+package cpu
+
+import (
+ "context"
+ "fmt"
+ "os/exec"
+ "reflect"
+ "regexp"
+ "strconv"
+ "strings"
+ "unsafe"
+
+ "github.com/shirou/gopsutil/internal/common"
+ "golang.org/x/sys/unix"
+)
+
+var ClocksPerSec = float64(128)
+var cpuMatch = regexp.MustCompile(`^CPU:`)
+var originMatch = regexp.MustCompile(`Origin\s*=\s*"(.+)"\s+Id\s*=\s*(.+)\s+Family\s*=\s*(.+)\s+Model\s*=\s*(.+)\s+Stepping\s*=\s*(.+)`)
+var featuresMatch = regexp.MustCompile(`Features=.+<(.+)>`)
+var featuresMatch2 = regexp.MustCompile(`Features2=[a-f\dx]+<(.+)>`)
+var cpuEnd = regexp.MustCompile(`^Trying to mount root`)
+var cpuCores = regexp.MustCompile(`FreeBSD/SMP: (\d*) package\(s\) x (\d*) core\(s\)`)
+var cpuTimesSize int
+var emptyTimes cpuTimes
+
+func init() {
+ getconf, err := exec.LookPath("/usr/bin/getconf")
+ if err != nil {
+ return
+ }
+ out, err := invoke.Command(getconf, "CLK_TCK")
+ // ignore errors
+ if err == nil {
+ i, err := strconv.ParseFloat(strings.TrimSpace(string(out)), 64)
+ if err == nil {
+ ClocksPerSec = float64(i)
+ }
+ }
+}
+
+func timeStat(name string, t *cpuTimes) *TimesStat {
+ return &TimesStat{
+ User: float64(t.User) / ClocksPerSec,
+ Nice: float64(t.Nice) / ClocksPerSec,
+ System: float64(t.Sys) / ClocksPerSec,
+ Idle: float64(t.Idle) / ClocksPerSec,
+ Irq: float64(t.Intr) / ClocksPerSec,
+ CPU: name,
+ }
+}
+
+func Times(percpu bool) ([]TimesStat, error) {
+ return TimesWithContext(context.Background(), percpu)
+}
+
+func TimesWithContext(ctx context.Context, percpu bool) ([]TimesStat, error) {
+ if percpu {
+ buf, err := unix.SysctlRaw("kern.cp_times")
+ if err != nil {
+ return nil, err
+ }
+
+ // We can't do this in init due to the conflict with cpu.init()
+ if cpuTimesSize == 0 {
+ cpuTimesSize = int(reflect.TypeOf(cpuTimes{}).Size())
+ }
+
+ ncpus := len(buf) / cpuTimesSize
+ ret := make([]TimesStat, 0, ncpus)
+ for i := 0; i < ncpus; i++ {
+ times := (*cpuTimes)(unsafe.Pointer(&buf[i*cpuTimesSize]))
+ if *times == emptyTimes {
+ // CPU not present
+ continue
+ }
+ ret = append(ret, *timeStat(fmt.Sprintf("cpu%d", len(ret)), times))
+ }
+ return ret, nil
+ }
+
+ buf, err := unix.SysctlRaw("kern.cp_time")
+ if err != nil {
+ return nil, err
+ }
+
+ times := (*cpuTimes)(unsafe.Pointer(&buf[0]))
+ return []TimesStat{*timeStat("cpu-total", times)}, nil
+}
+
+// Returns only one InfoStat on FreeBSD. The information regarding core
+// count, however is accurate and it is assumed that all InfoStat attributes
+// are the same across CPUs.
+func Info() ([]InfoStat, error) {
+ return InfoWithContext(context.Background())
+}
+
+func InfoWithContext(ctx context.Context) ([]InfoStat, error) {
+ const dmesgBoot = "/var/run/dmesg.boot"
+
+ c, num, err := parseDmesgBoot(dmesgBoot)
+ if err != nil {
+ return nil, err
+ }
+
+ var u32 uint32
+ if u32, err = unix.SysctlUint32("hw.clockrate"); err != nil {
+ return nil, err
+ }
+ c.Mhz = float64(u32)
+
+ if u32, err = unix.SysctlUint32("hw.ncpu"); err != nil {
+ return nil, err
+ }
+ c.Cores = int32(u32)
+
+ if c.ModelName, err = unix.Sysctl("hw.model"); err != nil {
+ return nil, err
+ }
+
+ ret := make([]InfoStat, num)
+ for i := 0; i < num; i++ {
+ ret[i] = c
+ }
+
+ return ret, nil
+}
+
+func parseDmesgBoot(fileName string) (InfoStat, int, error) {
+ c := InfoStat{}
+ lines, _ := common.ReadLines(fileName)
+ cpuNum := 1 // default cpu num is 1
+ for _, line := range lines {
+ if matches := cpuEnd.FindStringSubmatch(line); matches != nil {
+ break
+ } else if matches := originMatch.FindStringSubmatch(line); matches != nil {
+ c.VendorID = matches[1]
+ c.Family = matches[3]
+ c.Model = matches[4]
+ t, err := strconv.ParseInt(matches[5], 10, 32)
+ if err != nil {
+ return c, 0, fmt.Errorf("unable to parse FreeBSD CPU stepping information from %q: %v", line, err)
+ }
+ c.Stepping = int32(t)
+ } else if matches := featuresMatch.FindStringSubmatch(line); matches != nil {
+ for _, v := range strings.Split(matches[1], ",") {
+ c.Flags = append(c.Flags, strings.ToLower(v))
+ }
+ } else if matches := featuresMatch2.FindStringSubmatch(line); matches != nil {
+ for _, v := range strings.Split(matches[1], ",") {
+ c.Flags = append(c.Flags, strings.ToLower(v))
+ }
+ } else if matches := cpuCores.FindStringSubmatch(line); matches != nil {
+ t, err := strconv.ParseInt(matches[1], 10, 32)
+ if err != nil {
+ return c, 0, fmt.Errorf("unable to parse FreeBSD CPU Nums from %q: %v", line, err)
+ }
+ cpuNum = int(t)
+ t2, err := strconv.ParseInt(matches[2], 10, 32)
+ if err != nil {
+ return c, 0, fmt.Errorf("unable to parse FreeBSD CPU cores from %q: %v", line, err)
+ }
+ c.Cores = int32(t2)
+ }
+ }
+
+ return c, cpuNum, nil
+}
diff --git a/vendor/github.com/shirou/gopsutil/cpu/cpu_freebsd_386.go b/vendor/github.com/shirou/gopsutil/cpu/cpu_freebsd_386.go
new file mode 100644
index 0000000..8b7f4c3
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/cpu/cpu_freebsd_386.go
@@ -0,0 +1,9 @@
+package cpu
+
+type cpuTimes struct {
+ User uint32
+ Nice uint32
+ Sys uint32
+ Intr uint32
+ Idle uint32
+}
diff --git a/vendor/github.com/shirou/gopsutil/cpu/cpu_freebsd_amd64.go b/vendor/github.com/shirou/gopsutil/cpu/cpu_freebsd_amd64.go
new file mode 100644
index 0000000..57e1452
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/cpu/cpu_freebsd_amd64.go
@@ -0,0 +1,9 @@
+package cpu
+
+type cpuTimes struct {
+ User uint64
+ Nice uint64
+ Sys uint64
+ Intr uint64
+ Idle uint64
+}
diff --git a/vendor/github.com/shirou/gopsutil/cpu/cpu_linux.go b/vendor/github.com/shirou/gopsutil/cpu/cpu_linux.go
new file mode 100644
index 0000000..2fffe85
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/cpu/cpu_linux.go
@@ -0,0 +1,284 @@
+// +build linux
+
+package cpu
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "os/exec"
+ "strconv"
+ "strings"
+
+ "github.com/shirou/gopsutil/internal/common"
+)
+
+var CPUTick = float64(100)
+
+func init() {
+ getconf, err := exec.LookPath("/usr/bin/getconf")
+ if err != nil {
+ return
+ }
+ out, err := invoke.CommandWithContext(context.Background(), getconf, "CLK_TCK")
+ // ignore errors
+ if err == nil {
+ i, err := strconv.ParseFloat(strings.TrimSpace(string(out)), 64)
+ if err == nil {
+ CPUTick = i
+ }
+ }
+}
+
+func Times(percpu bool) ([]TimesStat, error) {
+ return TimesWithContext(context.Background(), percpu)
+}
+
+func TimesWithContext(ctx context.Context, percpu bool) ([]TimesStat, error) {
+ filename := common.HostProc("stat")
+ var lines = []string{}
+ if percpu {
+ statlines, err := common.ReadLines(filename)
+ if err != nil || len(statlines) < 2 {
+ return []TimesStat{}, nil
+ }
+ for _, line := range statlines[1:] {
+ if !strings.HasPrefix(line, "cpu") {
+ break
+ }
+ lines = append(lines, line)
+ }
+ } else {
+ lines, _ = common.ReadLinesOffsetN(filename, 0, 1)
+ }
+
+ ret := make([]TimesStat, 0, len(lines))
+
+ for _, line := range lines {
+ ct, err := parseStatLine(line)
+ if err != nil {
+ continue
+ }
+ ret = append(ret, *ct)
+
+ }
+ return ret, nil
+}
+
+func sysCPUPath(cpu int32, relPath string) string {
+ return common.HostSys(fmt.Sprintf("devices/system/cpu/cpu%d", cpu), relPath)
+}
+
+func finishCPUInfo(c *InfoStat) error {
+ var lines []string
+ var err error
+ var value float64
+
+ if len(c.CoreID) == 0 {
+ lines, err = common.ReadLines(sysCPUPath(c.CPU, "topology/core_id"))
+ if err == nil {
+ c.CoreID = lines[0]
+ }
+ }
+
+ // override the value of c.Mhz with cpufreq/cpuinfo_max_freq regardless
+ // of the value from /proc/cpuinfo because we want to report the maximum
+ // clock-speed of the CPU for c.Mhz, matching the behaviour of Windows
+ lines, err = common.ReadLines(sysCPUPath(c.CPU, "cpufreq/cpuinfo_max_freq"))
+ // if we encounter errors below such as there are no cpuinfo_max_freq file,
+ // we just ignore. so let Mhz is 0.
+ if err != nil {
+ return nil
+ }
+ value, err = strconv.ParseFloat(lines[0], 64)
+ if err != nil {
+ return nil
+ }
+ c.Mhz = value / 1000.0 // value is in kHz
+ if c.Mhz > 9999 {
+ c.Mhz = c.Mhz / 1000.0 // value in Hz
+ }
+ return nil
+}
+
+// CPUInfo on linux will return 1 item per physical thread.
+//
+// CPUs have three levels of counting: sockets, cores, threads.
+// Cores with HyperThreading count as having 2 threads per core.
+// Sockets often come with many physical CPU cores.
+// For example a single socket board with two cores each with HT will
+// return 4 CPUInfoStat structs on Linux and the "Cores" field set to 1.
+func Info() ([]InfoStat, error) {
+ return InfoWithContext(context.Background())
+}
+
+func InfoWithContext(ctx context.Context) ([]InfoStat, error) {
+ filename := common.HostProc("cpuinfo")
+ lines, _ := common.ReadLines(filename)
+
+ var ret []InfoStat
+ var processorName string
+
+ c := InfoStat{CPU: -1, Cores: 1}
+ for _, line := range lines {
+ fields := strings.Split(line, ":")
+ if len(fields) < 2 {
+ continue
+ }
+ key := strings.TrimSpace(fields[0])
+ value := strings.TrimSpace(fields[1])
+
+ switch key {
+ case "Processor":
+ processorName = value
+ case "processor":
+ if c.CPU >= 0 {
+ err := finishCPUInfo(&c)
+ if err != nil {
+ return ret, err
+ }
+ ret = append(ret, c)
+ }
+ c = InfoStat{Cores: 1, ModelName: processorName}
+ t, err := strconv.ParseInt(value, 10, 64)
+ if err != nil {
+ return ret, err
+ }
+ c.CPU = int32(t)
+ case "vendorId", "vendor_id":
+ c.VendorID = value
+ case "cpu family":
+ c.Family = value
+ case "model":
+ c.Model = value
+ case "model name", "cpu":
+ c.ModelName = value
+ if strings.Contains(value, "POWER8") ||
+ strings.Contains(value, "POWER7") {
+ c.Model = strings.Split(value, " ")[0]
+ c.Family = "POWER"
+ c.VendorID = "IBM"
+ }
+ case "stepping", "revision":
+ val := value
+
+ if key == "revision" {
+ val = strings.Split(value, ".")[0]
+ }
+
+ t, err := strconv.ParseInt(val, 10, 64)
+ if err != nil {
+ return ret, err
+ }
+ c.Stepping = int32(t)
+ case "cpu MHz", "clock":
+ // treat this as the fallback value, thus we ignore error
+ if t, err := strconv.ParseFloat(strings.Replace(value, "MHz", "", 1), 64); err == nil {
+ c.Mhz = t
+ }
+ case "cache size":
+ t, err := strconv.ParseInt(strings.Replace(value, " KB", "", 1), 10, 64)
+ if err != nil {
+ return ret, err
+ }
+ c.CacheSize = int32(t)
+ case "physical id":
+ c.PhysicalID = value
+ case "core id":
+ c.CoreID = value
+ case "flags", "Features":
+ c.Flags = strings.FieldsFunc(value, func(r rune) bool {
+ return r == ',' || r == ' '
+ })
+ case "microcode":
+ c.Microcode = value
+ }
+ }
+ if c.CPU >= 0 {
+ err := finishCPUInfo(&c)
+ if err != nil {
+ return ret, err
+ }
+ ret = append(ret, c)
+ }
+ return ret, nil
+}
+
+func parseStatLine(line string) (*TimesStat, error) {
+ fields := strings.Fields(line)
+
+ if len(fields) == 0 {
+ return nil, errors.New("stat does not contain cpu info")
+ }
+
+ if strings.HasPrefix(fields[0], "cpu") == false {
+ return nil, errors.New("not contain cpu")
+ }
+
+ cpu := fields[0]
+ if cpu == "cpu" {
+ cpu = "cpu-total"
+ }
+ user, err := strconv.ParseFloat(fields[1], 64)
+ if err != nil {
+ return nil, err
+ }
+ nice, err := strconv.ParseFloat(fields[2], 64)
+ if err != nil {
+ return nil, err
+ }
+ system, err := strconv.ParseFloat(fields[3], 64)
+ if err != nil {
+ return nil, err
+ }
+ idle, err := strconv.ParseFloat(fields[4], 64)
+ if err != nil {
+ return nil, err
+ }
+ iowait, err := strconv.ParseFloat(fields[5], 64)
+ if err != nil {
+ return nil, err
+ }
+ irq, err := strconv.ParseFloat(fields[6], 64)
+ if err != nil {
+ return nil, err
+ }
+ softirq, err := strconv.ParseFloat(fields[7], 64)
+ if err != nil {
+ return nil, err
+ }
+
+ ct := &TimesStat{
+ CPU: cpu,
+ User: user / CPUTick,
+ Nice: nice / CPUTick,
+ System: system / CPUTick,
+ Idle: idle / CPUTick,
+ Iowait: iowait / CPUTick,
+ Irq: irq / CPUTick,
+ Softirq: softirq / CPUTick,
+ }
+ if len(fields) > 8 { // Linux >= 2.6.11
+ steal, err := strconv.ParseFloat(fields[8], 64)
+ if err != nil {
+ return nil, err
+ }
+ ct.Steal = steal / CPUTick
+ }
+ if len(fields) > 9 { // Linux >= 2.6.24
+ guest, err := strconv.ParseFloat(fields[9], 64)
+ if err != nil {
+ return nil, err
+ }
+ ct.Guest = guest / CPUTick
+ }
+ if len(fields) > 10 { // Linux >= 3.2.0
+ guestNice, err := strconv.ParseFloat(fields[10], 64)
+ if err != nil {
+ return nil, err
+ }
+ ct.GuestNice = guestNice / CPUTick
+ }
+
+ return ct, nil
+}
diff --git a/vendor/github.com/shirou/gopsutil/cpu/cpu_openbsd.go b/vendor/github.com/shirou/gopsutil/cpu/cpu_openbsd.go
new file mode 100644
index 0000000..82b920f
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/cpu/cpu_openbsd.go
@@ -0,0 +1,119 @@
+// +build openbsd
+
+package cpu
+
+import (
+ "bytes"
+ "context"
+ "encoding/binary"
+ "fmt"
+ "os/exec"
+ "strconv"
+ "strings"
+
+ "github.com/shirou/gopsutil/internal/common"
+ "golang.org/x/sys/unix"
+)
+
+// sys/sched.h
+const (
+ CPUser = 0
+ CPNice = 1
+ CPSys = 2
+ CPIntr = 3
+ CPIdle = 4
+ CPUStates = 5
+)
+
+// sys/sysctl.h
+const (
+ CTLKern = 1 // "high kernel": proc, limits
+ KernCptime = 40 // KERN_CPTIME
+ KernCptime2 = 71 // KERN_CPTIME2
+)
+
+var ClocksPerSec = float64(128)
+
+func init() {
+ getconf, err := exec.LookPath("/usr/bin/getconf")
+ if err != nil {
+ return
+ }
+ out, err := invoke.Command(getconf, "CLK_TCK")
+ // ignore errors
+ if err == nil {
+ i, err := strconv.ParseFloat(strings.TrimSpace(string(out)), 64)
+ if err == nil {
+ ClocksPerSec = float64(i)
+ }
+ }
+}
+
+func Times(percpu bool) ([]TimesStat, error) {
+ return TimesWithContext(context.Background(), percpu)
+}
+
+func TimesWithContext(ctx context.Context, percpu bool) ([]TimesStat, error) {
+ var ret []TimesStat
+
+ var ncpu int
+ if percpu {
+ ncpu, _ = Counts(true)
+ } else {
+ ncpu = 1
+ }
+
+ for i := 0; i < ncpu; i++ {
+ var cpuTimes [CPUStates]int64
+ var mib []int32
+ if percpu {
+ mib = []int32{CTLKern, KernCptime}
+ } else {
+ mib = []int32{CTLKern, KernCptime2, int32(i)}
+ }
+ buf, _, err := common.CallSyscall(mib)
+ if err != nil {
+ return ret, err
+ }
+
+ br := bytes.NewReader(buf)
+ err = binary.Read(br, binary.LittleEndian, &cpuTimes)
+ if err != nil {
+ return ret, err
+ }
+ c := TimesStat{
+ User: float64(cpuTimes[CPUser]) / ClocksPerSec,
+ Nice: float64(cpuTimes[CPNice]) / ClocksPerSec,
+ System: float64(cpuTimes[CPSys]) / ClocksPerSec,
+ Idle: float64(cpuTimes[CPIdle]) / ClocksPerSec,
+ Irq: float64(cpuTimes[CPIntr]) / ClocksPerSec,
+ }
+ if !percpu {
+ c.CPU = "cpu-total"
+ } else {
+ c.CPU = fmt.Sprintf("cpu%d", i)
+ }
+ ret = append(ret, c)
+ }
+
+ return ret, nil
+}
+
+// Returns only one (minimal) CPUInfoStat on OpenBSD
+func Info() ([]InfoStat, error) {
+ return InfoWithContext(context.Background())
+}
+
+func InfoWithContext(ctx context.Context) ([]InfoStat, error) {
+ var ret []InfoStat
+
+ c := InfoStat{}
+
+ v, err := unix.Sysctl("hw.model")
+ if err != nil {
+ return nil, err
+ }
+ c.ModelName = v
+
+ return append(ret, c), nil
+}
diff --git a/vendor/github.com/shirou/gopsutil/cpu/cpu_solaris.go b/vendor/github.com/shirou/gopsutil/cpu/cpu_solaris.go
new file mode 100644
index 0000000..117fd90
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/cpu/cpu_solaris.go
@@ -0,0 +1,198 @@
+package cpu
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "os/exec"
+ "regexp"
+ "sort"
+ "strconv"
+ "strings"
+
+ "github.com/shirou/gopsutil/internal/common"
+)
+
+var ClocksPerSec = float64(128)
+
+func init() {
+ getconf, err := exec.LookPath("/usr/bin/getconf")
+ if err != nil {
+ return
+ }
+ out, err := invoke.Command(getconf, "CLK_TCK")
+ // ignore errors
+ if err == nil {
+ i, err := strconv.ParseFloat(strings.TrimSpace(string(out)), 64)
+ if err == nil {
+ ClocksPerSec = float64(i)
+ }
+ }
+}
+
+func Times(percpu bool) ([]TimesStat, error) {
+ return TimesWithContext(context.Background(), percpu)
+}
+
+func TimesWithContext(ctx context.Context, percpu bool) ([]TimesStat, error) {
+ return []TimesStat{}, common.ErrNotImplementedError
+}
+
+func Info() ([]InfoStat, error) {
+ return InfoWithContext(context.Background())
+}
+
+func InfoWithContext(ctx context.Context) ([]InfoStat, error) {
+ psrInfo, err := exec.LookPath("/usr/sbin/psrinfo")
+ if err != nil {
+ return nil, fmt.Errorf("cannot find psrinfo: %s", err)
+ }
+ psrInfoOut, err := invoke.CommandWithContext(ctx, psrInfo, "-p", "-v")
+ if err != nil {
+ return nil, fmt.Errorf("cannot execute psrinfo: %s", err)
+ }
+
+ isaInfo, err := exec.LookPath("/usr/bin/isainfo")
+ if err != nil {
+ return nil, fmt.Errorf("cannot find isainfo: %s", err)
+ }
+ isaInfoOut, err := invoke.CommandWithContext(ctx, isaInfo, "-b", "-v")
+ if err != nil {
+ return nil, fmt.Errorf("cannot execute isainfo: %s", err)
+ }
+
+ procs, err := parseProcessorInfo(string(psrInfoOut))
+ if err != nil {
+ return nil, fmt.Errorf("error parsing psrinfo output: %s", err)
+ }
+
+ flags, err := parseISAInfo(string(isaInfoOut))
+ if err != nil {
+ return nil, fmt.Errorf("error parsing isainfo output: %s", err)
+ }
+
+ result := make([]InfoStat, 0, len(flags))
+ for _, proc := range procs {
+ procWithFlags := proc
+ procWithFlags.Flags = flags
+ result = append(result, procWithFlags)
+ }
+
+ return result, nil
+}
+
+var flagsMatch = regexp.MustCompile(`[\w\.]+`)
+
+func parseISAInfo(cmdOutput string) ([]string, error) {
+ words := flagsMatch.FindAllString(cmdOutput, -1)
+
+ // Sanity check the output
+ if len(words) < 4 || words[1] != "bit" || words[3] != "applications" {
+ return nil, errors.New("attempted to parse invalid isainfo output")
+ }
+
+ flags := make([]string, len(words)-4)
+ for i, val := range words[4:] {
+ flags[i] = val
+ }
+ sort.Strings(flags)
+
+ return flags, nil
+}
+
+var psrInfoMatch = regexp.MustCompile(`The physical processor has (?:([\d]+) virtual processor \(([\d]+)\)|([\d]+) cores and ([\d]+) virtual processors[^\n]+)\n(?:\s+ The core has.+\n)*\s+.+ \((\w+) ([\S]+) family (.+) model (.+) step (.+) clock (.+) MHz\)\n[\s]*(.*)`)
+
+const (
+ psrNumCoresOffset = 1
+ psrNumCoresHTOffset = 3
+ psrNumHTOffset = 4
+ psrVendorIDOffset = 5
+ psrFamilyOffset = 7
+ psrModelOffset = 8
+ psrStepOffset = 9
+ psrClockOffset = 10
+ psrModelNameOffset = 11
+)
+
+func parseProcessorInfo(cmdOutput string) ([]InfoStat, error) {
+ matches := psrInfoMatch.FindAllStringSubmatch(cmdOutput, -1)
+
+ var infoStatCount int32
+ result := make([]InfoStat, 0, len(matches))
+ for physicalIndex, physicalCPU := range matches {
+ var step int32
+ var clock float64
+
+ if physicalCPU[psrStepOffset] != "" {
+ stepParsed, err := strconv.ParseInt(physicalCPU[psrStepOffset], 10, 32)
+ if err != nil {
+ return nil, fmt.Errorf("cannot parse value %q for step as 32-bit integer: %s", physicalCPU[9], err)
+ }
+ step = int32(stepParsed)
+ }
+
+ if physicalCPU[psrClockOffset] != "" {
+ clockParsed, err := strconv.ParseInt(physicalCPU[psrClockOffset], 10, 64)
+ if err != nil {
+ return nil, fmt.Errorf("cannot parse value %q for clock as 32-bit integer: %s", physicalCPU[10], err)
+ }
+ clock = float64(clockParsed)
+ }
+
+ var err error
+ var numCores int64
+ var numHT int64
+ switch {
+ case physicalCPU[psrNumCoresOffset] != "":
+ numCores, err = strconv.ParseInt(physicalCPU[psrNumCoresOffset], 10, 32)
+ if err != nil {
+ return nil, fmt.Errorf("cannot parse value %q for core count as 32-bit integer: %s", physicalCPU[1], err)
+ }
+
+ for i := 0; i < int(numCores); i++ {
+ result = append(result, InfoStat{
+ CPU: infoStatCount,
+ PhysicalID: strconv.Itoa(physicalIndex),
+ CoreID: strconv.Itoa(i),
+ Cores: 1,
+ VendorID: physicalCPU[psrVendorIDOffset],
+ ModelName: physicalCPU[psrModelNameOffset],
+ Family: physicalCPU[psrFamilyOffset],
+ Model: physicalCPU[psrModelOffset],
+ Stepping: step,
+ Mhz: clock,
+ })
+ infoStatCount++
+ }
+ case physicalCPU[psrNumCoresHTOffset] != "":
+ numCores, err = strconv.ParseInt(physicalCPU[psrNumCoresHTOffset], 10, 32)
+ if err != nil {
+ return nil, fmt.Errorf("cannot parse value %q for core count as 32-bit integer: %s", physicalCPU[3], err)
+ }
+
+ numHT, err = strconv.ParseInt(physicalCPU[psrNumHTOffset], 10, 32)
+ if err != nil {
+ return nil, fmt.Errorf("cannot parse value %q for hyperthread count as 32-bit integer: %s", physicalCPU[4], err)
+ }
+
+ for i := 0; i < int(numCores); i++ {
+ result = append(result, InfoStat{
+ CPU: infoStatCount,
+ PhysicalID: strconv.Itoa(physicalIndex),
+ CoreID: strconv.Itoa(i),
+ Cores: int32(numHT) / int32(numCores),
+ VendorID: physicalCPU[psrVendorIDOffset],
+ ModelName: physicalCPU[psrModelNameOffset],
+ Family: physicalCPU[psrFamilyOffset],
+ Model: physicalCPU[psrModelOffset],
+ Stepping: step,
+ Mhz: clock,
+ })
+ infoStatCount++
+ }
+ default:
+ return nil, errors.New("values for cores with and without hyperthreading are both set")
+ }
+ }
+ return result, nil
+}
diff --git a/vendor/github.com/shirou/gopsutil/cpu/cpu_windows.go b/vendor/github.com/shirou/gopsutil/cpu/cpu_windows.go
new file mode 100644
index 0000000..3959212
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/cpu/cpu_windows.go
@@ -0,0 +1,171 @@
+// +build windows
+
+package cpu
+
+import (
+ "context"
+ "fmt"
+ "unsafe"
+
+ "github.com/StackExchange/wmi"
+ "github.com/shirou/gopsutil/internal/common"
+ "golang.org/x/sys/windows"
+)
+
+type Win32_Processor struct {
+ LoadPercentage *uint16
+ Family uint16
+ Manufacturer string
+ Name string
+ NumberOfLogicalProcessors uint32
+ ProcessorID *string
+ Stepping *string
+ MaxClockSpeed uint32
+}
+
+type win32_PerfRawData_Counters_ProcessorInformation struct {
+ Name string
+ PercentDPCTime uint64
+ PercentIdleTime uint64
+ PercentUserTime uint64
+ PercentProcessorTime uint64
+ PercentInterruptTime uint64
+ PercentPriorityTime uint64
+ PercentPrivilegedTime uint64
+ InterruptsPerSec uint32
+ ProcessorFrequency uint32
+ DPCRate uint32
+}
+
+// Win32_PerfFormattedData_PerfOS_System struct to have count of processes and processor queue length
+type Win32_PerfFormattedData_PerfOS_System struct {
+ Processes uint32
+ ProcessorQueueLength uint32
+}
+
+const (
+ win32_TicksPerSecond = 10000000.0
+)
+
+// Times returns times stat per cpu and combined for all CPUs
+func Times(percpu bool) ([]TimesStat, error) {
+ return TimesWithContext(context.Background(), percpu)
+}
+
+func TimesWithContext(ctx context.Context, percpu bool) ([]TimesStat, error) {
+ if percpu {
+ return perCPUTimesWithContext(ctx)
+ }
+
+ var ret []TimesStat
+ var lpIdleTime common.FILETIME
+ var lpKernelTime common.FILETIME
+ var lpUserTime common.FILETIME
+ r, _, _ := common.ProcGetSystemTimes.Call(
+ uintptr(unsafe.Pointer(&lpIdleTime)),
+ uintptr(unsafe.Pointer(&lpKernelTime)),
+ uintptr(unsafe.Pointer(&lpUserTime)))
+ if r == 0 {
+ return ret, windows.GetLastError()
+ }
+
+ LOT := float64(0.0000001)
+ HIT := (LOT * 4294967296.0)
+ idle := ((HIT * float64(lpIdleTime.DwHighDateTime)) + (LOT * float64(lpIdleTime.DwLowDateTime)))
+ user := ((HIT * float64(lpUserTime.DwHighDateTime)) + (LOT * float64(lpUserTime.DwLowDateTime)))
+ kernel := ((HIT * float64(lpKernelTime.DwHighDateTime)) + (LOT * float64(lpKernelTime.DwLowDateTime)))
+ system := (kernel - idle)
+
+ ret = append(ret, TimesStat{
+ CPU: "cpu-total",
+ Idle: float64(idle),
+ User: float64(user),
+ System: float64(system),
+ })
+ return ret, nil
+}
+
+func Info() ([]InfoStat, error) {
+ return InfoWithContext(context.Background())
+}
+
+func InfoWithContext(ctx context.Context) ([]InfoStat, error) {
+ var ret []InfoStat
+ var dst []Win32_Processor
+ q := wmi.CreateQuery(&dst, "")
+ if err := common.WMIQueryWithContext(ctx, q, &dst); err != nil {
+ return ret, err
+ }
+
+ var procID string
+ for i, l := range dst {
+ procID = ""
+ if l.ProcessorID != nil {
+ procID = *l.ProcessorID
+ }
+
+ cpu := InfoStat{
+ CPU: int32(i),
+ Family: fmt.Sprintf("%d", l.Family),
+ VendorID: l.Manufacturer,
+ ModelName: l.Name,
+ Cores: int32(l.NumberOfLogicalProcessors),
+ PhysicalID: procID,
+ Mhz: float64(l.MaxClockSpeed),
+ Flags: []string{},
+ }
+ ret = append(ret, cpu)
+ }
+
+ return ret, nil
+}
+
+// PerfInfo returns the performance counter's instance value for ProcessorInformation.
+// Name property is the key by which overall, per cpu and per core metric is known.
+func perfInfoWithContext(ctx context.Context) ([]win32_PerfRawData_Counters_ProcessorInformation, error) {
+ var ret []win32_PerfRawData_Counters_ProcessorInformation
+
+ q := wmi.CreateQuery(&ret, "WHERE NOT Name LIKE '%_Total'")
+ err := common.WMIQueryWithContext(ctx, q, &ret)
+ if err != nil {
+ return []win32_PerfRawData_Counters_ProcessorInformation{}, err
+ }
+
+ return ret, err
+}
+
+// ProcInfo returns processes count and processor queue length in the system.
+// There is a single queue for processor even on multiprocessors systems.
+func ProcInfo() ([]Win32_PerfFormattedData_PerfOS_System, error) {
+ return ProcInfoWithContext(context.Background())
+}
+
+func ProcInfoWithContext(ctx context.Context) ([]Win32_PerfFormattedData_PerfOS_System, error) {
+ var ret []Win32_PerfFormattedData_PerfOS_System
+ q := wmi.CreateQuery(&ret, "")
+ err := common.WMIQueryWithContext(ctx, q, &ret)
+ if err != nil {
+ return []Win32_PerfFormattedData_PerfOS_System{}, err
+ }
+ return ret, err
+}
+
+// perCPUTimes returns times stat per cpu, per core and overall for all CPUs
+func perCPUTimesWithContext(ctx context.Context) ([]TimesStat, error) {
+ var ret []TimesStat
+ stats, err := perfInfoWithContext(ctx)
+ if err != nil {
+ return nil, err
+ }
+ for _, v := range stats {
+ c := TimesStat{
+ CPU: v.Name,
+ User: float64(v.PercentUserTime) / win32_TicksPerSecond,
+ System: float64(v.PercentPrivilegedTime) / win32_TicksPerSecond,
+ Idle: float64(v.PercentIdleTime) / win32_TicksPerSecond,
+ Irq: float64(v.PercentInterruptTime) / win32_TicksPerSecond,
+ }
+ ret = append(ret, c)
+ }
+ return ret, nil
+}
diff --git a/vendor/github.com/shirou/gopsutil/host/host.go b/vendor/github.com/shirou/gopsutil/host/host.go
new file mode 100644
index 0000000..1e9e9bb
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/host/host.go
@@ -0,0 +1,53 @@
+package host
+
+import (
+ "encoding/json"
+
+ "github.com/shirou/gopsutil/internal/common"
+)
+
+var invoke common.Invoker = common.Invoke{}
+
+// A HostInfoStat describes the host status.
+// This is not in the psutil but it useful.
+type InfoStat struct {
+ Hostname string `json:"hostname"`
+ Uptime uint64 `json:"uptime"`
+ BootTime uint64 `json:"bootTime"`
+ Procs uint64 `json:"procs"` // number of processes
+ OS string `json:"os"` // ex: freebsd, linux
+ Platform string `json:"platform"` // ex: ubuntu, linuxmint
+ PlatformFamily string `json:"platformFamily"` // ex: debian, rhel
+ PlatformVersion string `json:"platformVersion"` // version of the complete OS
+ KernelVersion string `json:"kernelVersion"` // version of the OS kernel (if available)
+ VirtualizationSystem string `json:"virtualizationSystem"`
+ VirtualizationRole string `json:"virtualizationRole"` // guest or host
+ HostID string `json:"hostid"` // ex: uuid
+}
+
+type UserStat struct {
+ User string `json:"user"`
+ Terminal string `json:"terminal"`
+ Host string `json:"host"`
+ Started int `json:"started"`
+}
+
+type TemperatureStat struct {
+ SensorKey string `json:"sensorKey"`
+ Temperature float64 `json:"sensorTemperature"`
+}
+
+func (h InfoStat) String() string {
+ s, _ := json.Marshal(h)
+ return string(s)
+}
+
+func (u UserStat) String() string {
+ s, _ := json.Marshal(u)
+ return string(s)
+}
+
+func (t TemperatureStat) String() string {
+ s, _ := json.Marshal(t)
+ return string(s)
+}
diff --git a/vendor/github.com/shirou/gopsutil/host/host_darwin.go b/vendor/github.com/shirou/gopsutil/host/host_darwin.go
new file mode 100644
index 0000000..8241fc0
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/host/host_darwin.go
@@ -0,0 +1,232 @@
+// +build darwin
+
+package host
+
+import (
+ "bytes"
+ "context"
+ "encoding/binary"
+ "io/ioutil"
+ "os"
+ "os/exec"
+ "runtime"
+ "strconv"
+ "strings"
+ "sync/atomic"
+ "time"
+ "unsafe"
+
+ "github.com/shirou/gopsutil/internal/common"
+ "github.com/shirou/gopsutil/process"
+)
+
+// from utmpx.h
+const USER_PROCESS = 7
+
+func Info() (*InfoStat, error) {
+ return InfoWithContext(context.Background())
+}
+
+func InfoWithContext(ctx context.Context) (*InfoStat, error) {
+ ret := &InfoStat{
+ OS: runtime.GOOS,
+ PlatformFamily: "darwin",
+ }
+
+ hostname, err := os.Hostname()
+ if err == nil {
+ ret.Hostname = hostname
+ }
+
+ kernelVersion, err := KernelVersionWithContext(ctx)
+ if err == nil {
+ ret.KernelVersion = kernelVersion
+ }
+
+ platform, family, pver, err := PlatformInformation()
+ if err == nil {
+ ret.Platform = platform
+ ret.PlatformFamily = family
+ ret.PlatformVersion = pver
+ }
+
+ system, role, err := Virtualization()
+ if err == nil {
+ ret.VirtualizationSystem = system
+ ret.VirtualizationRole = role
+ }
+
+ boot, err := BootTime()
+ if err == nil {
+ ret.BootTime = boot
+ ret.Uptime = uptime(boot)
+ }
+
+ procs, err := process.Pids()
+ if err == nil {
+ ret.Procs = uint64(len(procs))
+ }
+
+ values, err := common.DoSysctrlWithContext(ctx, "kern.uuid")
+ if err == nil && len(values) == 1 && values[0] != "" {
+ ret.HostID = strings.ToLower(values[0])
+ }
+
+ return ret, nil
+}
+
+// cachedBootTime must be accessed via atomic.Load/StoreUint64
+var cachedBootTime uint64
+
+func BootTime() (uint64, error) {
+ return BootTimeWithContext(context.Background())
+}
+
+func BootTimeWithContext(ctx context.Context) (uint64, error) {
+ t := atomic.LoadUint64(&cachedBootTime)
+ if t != 0 {
+ return t, nil
+ }
+ values, err := common.DoSysctrlWithContext(ctx, "kern.boottime")
+ if err != nil {
+ return 0, err
+ }
+ // ex: { sec = 1392261637, usec = 627534 } Thu Feb 13 12:20:37 2014
+ v := strings.Replace(values[2], ",", "", 1)
+ boottime, err := strconv.ParseInt(v, 10, 64)
+ if err != nil {
+ return 0, err
+ }
+ t = uint64(boottime)
+ atomic.StoreUint64(&cachedBootTime, t)
+
+ return t, nil
+}
+
+func uptime(boot uint64) uint64 {
+ return uint64(time.Now().Unix()) - boot
+}
+
+func Uptime() (uint64, error) {
+ return UptimeWithContext(context.Background())
+}
+
+func UptimeWithContext(ctx context.Context) (uint64, error) {
+ boot, err := BootTime()
+ if err != nil {
+ return 0, err
+ }
+ return uptime(boot), nil
+}
+
+func Users() ([]UserStat, error) {
+ return UsersWithContext(context.Background())
+}
+
+func UsersWithContext(ctx context.Context) ([]UserStat, error) {
+ utmpfile := "/var/run/utmpx"
+ var ret []UserStat
+
+ file, err := os.Open(utmpfile)
+ if err != nil {
+ return ret, err
+ }
+ defer file.Close()
+
+ buf, err := ioutil.ReadAll(file)
+ if err != nil {
+ return ret, err
+ }
+
+ u := Utmpx{}
+ entrySize := int(unsafe.Sizeof(u))
+ count := len(buf) / entrySize
+
+ for i := 0; i < count; i++ {
+ b := buf[i*entrySize : i*entrySize+entrySize]
+
+ var u Utmpx
+ br := bytes.NewReader(b)
+ err := binary.Read(br, binary.LittleEndian, &u)
+ if err != nil {
+ continue
+ }
+ if u.Type != USER_PROCESS {
+ continue
+ }
+ user := UserStat{
+ User: common.IntToString(u.User[:]),
+ Terminal: common.IntToString(u.Line[:]),
+ Host: common.IntToString(u.Host[:]),
+ Started: int(u.Tv.Sec),
+ }
+ ret = append(ret, user)
+ }
+
+ return ret, nil
+
+}
+
+func PlatformInformation() (string, string, string, error) {
+ return PlatformInformationWithContext(context.Background())
+}
+
+func PlatformInformationWithContext(ctx context.Context) (string, string, string, error) {
+ platform := ""
+ family := ""
+ pver := ""
+
+ sw_vers, err := exec.LookPath("sw_vers")
+ if err != nil {
+ return "", "", "", err
+ }
+ uname, err := exec.LookPath("uname")
+ if err != nil {
+ return "", "", "", err
+ }
+
+ out, err := invoke.CommandWithContext(ctx, uname, "-s")
+ if err == nil {
+ platform = strings.ToLower(strings.TrimSpace(string(out)))
+ }
+
+ out, err = invoke.CommandWithContext(ctx, sw_vers, "-productVersion")
+ if err == nil {
+ pver = strings.ToLower(strings.TrimSpace(string(out)))
+ }
+
+ return platform, family, pver, nil
+}
+
+func Virtualization() (string, string, error) {
+ return VirtualizationWithContext(context.Background())
+}
+
+func VirtualizationWithContext(ctx context.Context) (string, string, error) {
+ return "", "", common.ErrNotImplementedError
+}
+
+func KernelVersion() (string, error) {
+ return KernelVersionWithContext(context.Background())
+}
+
+func KernelVersionWithContext(ctx context.Context) (string, error) {
+ uname, err := exec.LookPath("uname")
+ if err != nil {
+ return "", err
+ }
+ out, err := invoke.CommandWithContext(ctx, uname, "-r")
+ if err != nil {
+ return "", err
+ }
+ version := strings.ToLower(strings.TrimSpace(string(out)))
+ return version, err
+}
+
+func SensorsTemperatures() ([]TemperatureStat, error) {
+ return SensorsTemperaturesWithContext(context.Background())
+}
+
+func SensorsTemperaturesWithContext(ctx context.Context) ([]TemperatureStat, error) {
+ return []TemperatureStat{}, common.ErrNotImplementedError
+}
diff --git a/vendor/github.com/shirou/gopsutil/host/host_darwin_386.go b/vendor/github.com/shirou/gopsutil/host/host_darwin_386.go
new file mode 100644
index 0000000..c3596f9
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/host/host_darwin_386.go
@@ -0,0 +1,19 @@
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs types_darwin.go
+
+package host
+
+type Utmpx struct {
+ User [256]int8
+ ID [4]int8
+ Line [32]int8
+ Pid int32
+ Type int16
+ Pad_cgo_0 [6]byte
+ Tv Timeval
+ Host [256]int8
+ Pad [16]uint32
+}
+type Timeval struct {
+ Sec int32
+}
diff --git a/vendor/github.com/shirou/gopsutil/host/host_darwin_amd64.go b/vendor/github.com/shirou/gopsutil/host/host_darwin_amd64.go
new file mode 100644
index 0000000..c3596f9
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/host/host_darwin_amd64.go
@@ -0,0 +1,19 @@
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs types_darwin.go
+
+package host
+
+type Utmpx struct {
+ User [256]int8
+ ID [4]int8
+ Line [32]int8
+ Pid int32
+ Type int16
+ Pad_cgo_0 [6]byte
+ Tv Timeval
+ Host [256]int8
+ Pad [16]uint32
+}
+type Timeval struct {
+ Sec int32
+}
diff --git a/vendor/github.com/shirou/gopsutil/host/host_fallback.go b/vendor/github.com/shirou/gopsutil/host/host_fallback.go
new file mode 100644
index 0000000..e80d7ea
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/host/host_fallback.go
@@ -0,0 +1,65 @@
+// +build !darwin,!linux,!freebsd,!openbsd,!solaris,!windows
+
+package host
+
+import (
+ "context"
+
+ "github.com/shirou/gopsutil/internal/common"
+)
+
+func Info() (*InfoStat, error) {
+ return InfoWithContext(context.Background())
+}
+
+func InfoWithContext(ctx context.Context) (*InfoStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func BootTime() (uint64, error) {
+ return BootTimeWithContext(context.Background())
+}
+
+func BootTimeWithContext(ctx context.Context) (uint64, error) {
+ return 0, common.ErrNotImplementedError
+}
+
+func Uptime() (uint64, error) {
+ return UptimeWithContext(context.Background())
+}
+
+func UptimeWithContext(ctx context.Context) (uint64, error) {
+ return 0, common.ErrNotImplementedError
+}
+
+func Users() ([]UserStat, error) {
+ return UsersWithContext(context.Background())
+}
+
+func UsersWithContext(ctx context.Context) ([]UserStat, error) {
+ return []UserStat{}, common.ErrNotImplementedError
+}
+
+func Virtualization() (string, string, error) {
+ return VirtualizationWithContext(context.Background())
+}
+
+func VirtualizationWithContext(ctx context.Context) (string, string, error) {
+ return "", "", common.ErrNotImplementedError
+}
+
+func KernelVersion() (string, error) {
+ return KernelVersionWithContext(context.Background())
+}
+
+func KernelVersionWithContext(ctx context.Context) (string, error) {
+ return "", common.ErrNotImplementedError
+}
+
+func PlatformInformation() (string, string, string, error) {
+ return PlatformInformationWithContext(context.Background())
+}
+
+func PlatformInformationWithContext(ctx context.Context) (string, string, string, error) {
+ return "", "", "", common.ErrNotImplementedError
+}
diff --git a/vendor/github.com/shirou/gopsutil/host/host_freebsd.go b/vendor/github.com/shirou/gopsutil/host/host_freebsd.go
new file mode 100644
index 0000000..00a8519
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/host/host_freebsd.go
@@ -0,0 +1,245 @@
+// +build freebsd
+
+package host
+
+import (
+ "bytes"
+ "context"
+ "encoding/binary"
+ "io/ioutil"
+ "os"
+ "runtime"
+ "strings"
+ "sync/atomic"
+ "syscall"
+ "time"
+ "unsafe"
+
+ "github.com/shirou/gopsutil/internal/common"
+ "github.com/shirou/gopsutil/process"
+ "golang.org/x/sys/unix"
+)
+
+const (
+ UTNameSize = 16 /* see MAXLOGNAME in */
+ UTLineSize = 8
+ UTHostSize = 16
+)
+
+func Info() (*InfoStat, error) {
+ return InfoWithContext(context.Background())
+}
+
+func InfoWithContext(ctx context.Context) (*InfoStat, error) {
+ ret := &InfoStat{
+ OS: runtime.GOOS,
+ PlatformFamily: "freebsd",
+ }
+
+ hostname, err := os.Hostname()
+ if err == nil {
+ ret.Hostname = hostname
+ }
+
+ platform, family, version, err := PlatformInformation()
+ if err == nil {
+ ret.Platform = platform
+ ret.PlatformFamily = family
+ ret.PlatformVersion = version
+ ret.KernelVersion = version
+ }
+
+ system, role, err := Virtualization()
+ if err == nil {
+ ret.VirtualizationSystem = system
+ ret.VirtualizationRole = role
+ }
+
+ boot, err := BootTime()
+ if err == nil {
+ ret.BootTime = boot
+ ret.Uptime = uptime(boot)
+ }
+
+ procs, err := process.Pids()
+ if err == nil {
+ ret.Procs = uint64(len(procs))
+ }
+
+ hostid, err := unix.Sysctl("kern.hostuuid")
+ if err == nil && hostid != "" {
+ ret.HostID = strings.ToLower(hostid)
+ }
+
+ return ret, nil
+}
+
+// cachedBootTime must be accessed via atomic.Load/StoreUint64
+var cachedBootTime uint64
+
+func BootTime() (uint64, error) {
+ return BootTimeWithContext(context.Background())
+}
+
+func BootTimeWithContext(ctx context.Context) (uint64, error) {
+ t := atomic.LoadUint64(&cachedBootTime)
+ if t != 0 {
+ return t, nil
+ }
+ buf, err := unix.SysctlRaw("kern.boottime")
+ if err != nil {
+ return 0, err
+ }
+
+ tv := *(*syscall.Timeval)(unsafe.Pointer((&buf[0])))
+ atomic.StoreUint64(&cachedBootTime, uint64(tv.Sec))
+
+ return t, nil
+}
+
+func uptime(boot uint64) uint64 {
+ return uint64(time.Now().Unix()) - boot
+}
+
+func Uptime() (uint64, error) {
+ return UptimeWithContext(context.Background())
+}
+
+func UptimeWithContext(ctx context.Context) (uint64, error) {
+ boot, err := BootTime()
+ if err != nil {
+ return 0, err
+ }
+ return uptime(boot), nil
+}
+
+func Users() ([]UserStat, error) {
+ return UsersWithContext(context.Background())
+}
+
+func UsersWithContext(ctx context.Context) ([]UserStat, error) {
+ utmpfile := "/var/run/utx.active"
+ if !common.PathExists(utmpfile) {
+ utmpfile = "/var/run/utmp" // before 9.0
+ return getUsersFromUtmp(utmpfile)
+ }
+
+ var ret []UserStat
+ file, err := os.Open(utmpfile)
+ if err != nil {
+ return ret, err
+ }
+ defer file.Close()
+
+ buf, err := ioutil.ReadAll(file)
+ if err != nil {
+ return ret, err
+ }
+
+ entrySize := sizeOfUtmpx
+ count := len(buf) / entrySize
+
+ for i := 0; i < count; i++ {
+ b := buf[i*sizeOfUtmpx : (i+1)*sizeOfUtmpx]
+ var u Utmpx
+ br := bytes.NewReader(b)
+ err := binary.Read(br, binary.LittleEndian, &u)
+ if err != nil || u.Type != 4 {
+ continue
+ }
+ sec := (binary.LittleEndian.Uint32(u.Tv.Sec[:])) / 2 // TODO:
+ user := UserStat{
+ User: common.IntToString(u.User[:]),
+ Terminal: common.IntToString(u.Line[:]),
+ Host: common.IntToString(u.Host[:]),
+ Started: int(sec),
+ }
+
+ ret = append(ret, user)
+ }
+
+ return ret, nil
+
+}
+
+func PlatformInformation() (string, string, string, error) {
+ return PlatformInformationWithContext(context.Background())
+}
+
+func PlatformInformationWithContext(ctx context.Context) (string, string, string, error) {
+ platform, err := unix.Sysctl("kern.ostype")
+ if err != nil {
+ return "", "", "", err
+ }
+
+ version, err := unix.Sysctl("kern.osrelease")
+ if err != nil {
+ return "", "", "", err
+ }
+
+ return strings.ToLower(platform), "", strings.ToLower(version), nil
+}
+
+func Virtualization() (string, string, error) {
+ return VirtualizationWithContext(context.Background())
+}
+
+func VirtualizationWithContext(ctx context.Context) (string, string, error) {
+ return "", "", common.ErrNotImplementedError
+}
+
+// before 9.0
+func getUsersFromUtmp(utmpfile string) ([]UserStat, error) {
+ var ret []UserStat
+ file, err := os.Open(utmpfile)
+ if err != nil {
+ return ret, err
+ }
+ defer file.Close()
+
+ buf, err := ioutil.ReadAll(file)
+ if err != nil {
+ return ret, err
+ }
+
+ u := Utmp{}
+ entrySize := int(unsafe.Sizeof(u))
+ count := len(buf) / entrySize
+
+ for i := 0; i < count; i++ {
+ b := buf[i*entrySize : i*entrySize+entrySize]
+ var u Utmp
+ br := bytes.NewReader(b)
+ err := binary.Read(br, binary.LittleEndian, &u)
+ if err != nil || u.Time == 0 {
+ continue
+ }
+ user := UserStat{
+ User: common.IntToString(u.Name[:]),
+ Terminal: common.IntToString(u.Line[:]),
+ Host: common.IntToString(u.Host[:]),
+ Started: int(u.Time),
+ }
+
+ ret = append(ret, user)
+ }
+
+ return ret, nil
+}
+
+func SensorsTemperatures() ([]TemperatureStat, error) {
+ return SensorsTemperaturesWithContext(context.Background())
+}
+
+func SensorsTemperaturesWithContext(ctx context.Context) ([]TemperatureStat, error) {
+ return []TemperatureStat{}, common.ErrNotImplementedError
+}
+
+func KernelVersion() (string, error) {
+ return KernelVersionWithContext(context.Background())
+}
+
+func KernelVersionWithContext(ctx context.Context) (string, error) {
+ _, _, version, err := PlatformInformation()
+ return version, err
+}
diff --git a/vendor/github.com/shirou/gopsutil/host/host_freebsd_386.go b/vendor/github.com/shirou/gopsutil/host/host_freebsd_386.go
new file mode 100644
index 0000000..7f06d8f
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/host/host_freebsd_386.go
@@ -0,0 +1,43 @@
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs types_freebsd.go
+
+package host
+
+const (
+ sizeofPtr = 0x4
+ sizeofShort = 0x2
+ sizeofInt = 0x4
+ sizeofLong = 0x4
+ sizeofLongLong = 0x8
+ sizeOfUtmpx = 197 // TODO why should 197
+)
+
+type (
+ _C_short int16
+ _C_int int32
+ _C_long int32
+ _C_long_long int64
+)
+
+type Utmp struct {
+ Line [8]int8
+ Name [16]int8
+ Host [16]int8
+ Time int32
+}
+
+type Utmpx struct {
+ Type int16
+ Tv Timeval
+ Id [8]int8
+ Pid int32
+ User [32]int8
+ Line [16]int8
+ Host [125]int8
+ // X__ut_spare [64]int8
+}
+
+type Timeval struct {
+ Sec [4]byte
+ Usec [3]byte
+}
diff --git a/vendor/github.com/shirou/gopsutil/host/host_freebsd_amd64.go b/vendor/github.com/shirou/gopsutil/host/host_freebsd_amd64.go
new file mode 100644
index 0000000..3f015f0
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/host/host_freebsd_amd64.go
@@ -0,0 +1,44 @@
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs types_freebsd.go
+
+package host
+
+const (
+ sizeofPtr = 0x8
+ sizeofShort = 0x2
+ sizeofInt = 0x4
+ sizeofLong = 0x8
+ sizeofLongLong = 0x8
+ sizeOfUtmpx = 197 // TODO: why should 197, not 0x118
+)
+
+type (
+ _C_short int16
+ _C_int int32
+ _C_long int64
+ _C_long_long int64
+)
+
+type Utmp struct {
+ Line [8]int8
+ Name [16]int8
+ Host [16]int8
+ Time int32
+}
+
+type Utmpx struct {
+ Type int16
+ Tv Timeval
+ Id [8]int8
+ Pid int32
+ User [32]int8
+ Line [16]int8
+ Host [125]int8
+ // Host [128]int8
+ // X__ut_spare [64]int8
+}
+
+type Timeval struct {
+ Sec [4]byte
+ Usec [3]byte
+}
diff --git a/vendor/github.com/shirou/gopsutil/host/host_freebsd_arm.go b/vendor/github.com/shirou/gopsutil/host/host_freebsd_arm.go
new file mode 100644
index 0000000..ac74980
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/host/host_freebsd_arm.go
@@ -0,0 +1,44 @@
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs types_freebsd.go
+
+package host
+
+const (
+ sizeofPtr = 0x4
+ sizeofShort = 0x2
+ sizeofInt = 0x4
+ sizeofLong = 0x8
+ sizeofLongLong = 0x8
+ sizeOfUtmpx = 197 // TODO: why should 197, not 0x118
+)
+
+type (
+ _C_short int16
+ _C_int int32
+ _C_long int32
+ _C_long_long int64
+)
+
+type Utmp struct {
+ Line [8]int8
+ Name [16]int8
+ Host [16]int8
+ Time int32
+}
+
+type Utmpx struct {
+ Type int16
+ Tv Timeval
+ Id [8]int8
+ Pid int32
+ User [32]int8
+ Line [16]int8
+ Host [125]int8
+ // Host [128]int8
+ // X__ut_spare [64]int8
+}
+
+type Timeval struct {
+ Sec [4]byte
+ Usec [3]byte
+}
diff --git a/vendor/github.com/shirou/gopsutil/host/host_linux.go b/vendor/github.com/shirou/gopsutil/host/host_linux.go
new file mode 100644
index 0000000..2c1ac6b
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/host/host_linux.go
@@ -0,0 +1,682 @@
+// +build linux
+
+package host
+
+import (
+ "bytes"
+ "context"
+ "encoding/binary"
+ "fmt"
+ "io/ioutil"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "regexp"
+ "runtime"
+ "strconv"
+ "strings"
+ "sync/atomic"
+ "time"
+
+ "github.com/shirou/gopsutil/internal/common"
+)
+
+type LSB struct {
+ ID string
+ Release string
+ Codename string
+ Description string
+}
+
+// from utmp.h
+const USER_PROCESS = 7
+
+func Info() (*InfoStat, error) {
+ return InfoWithContext(context.Background())
+}
+
+func InfoWithContext(ctx context.Context) (*InfoStat, error) {
+ ret := &InfoStat{
+ OS: runtime.GOOS,
+ }
+
+ hostname, err := os.Hostname()
+ if err == nil {
+ ret.Hostname = hostname
+ }
+
+ platform, family, version, err := PlatformInformation()
+ if err == nil {
+ ret.Platform = platform
+ ret.PlatformFamily = family
+ ret.PlatformVersion = version
+ }
+ kernelVersion, err := KernelVersion()
+ if err == nil {
+ ret.KernelVersion = kernelVersion
+ }
+
+ system, role, err := Virtualization()
+ if err == nil {
+ ret.VirtualizationSystem = system
+ ret.VirtualizationRole = role
+ }
+
+ boot, err := BootTime()
+ if err == nil {
+ ret.BootTime = boot
+ ret.Uptime = uptime(boot)
+ }
+
+ if numProcs, err := common.NumProcs(); err == nil {
+ ret.Procs = numProcs
+ }
+
+ sysProductUUID := common.HostSys("class/dmi/id/product_uuid")
+ machineID := common.HostEtc("machine-id")
+ switch {
+ // In order to read this file, needs to be supported by kernel/arch and run as root
+ // so having fallback is important
+ case common.PathExists(sysProductUUID):
+ lines, err := common.ReadLines(sysProductUUID)
+ if err == nil && len(lines) > 0 && lines[0] != "" {
+ ret.HostID = strings.ToLower(lines[0])
+ break
+ }
+ fallthrough
+ // Fallback on GNU Linux systems with systemd, readable by everyone
+ case common.PathExists(machineID):
+ lines, err := common.ReadLines(machineID)
+ if err == nil && len(lines) > 0 && len(lines[0]) == 32 {
+ st := lines[0]
+ ret.HostID = fmt.Sprintf("%s-%s-%s-%s-%s", st[0:8], st[8:12], st[12:16], st[16:20], st[20:32])
+ break
+ }
+ fallthrough
+ // Not stable between reboot, but better than nothing
+ default:
+ values, err := common.DoSysctrl("kernel.random.boot_id")
+ if err == nil && len(values) == 1 && values[0] != "" {
+ ret.HostID = strings.ToLower(values[0])
+ }
+ }
+
+ return ret, nil
+}
+
+// cachedBootTime must be accessed via atomic.Load/StoreUint64
+var cachedBootTime uint64
+
+// BootTime returns the system boot time expressed in seconds since the epoch.
+func BootTime() (uint64, error) {
+ return BootTimeWithContext(context.Background())
+}
+
+func BootTimeWithContext(ctx context.Context) (uint64, error) {
+ t := atomic.LoadUint64(&cachedBootTime)
+ if t != 0 {
+ return t, nil
+ }
+
+ system, role, err := Virtualization()
+ if err != nil {
+ return 0, err
+ }
+
+ statFile := "stat"
+ if system == "lxc" && role == "guest" {
+ // if lxc, /proc/uptime is used.
+ statFile = "uptime"
+ } else if system == "docker" && role == "guest" {
+ // also docker, guest
+ statFile = "uptime"
+ }
+
+ filename := common.HostProc(statFile)
+ lines, err := common.ReadLines(filename)
+ if err != nil {
+ return 0, err
+ }
+
+ if statFile == "stat" {
+ for _, line := range lines {
+ if strings.HasPrefix(line, "btime") {
+ f := strings.Fields(line)
+ if len(f) != 2 {
+ return 0, fmt.Errorf("wrong btime format")
+ }
+ b, err := strconv.ParseInt(f[1], 10, 64)
+ if err != nil {
+ return 0, err
+ }
+ t = uint64(b)
+ atomic.StoreUint64(&cachedBootTime, t)
+ return t, nil
+ }
+ }
+ } else if statFile == "uptime" {
+ if len(lines) != 1 {
+ return 0, fmt.Errorf("wrong uptime format")
+ }
+ f := strings.Fields(lines[0])
+ b, err := strconv.ParseFloat(f[0], 64)
+ if err != nil {
+ return 0, err
+ }
+ t = uint64(time.Now().Unix()) - uint64(b)
+ atomic.StoreUint64(&cachedBootTime, t)
+ return t, nil
+ }
+
+ return 0, fmt.Errorf("could not find btime")
+}
+
+func uptime(boot uint64) uint64 {
+ return uint64(time.Now().Unix()) - boot
+}
+
+func Uptime() (uint64, error) {
+ return UptimeWithContext(context.Background())
+}
+
+func UptimeWithContext(ctx context.Context) (uint64, error) {
+ boot, err := BootTime()
+ if err != nil {
+ return 0, err
+ }
+ return uptime(boot), nil
+}
+
+func Users() ([]UserStat, error) {
+ return UsersWithContext(context.Background())
+}
+
+func UsersWithContext(ctx context.Context) ([]UserStat, error) {
+ utmpfile := common.HostVar("run/utmp")
+
+ file, err := os.Open(utmpfile)
+ if err != nil {
+ return nil, err
+ }
+ defer file.Close()
+
+ buf, err := ioutil.ReadAll(file)
+ if err != nil {
+ return nil, err
+ }
+
+ count := len(buf) / sizeOfUtmp
+
+ ret := make([]UserStat, 0, count)
+
+ for i := 0; i < count; i++ {
+ b := buf[i*sizeOfUtmp : (i+1)*sizeOfUtmp]
+
+ var u utmp
+ br := bytes.NewReader(b)
+ err := binary.Read(br, binary.LittleEndian, &u)
+ if err != nil {
+ continue
+ }
+ if u.Type != USER_PROCESS {
+ continue
+ }
+ user := UserStat{
+ User: common.IntToString(u.User[:]),
+ Terminal: common.IntToString(u.Line[:]),
+ Host: common.IntToString(u.Host[:]),
+ Started: int(u.Tv.Sec),
+ }
+ ret = append(ret, user)
+ }
+
+ return ret, nil
+
+}
+
+func getOSRelease() (platform string, version string, err error) {
+ contents, err := common.ReadLines(common.HostEtc("os-release"))
+ if err != nil {
+ return "", "", nil // return empty
+ }
+ for _, line := range contents {
+ field := strings.Split(line, "=")
+ if len(field) < 2 {
+ continue
+ }
+ switch field[0] {
+ case "ID": // use ID for lowercase
+ platform = field[1]
+ case "VERSION":
+ version = field[1]
+ }
+ }
+ return platform, version, nil
+}
+
+func getLSB() (*LSB, error) {
+ ret := &LSB{}
+ if common.PathExists(common.HostEtc("lsb-release")) {
+ contents, err := common.ReadLines(common.HostEtc("lsb-release"))
+ if err != nil {
+ return ret, err // return empty
+ }
+ for _, line := range contents {
+ field := strings.Split(line, "=")
+ if len(field) < 2 {
+ continue
+ }
+ switch field[0] {
+ case "DISTRIB_ID":
+ ret.ID = field[1]
+ case "DISTRIB_RELEASE":
+ ret.Release = field[1]
+ case "DISTRIB_CODENAME":
+ ret.Codename = field[1]
+ case "DISTRIB_DESCRIPTION":
+ ret.Description = field[1]
+ }
+ }
+ } else if common.PathExists("/usr/bin/lsb_release") {
+ lsb_release, err := exec.LookPath("/usr/bin/lsb_release")
+ if err != nil {
+ return ret, err
+ }
+ out, err := invoke.Command(lsb_release)
+ if err != nil {
+ return ret, err
+ }
+ for _, line := range strings.Split(string(out), "\n") {
+ field := strings.Split(line, ":")
+ if len(field) < 2 {
+ continue
+ }
+ switch field[0] {
+ case "Distributor ID":
+ ret.ID = field[1]
+ case "Release":
+ ret.Release = field[1]
+ case "Codename":
+ ret.Codename = field[1]
+ case "Description":
+ ret.Description = field[1]
+ }
+ }
+
+ }
+
+ return ret, nil
+}
+
+func PlatformInformation() (platform string, family string, version string, err error) {
+ return PlatformInformationWithContext(context.Background())
+}
+
+func PlatformInformationWithContext(ctx context.Context) (platform string, family string, version string, err error) {
+
+ lsb, err := getLSB()
+ if err != nil {
+ lsb = &LSB{}
+ }
+
+ if common.PathExists(common.HostEtc("oracle-release")) {
+ platform = "oracle"
+ contents, err := common.ReadLines(common.HostEtc("oracle-release"))
+ if err == nil {
+ version = getRedhatishVersion(contents)
+ }
+
+ } else if common.PathExists(common.HostEtc("enterprise-release")) {
+ platform = "oracle"
+ contents, err := common.ReadLines(common.HostEtc("enterprise-release"))
+ if err == nil {
+ version = getRedhatishVersion(contents)
+ }
+ } else if common.PathExists(common.HostEtc("slackware-version")) {
+ platform = "slackware"
+ contents, err := common.ReadLines(common.HostEtc("slackware-version"))
+ if err == nil {
+ version = getSlackwareVersion(contents)
+ }
+ } else if common.PathExists(common.HostEtc("debian_version")) {
+ if lsb.ID == "Ubuntu" {
+ platform = "ubuntu"
+ version = lsb.Release
+ } else if lsb.ID == "LinuxMint" {
+ platform = "linuxmint"
+ version = lsb.Release
+ } else {
+ if common.PathExists("/usr/bin/raspi-config") {
+ platform = "raspbian"
+ } else {
+ platform = "debian"
+ }
+ contents, err := common.ReadLines(common.HostEtc("debian_version"))
+ if err == nil {
+ version = contents[0]
+ }
+ }
+ } else if common.PathExists(common.HostEtc("redhat-release")) {
+ contents, err := common.ReadLines(common.HostEtc("redhat-release"))
+ if err == nil {
+ version = getRedhatishVersion(contents)
+ platform = getRedhatishPlatform(contents)
+ }
+ } else if common.PathExists(common.HostEtc("system-release")) {
+ contents, err := common.ReadLines(common.HostEtc("system-release"))
+ if err == nil {
+ version = getRedhatishVersion(contents)
+ platform = getRedhatishPlatform(contents)
+ }
+ } else if common.PathExists(common.HostEtc("gentoo-release")) {
+ platform = "gentoo"
+ contents, err := common.ReadLines(common.HostEtc("gentoo-release"))
+ if err == nil {
+ version = getRedhatishVersion(contents)
+ }
+ } else if common.PathExists(common.HostEtc("SuSE-release")) {
+ contents, err := common.ReadLines(common.HostEtc("SuSE-release"))
+ if err == nil {
+ version = getSuseVersion(contents)
+ platform = getSusePlatform(contents)
+ }
+ // TODO: slackware detecion
+ } else if common.PathExists(common.HostEtc("arch-release")) {
+ platform = "arch"
+ version = lsb.Release
+ } else if common.PathExists(common.HostEtc("alpine-release")) {
+ platform = "alpine"
+ contents, err := common.ReadLines(common.HostEtc("alpine-release"))
+ if err == nil && len(contents) > 0 {
+ version = contents[0]
+ }
+ } else if common.PathExists(common.HostEtc("os-release")) {
+ p, v, err := getOSRelease()
+ if err == nil {
+ platform = p
+ version = v
+ }
+ } else if lsb.ID == "RedHat" {
+ platform = "redhat"
+ version = lsb.Release
+ } else if lsb.ID == "Amazon" {
+ platform = "amazon"
+ version = lsb.Release
+ } else if lsb.ID == "ScientificSL" {
+ platform = "scientific"
+ version = lsb.Release
+ } else if lsb.ID == "XenServer" {
+ platform = "xenserver"
+ version = lsb.Release
+ } else if lsb.ID != "" {
+ platform = strings.ToLower(lsb.ID)
+ version = lsb.Release
+ }
+
+ switch platform {
+ case "debian", "ubuntu", "linuxmint", "raspbian":
+ family = "debian"
+ case "fedora":
+ family = "fedora"
+ case "oracle", "centos", "redhat", "scientific", "enterpriseenterprise", "amazon", "xenserver", "cloudlinux", "ibm_powerkvm":
+ family = "rhel"
+ case "suse", "opensuse":
+ family = "suse"
+ case "gentoo":
+ family = "gentoo"
+ case "slackware":
+ family = "slackware"
+ case "arch":
+ family = "arch"
+ case "exherbo":
+ family = "exherbo"
+ case "alpine":
+ family = "alpine"
+ case "coreos":
+ family = "coreos"
+ }
+
+ return platform, family, version, nil
+
+}
+
+func KernelVersion() (version string, err error) {
+ return KernelVersionWithContext(context.Background())
+}
+
+func KernelVersionWithContext(ctx context.Context) (version string, err error) {
+ filename := common.HostProc("sys/kernel/osrelease")
+ if common.PathExists(filename) {
+ contents, err := common.ReadLines(filename)
+ if err != nil {
+ return "", err
+ }
+
+ if len(contents) > 0 {
+ version = contents[0]
+ }
+ }
+
+ return version, nil
+}
+
+func getSlackwareVersion(contents []string) string {
+ c := strings.ToLower(strings.Join(contents, ""))
+ c = strings.Replace(c, "slackware ", "", 1)
+ return c
+}
+
+func getRedhatishVersion(contents []string) string {
+ c := strings.ToLower(strings.Join(contents, ""))
+
+ if strings.Contains(c, "rawhide") {
+ return "rawhide"
+ }
+ if matches := regexp.MustCompile(`release (\d[\d.]*)`).FindStringSubmatch(c); matches != nil {
+ return matches[1]
+ }
+ return ""
+}
+
+func getRedhatishPlatform(contents []string) string {
+ c := strings.ToLower(strings.Join(contents, ""))
+
+ if strings.Contains(c, "red hat") {
+ return "redhat"
+ }
+ f := strings.Split(c, " ")
+
+ return f[0]
+}
+
+func getSuseVersion(contents []string) string {
+ version := ""
+ for _, line := range contents {
+ if matches := regexp.MustCompile(`VERSION = ([\d.]+)`).FindStringSubmatch(line); matches != nil {
+ version = matches[1]
+ } else if matches := regexp.MustCompile(`PATCHLEVEL = ([\d]+)`).FindStringSubmatch(line); matches != nil {
+ version = version + "." + matches[1]
+ }
+ }
+ return version
+}
+
+func getSusePlatform(contents []string) string {
+ c := strings.ToLower(strings.Join(contents, ""))
+ if strings.Contains(c, "opensuse") {
+ return "opensuse"
+ }
+ return "suse"
+}
+
+func Virtualization() (string, string, error) {
+ return VirtualizationWithContext(context.Background())
+}
+
+func VirtualizationWithContext(ctx context.Context) (string, string, error) {
+ var system string
+ var role string
+
+ filename := common.HostProc("xen")
+ if common.PathExists(filename) {
+ system = "xen"
+ role = "guest" // assume guest
+
+ if common.PathExists(filepath.Join(filename, "capabilities")) {
+ contents, err := common.ReadLines(filepath.Join(filename, "capabilities"))
+ if err == nil {
+ if common.StringsContains(contents, "control_d") {
+ role = "host"
+ }
+ }
+ }
+ }
+
+ filename = common.HostProc("modules")
+ if common.PathExists(filename) {
+ contents, err := common.ReadLines(filename)
+ if err == nil {
+ if common.StringsContains(contents, "kvm") {
+ system = "kvm"
+ role = "host"
+ } else if common.StringsContains(contents, "vboxdrv") {
+ system = "vbox"
+ role = "host"
+ } else if common.StringsContains(contents, "vboxguest") {
+ system = "vbox"
+ role = "guest"
+ } else if common.StringsContains(contents, "vmware") {
+ system = "vmware"
+ role = "guest"
+ }
+ }
+ }
+
+ filename = common.HostProc("cpuinfo")
+ if common.PathExists(filename) {
+ contents, err := common.ReadLines(filename)
+ if err == nil {
+ if common.StringsContains(contents, "QEMU Virtual CPU") ||
+ common.StringsContains(contents, "Common KVM processor") ||
+ common.StringsContains(contents, "Common 32-bit KVM processor") {
+ system = "kvm"
+ role = "guest"
+ }
+ }
+ }
+
+ filename = common.HostProc()
+ if common.PathExists(filepath.Join(filename, "bc", "0")) {
+ system = "openvz"
+ role = "host"
+ } else if common.PathExists(filepath.Join(filename, "vz")) {
+ system = "openvz"
+ role = "guest"
+ }
+
+ // not use dmidecode because it requires root
+ if common.PathExists(filepath.Join(filename, "self", "status")) {
+ contents, err := common.ReadLines(filepath.Join(filename, "self", "status"))
+ if err == nil {
+
+ if common.StringsContains(contents, "s_context:") ||
+ common.StringsContains(contents, "VxID:") {
+ system = "linux-vserver"
+ }
+ // TODO: guest or host
+ }
+ }
+
+ if common.PathExists(filepath.Join(filename, "self", "cgroup")) {
+ contents, err := common.ReadLines(filepath.Join(filename, "self", "cgroup"))
+ if err == nil {
+ if common.StringsContains(contents, "lxc") {
+ system = "lxc"
+ role = "guest"
+ } else if common.StringsContains(contents, "docker") {
+ system = "docker"
+ role = "guest"
+ } else if common.StringsContains(contents, "machine-rkt") {
+ system = "rkt"
+ role = "guest"
+ } else if common.PathExists("/usr/bin/lxc-version") {
+ system = "lxc"
+ role = "host"
+ }
+ }
+ }
+
+ if common.PathExists(common.HostEtc("os-release")) {
+ p, _, err := getOSRelease()
+ if err == nil && p == "coreos" {
+ system = "rkt" // Is it true?
+ role = "host"
+ }
+ }
+ return system, role, nil
+}
+
+func SensorsTemperatures() ([]TemperatureStat, error) {
+ return SensorsTemperaturesWithContext(context.Background())
+}
+
+func SensorsTemperaturesWithContext(ctx context.Context) ([]TemperatureStat, error) {
+ var temperatures []TemperatureStat
+ files, err := filepath.Glob(common.HostSys("/class/hwmon/hwmon*/temp*_*"))
+ if err != nil {
+ return temperatures, err
+ }
+ if len(files) == 0 {
+ // CentOS has an intermediate /device directory:
+ // https://github.com/giampaolo/psutil/issues/971
+ files, err = filepath.Glob(common.HostSys("/class/hwmon/hwmon*/device/temp*_*"))
+ if err != nil {
+ return temperatures, err
+ }
+ }
+
+ // example directory
+ // device/ temp1_crit_alarm temp2_crit_alarm temp3_crit_alarm temp4_crit_alarm temp5_crit_alarm temp6_crit_alarm temp7_crit_alarm
+ // name temp1_input temp2_input temp3_input temp4_input temp5_input temp6_input temp7_input
+ // power/ temp1_label temp2_label temp3_label temp4_label temp5_label temp6_label temp7_label
+ // subsystem/ temp1_max temp2_max temp3_max temp4_max temp5_max temp6_max temp7_max
+ // temp1_crit temp2_crit temp3_crit temp4_crit temp5_crit temp6_crit temp7_crit uevent
+ for _, file := range files {
+ filename := strings.Split(filepath.Base(file), "_")
+ if filename[1] == "label" {
+ // Do not try to read the temperature of the label file
+ continue
+ }
+
+ // Get the label of the temperature you are reading
+ var label string
+ c, _ := ioutil.ReadFile(filepath.Join(filepath.Dir(file), filename[0]+"_label"))
+ if c != nil {
+ //format the label from "Core 0" to "core0_"
+ label = fmt.Sprintf("%s_", strings.Join(strings.Split(strings.TrimSpace(strings.ToLower(string(c))), " "), ""))
+ }
+
+ // Get the name of the tempearture you are reading
+ name, err := ioutil.ReadFile(filepath.Join(filepath.Dir(file), "name"))
+ if err != nil {
+ return temperatures, err
+ }
+
+ // Get the temperature reading
+ current, err := ioutil.ReadFile(file)
+ if err != nil {
+ return temperatures, err
+ }
+ temperature, err := strconv.ParseFloat(strings.TrimSpace(string(current)), 64)
+ if err != nil {
+ continue
+ }
+
+ tempName := strings.TrimSpace(strings.ToLower(string(strings.Join(filename[1:], ""))))
+ temperatures = append(temperatures, TemperatureStat{
+ SensorKey: fmt.Sprintf("%s_%s%s", strings.TrimSpace(string(name)), label, tempName),
+ Temperature: temperature / 1000.0,
+ })
+ }
+ return temperatures, nil
+}
diff --git a/vendor/github.com/shirou/gopsutil/host/host_linux_386.go b/vendor/github.com/shirou/gopsutil/host/host_linux_386.go
new file mode 100644
index 0000000..79b5cb5
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/host/host_linux_386.go
@@ -0,0 +1,45 @@
+// ATTENTION - FILE MANUAL FIXED AFTER CGO.
+// Fixed line: Tv _Ctype_struct_timeval -> Tv UtTv
+// Created by cgo -godefs, MANUAL FIXED
+// cgo -godefs types_linux.go
+
+package host
+
+const (
+ sizeofPtr = 0x4
+ sizeofShort = 0x2
+ sizeofInt = 0x4
+ sizeofLong = 0x4
+ sizeofLongLong = 0x8
+ sizeOfUtmp = 0x180
+)
+
+type (
+ _C_short int16
+ _C_int int32
+ _C_long int32
+ _C_long_long int64
+)
+
+type utmp struct {
+ Type int16
+ Pad_cgo_0 [2]byte
+ Pid int32
+ Line [32]int8
+ ID [4]int8
+ User [32]int8
+ Host [256]int8
+ Exit exit_status
+ Session int32
+ Tv UtTv
+ Addr_v6 [4]int32
+ X__unused [20]int8
+}
+type exit_status struct {
+ Termination int16
+ Exit int16
+}
+type UtTv struct {
+ Sec int32
+ Usec int32
+}
diff --git a/vendor/github.com/shirou/gopsutil/host/host_linux_amd64.go b/vendor/github.com/shirou/gopsutil/host/host_linux_amd64.go
new file mode 100644
index 0000000..9a69652
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/host/host_linux_amd64.go
@@ -0,0 +1,48 @@
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs types_linux.go
+
+package host
+
+const (
+ sizeofPtr = 0x8
+ sizeofShort = 0x2
+ sizeofInt = 0x4
+ sizeofLong = 0x8
+ sizeofLongLong = 0x8
+ sizeOfUtmp = 0x180
+)
+
+type (
+ _C_short int16
+ _C_int int32
+ _C_long int64
+ _C_long_long int64
+)
+
+type utmp struct {
+ Type int16
+ Pad_cgo_0 [2]byte
+ Pid int32
+ Line [32]int8
+ Id [4]int8
+ User [32]int8
+ Host [256]int8
+ Exit exit_status
+ Session int32
+ Tv _Ctype_struct___0
+ Addr_v6 [4]int32
+ X__glibc_reserved [20]int8
+}
+type exit_status struct {
+ Termination int16
+ Exit int16
+}
+type timeval struct {
+ Sec int64
+ Usec int64
+}
+
+type _Ctype_struct___0 struct {
+ Sec int32
+ Usec int32
+}
diff --git a/vendor/github.com/shirou/gopsutil/host/host_linux_arm.go b/vendor/github.com/shirou/gopsutil/host/host_linux_arm.go
new file mode 100644
index 0000000..e2cf448
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/host/host_linux_arm.go
@@ -0,0 +1,43 @@
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs types_linux.go | sed "s/uint8/int8/g"
+
+package host
+
+const (
+ sizeofPtr = 0x4
+ sizeofShort = 0x2
+ sizeofInt = 0x4
+ sizeofLong = 0x4
+ sizeofLongLong = 0x8
+ sizeOfUtmp = 0x180
+)
+
+type (
+ _C_short int16
+ _C_int int32
+ _C_long int32
+ _C_long_long int64
+)
+
+type utmp struct {
+ Type int16
+ Pad_cgo_0 [2]byte
+ Pid int32
+ Line [32]int8
+ Id [4]int8
+ User [32]int8
+ Host [256]int8
+ Exit exit_status
+ Session int32
+ Tv timeval
+ Addr_v6 [4]int32
+ X__glibc_reserved [20]int8
+}
+type exit_status struct {
+ Termination int16
+ Exit int16
+}
+type timeval struct {
+ Sec int32
+ Usec int32
+}
diff --git a/vendor/github.com/shirou/gopsutil/host/host_linux_arm64.go b/vendor/github.com/shirou/gopsutil/host/host_linux_arm64.go
new file mode 100644
index 0000000..37dbe5c
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/host/host_linux_arm64.go
@@ -0,0 +1,43 @@
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs types_linux.go
+
+package host
+
+const (
+ sizeofPtr = 0x8
+ sizeofShort = 0x2
+ sizeofInt = 0x4
+ sizeofLong = 0x8
+ sizeofLongLong = 0x8
+ sizeOfUtmp = 0x180
+)
+
+type (
+ _C_short int16
+ _C_int int32
+ _C_long int64
+ _C_long_long int64
+)
+
+type utmp struct {
+ Type int16
+ Pad_cgo_0 [2]byte
+ Pid int32
+ Line [32]int8
+ Id [4]int8
+ User [32]int8
+ Host [256]int8
+ Exit exit_status
+ Session int32
+ Tv timeval
+ Addr_v6 [4]int32
+ X__glibc_reserved [20]int8
+}
+type exit_status struct {
+ Termination int16
+ Exit int16
+}
+type timeval struct {
+ Sec int64
+ Usec int64
+}
diff --git a/vendor/github.com/shirou/gopsutil/host/host_linux_mips.go b/vendor/github.com/shirou/gopsutil/host/host_linux_mips.go
new file mode 100644
index 0000000..b0fca09
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/host/host_linux_mips.go
@@ -0,0 +1,43 @@
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs types_linux.go
+
+package host
+
+const (
+ sizeofPtr = 0x4
+ sizeofShort = 0x2
+ sizeofInt = 0x4
+ sizeofLong = 0x4
+ sizeofLongLong = 0x8
+ sizeOfUtmp = 0x180
+)
+
+type (
+ _C_short int16
+ _C_int int32
+ _C_long int32
+ _C_long_long int64
+)
+
+type utmp struct {
+ Type int16
+ Pad_cgo_0 [2]byte
+ Pid int32
+ Line [32]int8
+ Id [4]int8
+ User [32]int8
+ Host [256]int8
+ Exit exit_status
+ Session int32
+ Tv timeval
+ Addr_v6 [4]int32
+ X__unused [20]int8
+}
+type exit_status struct {
+ Termination int16
+ Exit int16
+}
+type timeval struct {
+ Sec int32
+ Usec int32
+}
diff --git a/vendor/github.com/shirou/gopsutil/host/host_linux_mips64.go b/vendor/github.com/shirou/gopsutil/host/host_linux_mips64.go
new file mode 100644
index 0000000..b0fca09
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/host/host_linux_mips64.go
@@ -0,0 +1,43 @@
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs types_linux.go
+
+package host
+
+const (
+ sizeofPtr = 0x4
+ sizeofShort = 0x2
+ sizeofInt = 0x4
+ sizeofLong = 0x4
+ sizeofLongLong = 0x8
+ sizeOfUtmp = 0x180
+)
+
+type (
+ _C_short int16
+ _C_int int32
+ _C_long int32
+ _C_long_long int64
+)
+
+type utmp struct {
+ Type int16
+ Pad_cgo_0 [2]byte
+ Pid int32
+ Line [32]int8
+ Id [4]int8
+ User [32]int8
+ Host [256]int8
+ Exit exit_status
+ Session int32
+ Tv timeval
+ Addr_v6 [4]int32
+ X__unused [20]int8
+}
+type exit_status struct {
+ Termination int16
+ Exit int16
+}
+type timeval struct {
+ Sec int32
+ Usec int32
+}
diff --git a/vendor/github.com/shirou/gopsutil/host/host_linux_mips64le.go b/vendor/github.com/shirou/gopsutil/host/host_linux_mips64le.go
new file mode 100644
index 0000000..b0fca09
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/host/host_linux_mips64le.go
@@ -0,0 +1,43 @@
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs types_linux.go
+
+package host
+
+const (
+ sizeofPtr = 0x4
+ sizeofShort = 0x2
+ sizeofInt = 0x4
+ sizeofLong = 0x4
+ sizeofLongLong = 0x8
+ sizeOfUtmp = 0x180
+)
+
+type (
+ _C_short int16
+ _C_int int32
+ _C_long int32
+ _C_long_long int64
+)
+
+type utmp struct {
+ Type int16
+ Pad_cgo_0 [2]byte
+ Pid int32
+ Line [32]int8
+ Id [4]int8
+ User [32]int8
+ Host [256]int8
+ Exit exit_status
+ Session int32
+ Tv timeval
+ Addr_v6 [4]int32
+ X__unused [20]int8
+}
+type exit_status struct {
+ Termination int16
+ Exit int16
+}
+type timeval struct {
+ Sec int32
+ Usec int32
+}
diff --git a/vendor/github.com/shirou/gopsutil/host/host_linux_mipsle.go b/vendor/github.com/shirou/gopsutil/host/host_linux_mipsle.go
new file mode 100644
index 0000000..b0fca09
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/host/host_linux_mipsle.go
@@ -0,0 +1,43 @@
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs types_linux.go
+
+package host
+
+const (
+ sizeofPtr = 0x4
+ sizeofShort = 0x2
+ sizeofInt = 0x4
+ sizeofLong = 0x4
+ sizeofLongLong = 0x8
+ sizeOfUtmp = 0x180
+)
+
+type (
+ _C_short int16
+ _C_int int32
+ _C_long int32
+ _C_long_long int64
+)
+
+type utmp struct {
+ Type int16
+ Pad_cgo_0 [2]byte
+ Pid int32
+ Line [32]int8
+ Id [4]int8
+ User [32]int8
+ Host [256]int8
+ Exit exit_status
+ Session int32
+ Tv timeval
+ Addr_v6 [4]int32
+ X__unused [20]int8
+}
+type exit_status struct {
+ Termination int16
+ Exit int16
+}
+type timeval struct {
+ Sec int32
+ Usec int32
+}
diff --git a/vendor/github.com/shirou/gopsutil/host/host_linux_ppc64le.go b/vendor/github.com/shirou/gopsutil/host/host_linux_ppc64le.go
new file mode 100644
index 0000000..d081a08
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/host/host_linux_ppc64le.go
@@ -0,0 +1,45 @@
+// +build linux
+// +build ppc64le
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs types_linux.go
+
+package host
+
+const (
+ sizeofPtr = 0x8
+ sizeofShort = 0x2
+ sizeofInt = 0x4
+ sizeofLong = 0x8
+ sizeofLongLong = 0x8
+ sizeOfUtmp = 0x180
+)
+
+type (
+ _C_short int16
+ _C_int int32
+ _C_long int64
+ _C_long_long int64
+)
+
+type utmp struct {
+ Type int16
+ Pad_cgo_0 [2]byte
+ Pid int32
+ Line [32]int8
+ Id [4]int8
+ User [32]int8
+ Host [256]int8
+ Exit exit_status
+ Session int32
+ Tv timeval
+ Addr_v6 [4]int32
+ X__glibc_reserved [20]int8
+}
+type exit_status struct {
+ Termination int16
+ Exit int16
+}
+type timeval struct {
+ Sec int64
+ Usec int64
+}
diff --git a/vendor/github.com/shirou/gopsutil/host/host_linux_s390x.go b/vendor/github.com/shirou/gopsutil/host/host_linux_s390x.go
new file mode 100644
index 0000000..083fbf9
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/host/host_linux_s390x.go
@@ -0,0 +1,45 @@
+// +build linux
+// +build s390x
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs types_linux.go
+
+package host
+
+const (
+ sizeofPtr = 0x8
+ sizeofShort = 0x2
+ sizeofInt = 0x4
+ sizeofLong = 0x8
+ sizeofLongLong = 0x8
+ sizeOfUtmp = 0x180
+)
+
+type (
+ _C_short int16
+ _C_int int32
+ _C_long int64
+ _C_long_long int64
+)
+
+type utmp struct {
+ Type int16
+ Pad_cgo_0 [2]byte
+ Pid int32
+ Line [32]int8
+ Id [4]int8
+ User [32]int8
+ Host [256]int8
+ Exit exit_status
+ Session int32
+ Tv timeval
+ Addr_v6 [4]int32
+ X__glibc_reserved [20]int8
+}
+type exit_status struct {
+ Termination int16
+ Exit int16
+}
+type timeval struct {
+ Sec int64
+ Usec int64
+}
diff --git a/vendor/github.com/shirou/gopsutil/host/host_openbsd.go b/vendor/github.com/shirou/gopsutil/host/host_openbsd.go
new file mode 100644
index 0000000..2ad64d7
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/host/host_openbsd.go
@@ -0,0 +1,195 @@
+// +build openbsd
+
+package host
+
+import (
+ "bytes"
+ "context"
+ "encoding/binary"
+ "io/ioutil"
+ "os"
+ "os/exec"
+ "runtime"
+ "strconv"
+ "strings"
+ "time"
+ "unsafe"
+
+ "github.com/shirou/gopsutil/internal/common"
+ "github.com/shirou/gopsutil/process"
+)
+
+const (
+ UTNameSize = 32 /* see MAXLOGNAME in */
+ UTLineSize = 8
+ UTHostSize = 16
+)
+
+func Info() (*InfoStat, error) {
+ return InfoWithContext(context.Background())
+}
+
+func InfoWithContext(ctx context.Context) (*InfoStat, error) {
+ ret := &InfoStat{
+ OS: runtime.GOOS,
+ PlatformFamily: "openbsd",
+ }
+
+ hostname, err := os.Hostname()
+ if err == nil {
+ ret.Hostname = hostname
+ }
+
+ platform, family, version, err := PlatformInformation()
+ if err == nil {
+ ret.Platform = platform
+ ret.PlatformFamily = family
+ ret.PlatformVersion = version
+ }
+ system, role, err := Virtualization()
+ if err == nil {
+ ret.VirtualizationSystem = system
+ ret.VirtualizationRole = role
+ }
+
+ procs, err := process.Pids()
+ if err == nil {
+ ret.Procs = uint64(len(procs))
+ }
+
+ boot, err := BootTime()
+ if err == nil {
+ ret.BootTime = boot
+ ret.Uptime = uptime(boot)
+ }
+
+ return ret, nil
+}
+
+func BootTime() (uint64, error) {
+ return BootTimeWithContext(context.Background())
+}
+
+func BootTimeWithContext(ctx context.Context) (uint64, error) {
+ val, err := common.DoSysctrl("kern.boottime")
+ if err != nil {
+ return 0, err
+ }
+
+ boottime, err := strconv.ParseUint(val[0], 10, 64)
+ if err != nil {
+ return 0, err
+ }
+
+ return boottime, nil
+}
+
+func uptime(boot uint64) uint64 {
+ return uint64(time.Now().Unix()) - boot
+}
+
+func Uptime() (uint64, error) {
+ return UptimeWithContext(context.Background())
+}
+
+func UptimeWithContext(ctx context.Context) (uint64, error) {
+ boot, err := BootTime()
+ if err != nil {
+ return 0, err
+ }
+ return uptime(boot), nil
+}
+
+func PlatformInformation() (string, string, string, error) {
+ return PlatformInformationWithContext(context.Background())
+}
+
+func PlatformInformationWithContext(ctx context.Context) (string, string, string, error) {
+ platform := ""
+ family := ""
+ version := ""
+ uname, err := exec.LookPath("uname")
+ if err != nil {
+ return "", "", "", err
+ }
+
+ out, err := invoke.CommandWithContext(ctx, uname, "-s")
+ if err == nil {
+ platform = strings.ToLower(strings.TrimSpace(string(out)))
+ }
+
+ out, err = invoke.CommandWithContext(ctx, uname, "-r")
+ if err == nil {
+ version = strings.ToLower(strings.TrimSpace(string(out)))
+ }
+
+ return platform, family, version, nil
+}
+
+func Virtualization() (string, string, error) {
+ return VirtualizationWithContext(context.Background())
+}
+
+func VirtualizationWithContext(ctx context.Context) (string, string, error) {
+ return "", "", common.ErrNotImplementedError
+}
+
+func Users() ([]UserStat, error) {
+ return UsersWithContext(context.Background())
+}
+
+func UsersWithContext(ctx context.Context) ([]UserStat, error) {
+ var ret []UserStat
+ utmpfile := "/var/run/utmp"
+ file, err := os.Open(utmpfile)
+ if err != nil {
+ return ret, err
+ }
+ defer file.Close()
+
+ buf, err := ioutil.ReadAll(file)
+ if err != nil {
+ return ret, err
+ }
+
+ u := Utmp{}
+ entrySize := int(unsafe.Sizeof(u))
+ count := len(buf) / entrySize
+
+ for i := 0; i < count; i++ {
+ b := buf[i*entrySize : i*entrySize+entrySize]
+ var u Utmp
+ br := bytes.NewReader(b)
+ err := binary.Read(br, binary.LittleEndian, &u)
+ if err != nil || u.Time == 0 {
+ continue
+ }
+ user := UserStat{
+ User: common.IntToString(u.Name[:]),
+ Terminal: common.IntToString(u.Line[:]),
+ Host: common.IntToString(u.Host[:]),
+ Started: int(u.Time),
+ }
+
+ ret = append(ret, user)
+ }
+
+ return ret, nil
+}
+
+func SensorsTemperatures() ([]TemperatureStat, error) {
+ return SensorsTemperaturesWithContext(context.Background())
+}
+
+func SensorsTemperaturesWithContext(ctx context.Context) ([]TemperatureStat, error) {
+ return []TemperatureStat{}, common.ErrNotImplementedError
+}
+
+func KernelVersion() (string, error) {
+ return KernelVersionWithContext(context.Background())
+}
+
+func KernelVersionWithContext(ctx context.Context) (string, error) {
+ _, _, version, err := PlatformInformation()
+ return version, err
+}
diff --git a/vendor/github.com/shirou/gopsutil/host/host_openbsd_amd64.go b/vendor/github.com/shirou/gopsutil/host/host_openbsd_amd64.go
new file mode 100644
index 0000000..afe0943
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/host/host_openbsd_amd64.go
@@ -0,0 +1,31 @@
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs types_openbsd.go
+
+package host
+
+const (
+ sizeofPtr = 0x8
+ sizeofShort = 0x2
+ sizeofInt = 0x4
+ sizeofLong = 0x8
+ sizeofLongLong = 0x8
+ sizeOfUtmp = 0x130
+)
+
+type (
+ _C_short int16
+ _C_int int32
+ _C_long int64
+ _C_long_long int64
+)
+
+type Utmp struct {
+ Line [8]int8
+ Name [32]int8
+ Host [256]int8
+ Time int64
+}
+type Timeval struct {
+ Sec int64
+ Usec int64
+}
diff --git a/vendor/github.com/shirou/gopsutil/host/host_solaris.go b/vendor/github.com/shirou/gopsutil/host/host_solaris.go
new file mode 100644
index 0000000..bb83bfc
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/host/host_solaris.go
@@ -0,0 +1,248 @@
+package host
+
+import (
+ "bufio"
+ "bytes"
+ "context"
+ "fmt"
+ "io/ioutil"
+ "os"
+ "os/exec"
+ "regexp"
+ "runtime"
+ "strconv"
+ "strings"
+ "time"
+
+ "github.com/shirou/gopsutil/internal/common"
+)
+
+func Info() (*InfoStat, error) {
+ return InfoWithContext(context.Background())
+}
+
+func InfoWithContext(ctx context.Context) (*InfoStat, error) {
+ result := &InfoStat{
+ OS: runtime.GOOS,
+ }
+
+ hostname, err := os.Hostname()
+ if err != nil {
+ return nil, err
+ }
+ result.Hostname = hostname
+
+ // Parse versions from output of `uname(1)`
+ uname, err := exec.LookPath("/usr/bin/uname")
+ if err != nil {
+ return nil, err
+ }
+
+ out, err := invoke.CommandWithContext(ctx, uname, "-srv")
+ if err != nil {
+ return nil, err
+ }
+
+ fields := strings.Fields(string(out))
+ if len(fields) >= 1 {
+ result.PlatformFamily = fields[0]
+ }
+ if len(fields) >= 2 {
+ result.KernelVersion = fields[1]
+ }
+ if len(fields) == 3 {
+ result.PlatformVersion = fields[2]
+ }
+
+ // Find distribution name from /etc/release
+ fh, err := os.Open("/etc/release")
+ if err != nil {
+ return nil, err
+ }
+ defer fh.Close()
+
+ sc := bufio.NewScanner(fh)
+ if sc.Scan() {
+ line := strings.TrimSpace(sc.Text())
+ switch {
+ case strings.HasPrefix(line, "SmartOS"):
+ result.Platform = "SmartOS"
+ case strings.HasPrefix(line, "OpenIndiana"):
+ result.Platform = "OpenIndiana"
+ case strings.HasPrefix(line, "OmniOS"):
+ result.Platform = "OmniOS"
+ case strings.HasPrefix(line, "Open Storage"):
+ result.Platform = "NexentaStor"
+ case strings.HasPrefix(line, "Solaris"):
+ result.Platform = "Solaris"
+ case strings.HasPrefix(line, "Oracle Solaris"):
+ result.Platform = "Solaris"
+ default:
+ result.Platform = strings.Fields(line)[0]
+ }
+ }
+
+ switch result.Platform {
+ case "SmartOS":
+ // If everything works, use the current zone ID as the HostID if present.
+ zonename, err := exec.LookPath("/usr/bin/zonename")
+ if err == nil {
+ out, err := invoke.CommandWithContext(ctx, zonename)
+ if err == nil {
+ sc := bufio.NewScanner(bytes.NewReader(out))
+ for sc.Scan() {
+ line := sc.Text()
+
+ // If we're in the global zone, rely on the hostname.
+ if line == "global" {
+ hostname, err := os.Hostname()
+ if err == nil {
+ result.HostID = hostname
+ }
+ } else {
+ result.HostID = strings.TrimSpace(line)
+ break
+ }
+ }
+ }
+ }
+ }
+
+ // If HostID is still empty, use hostid(1), which can lie to callers but at
+ // this point there are no hardware facilities available. This behavior
+ // matches that of other supported OSes.
+ if result.HostID == "" {
+ hostID, err := exec.LookPath("/usr/bin/hostid")
+ if err == nil {
+ out, err := invoke.CommandWithContext(ctx, hostID)
+ if err == nil {
+ sc := bufio.NewScanner(bytes.NewReader(out))
+ for sc.Scan() {
+ line := sc.Text()
+ result.HostID = strings.TrimSpace(line)
+ break
+ }
+ }
+ }
+ }
+
+ // Find the boot time and calculate uptime relative to it
+ bootTime, err := BootTime()
+ if err != nil {
+ return nil, err
+ }
+ result.BootTime = bootTime
+ result.Uptime = uptimeSince(bootTime)
+
+ // Count number of processes based on the number of entries in /proc
+ dirs, err := ioutil.ReadDir("/proc")
+ if err != nil {
+ return nil, err
+ }
+ result.Procs = uint64(len(dirs))
+
+ return result, nil
+}
+
+var kstatMatch = regexp.MustCompile(`([^\s]+)[\s]+([^\s]*)`)
+
+func BootTime() (uint64, error) {
+ return BootTimeWithContext(context.Background())
+}
+
+func BootTimeWithContext(ctx context.Context) (uint64, error) {
+ kstat, err := exec.LookPath("/usr/bin/kstat")
+ if err != nil {
+ return 0, err
+ }
+
+ out, err := invoke.CommandWithContext(ctx, kstat, "-p", "unix:0:system_misc:boot_time")
+ if err != nil {
+ return 0, err
+ }
+
+ kstats := kstatMatch.FindAllStringSubmatch(string(out), -1)
+ if len(kstats) != 1 {
+ return 0, fmt.Errorf("expected 1 kstat, found %d", len(kstats))
+ }
+
+ return strconv.ParseUint(kstats[0][2], 10, 64)
+}
+
+func Uptime() (uint64, error) {
+ return UptimeWithContext(context.Background())
+}
+
+func UptimeWithContext(ctx context.Context) (uint64, error) {
+ bootTime, err := BootTime()
+ if err != nil {
+ return 0, err
+ }
+ return uptimeSince(bootTime), nil
+}
+
+func uptimeSince(since uint64) uint64 {
+ return uint64(time.Now().Unix()) - since
+}
+
+func Users() ([]UserStat, error) {
+ return UsersWithContext(context.Background())
+}
+
+func UsersWithContext(ctx context.Context) ([]UserStat, error) {
+ return []UserStat{}, common.ErrNotImplementedError
+}
+
+func SensorsTemperatures() ([]TemperatureStat, error) {
+ return SensorsTemperaturesWithContext(context.Background())
+}
+
+func SensorsTemperaturesWithContext(ctx context.Context) ([]TemperatureStat, error) {
+ return []TemperatureStat{}, common.ErrNotImplementedError
+}
+
+func Virtualization() (string, string, error) {
+ return VirtualizationWithContext(context.Background())
+}
+
+func VirtualizationWithContext(ctx context.Context) (string, string, error) {
+ return "", "", common.ErrNotImplementedError
+}
+
+func KernelVersion() (string, error) {
+ return KernelVersionWithContext(context.Background())
+}
+
+func KernelVersionWithContext(ctx context.Context) (string, error) {
+ // Parse versions from output of `uname(1)`
+ uname, err := exec.LookPath("/usr/bin/uname")
+ if err != nil {
+ return "", err
+ }
+
+ out, err := invoke.CommandWithContext(ctx, uname, "-srv")
+ if err != nil {
+ return "", err
+ }
+
+ fields := strings.Fields(string(out))
+ if len(fields) >= 2 {
+ return fields[1], nil
+ }
+ return "", fmt.Errorf("could not get kernel version")
+}
+
+func PlatformInformation() (platform string, family string, version string, err error) {
+ return PlatformInformationWithContext(context.Background())
+}
+
+func PlatformInformationWithContext(ctx context.Context) (platform string, family string, version string, err error) {
+ /* This is not finished yet at all. Please contribute! */
+
+ version, err = KernelVersion()
+ if err != nil {
+ return "", "", "", err
+ }
+
+ return "solaris", "solaris", version, nil
+}
diff --git a/vendor/github.com/shirou/gopsutil/host/host_windows.go b/vendor/github.com/shirou/gopsutil/host/host_windows.go
new file mode 100644
index 0000000..d89e191
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/host/host_windows.go
@@ -0,0 +1,295 @@
+// +build windows
+
+package host
+
+import (
+ "context"
+ "fmt"
+ "math"
+ "os"
+ "runtime"
+ "strings"
+ "sync/atomic"
+ "syscall"
+ "time"
+ "unsafe"
+
+ "github.com/StackExchange/wmi"
+ "github.com/shirou/gopsutil/internal/common"
+ process "github.com/shirou/gopsutil/process"
+ "golang.org/x/sys/windows"
+)
+
+var (
+ procGetSystemTimeAsFileTime = common.Modkernel32.NewProc("GetSystemTimeAsFileTime")
+ procGetTickCount32 = common.Modkernel32.NewProc("GetTickCount")
+ procGetTickCount64 = common.Modkernel32.NewProc("GetTickCount64")
+ procRtlGetVersion = common.ModNt.NewProc("RtlGetVersion")
+)
+
+// https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/content/wdm/ns-wdm-_osversioninfoexw
+type osVersionInfoExW struct {
+ dwOSVersionInfoSize uint32
+ dwMajorVersion uint32
+ dwMinorVersion uint32
+ dwBuildNumber uint32
+ dwPlatformId uint32
+ szCSDVersion [128]uint16
+ wServicePackMajor uint16
+ wServicePackMinor uint16
+ wSuiteMask uint16
+ wProductType uint8
+ wReserved uint8
+}
+
+type msAcpi_ThermalZoneTemperature struct {
+ Active bool
+ CriticalTripPoint uint32
+ CurrentTemperature uint32
+ InstanceName string
+}
+
+func Info() (*InfoStat, error) {
+ return InfoWithContext(context.Background())
+}
+
+func InfoWithContext(ctx context.Context) (*InfoStat, error) {
+ ret := &InfoStat{
+ OS: runtime.GOOS,
+ }
+
+ {
+ hostname, err := os.Hostname()
+ if err == nil {
+ ret.Hostname = hostname
+ }
+ }
+
+ {
+ platform, family, version, err := PlatformInformationWithContext(ctx)
+ if err == nil {
+ ret.Platform = platform
+ ret.PlatformFamily = family
+ ret.PlatformVersion = version
+ } else {
+ return ret, err
+ }
+ }
+
+ {
+ boot, err := BootTime()
+ if err == nil {
+ ret.BootTime = boot
+ ret.Uptime, _ = Uptime()
+ }
+ }
+
+ {
+ hostID, err := getMachineGuid()
+ if err == nil {
+ ret.HostID = strings.ToLower(hostID)
+ }
+ }
+
+ {
+ procs, err := process.Pids()
+ if err == nil {
+ ret.Procs = uint64(len(procs))
+ }
+ }
+
+ return ret, nil
+}
+
+func getMachineGuid() (string, error) {
+ // there has been reports of issues on 32bit using golang.org/x/sys/windows/registry, see https://github.com/shirou/gopsutil/pull/312#issuecomment-277422612
+ // for rationale of using windows.RegOpenKeyEx/RegQueryValueEx instead of registry.OpenKey/GetStringValue
+ var h windows.Handle
+ err := windows.RegOpenKeyEx(windows.HKEY_LOCAL_MACHINE, windows.StringToUTF16Ptr(`SOFTWARE\Microsoft\Cryptography`), 0, windows.KEY_READ|windows.KEY_WOW64_64KEY, &h)
+ if err != nil {
+ return "", err
+ }
+ defer windows.RegCloseKey(h)
+
+ const windowsRegBufLen = 74 // len(`{`) + len(`abcdefgh-1234-456789012-123345456671` * 2) + len(`}`) // 2 == bytes/UTF16
+ const uuidLen = 36
+
+ var regBuf [windowsRegBufLen]uint16
+ bufLen := uint32(windowsRegBufLen)
+ var valType uint32
+ err = windows.RegQueryValueEx(h, windows.StringToUTF16Ptr(`MachineGuid`), nil, &valType, (*byte)(unsafe.Pointer(®Buf[0])), &bufLen)
+ if err != nil {
+ return "", err
+ }
+
+ hostID := windows.UTF16ToString(regBuf[:])
+ hostIDLen := len(hostID)
+ if hostIDLen != uuidLen {
+ return "", fmt.Errorf("HostID incorrect: %q\n", hostID)
+ }
+
+ return hostID, nil
+}
+
+func Uptime() (uint64, error) {
+ return UptimeWithContext(context.Background())
+}
+
+func UptimeWithContext(ctx context.Context) (uint64, error) {
+ procGetTickCount := procGetTickCount64
+ err := procGetTickCount64.Find()
+ if err != nil {
+ procGetTickCount = procGetTickCount32 // handle WinXP, but keep in mind that "the time will wrap around to zero if the system is run continuously for 49.7 days." from MSDN
+ }
+ r1, _, lastErr := syscall.Syscall(procGetTickCount.Addr(), 0, 0, 0, 0)
+ if lastErr != 0 {
+ return 0, lastErr
+ }
+ return uint64((time.Duration(r1) * time.Millisecond).Seconds()), nil
+}
+
+func bootTimeFromUptime(up uint64) uint64 {
+ return uint64(time.Now().Unix()) - up
+}
+
+// cachedBootTime must be accessed via atomic.Load/StoreUint64
+var cachedBootTime uint64
+
+func BootTime() (uint64, error) {
+ return BootTimeWithContext(context.Background())
+}
+
+func BootTimeWithContext(ctx context.Context) (uint64, error) {
+ t := atomic.LoadUint64(&cachedBootTime)
+ if t != 0 {
+ return t, nil
+ }
+ up, err := Uptime()
+ if err != nil {
+ return 0, err
+ }
+ t = bootTimeFromUptime(up)
+ atomic.StoreUint64(&cachedBootTime, t)
+ return t, nil
+}
+
+func PlatformInformation() (platform string, family string, version string, err error) {
+ return PlatformInformationWithContext(context.Background())
+}
+
+func PlatformInformationWithContext(ctx context.Context) (platform string, family string, version string, err error) {
+ // GetVersionEx lies on Windows 8.1 and returns as Windows 8 if we don't declare compatibility in manifest
+ // RtlGetVersion bypasses this lying layer and returns the true Windows version
+ // https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/content/wdm/nf-wdm-rtlgetversion
+ // https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/content/wdm/ns-wdm-_osversioninfoexw
+ var osInfo osVersionInfoExW
+ osInfo.dwOSVersionInfoSize = uint32(unsafe.Sizeof(osInfo))
+ ret, _, err := procRtlGetVersion.Call(uintptr(unsafe.Pointer(&osInfo)))
+ if ret != 0 {
+ return
+ }
+
+ // Platform
+ var h windows.Handle // like getMachineGuid(), we query the registry using the raw windows.RegOpenKeyEx/RegQueryValueEx
+ err = windows.RegOpenKeyEx(windows.HKEY_LOCAL_MACHINE, windows.StringToUTF16Ptr(`SOFTWARE\Microsoft\Windows NT\CurrentVersion`), 0, windows.KEY_READ|windows.KEY_WOW64_64KEY, &h)
+ if err != nil {
+ return
+ }
+ defer windows.RegCloseKey(h)
+ var bufLen uint32
+ var valType uint32
+ err = windows.RegQueryValueEx(h, windows.StringToUTF16Ptr(`ProductName`), nil, &valType, nil, &bufLen)
+ if err != nil {
+ return
+ }
+ regBuf := make([]uint16, bufLen/2+1)
+ err = windows.RegQueryValueEx(h, windows.StringToUTF16Ptr(`ProductName`), nil, &valType, (*byte)(unsafe.Pointer(®Buf[0])), &bufLen)
+ if err != nil {
+ return
+ }
+ platform = windows.UTF16ToString(regBuf[:])
+ if !strings.HasPrefix(platform, "Microsoft") {
+ platform = "Microsoft " + platform
+ }
+ err = windows.RegQueryValueEx(h, windows.StringToUTF16Ptr(`CSDVersion`), nil, &valType, nil, &bufLen) // append Service Pack number, only on success
+ if err == nil { // don't return an error if only the Service Pack retrieval fails
+ regBuf = make([]uint16, bufLen/2+1)
+ err = windows.RegQueryValueEx(h, windows.StringToUTF16Ptr(`CSDVersion`), nil, &valType, (*byte)(unsafe.Pointer(®Buf[0])), &bufLen)
+ if err == nil {
+ platform += " " + windows.UTF16ToString(regBuf[:])
+ }
+ }
+
+ // PlatformFamily
+ switch osInfo.wProductType {
+ case 1:
+ family = "Standalone Workstation"
+ case 2:
+ family = "Server (Domain Controller)"
+ case 3:
+ family = "Server"
+ }
+
+ // Platform Version
+ version = fmt.Sprintf("%d.%d.%d Build %d", osInfo.dwMajorVersion, osInfo.dwMinorVersion, osInfo.dwBuildNumber, osInfo.dwBuildNumber)
+
+ return platform, family, version, nil
+}
+
+func Users() ([]UserStat, error) {
+ return UsersWithContext(context.Background())
+}
+
+func UsersWithContext(ctx context.Context) ([]UserStat, error) {
+ var ret []UserStat
+
+ return ret, nil
+}
+
+func SensorsTemperatures() ([]TemperatureStat, error) {
+ return SensorsTemperaturesWithContext(context.Background())
+}
+
+func SensorsTemperaturesWithContext(ctx context.Context) ([]TemperatureStat, error) {
+ var ret []TemperatureStat
+ var dst []msAcpi_ThermalZoneTemperature
+ q := wmi.CreateQuery(&dst, "")
+ if err := common.WMIQueryWithContext(ctx, q, &dst, nil, "root/wmi"); err != nil {
+ return ret, err
+ }
+
+ for _, v := range dst {
+ ts := TemperatureStat{
+ SensorKey: v.InstanceName,
+ Temperature: kelvinToCelsius(v.CurrentTemperature, 2),
+ }
+ ret = append(ret, ts)
+ }
+
+ return ret, nil
+}
+
+func kelvinToCelsius(temp uint32, n int) float64 {
+ // wmi return temperature Kelvin * 10, so need to divide the result by 10,
+ // and then minus 273.15 to get °Celsius.
+ t := float64(temp/10) - 273.15
+ n10 := math.Pow10(n)
+ return math.Trunc((t+0.5/n10)*n10) / n10
+}
+
+func Virtualization() (string, string, error) {
+ return VirtualizationWithContext(context.Background())
+}
+
+func VirtualizationWithContext(ctx context.Context) (string, string, error) {
+ return "", "", common.ErrNotImplementedError
+}
+
+func KernelVersion() (string, error) {
+ return KernelVersionWithContext(context.Background())
+}
+
+func KernelVersionWithContext(ctx context.Context) (string, error) {
+ _, _, version, err := PlatformInformation()
+ return version, err
+}
diff --git a/vendor/github.com/shirou/gopsutil/internal/common/binary.go b/vendor/github.com/shirou/gopsutil/internal/common/binary.go
new file mode 100644
index 0000000..9b5dc55
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/internal/common/binary.go
@@ -0,0 +1,634 @@
+package common
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package binary implements simple translation between numbers and byte
+// sequences and encoding and decoding of varints.
+//
+// Numbers are translated by reading and writing fixed-size values.
+// A fixed-size value is either a fixed-size arithmetic
+// type (int8, uint8, int16, float32, complex64, ...)
+// or an array or struct containing only fixed-size values.
+//
+// The varint functions encode and decode single integer values using
+// a variable-length encoding; smaller values require fewer bytes.
+// For a specification, see
+// http://code.google.com/apis/protocolbuffers/docs/encoding.html.
+//
+// This package favors simplicity over efficiency. Clients that require
+// high-performance serialization, especially for large data structures,
+// should look at more advanced solutions such as the encoding/gob
+// package or protocol buffers.
+import (
+ "errors"
+ "io"
+ "math"
+ "reflect"
+)
+
+// A ByteOrder specifies how to convert byte sequences into
+// 16-, 32-, or 64-bit unsigned integers.
+type ByteOrder interface {
+ Uint16([]byte) uint16
+ Uint32([]byte) uint32
+ Uint64([]byte) uint64
+ PutUint16([]byte, uint16)
+ PutUint32([]byte, uint32)
+ PutUint64([]byte, uint64)
+ String() string
+}
+
+// LittleEndian is the little-endian implementation of ByteOrder.
+var LittleEndian littleEndian
+
+// BigEndian is the big-endian implementation of ByteOrder.
+var BigEndian bigEndian
+
+type littleEndian struct{}
+
+func (littleEndian) Uint16(b []byte) uint16 { return uint16(b[0]) | uint16(b[1])<<8 }
+
+func (littleEndian) PutUint16(b []byte, v uint16) {
+ b[0] = byte(v)
+ b[1] = byte(v >> 8)
+}
+
+func (littleEndian) Uint32(b []byte) uint32 {
+ return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24
+}
+
+func (littleEndian) PutUint32(b []byte, v uint32) {
+ b[0] = byte(v)
+ b[1] = byte(v >> 8)
+ b[2] = byte(v >> 16)
+ b[3] = byte(v >> 24)
+}
+
+func (littleEndian) Uint64(b []byte) uint64 {
+ return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 |
+ uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56
+}
+
+func (littleEndian) PutUint64(b []byte, v uint64) {
+ b[0] = byte(v)
+ b[1] = byte(v >> 8)
+ b[2] = byte(v >> 16)
+ b[3] = byte(v >> 24)
+ b[4] = byte(v >> 32)
+ b[5] = byte(v >> 40)
+ b[6] = byte(v >> 48)
+ b[7] = byte(v >> 56)
+}
+
+func (littleEndian) String() string { return "LittleEndian" }
+
+func (littleEndian) GoString() string { return "binary.LittleEndian" }
+
+type bigEndian struct{}
+
+func (bigEndian) Uint16(b []byte) uint16 { return uint16(b[1]) | uint16(b[0])<<8 }
+
+func (bigEndian) PutUint16(b []byte, v uint16) {
+ b[0] = byte(v >> 8)
+ b[1] = byte(v)
+}
+
+func (bigEndian) Uint32(b []byte) uint32 {
+ return uint32(b[3]) | uint32(b[2])<<8 | uint32(b[1])<<16 | uint32(b[0])<<24
+}
+
+func (bigEndian) PutUint32(b []byte, v uint32) {
+ b[0] = byte(v >> 24)
+ b[1] = byte(v >> 16)
+ b[2] = byte(v >> 8)
+ b[3] = byte(v)
+}
+
+func (bigEndian) Uint64(b []byte) uint64 {
+ return uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 |
+ uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56
+}
+
+func (bigEndian) PutUint64(b []byte, v uint64) {
+ b[0] = byte(v >> 56)
+ b[1] = byte(v >> 48)
+ b[2] = byte(v >> 40)
+ b[3] = byte(v >> 32)
+ b[4] = byte(v >> 24)
+ b[5] = byte(v >> 16)
+ b[6] = byte(v >> 8)
+ b[7] = byte(v)
+}
+
+func (bigEndian) String() string { return "BigEndian" }
+
+func (bigEndian) GoString() string { return "binary.BigEndian" }
+
+// Read reads structured binary data from r into data.
+// Data must be a pointer to a fixed-size value or a slice
+// of fixed-size values.
+// Bytes read from r are decoded using the specified byte order
+// and written to successive fields of the data.
+// When reading into structs, the field data for fields with
+// blank (_) field names is skipped; i.e., blank field names
+// may be used for padding.
+// When reading into a struct, all non-blank fields must be exported.
+func Read(r io.Reader, order ByteOrder, data interface{}) error {
+ // Fast path for basic types and slices.
+ if n := intDataSize(data); n != 0 {
+ var b [8]byte
+ var bs []byte
+ if n > len(b) {
+ bs = make([]byte, n)
+ } else {
+ bs = b[:n]
+ }
+ if _, err := io.ReadFull(r, bs); err != nil {
+ return err
+ }
+ switch data := data.(type) {
+ case *int8:
+ *data = int8(b[0])
+ case *uint8:
+ *data = b[0]
+ case *int16:
+ *data = int16(order.Uint16(bs))
+ case *uint16:
+ *data = order.Uint16(bs)
+ case *int32:
+ *data = int32(order.Uint32(bs))
+ case *uint32:
+ *data = order.Uint32(bs)
+ case *int64:
+ *data = int64(order.Uint64(bs))
+ case *uint64:
+ *data = order.Uint64(bs)
+ case []int8:
+ for i, x := range bs { // Easier to loop over the input for 8-bit values.
+ data[i] = int8(x)
+ }
+ case []uint8:
+ copy(data, bs)
+ case []int16:
+ for i := range data {
+ data[i] = int16(order.Uint16(bs[2*i:]))
+ }
+ case []uint16:
+ for i := range data {
+ data[i] = order.Uint16(bs[2*i:])
+ }
+ case []int32:
+ for i := range data {
+ data[i] = int32(order.Uint32(bs[4*i:]))
+ }
+ case []uint32:
+ for i := range data {
+ data[i] = order.Uint32(bs[4*i:])
+ }
+ case []int64:
+ for i := range data {
+ data[i] = int64(order.Uint64(bs[8*i:]))
+ }
+ case []uint64:
+ for i := range data {
+ data[i] = order.Uint64(bs[8*i:])
+ }
+ }
+ return nil
+ }
+
+ // Fallback to reflect-based decoding.
+ v := reflect.ValueOf(data)
+ size := -1
+ switch v.Kind() {
+ case reflect.Ptr:
+ v = v.Elem()
+ size = dataSize(v)
+ case reflect.Slice:
+ size = dataSize(v)
+ }
+ if size < 0 {
+ return errors.New("binary.Read: invalid type " + reflect.TypeOf(data).String())
+ }
+ d := &decoder{order: order, buf: make([]byte, size)}
+ if _, err := io.ReadFull(r, d.buf); err != nil {
+ return err
+ }
+ d.value(v)
+ return nil
+}
+
+// Write writes the binary representation of data into w.
+// Data must be a fixed-size value or a slice of fixed-size
+// values, or a pointer to such data.
+// Bytes written to w are encoded using the specified byte order
+// and read from successive fields of the data.
+// When writing structs, zero values are written for fields
+// with blank (_) field names.
+func Write(w io.Writer, order ByteOrder, data interface{}) error {
+ // Fast path for basic types and slices.
+ if n := intDataSize(data); n != 0 {
+ var b [8]byte
+ var bs []byte
+ if n > len(b) {
+ bs = make([]byte, n)
+ } else {
+ bs = b[:n]
+ }
+ switch v := data.(type) {
+ case *int8:
+ bs = b[:1]
+ b[0] = byte(*v)
+ case int8:
+ bs = b[:1]
+ b[0] = byte(v)
+ case []int8:
+ for i, x := range v {
+ bs[i] = byte(x)
+ }
+ case *uint8:
+ bs = b[:1]
+ b[0] = *v
+ case uint8:
+ bs = b[:1]
+ b[0] = byte(v)
+ case []uint8:
+ bs = v
+ case *int16:
+ bs = b[:2]
+ order.PutUint16(bs, uint16(*v))
+ case int16:
+ bs = b[:2]
+ order.PutUint16(bs, uint16(v))
+ case []int16:
+ for i, x := range v {
+ order.PutUint16(bs[2*i:], uint16(x))
+ }
+ case *uint16:
+ bs = b[:2]
+ order.PutUint16(bs, *v)
+ case uint16:
+ bs = b[:2]
+ order.PutUint16(bs, v)
+ case []uint16:
+ for i, x := range v {
+ order.PutUint16(bs[2*i:], x)
+ }
+ case *int32:
+ bs = b[:4]
+ order.PutUint32(bs, uint32(*v))
+ case int32:
+ bs = b[:4]
+ order.PutUint32(bs, uint32(v))
+ case []int32:
+ for i, x := range v {
+ order.PutUint32(bs[4*i:], uint32(x))
+ }
+ case *uint32:
+ bs = b[:4]
+ order.PutUint32(bs, *v)
+ case uint32:
+ bs = b[:4]
+ order.PutUint32(bs, v)
+ case []uint32:
+ for i, x := range v {
+ order.PutUint32(bs[4*i:], x)
+ }
+ case *int64:
+ bs = b[:8]
+ order.PutUint64(bs, uint64(*v))
+ case int64:
+ bs = b[:8]
+ order.PutUint64(bs, uint64(v))
+ case []int64:
+ for i, x := range v {
+ order.PutUint64(bs[8*i:], uint64(x))
+ }
+ case *uint64:
+ bs = b[:8]
+ order.PutUint64(bs, *v)
+ case uint64:
+ bs = b[:8]
+ order.PutUint64(bs, v)
+ case []uint64:
+ for i, x := range v {
+ order.PutUint64(bs[8*i:], x)
+ }
+ }
+ _, err := w.Write(bs)
+ return err
+ }
+
+ // Fallback to reflect-based encoding.
+ v := reflect.Indirect(reflect.ValueOf(data))
+ size := dataSize(v)
+ if size < 0 {
+ return errors.New("binary.Write: invalid type " + reflect.TypeOf(data).String())
+ }
+ buf := make([]byte, size)
+ e := &encoder{order: order, buf: buf}
+ e.value(v)
+ _, err := w.Write(buf)
+ return err
+}
+
+// Size returns how many bytes Write would generate to encode the value v, which
+// must be a fixed-size value or a slice of fixed-size values, or a pointer to such data.
+// If v is neither of these, Size returns -1.
+func Size(v interface{}) int {
+ return dataSize(reflect.Indirect(reflect.ValueOf(v)))
+}
+
+// dataSize returns the number of bytes the actual data represented by v occupies in memory.
+// For compound structures, it sums the sizes of the elements. Thus, for instance, for a slice
+// it returns the length of the slice times the element size and does not count the memory
+// occupied by the header. If the type of v is not acceptable, dataSize returns -1.
+func dataSize(v reflect.Value) int {
+ if v.Kind() == reflect.Slice {
+ if s := sizeof(v.Type().Elem()); s >= 0 {
+ return s * v.Len()
+ }
+ return -1
+ }
+ return sizeof(v.Type())
+}
+
+// sizeof returns the size >= 0 of variables for the given type or -1 if the type is not acceptable.
+func sizeof(t reflect.Type) int {
+ switch t.Kind() {
+ case reflect.Array:
+ if s := sizeof(t.Elem()); s >= 0 {
+ return s * t.Len()
+ }
+
+ case reflect.Struct:
+ sum := 0
+ for i, n := 0, t.NumField(); i < n; i++ {
+ s := sizeof(t.Field(i).Type)
+ if s < 0 {
+ return -1
+ }
+ sum += s
+ }
+ return sum
+
+ case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
+ reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
+ reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128, reflect.Ptr:
+ return int(t.Size())
+ }
+
+ return -1
+}
+
+type coder struct {
+ order ByteOrder
+ buf []byte
+}
+
+type decoder coder
+type encoder coder
+
+func (d *decoder) uint8() uint8 {
+ x := d.buf[0]
+ d.buf = d.buf[1:]
+ return x
+}
+
+func (e *encoder) uint8(x uint8) {
+ e.buf[0] = x
+ e.buf = e.buf[1:]
+}
+
+func (d *decoder) uint16() uint16 {
+ x := d.order.Uint16(d.buf[0:2])
+ d.buf = d.buf[2:]
+ return x
+}
+
+func (e *encoder) uint16(x uint16) {
+ e.order.PutUint16(e.buf[0:2], x)
+ e.buf = e.buf[2:]
+}
+
+func (d *decoder) uint32() uint32 {
+ x := d.order.Uint32(d.buf[0:4])
+ d.buf = d.buf[4:]
+ return x
+}
+
+func (e *encoder) uint32(x uint32) {
+ e.order.PutUint32(e.buf[0:4], x)
+ e.buf = e.buf[4:]
+}
+
+func (d *decoder) uint64() uint64 {
+ x := d.order.Uint64(d.buf[0:8])
+ d.buf = d.buf[8:]
+ return x
+}
+
+func (e *encoder) uint64(x uint64) {
+ e.order.PutUint64(e.buf[0:8], x)
+ e.buf = e.buf[8:]
+}
+
+func (d *decoder) int8() int8 { return int8(d.uint8()) }
+
+func (e *encoder) int8(x int8) { e.uint8(uint8(x)) }
+
+func (d *decoder) int16() int16 { return int16(d.uint16()) }
+
+func (e *encoder) int16(x int16) { e.uint16(uint16(x)) }
+
+func (d *decoder) int32() int32 { return int32(d.uint32()) }
+
+func (e *encoder) int32(x int32) { e.uint32(uint32(x)) }
+
+func (d *decoder) int64() int64 { return int64(d.uint64()) }
+
+func (e *encoder) int64(x int64) { e.uint64(uint64(x)) }
+
+func (d *decoder) value(v reflect.Value) {
+ switch v.Kind() {
+ case reflect.Array:
+ l := v.Len()
+ for i := 0; i < l; i++ {
+ d.value(v.Index(i))
+ }
+
+ case reflect.Struct:
+ t := v.Type()
+ l := v.NumField()
+ for i := 0; i < l; i++ {
+ // Note: Calling v.CanSet() below is an optimization.
+ // It would be sufficient to check the field name,
+ // but creating the StructField info for each field is
+ // costly (run "go test -bench=ReadStruct" and compare
+ // results when making changes to this code).
+ if v := v.Field(i); v.CanSet() || t.Field(i).Name != "_" {
+ d.value(v)
+ } else {
+ d.skip(v)
+ }
+ }
+
+ case reflect.Slice:
+ l := v.Len()
+ for i := 0; i < l; i++ {
+ d.value(v.Index(i))
+ }
+
+ case reflect.Int8:
+ v.SetInt(int64(d.int8()))
+ case reflect.Int16:
+ v.SetInt(int64(d.int16()))
+ case reflect.Int32:
+ v.SetInt(int64(d.int32()))
+ case reflect.Int64:
+ v.SetInt(d.int64())
+
+ case reflect.Uint8:
+ v.SetUint(uint64(d.uint8()))
+ case reflect.Uint16:
+ v.SetUint(uint64(d.uint16()))
+ case reflect.Uint32:
+ v.SetUint(uint64(d.uint32()))
+ case reflect.Uint64:
+ v.SetUint(d.uint64())
+
+ case reflect.Float32:
+ v.SetFloat(float64(math.Float32frombits(d.uint32())))
+ case reflect.Float64:
+ v.SetFloat(math.Float64frombits(d.uint64()))
+
+ case reflect.Complex64:
+ v.SetComplex(complex(
+ float64(math.Float32frombits(d.uint32())),
+ float64(math.Float32frombits(d.uint32())),
+ ))
+ case reflect.Complex128:
+ v.SetComplex(complex(
+ math.Float64frombits(d.uint64()),
+ math.Float64frombits(d.uint64()),
+ ))
+ }
+}
+
+func (e *encoder) value(v reflect.Value) {
+ switch v.Kind() {
+ case reflect.Array:
+ l := v.Len()
+ for i := 0; i < l; i++ {
+ e.value(v.Index(i))
+ }
+
+ case reflect.Struct:
+ t := v.Type()
+ l := v.NumField()
+ for i := 0; i < l; i++ {
+ // see comment for corresponding code in decoder.value()
+ if v := v.Field(i); v.CanSet() || t.Field(i).Name != "_" {
+ e.value(v)
+ } else {
+ e.skip(v)
+ }
+ }
+
+ case reflect.Slice:
+ l := v.Len()
+ for i := 0; i < l; i++ {
+ e.value(v.Index(i))
+ }
+
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ switch v.Type().Kind() {
+ case reflect.Int8:
+ e.int8(int8(v.Int()))
+ case reflect.Int16:
+ e.int16(int16(v.Int()))
+ case reflect.Int32:
+ e.int32(int32(v.Int()))
+ case reflect.Int64:
+ e.int64(v.Int())
+ }
+
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+ switch v.Type().Kind() {
+ case reflect.Uint8:
+ e.uint8(uint8(v.Uint()))
+ case reflect.Uint16:
+ e.uint16(uint16(v.Uint()))
+ case reflect.Uint32:
+ e.uint32(uint32(v.Uint()))
+ case reflect.Uint64:
+ e.uint64(v.Uint())
+ }
+
+ case reflect.Float32, reflect.Float64:
+ switch v.Type().Kind() {
+ case reflect.Float32:
+ e.uint32(math.Float32bits(float32(v.Float())))
+ case reflect.Float64:
+ e.uint64(math.Float64bits(v.Float()))
+ }
+
+ case reflect.Complex64, reflect.Complex128:
+ switch v.Type().Kind() {
+ case reflect.Complex64:
+ x := v.Complex()
+ e.uint32(math.Float32bits(float32(real(x))))
+ e.uint32(math.Float32bits(float32(imag(x))))
+ case reflect.Complex128:
+ x := v.Complex()
+ e.uint64(math.Float64bits(real(x)))
+ e.uint64(math.Float64bits(imag(x)))
+ }
+ }
+}
+
+func (d *decoder) skip(v reflect.Value) {
+ d.buf = d.buf[dataSize(v):]
+}
+
+func (e *encoder) skip(v reflect.Value) {
+ n := dataSize(v)
+ for i := range e.buf[0:n] {
+ e.buf[i] = 0
+ }
+ e.buf = e.buf[n:]
+}
+
+// intDataSize returns the size of the data required to represent the data when encoded.
+// It returns zero if the type cannot be implemented by the fast path in Read or Write.
+func intDataSize(data interface{}) int {
+ switch data := data.(type) {
+ case int8, *int8, *uint8:
+ return 1
+ case []int8:
+ return len(data)
+ case []uint8:
+ return len(data)
+ case int16, *int16, *uint16:
+ return 2
+ case []int16:
+ return 2 * len(data)
+ case []uint16:
+ return 2 * len(data)
+ case int32, *int32, *uint32:
+ return 4
+ case []int32:
+ return 4 * len(data)
+ case []uint32:
+ return 4 * len(data)
+ case int64, *int64, *uint64:
+ return 8
+ case []int64:
+ return 8 * len(data)
+ case []uint64:
+ return 8 * len(data)
+ }
+ return 0
+}
diff --git a/vendor/github.com/shirou/gopsutil/internal/common/common.go b/vendor/github.com/shirou/gopsutil/internal/common/common.go
new file mode 100644
index 0000000..71c2257
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/internal/common/common.go
@@ -0,0 +1,392 @@
+package common
+
+//
+// gopsutil is a port of psutil(http://pythonhosted.org/psutil/).
+// This covers these architectures.
+// - linux (amd64, arm)
+// - freebsd (amd64)
+// - windows (amd64)
+import (
+ "bufio"
+ "bytes"
+ "context"
+ "errors"
+ "fmt"
+ "io/ioutil"
+ "net/url"
+ "os"
+ "os/exec"
+ "path"
+ "path/filepath"
+ "reflect"
+ "runtime"
+ "strconv"
+ "strings"
+ "time"
+)
+
+var (
+ Timeout = 3 * time.Second
+ ErrTimeout = errors.New("command timed out")
+)
+
+type Invoker interface {
+ Command(string, ...string) ([]byte, error)
+ CommandWithContext(context.Context, string, ...string) ([]byte, error)
+}
+
+type Invoke struct{}
+
+func (i Invoke) Command(name string, arg ...string) ([]byte, error) {
+ ctx, cancel := context.WithTimeout(context.Background(), Timeout)
+ defer cancel()
+ return i.CommandWithContext(ctx, name, arg...)
+}
+
+func (i Invoke) CommandWithContext(ctx context.Context, name string, arg ...string) ([]byte, error) {
+ cmd := exec.CommandContext(ctx, name, arg...)
+
+ var buf bytes.Buffer
+ cmd.Stdout = &buf
+ cmd.Stderr = &buf
+
+ if err := cmd.Start(); err != nil {
+ return buf.Bytes(), err
+ }
+
+ if err := cmd.Wait(); err != nil {
+ return buf.Bytes(), err
+ }
+
+ return buf.Bytes(), nil
+}
+
+type FakeInvoke struct {
+ Suffix string // Suffix species expected file name suffix such as "fail"
+ Error error // If Error specfied, return the error.
+}
+
+// Command in FakeInvoke returns from expected file if exists.
+func (i FakeInvoke) Command(name string, arg ...string) ([]byte, error) {
+ if i.Error != nil {
+ return []byte{}, i.Error
+ }
+
+ arch := runtime.GOOS
+
+ commandName := filepath.Base(name)
+
+ fname := strings.Join(append([]string{commandName}, arg...), "")
+ fname = url.QueryEscape(fname)
+ fpath := path.Join("testdata", arch, fname)
+ if i.Suffix != "" {
+ fpath += "_" + i.Suffix
+ }
+ if PathExists(fpath) {
+ return ioutil.ReadFile(fpath)
+ }
+ return []byte{}, fmt.Errorf("could not find testdata: %s", fpath)
+}
+
+func (i FakeInvoke) CommandWithContext(ctx context.Context, name string, arg ...string) ([]byte, error) {
+ return i.Command(name, arg...)
+}
+
+var ErrNotImplementedError = errors.New("not implemented yet")
+
+// ReadLines reads contents from a file and splits them by new lines.
+// A convenience wrapper to ReadLinesOffsetN(filename, 0, -1).
+func ReadLines(filename string) ([]string, error) {
+ return ReadLinesOffsetN(filename, 0, -1)
+}
+
+// ReadLines reads contents from file and splits them by new line.
+// The offset tells at which line number to start.
+// The count determines the number of lines to read (starting from offset):
+// n >= 0: at most n lines
+// n < 0: whole file
+func ReadLinesOffsetN(filename string, offset uint, n int) ([]string, error) {
+ f, err := os.Open(filename)
+ if err != nil {
+ return []string{""}, err
+ }
+ defer f.Close()
+
+ var ret []string
+
+ r := bufio.NewReader(f)
+ for i := 0; i < n+int(offset) || n < 0; i++ {
+ line, err := r.ReadString('\n')
+ if err != nil {
+ break
+ }
+ if i < int(offset) {
+ continue
+ }
+ ret = append(ret, strings.Trim(line, "\n"))
+ }
+
+ return ret, nil
+}
+
+func IntToString(orig []int8) string {
+ ret := make([]byte, len(orig))
+ size := -1
+ for i, o := range orig {
+ if o == 0 {
+ size = i
+ break
+ }
+ ret[i] = byte(o)
+ }
+ if size == -1 {
+ size = len(orig)
+ }
+
+ return string(ret[0:size])
+}
+
+func UintToString(orig []uint8) string {
+ ret := make([]byte, len(orig))
+ size := -1
+ for i, o := range orig {
+ if o == 0 {
+ size = i
+ break
+ }
+ ret[i] = byte(o)
+ }
+ if size == -1 {
+ size = len(orig)
+ }
+
+ return string(ret[0:size])
+}
+
+func ByteToString(orig []byte) string {
+ n := -1
+ l := -1
+ for i, b := range orig {
+ // skip left side null
+ if l == -1 && b == 0 {
+ continue
+ }
+ if l == -1 {
+ l = i
+ }
+
+ if b == 0 {
+ break
+ }
+ n = i + 1
+ }
+ if n == -1 {
+ return string(orig)
+ }
+ return string(orig[l:n])
+}
+
+// ReadInts reads contents from single line file and returns them as []int32.
+func ReadInts(filename string) ([]int64, error) {
+ f, err := os.Open(filename)
+ if err != nil {
+ return []int64{}, err
+ }
+ defer f.Close()
+
+ var ret []int64
+
+ r := bufio.NewReader(f)
+
+ // The int files that this is concerned with should only be one liners.
+ line, err := r.ReadString('\n')
+ if err != nil {
+ return []int64{}, err
+ }
+
+ i, err := strconv.ParseInt(strings.Trim(line, "\n"), 10, 32)
+ if err != nil {
+ return []int64{}, err
+ }
+ ret = append(ret, i)
+
+ return ret, nil
+}
+
+// Parse to int32 without error
+func mustParseInt32(val string) int32 {
+ vv, _ := strconv.ParseInt(val, 10, 32)
+ return int32(vv)
+}
+
+// Parse to uint64 without error
+func mustParseUint64(val string) uint64 {
+ vv, _ := strconv.ParseInt(val, 10, 64)
+ return uint64(vv)
+}
+
+// Parse to Float64 without error
+func mustParseFloat64(val string) float64 {
+ vv, _ := strconv.ParseFloat(val, 64)
+ return vv
+}
+
+// StringsHas checks the target string slice contains src or not
+func StringsHas(target []string, src string) bool {
+ for _, t := range target {
+ if strings.TrimSpace(t) == src {
+ return true
+ }
+ }
+ return false
+}
+
+// StringsContains checks the src in any string of the target string slice
+func StringsContains(target []string, src string) bool {
+ for _, t := range target {
+ if strings.Contains(t, src) {
+ return true
+ }
+ }
+ return false
+}
+
+// IntContains checks the src in any int of the target int slice.
+func IntContains(target []int, src int) bool {
+ for _, t := range target {
+ if src == t {
+ return true
+ }
+ }
+ return false
+}
+
+// get struct attributes.
+// This method is used only for debugging platform dependent code.
+func attributes(m interface{}) map[string]reflect.Type {
+ typ := reflect.TypeOf(m)
+ if typ.Kind() == reflect.Ptr {
+ typ = typ.Elem()
+ }
+
+ attrs := make(map[string]reflect.Type)
+ if typ.Kind() != reflect.Struct {
+ return nil
+ }
+
+ for i := 0; i < typ.NumField(); i++ {
+ p := typ.Field(i)
+ if !p.Anonymous {
+ attrs[p.Name] = p.Type
+ }
+ }
+
+ return attrs
+}
+
+func PathExists(filename string) bool {
+ if _, err := os.Stat(filename); err == nil {
+ return true
+ }
+ return false
+}
+
+//GetEnv retrieves the environment variable key. If it does not exist it returns the default.
+func GetEnv(key string, dfault string, combineWith ...string) string {
+ value := os.Getenv(key)
+ if value == "" {
+ value = dfault
+ }
+
+ switch len(combineWith) {
+ case 0:
+ return value
+ case 1:
+ return filepath.Join(value, combineWith[0])
+ default:
+ all := make([]string, len(combineWith)+1)
+ all[0] = value
+ copy(all[1:], combineWith)
+ return filepath.Join(all...)
+ }
+ panic("invalid switch case")
+}
+
+func HostProc(combineWith ...string) string {
+ return GetEnv("HOST_PROC", "/proc", combineWith...)
+}
+
+func HostSys(combineWith ...string) string {
+ return GetEnv("HOST_SYS", "/sys", combineWith...)
+}
+
+func HostEtc(combineWith ...string) string {
+ return GetEnv("HOST_ETC", "/etc", combineWith...)
+}
+
+func HostVar(combineWith ...string) string {
+ return GetEnv("HOST_VAR", "/var", combineWith...)
+}
+
+func HostRun(combineWith ...string) string {
+ return GetEnv("HOST_RUN", "/run", combineWith...)
+}
+
+// https://gist.github.com/kylelemons/1525278
+func Pipeline(cmds ...*exec.Cmd) ([]byte, []byte, error) {
+ // Require at least one command
+ if len(cmds) < 1 {
+ return nil, nil, nil
+ }
+
+ // Collect the output from the command(s)
+ var output bytes.Buffer
+ var stderr bytes.Buffer
+
+ last := len(cmds) - 1
+ for i, cmd := range cmds[:last] {
+ var err error
+ // Connect each command's stdin to the previous command's stdout
+ if cmds[i+1].Stdin, err = cmd.StdoutPipe(); err != nil {
+ return nil, nil, err
+ }
+ // Connect each command's stderr to a buffer
+ cmd.Stderr = &stderr
+ }
+
+ // Connect the output and error for the last command
+ cmds[last].Stdout, cmds[last].Stderr = &output, &stderr
+
+ // Start each command
+ for _, cmd := range cmds {
+ if err := cmd.Start(); err != nil {
+ return output.Bytes(), stderr.Bytes(), err
+ }
+ }
+
+ // Wait for each command to complete
+ for _, cmd := range cmds {
+ if err := cmd.Wait(); err != nil {
+ return output.Bytes(), stderr.Bytes(), err
+ }
+ }
+
+ // Return the pipeline output and the collected standard error
+ return output.Bytes(), stderr.Bytes(), nil
+}
+
+// getSysctrlEnv sets LC_ALL=C in a list of env vars for use when running
+// sysctl commands (see DoSysctrl).
+func getSysctrlEnv(env []string) []string {
+ foundLC := false
+ for i, line := range env {
+ if strings.HasPrefix(line, "LC_ALL") {
+ env[i] = "LC_ALL=C"
+ foundLC = true
+ }
+ }
+ if !foundLC {
+ env = append(env, "LC_ALL=C")
+ }
+ return env
+}
diff --git a/vendor/github.com/shirou/gopsutil/internal/common/common_darwin.go b/vendor/github.com/shirou/gopsutil/internal/common/common_darwin.go
new file mode 100644
index 0000000..3e85cc0
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/internal/common/common_darwin.go
@@ -0,0 +1,69 @@
+// +build darwin
+
+package common
+
+import (
+ "context"
+ "os"
+ "os/exec"
+ "strings"
+ "unsafe"
+
+ "golang.org/x/sys/unix"
+)
+
+func DoSysctrlWithContext(ctx context.Context, mib string) ([]string, error) {
+ sysctl, err := exec.LookPath("/usr/sbin/sysctl")
+ if err != nil {
+ return []string{}, err
+ }
+ cmd := exec.CommandContext(ctx, sysctl, "-n", mib)
+ cmd.Env = getSysctrlEnv(os.Environ())
+ out, err := cmd.Output()
+ if err != nil {
+ return []string{}, err
+ }
+ v := strings.Replace(string(out), "{ ", "", 1)
+ v = strings.Replace(string(v), " }", "", 1)
+ values := strings.Fields(string(v))
+
+ return values, nil
+}
+
+func CallSyscall(mib []int32) ([]byte, uint64, error) {
+ miblen := uint64(len(mib))
+
+ // get required buffer size
+ length := uint64(0)
+ _, _, err := unix.Syscall6(
+ unix.SYS___SYSCTL,
+ uintptr(unsafe.Pointer(&mib[0])),
+ uintptr(miblen),
+ 0,
+ uintptr(unsafe.Pointer(&length)),
+ 0,
+ 0)
+ if err != 0 {
+ var b []byte
+ return b, length, err
+ }
+ if length == 0 {
+ var b []byte
+ return b, length, err
+ }
+ // get proc info itself
+ buf := make([]byte, length)
+ _, _, err = unix.Syscall6(
+ unix.SYS___SYSCTL,
+ uintptr(unsafe.Pointer(&mib[0])),
+ uintptr(miblen),
+ uintptr(unsafe.Pointer(&buf[0])),
+ uintptr(unsafe.Pointer(&length)),
+ 0,
+ 0)
+ if err != 0 {
+ return buf, length, err
+ }
+
+ return buf, length, nil
+}
diff --git a/vendor/github.com/shirou/gopsutil/internal/common/common_freebsd.go b/vendor/github.com/shirou/gopsutil/internal/common/common_freebsd.go
new file mode 100644
index 0000000..107e2c9
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/internal/common/common_freebsd.go
@@ -0,0 +1,69 @@
+// +build freebsd openbsd
+
+package common
+
+import (
+ "os"
+ "os/exec"
+ "strings"
+ "unsafe"
+
+ "golang.org/x/sys/unix"
+)
+
+func DoSysctrl(mib string) ([]string, error) {
+ sysctl, err := exec.LookPath("/sbin/sysctl")
+ if err != nil {
+ return []string{}, err
+ }
+ cmd := exec.Command(sysctl, "-n", mib)
+ cmd.Env = getSysctrlEnv(os.Environ())
+ out, err := cmd.Output()
+ if err != nil {
+ return []string{}, err
+ }
+ v := strings.Replace(string(out), "{ ", "", 1)
+ v = strings.Replace(string(v), " }", "", 1)
+ values := strings.Fields(string(v))
+
+ return values, nil
+}
+
+func CallSyscall(mib []int32) ([]byte, uint64, error) {
+ mibptr := unsafe.Pointer(&mib[0])
+ miblen := uint64(len(mib))
+
+ // get required buffer size
+ length := uint64(0)
+ _, _, err := unix.Syscall6(
+ unix.SYS___SYSCTL,
+ uintptr(mibptr),
+ uintptr(miblen),
+ 0,
+ uintptr(unsafe.Pointer(&length)),
+ 0,
+ 0)
+ if err != 0 {
+ var b []byte
+ return b, length, err
+ }
+ if length == 0 {
+ var b []byte
+ return b, length, err
+ }
+ // get proc info itself
+ buf := make([]byte, length)
+ _, _, err = unix.Syscall6(
+ unix.SYS___SYSCTL,
+ uintptr(mibptr),
+ uintptr(miblen),
+ uintptr(unsafe.Pointer(&buf[0])),
+ uintptr(unsafe.Pointer(&length)),
+ 0,
+ 0)
+ if err != 0 {
+ return buf, length, err
+ }
+
+ return buf, length, nil
+}
diff --git a/vendor/github.com/shirou/gopsutil/internal/common/common_linux.go b/vendor/github.com/shirou/gopsutil/internal/common/common_linux.go
new file mode 100644
index 0000000..4e829e0
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/internal/common/common_linux.go
@@ -0,0 +1,41 @@
+// +build linux
+
+package common
+
+import (
+ "os"
+ "os/exec"
+ "strings"
+)
+
+func DoSysctrl(mib string) ([]string, error) {
+ sysctl, err := exec.LookPath("/sbin/sysctl")
+ if err != nil {
+ return []string{}, err
+ }
+ cmd := exec.Command(sysctl, "-n", mib)
+ cmd.Env = getSysctrlEnv(os.Environ())
+ out, err := cmd.Output()
+ if err != nil {
+ return []string{}, err
+ }
+ v := strings.Replace(string(out), "{ ", "", 1)
+ v = strings.Replace(string(v), " }", "", 1)
+ values := strings.Fields(string(v))
+
+ return values, nil
+}
+
+func NumProcs() (uint64, error) {
+ f, err := os.Open(HostProc())
+ if err != nil {
+ return 0, err
+ }
+ defer f.Close()
+
+ list, err := f.Readdirnames(-1)
+ if err != nil {
+ return 0, err
+ }
+ return uint64(len(list)), err
+}
diff --git a/vendor/github.com/shirou/gopsutil/internal/common/common_openbsd.go b/vendor/github.com/shirou/gopsutil/internal/common/common_openbsd.go
new file mode 100644
index 0000000..398f785
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/internal/common/common_openbsd.go
@@ -0,0 +1,69 @@
+// +build openbsd
+
+package common
+
+import (
+ "os"
+ "os/exec"
+ "strings"
+ "unsafe"
+
+ "golang.org/x/sys/unix"
+)
+
+func DoSysctrl(mib string) ([]string, error) {
+ sysctl, err := exec.LookPath("/sbin/sysctl")
+ if err != nil {
+ return []string{}, err
+ }
+ cmd := exec.Command(sysctl, "-n", mib)
+ cmd.Env = getSysctrlEnv(os.Environ())
+ out, err := cmd.Output()
+ if err != nil {
+ return []string{}, err
+ }
+ v := strings.Replace(string(out), "{ ", "", 1)
+ v = strings.Replace(string(v), " }", "", 1)
+ values := strings.Fields(string(v))
+
+ return values, nil
+}
+
+func CallSyscall(mib []int32) ([]byte, uint64, error) {
+ mibptr := unsafe.Pointer(&mib[0])
+ miblen := uint64(len(mib))
+
+ // get required buffer size
+ length := uint64(0)
+ _, _, err := unix.Syscall6(
+ unix.SYS___SYSCTL,
+ uintptr(mibptr),
+ uintptr(miblen),
+ 0,
+ uintptr(unsafe.Pointer(&length)),
+ 0,
+ 0)
+ if err != 0 {
+ var b []byte
+ return b, length, err
+ }
+ if length == 0 {
+ var b []byte
+ return b, length, err
+ }
+ // get proc info itself
+ buf := make([]byte, length)
+ _, _, err = unix.Syscall6(
+ unix.SYS___SYSCTL,
+ uintptr(mibptr),
+ uintptr(miblen),
+ uintptr(unsafe.Pointer(&buf[0])),
+ uintptr(unsafe.Pointer(&length)),
+ 0,
+ 0)
+ if err != 0 {
+ return buf, length, err
+ }
+
+ return buf, length, nil
+}
diff --git a/vendor/github.com/shirou/gopsutil/internal/common/common_unix.go b/vendor/github.com/shirou/gopsutil/internal/common/common_unix.go
new file mode 100644
index 0000000..750a592
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/internal/common/common_unix.go
@@ -0,0 +1,67 @@
+// +build linux freebsd darwin openbsd
+
+package common
+
+import (
+ "context"
+ "os/exec"
+ "strconv"
+ "strings"
+)
+
+func CallLsofWithContext(ctx context.Context, invoke Invoker, pid int32, args ...string) ([]string, error) {
+ var cmd []string
+ if pid == 0 { // will get from all processes.
+ cmd = []string{"-a", "-n", "-P"}
+ } else {
+ cmd = []string{"-a", "-n", "-P", "-p", strconv.Itoa(int(pid))}
+ }
+ cmd = append(cmd, args...)
+ lsof, err := exec.LookPath("lsof")
+ if err != nil {
+ return []string{}, err
+ }
+ out, err := invoke.CommandWithContext(ctx, lsof, cmd...)
+ if err != nil {
+ // if no pid found, lsof returnes code 1.
+ if err.Error() == "exit status 1" && len(out) == 0 {
+ return []string{}, nil
+ }
+ }
+ lines := strings.Split(string(out), "\n")
+
+ var ret []string
+ for _, l := range lines[1:] {
+ if len(l) == 0 {
+ continue
+ }
+ ret = append(ret, l)
+ }
+ return ret, nil
+}
+
+func CallPgrepWithContext(ctx context.Context, invoke Invoker, pid int32) ([]int32, error) {
+ var cmd []string
+ cmd = []string{"-P", strconv.Itoa(int(pid))}
+ pgrep, err := exec.LookPath("pgrep")
+ if err != nil {
+ return []int32{}, err
+ }
+ out, err := invoke.CommandWithContext(ctx, pgrep, cmd...)
+ if err != nil {
+ return []int32{}, err
+ }
+ lines := strings.Split(string(out), "\n")
+ ret := make([]int32, 0, len(lines))
+ for _, l := range lines {
+ if len(l) == 0 {
+ continue
+ }
+ i, err := strconv.Atoi(l)
+ if err != nil {
+ continue
+ }
+ ret = append(ret, int32(i))
+ }
+ return ret, nil
+}
diff --git a/vendor/github.com/shirou/gopsutil/internal/common/common_windows.go b/vendor/github.com/shirou/gopsutil/internal/common/common_windows.go
new file mode 100644
index 0000000..0997c9b
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/internal/common/common_windows.go
@@ -0,0 +1,135 @@
+// +build windows
+
+package common
+
+import (
+ "context"
+ "unsafe"
+
+ "github.com/StackExchange/wmi"
+ "golang.org/x/sys/windows"
+)
+
+// for double values
+type PDH_FMT_COUNTERVALUE_DOUBLE struct {
+ CStatus uint32
+ DoubleValue float64
+}
+
+// for 64 bit integer values
+type PDH_FMT_COUNTERVALUE_LARGE struct {
+ CStatus uint32
+ LargeValue int64
+}
+
+// for long values
+type PDH_FMT_COUNTERVALUE_LONG struct {
+ CStatus uint32
+ LongValue int32
+ padding [4]byte
+}
+
+// windows system const
+const (
+ ERROR_SUCCESS = 0
+ ERROR_FILE_NOT_FOUND = 2
+ DRIVE_REMOVABLE = 2
+ DRIVE_FIXED = 3
+ HKEY_LOCAL_MACHINE = 0x80000002
+ RRF_RT_REG_SZ = 0x00000002
+ RRF_RT_REG_DWORD = 0x00000010
+ PDH_FMT_LONG = 0x00000100
+ PDH_FMT_DOUBLE = 0x00000200
+ PDH_FMT_LARGE = 0x00000400
+ PDH_INVALID_DATA = 0xc0000bc6
+ PDH_INVALID_HANDLE = 0xC0000bbc
+ PDH_NO_DATA = 0x800007d5
+)
+
+var (
+ Modkernel32 = windows.NewLazySystemDLL("kernel32.dll")
+ ModNt = windows.NewLazySystemDLL("ntdll.dll")
+ ModPdh = windows.NewLazySystemDLL("pdh.dll")
+ ModPsapi = windows.NewLazySystemDLL("psapi.dll")
+
+ ProcGetSystemTimes = Modkernel32.NewProc("GetSystemTimes")
+ ProcNtQuerySystemInformation = ModNt.NewProc("NtQuerySystemInformation")
+ PdhOpenQuery = ModPdh.NewProc("PdhOpenQuery")
+ PdhAddCounter = ModPdh.NewProc("PdhAddCounterW")
+ PdhCollectQueryData = ModPdh.NewProc("PdhCollectQueryData")
+ PdhGetFormattedCounterValue = ModPdh.NewProc("PdhGetFormattedCounterValue")
+ PdhCloseQuery = ModPdh.NewProc("PdhCloseQuery")
+)
+
+type FILETIME struct {
+ DwLowDateTime uint32
+ DwHighDateTime uint32
+}
+
+// borrowed from net/interface_windows.go
+func BytePtrToString(p *uint8) string {
+ a := (*[10000]uint8)(unsafe.Pointer(p))
+ i := 0
+ for a[i] != 0 {
+ i++
+ }
+ return string(a[:i])
+}
+
+// CounterInfo
+// copied from https://github.com/mackerelio/mackerel-agent/
+type CounterInfo struct {
+ PostName string
+ CounterName string
+ Counter windows.Handle
+}
+
+// CreateQuery XXX
+// copied from https://github.com/mackerelio/mackerel-agent/
+func CreateQuery() (windows.Handle, error) {
+ var query windows.Handle
+ r, _, err := PdhOpenQuery.Call(0, 0, uintptr(unsafe.Pointer(&query)))
+ if r != 0 {
+ return 0, err
+ }
+ return query, nil
+}
+
+// CreateCounter XXX
+func CreateCounter(query windows.Handle, pname, cname string) (*CounterInfo, error) {
+ var counter windows.Handle
+ r, _, err := PdhAddCounter.Call(
+ uintptr(query),
+ uintptr(unsafe.Pointer(windows.StringToUTF16Ptr(cname))),
+ 0,
+ uintptr(unsafe.Pointer(&counter)))
+ if r != 0 {
+ return nil, err
+ }
+ return &CounterInfo{
+ PostName: pname,
+ CounterName: cname,
+ Counter: counter,
+ }, nil
+}
+
+// WMIQueryWithContext - wraps wmi.Query with a timed-out context to avoid hanging
+func WMIQueryWithContext(ctx context.Context, query string, dst interface{}, connectServerArgs ...interface{}) error {
+ if _, ok := ctx.Deadline(); !ok {
+ ctxTimeout, cancel := context.WithTimeout(ctx, Timeout)
+ defer cancel()
+ ctx = ctxTimeout
+ }
+
+ errChan := make(chan error, 1)
+ go func() {
+ errChan <- wmi.Query(query, dst, connectServerArgs...)
+ }()
+
+ select {
+ case <-ctx.Done():
+ return ctx.Err()
+ case err := <-errChan:
+ return err
+ }
+}
diff --git a/vendor/github.com/shirou/gopsutil/mem/mem.go b/vendor/github.com/shirou/gopsutil/mem/mem.go
new file mode 100644
index 0000000..995364f
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/mem/mem.go
@@ -0,0 +1,97 @@
+package mem
+
+import (
+ "encoding/json"
+
+ "github.com/shirou/gopsutil/internal/common"
+)
+
+var invoke common.Invoker = common.Invoke{}
+
+// Memory usage statistics. Total, Available and Used contain numbers of bytes
+// for human consumption.
+//
+// The other fields in this struct contain kernel specific values.
+type VirtualMemoryStat struct {
+ // Total amount of RAM on this system
+ Total uint64 `json:"total"`
+
+ // RAM available for programs to allocate
+ //
+ // This value is computed from the kernel specific values.
+ Available uint64 `json:"available"`
+
+ // RAM used by programs
+ //
+ // This value is computed from the kernel specific values.
+ Used uint64 `json:"used"`
+
+ // Percentage of RAM used by programs
+ //
+ // This value is computed from the kernel specific values.
+ UsedPercent float64 `json:"usedPercent"`
+
+ // This is the kernel's notion of free memory; RAM chips whose bits nobody
+ // cares about the value of right now. For a human consumable number,
+ // Available is what you really want.
+ Free uint64 `json:"free"`
+
+ // OS X / BSD specific numbers:
+ // http://www.macyourself.com/2010/02/17/what-is-free-wired-active-and-inactive-system-memory-ram/
+ Active uint64 `json:"active"`
+ Inactive uint64 `json:"inactive"`
+ Wired uint64 `json:"wired"`
+
+ // FreeBSD specific numbers:
+ // https://reviews.freebsd.org/D8467
+ Laundry uint64 `json:"laundry"`
+
+ // Linux specific numbers
+ // https://www.centos.org/docs/5/html/5.1/Deployment_Guide/s2-proc-meminfo.html
+ // https://www.kernel.org/doc/Documentation/filesystems/proc.txt
+ // https://www.kernel.org/doc/Documentation/vm/overcommit-accounting
+ Buffers uint64 `json:"buffers"`
+ Cached uint64 `json:"cached"`
+ Writeback uint64 `json:"writeback"`
+ Dirty uint64 `json:"dirty"`
+ WritebackTmp uint64 `json:"writebacktmp"`
+ Shared uint64 `json:"shared"`
+ Slab uint64 `json:"slab"`
+ SReclaimable uint64 `json:"sreclaimable"`
+ PageTables uint64 `json:"pagetables"`
+ SwapCached uint64 `json:"swapcached"`
+ CommitLimit uint64 `json:"commitlimit"`
+ CommittedAS uint64 `json:"committedas"`
+ HighTotal uint64 `json:"hightotal"`
+ HighFree uint64 `json:"highfree"`
+ LowTotal uint64 `json:"lowtotal"`
+ LowFree uint64 `json:"lowfree"`
+ SwapTotal uint64 `json:"swaptotal"`
+ SwapFree uint64 `json:"swapfree"`
+ Mapped uint64 `json:"mapped"`
+ VMallocTotal uint64 `json:"vmalloctotal"`
+ VMallocUsed uint64 `json:"vmallocused"`
+ VMallocChunk uint64 `json:"vmallocchunk"`
+ HugePagesTotal uint64 `json:"hugepagestotal"`
+ HugePagesFree uint64 `json:"hugepagesfree"`
+ HugePageSize uint64 `json:"hugepagesize"`
+}
+
+type SwapMemoryStat struct {
+ Total uint64 `json:"total"`
+ Used uint64 `json:"used"`
+ Free uint64 `json:"free"`
+ UsedPercent float64 `json:"usedPercent"`
+ Sin uint64 `json:"sin"`
+ Sout uint64 `json:"sout"`
+}
+
+func (m VirtualMemoryStat) String() string {
+ s, _ := json.Marshal(m)
+ return string(s)
+}
+
+func (m SwapMemoryStat) String() string {
+ s, _ := json.Marshal(m)
+ return string(s)
+}
diff --git a/vendor/github.com/shirou/gopsutil/mem/mem_darwin.go b/vendor/github.com/shirou/gopsutil/mem/mem_darwin.go
new file mode 100644
index 0000000..4fe7009
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/mem/mem_darwin.go
@@ -0,0 +1,74 @@
+// +build darwin
+
+package mem
+
+import (
+ "context"
+ "encoding/binary"
+ "strconv"
+ "strings"
+
+ "github.com/shirou/gopsutil/internal/common"
+ "golang.org/x/sys/unix"
+)
+
+func getHwMemsize() (uint64, error) {
+ totalString, err := unix.Sysctl("hw.memsize")
+ if err != nil {
+ return 0, err
+ }
+
+ // unix.sysctl() helpfully assumes the result is a null-terminated string and
+ // removes the last byte of the result if it's 0 :/
+ totalString += "\x00"
+
+ total := uint64(binary.LittleEndian.Uint64([]byte(totalString)))
+
+ return total, nil
+}
+
+// SwapMemory returns swapinfo.
+func SwapMemory() (*SwapMemoryStat, error) {
+ return SwapMemoryWithContext(context.Background())
+}
+
+func SwapMemoryWithContext(ctx context.Context) (*SwapMemoryStat, error) {
+ var ret *SwapMemoryStat
+
+ swapUsage, err := common.DoSysctrlWithContext(ctx, "vm.swapusage")
+ if err != nil {
+ return ret, err
+ }
+
+ total := strings.Replace(swapUsage[2], "M", "", 1)
+ used := strings.Replace(swapUsage[5], "M", "", 1)
+ free := strings.Replace(swapUsage[8], "M", "", 1)
+
+ total_v, err := strconv.ParseFloat(total, 64)
+ if err != nil {
+ return nil, err
+ }
+ used_v, err := strconv.ParseFloat(used, 64)
+ if err != nil {
+ return nil, err
+ }
+ free_v, err := strconv.ParseFloat(free, 64)
+ if err != nil {
+ return nil, err
+ }
+
+ u := float64(0)
+ if total_v != 0 {
+ u = ((total_v - free_v) / total_v) * 100.0
+ }
+
+ // vm.swapusage shows "M", multiply 1024 * 1024 to convert bytes.
+ ret = &SwapMemoryStat{
+ Total: uint64(total_v * 1024 * 1024),
+ Used: uint64(used_v * 1024 * 1024),
+ Free: uint64(free_v * 1024 * 1024),
+ UsedPercent: u,
+ }
+
+ return ret, nil
+}
diff --git a/vendor/github.com/shirou/gopsutil/mem/mem_darwin_cgo.go b/vendor/github.com/shirou/gopsutil/mem/mem_darwin_cgo.go
new file mode 100644
index 0000000..389f8cd
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/mem/mem_darwin_cgo.go
@@ -0,0 +1,59 @@
+// +build darwin
+// +build cgo
+
+package mem
+
+/*
+#include
+*/
+import "C"
+
+import (
+ "context"
+ "fmt"
+ "unsafe"
+
+ "golang.org/x/sys/unix"
+)
+
+// VirtualMemory returns VirtualmemoryStat.
+func VirtualMemory() (*VirtualMemoryStat, error) {
+ return VirtualMemoryWithContext(context.Background())
+}
+
+func VirtualMemoryWithContext(ctx context.Context) (*VirtualMemoryStat, error) {
+ count := C.mach_msg_type_number_t(C.HOST_VM_INFO_COUNT)
+ var vmstat C.vm_statistics_data_t
+
+ status := C.host_statistics(C.host_t(C.mach_host_self()),
+ C.HOST_VM_INFO,
+ C.host_info_t(unsafe.Pointer(&vmstat)),
+ &count)
+
+ if status != C.KERN_SUCCESS {
+ return nil, fmt.Errorf("host_statistics error=%d", status)
+ }
+
+ pageSize := uint64(unix.Getpagesize())
+ total, err := getHwMemsize()
+ if err != nil {
+ return nil, err
+ }
+ totalCount := C.natural_t(total / pageSize)
+
+ availableCount := vmstat.inactive_count + vmstat.free_count
+ usedPercent := 100 * float64(totalCount-availableCount) / float64(totalCount)
+
+ usedCount := totalCount - availableCount
+
+ return &VirtualMemoryStat{
+ Total: total,
+ Available: pageSize * uint64(availableCount),
+ Used: pageSize * uint64(usedCount),
+ UsedPercent: usedPercent,
+ Free: pageSize * uint64(vmstat.free_count),
+ Active: pageSize * uint64(vmstat.active_count),
+ Inactive: pageSize * uint64(vmstat.inactive_count),
+ Wired: pageSize * uint64(vmstat.wire_count),
+ }, nil
+}
diff --git a/vendor/github.com/shirou/gopsutil/mem/mem_darwin_nocgo.go b/vendor/github.com/shirou/gopsutil/mem/mem_darwin_nocgo.go
new file mode 100644
index 0000000..dd7c2e6
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/mem/mem_darwin_nocgo.go
@@ -0,0 +1,94 @@
+// +build darwin
+// +build !cgo
+
+package mem
+
+import (
+ "context"
+ "os/exec"
+ "strconv"
+ "strings"
+
+ "golang.org/x/sys/unix"
+)
+
+// Runs vm_stat and returns Free and inactive pages
+func getVMStat(vms *VirtualMemoryStat) error {
+ vm_stat, err := exec.LookPath("vm_stat")
+ if err != nil {
+ return err
+ }
+ out, err := invoke.Command(vm_stat)
+ if err != nil {
+ return err
+ }
+ return parseVMStat(string(out), vms)
+}
+
+func parseVMStat(out string, vms *VirtualMemoryStat) error {
+ var err error
+
+ lines := strings.Split(out, "\n")
+ pagesize := uint64(unix.Getpagesize())
+ for _, line := range lines {
+ fields := strings.Split(line, ":")
+ if len(fields) < 2 {
+ continue
+ }
+ key := strings.TrimSpace(fields[0])
+ value := strings.Trim(fields[1], " .")
+ switch key {
+ case "Pages free":
+ free, e := strconv.ParseUint(value, 10, 64)
+ if e != nil {
+ err = e
+ }
+ vms.Free = free * pagesize
+ case "Pages inactive":
+ inactive, e := strconv.ParseUint(value, 10, 64)
+ if e != nil {
+ err = e
+ }
+ vms.Inactive = inactive * pagesize
+ case "Pages active":
+ active, e := strconv.ParseUint(value, 10, 64)
+ if e != nil {
+ err = e
+ }
+ vms.Active = active * pagesize
+ case "Pages wired down":
+ wired, e := strconv.ParseUint(value, 10, 64)
+ if e != nil {
+ err = e
+ }
+ vms.Wired = wired * pagesize
+ }
+ }
+ return err
+}
+
+// VirtualMemory returns VirtualmemoryStat.
+func VirtualMemory() (*VirtualMemoryStat, error) {
+ return VirtualMemoryWithContext(context.Background())
+}
+
+func VirtualMemoryWithContext(ctx context.Context) (*VirtualMemoryStat, error) {
+ ret := &VirtualMemoryStat{}
+
+ total, err := getHwMemsize()
+ if err != nil {
+ return nil, err
+ }
+ err = getVMStat(ret)
+ if err != nil {
+ return nil, err
+ }
+
+ ret.Available = ret.Free + ret.Inactive
+ ret.Total = total
+
+ ret.Used = ret.Total - ret.Available
+ ret.UsedPercent = 100 * float64(ret.Used) / float64(ret.Total)
+
+ return ret, nil
+}
diff --git a/vendor/github.com/shirou/gopsutil/mem/mem_fallback.go b/vendor/github.com/shirou/gopsutil/mem/mem_fallback.go
new file mode 100644
index 0000000..2a0fd45
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/mem/mem_fallback.go
@@ -0,0 +1,25 @@
+// +build !darwin,!linux,!freebsd,!openbsd,!solaris,!windows
+
+package mem
+
+import (
+ "context"
+
+ "github.com/shirou/gopsutil/internal/common"
+)
+
+func VirtualMemory() (*VirtualMemoryStat, error) {
+ return VirtualMemoryWithContext(context.Background())
+}
+
+func VirtualMemoryWithContext(ctx context.Context) (*VirtualMemoryStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func SwapMemory() (*SwapMemoryStat, error) {
+ return SwapMemoryWithContext(context.Background())
+}
+
+func SwapMemoryWithContext(ctx context.Context) (*SwapMemoryStat, error) {
+ return nil, common.ErrNotImplementedError
+}
diff --git a/vendor/github.com/shirou/gopsutil/mem/mem_freebsd.go b/vendor/github.com/shirou/gopsutil/mem/mem_freebsd.go
new file mode 100644
index 0000000..a792281
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/mem/mem_freebsd.go
@@ -0,0 +1,142 @@
+// +build freebsd
+
+package mem
+
+import (
+ "context"
+ "errors"
+ "unsafe"
+
+ "golang.org/x/sys/unix"
+)
+
+func VirtualMemory() (*VirtualMemoryStat, error) {
+ return VirtualMemoryWithContext(context.Background())
+}
+
+func VirtualMemoryWithContext(ctx context.Context) (*VirtualMemoryStat, error) {
+ pageSize, err := unix.SysctlUint32("vm.stats.vm.v_page_size")
+ if err != nil {
+ return nil, err
+ }
+ physmem, err := unix.SysctlUint64("hw.physmem")
+ if err != nil {
+ return nil, err
+ }
+ free, err := unix.SysctlUint32("vm.stats.vm.v_free_count")
+ if err != nil {
+ return nil, err
+ }
+ active, err := unix.SysctlUint32("vm.stats.vm.v_active_count")
+ if err != nil {
+ return nil, err
+ }
+ inactive, err := unix.SysctlUint32("vm.stats.vm.v_inactive_count")
+ if err != nil {
+ return nil, err
+ }
+ buffers, err := unix.SysctlUint64("vfs.bufspace")
+ if err != nil {
+ return nil, err
+ }
+ wired, err := unix.SysctlUint32("vm.stats.vm.v_wire_count")
+ if err != nil {
+ return nil, err
+ }
+ var cached, laundry uint32
+ osreldate, _ := unix.SysctlUint32("kern.osreldate")
+ if osreldate < 1102000 {
+ cached, err = unix.SysctlUint32("vm.stats.vm.v_cache_count")
+ if err != nil {
+ return nil, err
+ }
+ } else {
+ laundry, err = unix.SysctlUint32("vm.stats.vm.v_laundry_count")
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ p := uint64(pageSize)
+ ret := &VirtualMemoryStat{
+ Total: uint64(physmem),
+ Free: uint64(free) * p,
+ Active: uint64(active) * p,
+ Inactive: uint64(inactive) * p,
+ Cached: uint64(cached) * p,
+ Buffers: uint64(buffers),
+ Wired: uint64(wired) * p,
+ Laundry: uint64(laundry) * p,
+ }
+
+ ret.Available = ret.Inactive + ret.Cached + ret.Free + ret.Laundry
+ ret.Used = ret.Total - ret.Available
+ ret.UsedPercent = float64(ret.Used) / float64(ret.Total) * 100.0
+
+ return ret, nil
+}
+
+// Return swapinfo
+func SwapMemory() (*SwapMemoryStat, error) {
+ return SwapMemoryWithContext(context.Background())
+}
+
+// Constants from vm/vm_param.h
+// nolint: golint
+const (
+ XSWDEV_VERSION = 1
+)
+
+// Types from vm/vm_param.h
+type xswdev struct {
+ Version uint32 // Version is the version
+ Dev uint32 // Dev is the device identifier
+ Flags int32 // Flags is the swap flags applied to the device
+ NBlks int32 // NBlks is the total number of blocks
+ Used int32 // Used is the number of blocks used
+}
+
+func SwapMemoryWithContext(ctx context.Context) (*SwapMemoryStat, error) {
+ // FreeBSD can have multiple swap devices so we total them up
+ i, err := unix.SysctlUint32("vm.nswapdev")
+ if err != nil {
+ return nil, err
+ }
+
+ if i == 0 {
+ return nil, errors.New("no swap devices found")
+ }
+
+ c := int(i)
+
+ i, err = unix.SysctlUint32("vm.stats.vm.v_page_size")
+ if err != nil {
+ return nil, err
+ }
+ pageSize := uint64(i)
+
+ var buf []byte
+ s := &SwapMemoryStat{}
+ for n := 0; n < c; n++ {
+ buf, err = unix.SysctlRaw("vm.swap_info", n)
+ if err != nil {
+ return nil, err
+ }
+
+ xsw := (*xswdev)(unsafe.Pointer(&buf[0]))
+ if xsw.Version != XSWDEV_VERSION {
+ return nil, errors.New("xswdev version mismatch")
+ }
+ s.Total += uint64(xsw.NBlks)
+ s.Used += uint64(xsw.Used)
+ }
+
+ if s.Total != 0 {
+ s.UsedPercent = float64(s.Used) / float64(s.Total) * 100
+ }
+ s.Total *= pageSize
+ s.Used *= pageSize
+ s.Free = s.Total - s.Used
+
+ return s, nil
+}
diff --git a/vendor/github.com/shirou/gopsutil/mem/mem_linux.go b/vendor/github.com/shirou/gopsutil/mem/mem_linux.go
new file mode 100644
index 0000000..a3425d7
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/mem/mem_linux.go
@@ -0,0 +1,158 @@
+// +build linux
+
+package mem
+
+import (
+ "context"
+ "strconv"
+ "strings"
+
+ "github.com/shirou/gopsutil/internal/common"
+ "golang.org/x/sys/unix"
+)
+
+func VirtualMemory() (*VirtualMemoryStat, error) {
+ return VirtualMemoryWithContext(context.Background())
+}
+
+func VirtualMemoryWithContext(ctx context.Context) (*VirtualMemoryStat, error) {
+ filename := common.HostProc("meminfo")
+ lines, _ := common.ReadLines(filename)
+ // flag if MemAvailable is in /proc/meminfo (kernel 3.14+)
+ memavail := false
+
+ ret := &VirtualMemoryStat{}
+ for _, line := range lines {
+ fields := strings.Split(line, ":")
+ if len(fields) != 2 {
+ continue
+ }
+ key := strings.TrimSpace(fields[0])
+ value := strings.TrimSpace(fields[1])
+ value = strings.Replace(value, " kB", "", -1)
+
+ t, err := strconv.ParseUint(value, 10, 64)
+ if err != nil {
+ return ret, err
+ }
+ switch key {
+ case "MemTotal":
+ ret.Total = t * 1024
+ case "MemFree":
+ ret.Free = t * 1024
+ case "MemAvailable":
+ memavail = true
+ ret.Available = t * 1024
+ case "Buffers":
+ ret.Buffers = t * 1024
+ case "Cached":
+ ret.Cached = t * 1024
+ case "Active":
+ ret.Active = t * 1024
+ case "Inactive":
+ ret.Inactive = t * 1024
+ case "Writeback":
+ ret.Writeback = t * 1024
+ case "WritebackTmp":
+ ret.WritebackTmp = t * 1024
+ case "Dirty":
+ ret.Dirty = t * 1024
+ case "Shmem":
+ ret.Shared = t * 1024
+ case "Slab":
+ ret.Slab = t * 1024
+ case "SReclaimable":
+ ret.SReclaimable = t * 1024
+ case "PageTables":
+ ret.PageTables = t * 1024
+ case "SwapCached":
+ ret.SwapCached = t * 1024
+ case "CommitLimit":
+ ret.CommitLimit = t * 1024
+ case "Committed_AS":
+ ret.CommittedAS = t * 1024
+ case "HighTotal":
+ ret.HighTotal = t * 1024
+ case "HighFree":
+ ret.HighFree = t * 1024
+ case "LowTotal":
+ ret.LowTotal = t * 1024
+ case "LowFree":
+ ret.LowFree = t * 1024
+ case "SwapTotal":
+ ret.SwapTotal = t * 1024
+ case "SwapFree":
+ ret.SwapFree = t * 1024
+ case "Mapped":
+ ret.Mapped = t * 1024
+ case "VmallocTotal":
+ ret.VMallocTotal = t * 1024
+ case "VmallocUsed":
+ ret.VMallocUsed = t * 1024
+ case "VmallocChunk":
+ ret.VMallocChunk = t * 1024
+ case "HugePages_Total":
+ ret.HugePagesTotal = t
+ case "HugePages_Free":
+ ret.HugePagesFree = t
+ case "Hugepagesize":
+ ret.HugePageSize = t * 1024
+ }
+ }
+
+ ret.Cached += ret.SReclaimable
+
+ if !memavail {
+ ret.Available = ret.Free + ret.Buffers + ret.Cached
+ }
+ ret.Used = ret.Total - ret.Free - ret.Buffers - ret.Cached
+ ret.UsedPercent = float64(ret.Used) / float64(ret.Total) * 100.0
+
+ return ret, nil
+}
+
+func SwapMemory() (*SwapMemoryStat, error) {
+ return SwapMemoryWithContext(context.Background())
+}
+
+func SwapMemoryWithContext(ctx context.Context) (*SwapMemoryStat, error) {
+ sysinfo := &unix.Sysinfo_t{}
+
+ if err := unix.Sysinfo(sysinfo); err != nil {
+ return nil, err
+ }
+ ret := &SwapMemoryStat{
+ Total: uint64(sysinfo.Totalswap) * uint64(sysinfo.Unit),
+ Free: uint64(sysinfo.Freeswap) * uint64(sysinfo.Unit),
+ }
+ ret.Used = ret.Total - ret.Free
+ //check Infinity
+ if ret.Total != 0 {
+ ret.UsedPercent = float64(ret.Total-ret.Free) / float64(ret.Total) * 100.0
+ } else {
+ ret.UsedPercent = 0
+ }
+ filename := common.HostProc("vmstat")
+ lines, _ := common.ReadLines(filename)
+ for _, l := range lines {
+ fields := strings.Fields(l)
+ if len(fields) < 2 {
+ continue
+ }
+ switch fields[0] {
+ case "pswpin":
+ value, err := strconv.ParseUint(fields[1], 10, 64)
+ if err != nil {
+ continue
+ }
+ ret.Sin = value * 4 * 1024
+ case "pswpout":
+ value, err := strconv.ParseUint(fields[1], 10, 64)
+ if err != nil {
+ continue
+ }
+ ret.Sout = value * 4 * 1024
+ }
+ }
+ return ret, nil
+}
diff --git a/vendor/github.com/shirou/gopsutil/mem/mem_openbsd.go b/vendor/github.com/shirou/gopsutil/mem/mem_openbsd.go
new file mode 100644
index 0000000..35472a3
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/mem/mem_openbsd.go
@@ -0,0 +1,124 @@
+// +build openbsd
+
+package mem
+
+import (
+ "bytes"
+ "context"
+ "encoding/binary"
+ "errors"
+ "fmt"
+ "os/exec"
+
+ "github.com/shirou/gopsutil/internal/common"
+)
+
+func GetPageSize() (uint64, error) {
+ return GetPageSizeWithContext(context.Background())
+}
+
+func GetPageSizeWithContext(ctx context.Context) (uint64, error) {
+ mib := []int32{CTLVm, VmUvmexp}
+ buf, length, err := common.CallSyscall(mib)
+ if err != nil {
+ return 0, err
+ }
+ if length < sizeOfUvmexp {
+ return 0, fmt.Errorf("short syscall ret %d bytes", length)
+ }
+ var uvmexp Uvmexp
+ br := bytes.NewReader(buf)
+ err = common.Read(br, binary.LittleEndian, &uvmexp)
+ if err != nil {
+ return 0, err
+ }
+ return uint64(uvmexp.Pagesize), nil
+}
+
+func VirtualMemory() (*VirtualMemoryStat, error) {
+ return VirtualMemoryWithContext(context.Background())
+}
+
+func VirtualMemoryWithContext(ctx context.Context) (*VirtualMemoryStat, error) {
+ mib := []int32{CTLVm, VmUvmexp}
+ buf, length, err := common.CallSyscall(mib)
+ if err != nil {
+ return nil, err
+ }
+ if length < sizeOfUvmexp {
+ return nil, fmt.Errorf("short syscall ret %d bytes", length)
+ }
+ var uvmexp Uvmexp
+ br := bytes.NewReader(buf)
+ err = common.Read(br, binary.LittleEndian, &uvmexp)
+ if err != nil {
+ return nil, err
+ }
+ p := uint64(uvmexp.Pagesize)
+
+ ret := &VirtualMemoryStat{
+ Total: uint64(uvmexp.Npages) * p,
+ Free: uint64(uvmexp.Free) * p,
+ Active: uint64(uvmexp.Active) * p,
+ Inactive: uint64(uvmexp.Inactive) * p,
+ Cached: 0, // not available
+ Wired: uint64(uvmexp.Wired) * p,
+ }
+
+ ret.Available = ret.Inactive + ret.Cached + ret.Free
+ ret.Used = ret.Total - ret.Available
+ ret.UsedPercent = float64(ret.Used) / float64(ret.Total) * 100.0
+
+ mib = []int32{CTLVfs, VfsGeneric, VfsBcacheStat}
+ buf, length, err = common.CallSyscall(mib)
+ if err != nil {
+ return nil, err
+ }
+ if length < sizeOfBcachestats {
+ return nil, fmt.Errorf("short syscall ret %d bytes", length)
+ }
+ var bcs Bcachestats
+ br = bytes.NewReader(buf)
+ err = common.Read(br, binary.LittleEndian, &bcs)
+ if err != nil {
+ return nil, err
+ }
+ ret.Buffers = uint64(bcs.Numbufpages) * p
+
+ return ret, nil
+}
+
+// Return swapctl summary info
+func SwapMemory() (*SwapMemoryStat, error) {
+ return SwapMemoryWithContext(context.Background())
+}
+
+func SwapMemoryWithContext(ctx context.Context) (*SwapMemoryStat, error) {
+ swapctl, err := exec.LookPath("swapctl")
+ if err != nil {
+ return nil, err
+ }
+
+ out, err := invoke.CommandWithContext(ctx, swapctl, "-sk")
+ if err != nil {
+ return &SwapMemoryStat{}, nil
+ }
+
+ line := string(out)
+ var total, used, free uint64
+
+ _, err = fmt.Sscanf(line,
+ "total: %d 1K-blocks allocated, %d used, %d available",
+ &total, &used, &free)
+ if err != nil {
+ return nil, errors.New("failed to parse swapctl output")
+ }
+
+ percent := float64(used) / float64(total) * 100
+ return &SwapMemoryStat{
+ Total: total * 1024,
+ Used: used * 1024,
+ Free: free * 1024,
+ UsedPercent: percent,
+ }, nil
+}
diff --git a/vendor/github.com/shirou/gopsutil/mem/mem_openbsd_amd64.go b/vendor/github.com/shirou/gopsutil/mem/mem_openbsd_amd64.go
new file mode 100644
index 0000000..e09b908
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/mem/mem_openbsd_amd64.go
@@ -0,0 +1,122 @@
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs types_openbsd.go
+
+package mem
+
+const (
+ CTLVm = 2
+ CTLVfs = 10
+ VmUvmexp = 4
+ VfsGeneric = 0
+ VfsBcacheStat = 3
+)
+
+const (
+ sizeOfUvmexp = 0x154
+ sizeOfBcachestats = 0x78
+)
+
+type Uvmexp struct {
+ Pagesize int32
+ Pagemask int32
+ Pageshift int32
+ Npages int32
+ Free int32
+ Active int32
+ Inactive int32
+ Paging int32
+ Wired int32
+ Zeropages int32
+ Reserve_pagedaemon int32
+ Reserve_kernel int32
+ Anonpages int32
+ Vnodepages int32
+ Vtextpages int32
+ Freemin int32
+ Freetarg int32
+ Inactarg int32
+ Wiredmax int32
+ Anonmin int32
+ Vtextmin int32
+ Vnodemin int32
+ Anonminpct int32
+ Vtextminpct int32
+ Vnodeminpct int32
+ Nswapdev int32
+ Swpages int32
+ Swpginuse int32
+ Swpgonly int32
+ Nswget int32
+ Nanon int32
+ Nanonneeded int32
+ Nfreeanon int32
+ Faults int32
+ Traps int32
+ Intrs int32
+ Swtch int32
+ Softs int32
+ Syscalls int32
+ Pageins int32
+ Obsolete_swapins int32
+ Obsolete_swapouts int32
+ Pgswapin int32
+ Pgswapout int32
+ Forks int32
+ Forks_ppwait int32
+ Forks_sharevm int32
+ Pga_zerohit int32
+ Pga_zeromiss int32
+ Zeroaborts int32
+ Fltnoram int32
+ Fltnoanon int32
+ Fltpgwait int32
+ Fltpgrele int32
+ Fltrelck int32
+ Fltrelckok int32
+ Fltanget int32
+ Fltanretry int32
+ Fltamcopy int32
+ Fltnamap int32
+ Fltnomap int32
+ Fltlget int32
+ Fltget int32
+ Flt_anon int32
+ Flt_acow int32
+ Flt_obj int32
+ Flt_prcopy int32
+ Flt_przero int32
+ Pdwoke int32
+ Pdrevs int32
+ Pdswout int32
+ Pdfreed int32
+ Pdscans int32
+ Pdanscan int32
+ Pdobscan int32
+ Pdreact int32
+ Pdbusy int32
+ Pdpageouts int32
+ Pdpending int32
+ Pddeact int32
+ Pdreanon int32
+ Pdrevnode int32
+ Pdrevtext int32
+ Fpswtch int32
+ Kmapent int32
+}
+type Bcachestats struct {
+ Numbufs int64
+ Numbufpages int64
+ Numdirtypages int64
+ Numcleanpages int64
+ Pendingwrites int64
+ Pendingreads int64
+ Numwrites int64
+ Numreads int64
+ Cachehits int64
+ Busymapped int64
+ Dmapages int64
+ Highpages int64
+ Delwribufs int64
+ Kvaslots int64
+ Avail int64
+}
diff --git a/vendor/github.com/shirou/gopsutil/mem/mem_solaris.go b/vendor/github.com/shirou/gopsutil/mem/mem_solaris.go
new file mode 100644
index 0000000..0736bc4
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/mem/mem_solaris.go
@@ -0,0 +1,121 @@
+package mem
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "os/exec"
+ "regexp"
+ "strconv"
+ "strings"
+
+ "github.com/shirou/gopsutil/internal/common"
+)
+
+// VirtualMemory for Solaris is a minimal implementation which only returns
+// what Nomad needs. It does take into account global vs zone, however.
+func VirtualMemory() (*VirtualMemoryStat, error) {
+ return VirtualMemoryWithContext(context.Background())
+}
+
+func VirtualMemoryWithContext(ctx context.Context) (*VirtualMemoryStat, error) {
+ result := &VirtualMemoryStat{}
+
+ zoneName, err := zoneName()
+ if err != nil {
+ return nil, err
+ }
+
+ if zoneName == "global" {
+ cap, err := globalZoneMemoryCapacity()
+ if err != nil {
+ return nil, err
+ }
+ result.Total = cap
+ } else {
+ cap, err := nonGlobalZoneMemoryCapacity()
+ if err != nil {
+ return nil, err
+ }
+ result.Total = cap
+ }
+
+ return result, nil
+}
+
+func SwapMemory() (*SwapMemoryStat, error) {
+ return SwapMemoryWithContext(context.Background())
+}
+
+func SwapMemoryWithContext(ctx context.Context) (*SwapMemoryStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func zoneName() (string, error) {
+ zonename, err := exec.LookPath("/usr/bin/zonename")
+ if err != nil {
+ return "", err
+ }
+
+ ctx := context.Background()
+ out, err := invoke.CommandWithContext(ctx, zonename)
+ if err != nil {
+ return "", err
+ }
+
+ return strings.TrimSpace(string(out)), nil
+}
+
+var globalZoneMemoryCapacityMatch = regexp.MustCompile(`memory size: ([\d]+) Megabytes`)
+
+func globalZoneMemoryCapacity() (uint64, error) {
+ prtconf, err := exec.LookPath("/usr/sbin/prtconf")
+ if err != nil {
+ return 0, err
+ }
+
+ ctx := context.Background()
+ out, err := invoke.CommandWithContext(ctx, prtconf)
+ if err != nil {
+ return 0, err
+ }
+
+ match := globalZoneMemoryCapacityMatch.FindAllStringSubmatch(string(out), -1)
+ if len(match) != 1 {
+ return 0, errors.New("memory size not contained in output of /usr/sbin/prtconf")
+ }
+
+ totalMB, err := strconv.ParseUint(match[0][1], 10, 64)
+ if err != nil {
+ return 0, err
+ }
+
+ return totalMB * 1024 * 1024, nil
+}
+
+var kstatMatch = regexp.MustCompile(`([^\s]+)[\s]+([^\s]*)`)
+
+func nonGlobalZoneMemoryCapacity() (uint64, error) {
+ kstat, err := exec.LookPath("/usr/bin/kstat")
+ if err != nil {
+ return 0, err
+ }
+
+ ctx := context.Background()
+ out, err := invoke.CommandWithContext(ctx, kstat, "-p", "-c", "zone_memory_cap", "memory_cap:*:*:physcap")
+ if err != nil {
+ return 0, err
+ }
+
+ kstats := kstatMatch.FindAllStringSubmatch(string(out), -1)
+ if len(kstats) != 1 {
+ return 0, fmt.Errorf("expected 1 kstat, found %d", len(kstats))
+ }
+
+ memSizeBytes, err := strconv.ParseUint(kstats[0][2], 10, 64)
+ if err != nil {
+ return 0, err
+ }
+
+ return memSizeBytes, nil
+}
diff --git a/vendor/github.com/shirou/gopsutil/mem/mem_windows.go b/vendor/github.com/shirou/gopsutil/mem/mem_windows.go
new file mode 100644
index 0000000..cfdf8bd
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/mem/mem_windows.go
@@ -0,0 +1,97 @@
+// +build windows
+
+package mem
+
+import (
+ "context"
+ "unsafe"
+
+ "github.com/shirou/gopsutil/internal/common"
+ "golang.org/x/sys/windows"
+)
+
+var (
+ procGlobalMemoryStatusEx = common.Modkernel32.NewProc("GlobalMemoryStatusEx")
+ procGetPerformanceInfo = common.ModPsapi.NewProc("GetPerformanceInfo")
+)
+
+type memoryStatusEx struct {
+ cbSize uint32
+ dwMemoryLoad uint32
+ ullTotalPhys uint64 // in bytes
+ ullAvailPhys uint64
+ ullTotalPageFile uint64
+ ullAvailPageFile uint64
+ ullTotalVirtual uint64
+ ullAvailVirtual uint64
+ ullAvailExtendedVirtual uint64
+}
+
+func VirtualMemory() (*VirtualMemoryStat, error) {
+ return VirtualMemoryWithContext(context.Background())
+}
+
+func VirtualMemoryWithContext(ctx context.Context) (*VirtualMemoryStat, error) {
+ var memInfo memoryStatusEx
+ memInfo.cbSize = uint32(unsafe.Sizeof(memInfo))
+ mem, _, _ := procGlobalMemoryStatusEx.Call(uintptr(unsafe.Pointer(&memInfo)))
+ if mem == 0 {
+ return nil, windows.GetLastError()
+ }
+
+ ret := &VirtualMemoryStat{
+ Total: memInfo.ullTotalPhys,
+ Available: memInfo.ullAvailPhys,
+ UsedPercent: float64(memInfo.dwMemoryLoad),
+ }
+
+ ret.Used = ret.Total - ret.Available
+ return ret, nil
+}
+
+type performanceInformation struct {
+ cb uint32
+ commitTotal uint64
+ commitLimit uint64
+ commitPeak uint64
+ physicalTotal uint64
+ physicalAvailable uint64
+ systemCache uint64
+ kernelTotal uint64
+ kernelPaged uint64
+ kernelNonpaged uint64
+ pageSize uint64
+ handleCount uint32
+ processCount uint32
+ threadCount uint32
+}
+
+func SwapMemory() (*SwapMemoryStat, error) {
+ return SwapMemoryWithContext(context.Background())
+}
+
+func SwapMemoryWithContext(ctx context.Context) (*SwapMemoryStat, error) {
+ var perfInfo performanceInformation
+ perfInfo.cb = uint32(unsafe.Sizeof(perfInfo))
+ mem, _, _ := procGetPerformanceInfo.Call(uintptr(unsafe.Pointer(&perfInfo)), uintptr(perfInfo.cb))
+ if mem == 0 {
+ return nil, windows.GetLastError()
+ }
+ tot := perfInfo.commitLimit * perfInfo.pageSize
+ used := perfInfo.commitTotal * perfInfo.pageSize
+ free := tot - used
+ var usedPercent float64
+ if tot == 0 {
+ usedPercent = 0
+ } else {
+ usedPercent = float64(used) / float64(tot)
+ }
+ ret := &SwapMemoryStat{
+ Total: tot,
+ Used: used,
+ Free: free,
+ UsedPercent: usedPercent,
+ }
+
+ return ret, nil
+}
diff --git a/vendor/github.com/shirou/gopsutil/net/net.go b/vendor/github.com/shirou/gopsutil/net/net.go
new file mode 100644
index 0000000..fce86c7
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/net/net.go
@@ -0,0 +1,259 @@
+package net
+
+import (
+ "context"
+ "encoding/json"
+ "fmt"
+ "net"
+ "strconv"
+ "strings"
+ "syscall"
+
+ "github.com/shirou/gopsutil/internal/common"
+)
+
+var invoke common.Invoker = common.Invoke{}
+
+type IOCountersStat struct {
+ Name string `json:"name"` // interface name
+ BytesSent uint64 `json:"bytesSent"` // number of bytes sent
+ BytesRecv uint64 `json:"bytesRecv"` // number of bytes received
+ PacketsSent uint64 `json:"packetsSent"` // number of packets sent
+ PacketsRecv uint64 `json:"packetsRecv"` // number of packets received
+ Errin uint64 `json:"errin"` // total number of errors while receiving
+ Errout uint64 `json:"errout"` // total number of errors while sending
+ Dropin uint64 `json:"dropin"` // total number of incoming packets which were dropped
+ Dropout uint64 `json:"dropout"` // total number of outgoing packets which were dropped (always 0 on OSX and BSD)
+ Fifoin uint64 `json:"fifoin"` // total number of FIFO buffers errors while receiving
+ Fifoout uint64 `json:"fifoout"` // total number of FIFO buffers errors while sending
+
+}
+
+// Addr is implemented compatibility to psutil
+type Addr struct {
+ IP string `json:"ip"`
+ Port uint32 `json:"port"`
+}
+
+type ConnectionStat struct {
+ Fd uint32 `json:"fd"`
+ Family uint32 `json:"family"`
+ Type uint32 `json:"type"`
+ Laddr Addr `json:"localaddr"`
+ Raddr Addr `json:"remoteaddr"`
+ Status string `json:"status"`
+ Uids []int32 `json:"uids"`
+ Pid int32 `json:"pid"`
+}
+
+// System wide stats about different network protocols
+type ProtoCountersStat struct {
+ Protocol string `json:"protocol"`
+ Stats map[string]int64 `json:"stats"`
+}
+
+// NetInterfaceAddr is designed for represent interface addresses
+type InterfaceAddr struct {
+ Addr string `json:"addr"`
+}
+
+type InterfaceStat struct {
+ MTU int `json:"mtu"` // maximum transmission unit
+ Name string `json:"name"` // e.g., "en0", "lo0", "eth0.100"
+ HardwareAddr string `json:"hardwareaddr"` // IEEE MAC-48, EUI-48 and EUI-64 form
+ Flags []string `json:"flags"` // e.g., FlagUp, FlagLoopback, FlagMulticast
+ Addrs []InterfaceAddr `json:"addrs"`
+}
+
+type FilterStat struct {
+ ConnTrackCount int64 `json:"conntrackCount"`
+ ConnTrackMax int64 `json:"conntrackMax"`
+}
+
+var constMap = map[string]int{
+ "unix": syscall.AF_UNIX,
+ "TCP": syscall.SOCK_STREAM,
+ "UDP": syscall.SOCK_DGRAM,
+ "IPv4": syscall.AF_INET,
+ "IPv6": syscall.AF_INET6,
+}
+
+func (n IOCountersStat) String() string {
+ s, _ := json.Marshal(n)
+ return string(s)
+}
+
+func (n ConnectionStat) String() string {
+ s, _ := json.Marshal(n)
+ return string(s)
+}
+
+func (n ProtoCountersStat) String() string {
+ s, _ := json.Marshal(n)
+ return string(s)
+}
+
+func (a Addr) String() string {
+ s, _ := json.Marshal(a)
+ return string(s)
+}
+
+func (n InterfaceStat) String() string {
+ s, _ := json.Marshal(n)
+ return string(s)
+}
+
+func (n InterfaceAddr) String() string {
+ s, _ := json.Marshal(n)
+ return string(s)
+}
+
+func Interfaces() ([]InterfaceStat, error) {
+ return InterfacesWithContext(context.Background())
+}
+
+func InterfacesWithContext(ctx context.Context) ([]InterfaceStat, error) {
+ is, err := net.Interfaces()
+ if err != nil {
+ return nil, err
+ }
+ ret := make([]InterfaceStat, 0, len(is))
+ for _, ifi := range is {
+
+ var flags []string
+ if ifi.Flags&net.FlagUp != 0 {
+ flags = append(flags, "up")
+ }
+ if ifi.Flags&net.FlagBroadcast != 0 {
+ flags = append(flags, "broadcast")
+ }
+ if ifi.Flags&net.FlagLoopback != 0 {
+ flags = append(flags, "loopback")
+ }
+ if ifi.Flags&net.FlagPointToPoint != 0 {
+ flags = append(flags, "pointtopoint")
+ }
+ if ifi.Flags&net.FlagMulticast != 0 {
+ flags = append(flags, "multicast")
+ }
+
+ r := InterfaceStat{
+ Name: ifi.Name,
+ MTU: ifi.MTU,
+ HardwareAddr: ifi.HardwareAddr.String(),
+ Flags: flags,
+ }
+ addrs, err := ifi.Addrs()
+ if err == nil {
+ r.Addrs = make([]InterfaceAddr, 0, len(addrs))
+ for _, addr := range addrs {
+ r.Addrs = append(r.Addrs, InterfaceAddr{
+ Addr: addr.String(),
+ })
+ }
+
+ }
+ ret = append(ret, r)
+ }
+
+ return ret, nil
+}
+
+func getIOCountersAll(n []IOCountersStat) ([]IOCountersStat, error) {
+ r := IOCountersStat{
+ Name: "all",
+ }
+ for _, nic := range n {
+ r.BytesRecv += nic.BytesRecv
+ r.PacketsRecv += nic.PacketsRecv
+ r.Errin += nic.Errin
+ r.Dropin += nic.Dropin
+ r.BytesSent += nic.BytesSent
+ r.PacketsSent += nic.PacketsSent
+ r.Errout += nic.Errout
+ r.Dropout += nic.Dropout
+ }
+
+ return []IOCountersStat{r}, nil
+}
+
+func parseNetLine(line string) (ConnectionStat, error) {
+ f := strings.Fields(line)
+ if len(f) < 8 {
+ return ConnectionStat{}, fmt.Errorf("wrong line,%s", line)
+ }
+
+ if len(f) == 8 {
+ f = append(f, f[7])
+ f[7] = "unix"
+ }
+
+ pid, err := strconv.Atoi(f[1])
+ if err != nil {
+ return ConnectionStat{}, err
+ }
+ fd, err := strconv.Atoi(strings.Trim(f[3], "u"))
+ if err != nil {
+ return ConnectionStat{}, fmt.Errorf("unknown fd, %s", f[3])
+ }
+ netFamily, ok := constMap[f[4]]
+ if !ok {
+ return ConnectionStat{}, fmt.Errorf("unknown family, %s", f[4])
+ }
+ netType, ok := constMap[f[7]]
+ if !ok {
+ return ConnectionStat{}, fmt.Errorf("unknown type, %s", f[7])
+ }
+
+ var laddr, raddr Addr
+ if f[7] == "unix" {
+ laddr.IP = f[8]
+ } else {
+ laddr, raddr, err = parseNetAddr(f[8])
+ if err != nil {
+ return ConnectionStat{}, fmt.Errorf("failed to parse netaddr, %s", f[8])
+ }
+ }
+
+ n := ConnectionStat{
+ Fd: uint32(fd),
+ Family: uint32(netFamily),
+ Type: uint32(netType),
+ Laddr: laddr,
+ Raddr: raddr,
+ Pid: int32(pid),
+ }
+ if len(f) == 10 {
+ n.Status = strings.Trim(f[9], "()")
+ }
+
+ return n, nil
+}
+
+func parseNetAddr(line string) (laddr Addr, raddr Addr, err error) {
+ parse := func(l string) (Addr, error) {
+ host, port, err := net.SplitHostPort(l)
+ if err != nil {
+ return Addr{}, fmt.Errorf("wrong addr, %s", l)
+ }
+ lport, err := strconv.Atoi(port)
+ if err != nil {
+ return Addr{}, err
+ }
+ return Addr{IP: host, Port: uint32(lport)}, nil
+ }
+
+ addrs := strings.Split(line, "->")
+ if len(addrs) == 0 {
+ return laddr, raddr, fmt.Errorf("wrong netaddr, %s", line)
+ }
+ laddr, err = parse(addrs[0])
+ if len(addrs) == 2 { // remote addr exists
+ raddr, err = parse(addrs[1])
+ if err != nil {
+ return laddr, raddr, err
+ }
+ }
+
+ return laddr, raddr, err
+}
diff --git a/vendor/github.com/shirou/gopsutil/net/net_darwin.go b/vendor/github.com/shirou/gopsutil/net/net_darwin.go
new file mode 100644
index 0000000..0d89280
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/net/net_darwin.go
@@ -0,0 +1,284 @@
+// +build darwin
+
+package net
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "os/exec"
+ "regexp"
+ "strconv"
+ "strings"
+)
+
+var (
+ errNetstatHeader = errors.New("Can't parse header of netstat output")
+ netstatLinkRegexp = regexp.MustCompile(`^$`)
+)
+
+const endOfLine = "\n"
+
+func parseNetstatLine(line string) (stat *IOCountersStat, linkID *uint, err error) {
+ var (
+ numericValue uint64
+ columns = strings.Fields(line)
+ )
+
+ if columns[0] == "Name" {
+ err = errNetstatHeader
+ return
+ }
+
+ // try to extract the numeric value from
+ if subMatch := netstatLinkRegexp.FindStringSubmatch(columns[2]); len(subMatch) == 2 {
+ numericValue, err = strconv.ParseUint(subMatch[1], 10, 64)
+ if err != nil {
+ return
+ }
+ linkIDUint := uint(numericValue)
+ linkID = &linkIDUint
+ }
+
+ base := 1
+ numberColumns := len(columns)
+ // sometimes Address is ommitted
+ if numberColumns < 12 {
+ base = 0
+ }
+ if numberColumns < 11 || numberColumns > 13 {
+ err = fmt.Errorf("Line %q do have an invalid number of columns %d", line, numberColumns)
+ return
+ }
+
+ parsed := make([]uint64, 0, 7)
+ vv := []string{
+ columns[base+3], // Ipkts == PacketsRecv
+ columns[base+4], // Ierrs == Errin
+ columns[base+5], // Ibytes == BytesRecv
+ columns[base+6], // Opkts == PacketsSent
+ columns[base+7], // Oerrs == Errout
+ columns[base+8], // Obytes == BytesSent
+ }
+ if len(columns) == 12 {
+ vv = append(vv, columns[base+10])
+ }
+
+ for _, target := range vv {
+ if target == "-" {
+ parsed = append(parsed, 0)
+ continue
+ }
+
+ if numericValue, err = strconv.ParseUint(target, 10, 64); err != nil {
+ return
+ }
+ parsed = append(parsed, numericValue)
+ }
+
+ stat = &IOCountersStat{
+ Name: strings.Trim(columns[0], "*"), // remove the * that sometimes is on right on interface
+ PacketsRecv: parsed[0],
+ Errin: parsed[1],
+ BytesRecv: parsed[2],
+ PacketsSent: parsed[3],
+ Errout: parsed[4],
+ BytesSent: parsed[5],
+ }
+ if len(parsed) == 7 {
+ stat.Dropout = parsed[6]
+ }
+ return
+}
+
+type netstatInterface struct {
+ linkID *uint
+ stat *IOCountersStat
+}
+
+func parseNetstatOutput(output string) ([]netstatInterface, error) {
+ var (
+ err error
+ lines = strings.Split(strings.Trim(output, endOfLine), endOfLine)
+ )
+
+ // number of interfaces is number of lines less one for the header
+ numberInterfaces := len(lines) - 1
+
+ interfaces := make([]netstatInterface, numberInterfaces)
+ // no output beside header
+ if numberInterfaces == 0 {
+ return interfaces, nil
+ }
+
+ for index := 0; index < numberInterfaces; index++ {
+ nsIface := netstatInterface{}
+ if nsIface.stat, nsIface.linkID, err = parseNetstatLine(lines[index+1]); err != nil {
+ return nil, err
+ }
+ interfaces[index] = nsIface
+ }
+ return interfaces, nil
+}
+
+// map that hold the name of a network interface and the number of usage
+type mapInterfaceNameUsage map[string]uint
+
+func newMapInterfaceNameUsage(ifaces []netstatInterface) mapInterfaceNameUsage {
+ output := make(mapInterfaceNameUsage)
+ for index := range ifaces {
+ if ifaces[index].linkID != nil {
+ ifaceName := ifaces[index].stat.Name
+ usage, ok := output[ifaceName]
+ if ok {
+ output[ifaceName] = usage + 1
+ } else {
+ output[ifaceName] = 1
+ }
+ }
+ }
+ return output
+}
+
+func (min mapInterfaceNameUsage) isTruncated() bool {
+ for _, usage := range min {
+ if usage > 1 {
+ return true
+ }
+ }
+ return false
+}
+
+func (min mapInterfaceNameUsage) notTruncated() []string {
+ output := make([]string, 0)
+ for ifaceName, usage := range min {
+ if usage == 1 {
+ output = append(output, ifaceName)
+ }
+ }
+ return output
+}
+
+// example of `netstat -ibdnW` output on yosemite
+// Name Mtu Network Address Ipkts Ierrs Ibytes Opkts Oerrs Obytes Coll Drop
+// lo0 16384 869107 0 169411755 869107 0 169411755 0 0
+// lo0 16384 ::1/128 ::1 869107 - 169411755 869107 - 169411755 - -
+// lo0 16384 127 127.0.0.1 869107 - 169411755 869107 - 169411755 - -
+func IOCounters(pernic bool) ([]IOCountersStat, error) {
+ return IOCountersWithContext(context.Background(), pernic)
+}
+
+func IOCountersWithContext(ctx context.Context, pernic bool) ([]IOCountersStat, error) {
+ var (
+ ret []IOCountersStat
+ retIndex int
+ )
+
+ netstat, err := exec.LookPath("/usr/sbin/netstat")
+ if err != nil {
+ return nil, err
+ }
+
+ // try to get all interface metrics, and hope there won't be any truncated
+ out, err := invoke.CommandWithContext(ctx, netstat, "-ibdnW")
+ if err != nil {
+ return nil, err
+ }
+
+ nsInterfaces, err := parseNetstatOutput(string(out))
+ if err != nil {
+ return nil, err
+ }
+
+ ifaceUsage := newMapInterfaceNameUsage(nsInterfaces)
+ notTruncated := ifaceUsage.notTruncated()
+ ret = make([]IOCountersStat, len(notTruncated))
+
+ if !ifaceUsage.isTruncated() {
+ // no truncated interface name, return stats of all interface with
+ for index := range nsInterfaces {
+ if nsInterfaces[index].linkID != nil {
+ ret[retIndex] = *nsInterfaces[index].stat
+ retIndex++
+ }
+ }
+ } else {
+ // duplicated interface, list all interfaces
+ ifconfig, err := exec.LookPath("/sbin/ifconfig")
+ if err != nil {
+ return nil, err
+ }
+ if out, err = invoke.CommandWithContext(ctx, ifconfig, "-l"); err != nil {
+ return nil, err
+ }
+ interfaceNames := strings.Fields(strings.TrimRight(string(out), endOfLine))
+
+ // for each of the interface name, run netstat if we don't have any stats yet
+ for _, interfaceName := range interfaceNames {
+ truncated := true
+ for index := range nsInterfaces {
+ if nsInterfaces[index].linkID != nil && nsInterfaces[index].stat.Name == interfaceName {
+ // handle the non truncated name to avoid execute netstat for them again
+ ret[retIndex] = *nsInterfaces[index].stat
+ retIndex++
+ truncated = false
+ break
+ }
+ }
+ if truncated {
+ // run netstat with -I$ifacename
+ if out, err = invoke.CommandWithContext(ctx, netstat, "-ibdnWI"+interfaceName); err != nil {
+ return nil, err
+ }
+ parsedIfaces, err := parseNetstatOutput(string(out))
+ if err != nil {
+ return nil, err
+ }
+ if len(parsedIfaces) == 0 {
+ // interface had been removed since `ifconfig -l` had been executed
+ continue
+ }
+ for index := range parsedIfaces {
+ if parsedIfaces[index].linkID != nil {
+ ret = append(ret, *parsedIfaces[index].stat)
+ break
+ }
+ }
+ }
+ }
+ }
+
+ if pernic == false {
+ return getIOCountersAll(ret)
+ }
+ return ret, nil
+}
+
+// NetIOCountersByFile is an method which is added just a compatibility for linux.
+func IOCountersByFile(pernic bool, filename string) ([]IOCountersStat, error) {
+ return IOCountersByFileWithContext(context.Background(), pernic, filename)
+}
+
+func IOCountersByFileWithContext(ctx context.Context, pernic bool, filename string) ([]IOCountersStat, error) {
+ return IOCounters(pernic)
+}
+
+func FilterCounters() ([]FilterStat, error) {
+ return FilterCountersWithContext(context.Background())
+}
+
+func FilterCountersWithContext(ctx context.Context) ([]FilterStat, error) {
+ return nil, errors.New("NetFilterCounters not implemented for darwin")
+}
+
+// NetProtoCounters returns network statistics for the entire system
+// If protocols is empty then all protocols are returned, otherwise
+// just the protocols in the list are returned.
+// Not Implemented for Darwin
+func ProtoCounters(protocols []string) ([]ProtoCountersStat, error) {
+ return ProtoCountersWithContext(context.Background(), protocols)
+}
+
+func ProtoCountersWithContext(ctx context.Context, protocols []string) ([]ProtoCountersStat, error) {
+ return nil, errors.New("NetProtoCounters not implemented for darwin")
+}
diff --git a/vendor/github.com/shirou/gopsutil/net/net_fallback.go b/vendor/github.com/shirou/gopsutil/net/net_fallback.go
new file mode 100644
index 0000000..7c5e632
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/net/net_fallback.go
@@ -0,0 +1,49 @@
+// +build !darwin,!linux,!freebsd,!openbsd,!windows
+
+package net
+
+import (
+ "context"
+
+ "github.com/shirou/gopsutil/internal/common"
+)
+
+func IOCounters(pernic bool) ([]IOCountersStat, error) {
+ return IOCountersWithContext(context.Background(), pernic)
+}
+
+func IOCountersWithContext(ctx context.Context, pernic bool) ([]IOCountersStat, error) {
+ return []IOCountersStat{}, common.ErrNotImplementedError
+}
+
+func FilterCounters() ([]FilterStat, error) {
+ return FilterCountersWithContext(context.Background())
+}
+
+func FilterCountersWithContext(ctx context.Context) ([]FilterStat, error) {
+ return []FilterStat{}, common.ErrNotImplementedError
+}
+
+func ProtoCounters(protocols []string) ([]ProtoCountersStat, error) {
+ return ProtoCountersWithContext(context.Background(), protocols)
+}
+
+func ProtoCountersWithContext(ctx context.Context, protocols []string) ([]ProtoCountersStat, error) {
+ return []ProtoCountersStat{}, common.ErrNotImplementedError
+}
+
+func Connections(kind string) ([]ConnectionStat, error) {
+ return ConnectionsWithContext(context.Background(), kind)
+}
+
+func ConnectionsWithContext(ctx context.Context, kind string) ([]ConnectionStat, error) {
+ return []ConnectionStat{}, common.ErrNotImplementedError
+}
+
+func ConnectionsMax(kind string, max int) ([]ConnectionStat, error) {
+ return ConnectionsMaxWithContext(context.Background(), kind, max)
+}
+
+func ConnectionsMaxWithContext(ctx context.Context, kind string, max int) ([]ConnectionStat, error) {
+ return []ConnectionStat{}, common.ErrNotImplementedError
+}
diff --git a/vendor/github.com/shirou/gopsutil/net/net_freebsd.go b/vendor/github.com/shirou/gopsutil/net/net_freebsd.go
new file mode 100644
index 0000000..ce02415
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/net/net_freebsd.go
@@ -0,0 +1,125 @@
+// +build freebsd
+
+package net
+
+import (
+ "context"
+ "errors"
+ "os/exec"
+ "strconv"
+ "strings"
+
+ "github.com/shirou/gopsutil/internal/common"
+)
+
+func IOCounters(pernic bool) ([]IOCountersStat, error) {
+ return IOCountersWithContext(context.Background(), pernic)
+}
+
+func IOCountersWithContext(ctx context.Context, pernic bool) ([]IOCountersStat, error) {
+ netstat, err := exec.LookPath("/usr/bin/netstat")
+ if err != nil {
+ return nil, err
+ }
+ out, err := invoke.CommandWithContext(ctx, netstat, "-ibdnW")
+ if err != nil {
+ return nil, err
+ }
+
+ lines := strings.Split(string(out), "\n")
+ ret := make([]IOCountersStat, 0, len(lines)-1)
+ exists := make([]string, 0, len(ret))
+
+ for _, line := range lines {
+ values := strings.Fields(line)
+ if len(values) < 1 || values[0] == "Name" {
+ continue
+ }
+ if common.StringsHas(exists, values[0]) {
+ // skip if already get
+ continue
+ }
+ exists = append(exists, values[0])
+
+ if len(values) < 12 {
+ continue
+ }
+ base := 1
+ // sometimes Address is ommitted
+ if len(values) < 13 {
+ base = 0
+ }
+
+ parsed := make([]uint64, 0, 8)
+ vv := []string{
+ values[base+3], // PacketsRecv
+ values[base+4], // Errin
+ values[base+5], // Dropin
+ values[base+6], // BytesRecvn
+ values[base+7], // PacketSent
+ values[base+8], // Errout
+ values[base+9], // BytesSent
+ values[base+11], // Dropout
+ }
+ for _, target := range vv {
+ if target == "-" {
+ parsed = append(parsed, 0)
+ continue
+ }
+
+ t, err := strconv.ParseUint(target, 10, 64)
+ if err != nil {
+ return nil, err
+ }
+ parsed = append(parsed, t)
+ }
+
+ n := IOCountersStat{
+ Name: values[0],
+ PacketsRecv: parsed[0],
+ Errin: parsed[1],
+ Dropin: parsed[2],
+ BytesRecv: parsed[3],
+ PacketsSent: parsed[4],
+ Errout: parsed[5],
+ BytesSent: parsed[6],
+ Dropout: parsed[7],
+ }
+ ret = append(ret, n)
+ }
+
+ if pernic == false {
+ return getIOCountersAll(ret)
+ }
+
+ return ret, nil
+}
+
+// NetIOCountersByFile is an method which is added just a compatibility for linux.
+func IOCountersByFile(pernic bool, filename string) ([]IOCountersStat, error) {
+ return IOCountersByFileWithContext(context.Background(), pernic, filename)
+}
+
+func IOCountersByFileWithContext(ctx context.Context, pernic bool, filename string) ([]IOCountersStat, error) {
+ return IOCounters(pernic)
+}
+
+func FilterCounters() ([]FilterStat, error) {
+ return FilterCountersWithContext(context.Background())
+}
+
+func FilterCountersWithContext(ctx context.Context) ([]FilterStat, error) {
+ return nil, errors.New("NetFilterCounters not implemented for freebsd")
+}
+
+// NetProtoCounters returns network statistics for the entire system
+// If protocols is empty then all protocols are returned, otherwise
+// just the protocols in the list are returned.
+// Not Implemented for FreeBSD
+func ProtoCounters(protocols []string) ([]ProtoCountersStat, error) {
+ return ProtoCountersWithContext(context.Background(), protocols)
+}
+
+func ProtoCountersWithContext(ctx context.Context, protocols []string) ([]ProtoCountersStat, error) {
+ return nil, errors.New("NetProtoCounters not implemented for freebsd")
+}
diff --git a/vendor/github.com/shirou/gopsutil/net/net_linux.go b/vendor/github.com/shirou/gopsutil/net/net_linux.go
new file mode 100644
index 0000000..71842fb
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/net/net_linux.go
@@ -0,0 +1,793 @@
+// +build linux
+
+package net
+
+import (
+ "bytes"
+ "context"
+ "encoding/hex"
+ "errors"
+ "fmt"
+ "io/ioutil"
+ "net"
+ "os"
+ "strconv"
+ "strings"
+ "syscall"
+
+ "github.com/shirou/gopsutil/internal/common"
+)
+
+// NetIOCounters returnes network I/O statistics for every network
+// interface installed on the system. If pernic argument is false,
+// return only sum of all information (which name is 'all'). If true,
+// every network interface installed on the system is returned
+// separately.
+func IOCounters(pernic bool) ([]IOCountersStat, error) {
+ return IOCountersWithContext(context.Background(), pernic)
+}
+
+func IOCountersWithContext(ctx context.Context, pernic bool) ([]IOCountersStat, error) {
+ filename := common.HostProc("net/dev")
+ return IOCountersByFile(pernic, filename)
+}
+
+func IOCountersByFile(pernic bool, filename string) ([]IOCountersStat, error) {
+ return IOCountersByFileWithContext(context.Background(), pernic, filename)
+}
+
+func IOCountersByFileWithContext(ctx context.Context, pernic bool, filename string) ([]IOCountersStat, error) {
+ lines, err := common.ReadLines(filename)
+ if err != nil {
+ return nil, err
+ }
+
+ parts := make([]string, 2)
+
+ statlen := len(lines) - 1
+
+ ret := make([]IOCountersStat, 0, statlen)
+
+ for _, line := range lines[2:] {
+ separatorPos := strings.LastIndex(line, ":")
+ if separatorPos == -1 {
+ continue
+ }
+ parts[0] = line[0:separatorPos]
+ parts[1] = line[separatorPos+1:]
+
+ interfaceName := strings.TrimSpace(parts[0])
+ if interfaceName == "" {
+ continue
+ }
+
+ fields := strings.Fields(strings.TrimSpace(parts[1]))
+ bytesRecv, err := strconv.ParseUint(fields[0], 10, 64)
+ if err != nil {
+ return ret, err
+ }
+ packetsRecv, err := strconv.ParseUint(fields[1], 10, 64)
+ if err != nil {
+ return ret, err
+ }
+ errIn, err := strconv.ParseUint(fields[2], 10, 64)
+ if err != nil {
+ return ret, err
+ }
+ dropIn, err := strconv.ParseUint(fields[3], 10, 64)
+ if err != nil {
+ return ret, err
+ }
+ fifoIn, err := strconv.ParseUint(fields[4], 10, 64)
+ if err != nil {
+ return ret, err
+ }
+ bytesSent, err := strconv.ParseUint(fields[8], 10, 64)
+ if err != nil {
+ return ret, err
+ }
+ packetsSent, err := strconv.ParseUint(fields[9], 10, 64)
+ if err != nil {
+ return ret, err
+ }
+ errOut, err := strconv.ParseUint(fields[10], 10, 64)
+ if err != nil {
+ return ret, err
+ }
+ dropOut, err := strconv.ParseUint(fields[11], 10, 64)
+ if err != nil {
+ return ret, err
+ }
+ fifoOut, err := strconv.ParseUint(fields[12], 10, 64)
+ if err != nil {
+ return ret, err
+ }
+
+ nic := IOCountersStat{
+ Name: interfaceName,
+ BytesRecv: bytesRecv,
+ PacketsRecv: packetsRecv,
+ Errin: errIn,
+ Dropin: dropIn,
+ Fifoin: fifoIn,
+ BytesSent: bytesSent,
+ PacketsSent: packetsSent,
+ Errout: errOut,
+ Dropout: dropOut,
+ Fifoout: fifoOut,
+ }
+ ret = append(ret, nic)
+ }
+
+ if pernic == false {
+ return getIOCountersAll(ret)
+ }
+
+ return ret, nil
+}
+
+var netProtocols = []string{
+ "ip",
+ "icmp",
+ "icmpmsg",
+ "tcp",
+ "udp",
+ "udplite",
+}
+
+// NetProtoCounters returns network statistics for the entire system
+// If protocols is empty then all protocols are returned, otherwise
+// just the protocols in the list are returned.
+// Available protocols:
+// ip,icmp,icmpmsg,tcp,udp,udplite
+func ProtoCounters(protocols []string) ([]ProtoCountersStat, error) {
+ return ProtoCountersWithContext(context.Background(), protocols)
+}
+
+func ProtoCountersWithContext(ctx context.Context, protocols []string) ([]ProtoCountersStat, error) {
+ if len(protocols) == 0 {
+ protocols = netProtocols
+ }
+
+ stats := make([]ProtoCountersStat, 0, len(protocols))
+ protos := make(map[string]bool, len(protocols))
+ for _, p := range protocols {
+ protos[p] = true
+ }
+
+ filename := common.HostProc("net/snmp")
+ lines, err := common.ReadLines(filename)
+ if err != nil {
+ return nil, err
+ }
+
+ linecount := len(lines)
+ for i := 0; i < linecount; i++ {
+ line := lines[i]
+ r := strings.IndexRune(line, ':')
+ if r == -1 {
+ return nil, errors.New(filename + " is not fomatted correctly, expected ':'.")
+ }
+ proto := strings.ToLower(line[:r])
+ if !protos[proto] {
+ // skip protocol and data line
+ i++
+ continue
+ }
+
+ // Read header line
+ statNames := strings.Split(line[r+2:], " ")
+
+ // Read data line
+ i++
+ statValues := strings.Split(lines[i][r+2:], " ")
+ if len(statNames) != len(statValues) {
+ return nil, errors.New(filename + " is not fomatted correctly, expected same number of columns.")
+ }
+ stat := ProtoCountersStat{
+ Protocol: proto,
+ Stats: make(map[string]int64, len(statNames)),
+ }
+ for j := range statNames {
+ value, err := strconv.ParseInt(statValues[j], 10, 64)
+ if err != nil {
+ return nil, err
+ }
+ stat.Stats[statNames[j]] = value
+ }
+ stats = append(stats, stat)
+ }
+ return stats, nil
+}
+
+// NetFilterCounters returns iptables conntrack statistics
+// the currently in use conntrack count and the max.
+// If the file does not exist or is invalid it will return nil.
+func FilterCounters() ([]FilterStat, error) {
+ return FilterCountersWithContext(context.Background())
+}
+
+func FilterCountersWithContext(ctx context.Context) ([]FilterStat, error) {
+ countfile := common.HostProc("sys/net/netfilter/nf_conntrack_count")
+ maxfile := common.HostProc("sys/net/netfilter/nf_conntrack_max")
+
+ count, err := common.ReadInts(countfile)
+
+ if err != nil {
+ return nil, err
+ }
+ stats := make([]FilterStat, 0, 1)
+
+ max, err := common.ReadInts(maxfile)
+ if err != nil {
+ return nil, err
+ }
+
+ payload := FilterStat{
+ ConnTrackCount: count[0],
+ ConnTrackMax: max[0],
+ }
+
+ stats = append(stats, payload)
+ return stats, nil
+}
+
+// http://students.mimuw.edu.pl/lxr/source/include/net/tcp_states.h
+var TCPStatuses = map[string]string{
+ "01": "ESTABLISHED",
+ "02": "SYN_SENT",
+ "03": "SYN_RECV",
+ "04": "FIN_WAIT1",
+ "05": "FIN_WAIT2",
+ "06": "TIME_WAIT",
+ "07": "CLOSE",
+ "08": "CLOSE_WAIT",
+ "09": "LAST_ACK",
+ "0A": "LISTEN",
+ "0B": "CLOSING",
+}
+
+type netConnectionKindType struct {
+ family uint32
+ sockType uint32
+ filename string
+}
+
+var kindTCP4 = netConnectionKindType{
+ family: syscall.AF_INET,
+ sockType: syscall.SOCK_STREAM,
+ filename: "tcp",
+}
+var kindTCP6 = netConnectionKindType{
+ family: syscall.AF_INET6,
+ sockType: syscall.SOCK_STREAM,
+ filename: "tcp6",
+}
+var kindUDP4 = netConnectionKindType{
+ family: syscall.AF_INET,
+ sockType: syscall.SOCK_DGRAM,
+ filename: "udp",
+}
+var kindUDP6 = netConnectionKindType{
+ family: syscall.AF_INET6,
+ sockType: syscall.SOCK_DGRAM,
+ filename: "udp6",
+}
+var kindUNIX = netConnectionKindType{
+ family: syscall.AF_UNIX,
+ filename: "unix",
+}
+
+var netConnectionKindMap = map[string][]netConnectionKindType{
+ "all": {kindTCP4, kindTCP6, kindUDP4, kindUDP6, kindUNIX},
+ "tcp": {kindTCP4, kindTCP6},
+ "tcp4": {kindTCP4},
+ "tcp6": {kindTCP6},
+ "udp": {kindUDP4, kindUDP6},
+ "udp4": {kindUDP4},
+ "udp6": {kindUDP6},
+ "unix": {kindUNIX},
+ "inet": {kindTCP4, kindTCP6, kindUDP4, kindUDP6},
+ "inet4": {kindTCP4, kindUDP4},
+ "inet6": {kindTCP6, kindUDP6},
+}
+
+type inodeMap struct {
+ pid int32
+ fd uint32
+}
+
+type connTmp struct {
+ fd uint32
+ family uint32
+ sockType uint32
+ laddr Addr
+ raddr Addr
+ status string
+ pid int32
+ boundPid int32
+ path string
+}
+
+// Return a list of network connections opened.
+func Connections(kind string) ([]ConnectionStat, error) {
+ return ConnectionsWithContext(context.Background(), kind)
+}
+
+func ConnectionsWithContext(ctx context.Context, kind string) ([]ConnectionStat, error) {
+ return ConnectionsPid(kind, 0)
+}
+
+// Return a list of network connections opened returning at most `max`
+// connections for each running process.
+func ConnectionsMax(kind string, max int) ([]ConnectionStat, error) {
+ return ConnectionsMaxWithContext(context.Background(), kind, max)
+}
+
+func ConnectionsMaxWithContext(ctx context.Context, kind string, max int) ([]ConnectionStat, error) {
+ return ConnectionsPidMax(kind, 0, max)
+}
+
+// Return a list of network connections opened by a process.
+func ConnectionsPid(kind string, pid int32) ([]ConnectionStat, error) {
+ return ConnectionsPidWithContext(context.Background(), kind, pid)
+}
+
+func ConnectionsPidWithContext(ctx context.Context, kind string, pid int32) ([]ConnectionStat, error) {
+ tmap, ok := netConnectionKindMap[kind]
+ if !ok {
+ return nil, fmt.Errorf("invalid kind, %s", kind)
+ }
+ root := common.HostProc()
+ var err error
+ var inodes map[string][]inodeMap
+ if pid == 0 {
+ inodes, err = getProcInodesAll(root, 0)
+ } else {
+ inodes, err = getProcInodes(root, pid, 0)
+ if len(inodes) == 0 {
+ // no connection for the pid
+ return []ConnectionStat{}, nil
+ }
+ }
+ if err != nil {
+ return nil, fmt.Errorf("cound not get pid(s), %d: %s", pid, err)
+ }
+ return statsFromInodes(root, pid, tmap, inodes)
+}
+
+// Return up to `max` network connections opened by a process.
+func ConnectionsPidMax(kind string, pid int32, max int) ([]ConnectionStat, error) {
+ return ConnectionsPidMaxWithContext(context.Background(), kind, pid, max)
+}
+
+func ConnectionsPidMaxWithContext(ctx context.Context, kind string, pid int32, max int) ([]ConnectionStat, error) {
+ tmap, ok := netConnectionKindMap[kind]
+ if !ok {
+ return nil, fmt.Errorf("invalid kind, %s", kind)
+ }
+ root := common.HostProc()
+ var err error
+ var inodes map[string][]inodeMap
+ if pid == 0 {
+ inodes, err = getProcInodesAll(root, max)
+ } else {
+ inodes, err = getProcInodes(root, pid, max)
+ if len(inodes) == 0 {
+ // no connection for the pid
+ return []ConnectionStat{}, nil
+ }
+ }
+ if err != nil {
+ return nil, fmt.Errorf("cound not get pid(s), %d", pid)
+ }
+ return statsFromInodes(root, pid, tmap, inodes)
+}
+
+func statsFromInodes(root string, pid int32, tmap []netConnectionKindType, inodes map[string][]inodeMap) ([]ConnectionStat, error) {
+ dupCheckMap := make(map[string]struct{})
+ var ret []ConnectionStat
+
+ var err error
+ for _, t := range tmap {
+ var path string
+ var connKey string
+ var ls []connTmp
+ if pid == 0 {
+ path = fmt.Sprintf("%s/net/%s", root, t.filename)
+ } else {
+ path = fmt.Sprintf("%s/%d/net/%s", root, pid, t.filename)
+ }
+ switch t.family {
+ case syscall.AF_INET, syscall.AF_INET6:
+ ls, err = processInet(path, t, inodes, pid)
+ case syscall.AF_UNIX:
+ ls, err = processUnix(path, t, inodes, pid)
+ }
+ if err != nil {
+ return nil, err
+ }
+ for _, c := range ls {
+ // Build TCP key to id the connection uniquely
+ // socket type, src ip, src port, dst ip, dst port and state should be enough
+ // to prevent duplications.
+ connKey = fmt.Sprintf("%d-%s:%d-%s:%d-%s", c.sockType, c.laddr.IP, c.laddr.Port, c.raddr.IP, c.raddr.Port, c.status)
+ if _, ok := dupCheckMap[connKey]; ok {
+ continue
+ }
+
+ conn := ConnectionStat{
+ Fd: c.fd,
+ Family: c.family,
+ Type: c.sockType,
+ Laddr: c.laddr,
+ Raddr: c.raddr,
+ Status: c.status,
+ Pid: c.pid,
+ }
+ if c.pid == 0 {
+ conn.Pid = c.boundPid
+ } else {
+ conn.Pid = c.pid
+ }
+
+ // fetch process owner Real, effective, saved set, and filesystem UIDs
+ proc := process{Pid: conn.Pid}
+ conn.Uids, _ = proc.getUids()
+
+ ret = append(ret, conn)
+ dupCheckMap[connKey] = struct{}{}
+ }
+
+ }
+
+ return ret, nil
+}
+
+// getProcInodes returnes fd of the pid.
+func getProcInodes(root string, pid int32, max int) (map[string][]inodeMap, error) {
+ ret := make(map[string][]inodeMap)
+
+ dir := fmt.Sprintf("%s/%d/fd", root, pid)
+ f, err := os.Open(dir)
+ if err != nil {
+ return ret, err
+ }
+ defer f.Close()
+ files, err := f.Readdir(max)
+ if err != nil {
+ return ret, err
+ }
+ for _, fd := range files {
+ inodePath := fmt.Sprintf("%s/%d/fd/%s", root, pid, fd.Name())
+
+ inode, err := os.Readlink(inodePath)
+ if err != nil {
+ continue
+ }
+ if !strings.HasPrefix(inode, "socket:[") {
+ continue
+ }
+ // the process is using a socket
+ l := len(inode)
+ inode = inode[8 : l-1]
+ _, ok := ret[inode]
+ if !ok {
+ ret[inode] = make([]inodeMap, 0)
+ }
+ fd, err := strconv.Atoi(fd.Name())
+ if err != nil {
+ continue
+ }
+
+ i := inodeMap{
+ pid: pid,
+ fd: uint32(fd),
+ }
+ ret[inode] = append(ret[inode], i)
+ }
+ return ret, nil
+}
+
+// Pids retunres all pids.
+// Note: this is a copy of process_linux.Pids()
+// FIXME: Import process occures import cycle.
+// move to common made other platform breaking. Need consider.
+func Pids() ([]int32, error) {
+ return PidsWithContext(context.Background())
+}
+
+func PidsWithContext(ctx context.Context) ([]int32, error) {
+ var ret []int32
+
+ d, err := os.Open(common.HostProc())
+ if err != nil {
+ return nil, err
+ }
+ defer d.Close()
+
+ fnames, err := d.Readdirnames(-1)
+ if err != nil {
+ return nil, err
+ }
+ for _, fname := range fnames {
+ pid, err := strconv.ParseInt(fname, 10, 32)
+ if err != nil {
+ // if not numeric name, just skip
+ continue
+ }
+ ret = append(ret, int32(pid))
+ }
+
+ return ret, nil
+}
+
+// Note: the following is based off process_linux structs and methods
+// we need these to fetch the owner of a process ID
+// FIXME: Import process occures import cycle.
+// see remarks on pids()
+type process struct {
+ Pid int32 `json:"pid"`
+ uids []int32
+}
+
+// Uids returns user ids of the process as a slice of the int
+func (p *process) getUids() ([]int32, error) {
+ err := p.fillFromStatus()
+ if err != nil {
+ return []int32{}, err
+ }
+ return p.uids, nil
+}
+
+// Get status from /proc/(pid)/status
+func (p *process) fillFromStatus() error {
+ pid := p.Pid
+ statPath := common.HostProc(strconv.Itoa(int(pid)), "status")
+ contents, err := ioutil.ReadFile(statPath)
+ if err != nil {
+ return err
+ }
+ lines := strings.Split(string(contents), "\n")
+ for _, line := range lines {
+ tabParts := strings.SplitN(line, "\t", 2)
+ if len(tabParts) < 2 {
+ continue
+ }
+ value := tabParts[1]
+ switch strings.TrimRight(tabParts[0], ":") {
+ case "Uid":
+ p.uids = make([]int32, 0, 4)
+ for _, i := range strings.Split(value, "\t") {
+ v, err := strconv.ParseInt(i, 10, 32)
+ if err != nil {
+ return err
+ }
+ p.uids = append(p.uids, int32(v))
+ }
+ }
+ }
+ return nil
+}
+
+func getProcInodesAll(root string, max int) (map[string][]inodeMap, error) {
+ pids, err := Pids()
+ if err != nil {
+ return nil, err
+ }
+ ret := make(map[string][]inodeMap)
+
+ for _, pid := range pids {
+ t, err := getProcInodes(root, pid, max)
+ if err != nil {
+ // skip if permission error or no longer exists
+ if os.IsPermission(err) || os.IsNotExist(err) {
+ continue
+ }
+ return ret, err
+ }
+ if len(t) == 0 {
+ continue
+ }
+ // TODO: update ret.
+ ret = updateMap(ret, t)
+ }
+ return ret, nil
+}
+
+// decodeAddress decode addresse represents addr in proc/net/*
+// ex:
+// "0500000A:0016" -> "10.0.0.5", 22
+// "0085002452100113070057A13F025401:0035" -> "2400:8500:1301:1052:a157:7:154:23f", 53
+func decodeAddress(family uint32, src string) (Addr, error) {
+ t := strings.Split(src, ":")
+ if len(t) != 2 {
+ return Addr{}, fmt.Errorf("does not contain port, %s", src)
+ }
+ addr := t[0]
+ port, err := strconv.ParseInt("0x"+t[1], 0, 64)
+ if err != nil {
+ return Addr{}, fmt.Errorf("invalid port, %s", src)
+ }
+ decoded, err := hex.DecodeString(addr)
+ if err != nil {
+ return Addr{}, fmt.Errorf("decode error, %s", err)
+ }
+ var ip net.IP
+ // Assumes this is little_endian
+ if family == syscall.AF_INET {
+ ip = net.IP(Reverse(decoded))
+ } else { // IPv6
+ ip, err = parseIPv6HexString(decoded)
+ if err != nil {
+ return Addr{}, err
+ }
+ }
+ return Addr{
+ IP: ip.String(),
+ Port: uint32(port),
+ }, nil
+}
+
+// Reverse reverses array of bytes.
+func Reverse(s []byte) []byte {
+ return ReverseWithContext(context.Background(), s)
+}
+
+func ReverseWithContext(ctx context.Context, s []byte) []byte {
+ for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 {
+ s[i], s[j] = s[j], s[i]
+ }
+ return s
+}
+
+// parseIPv6HexString parse array of bytes to IPv6 string
+func parseIPv6HexString(src []byte) (net.IP, error) {
+ if len(src) != 16 {
+ return nil, fmt.Errorf("invalid IPv6 string")
+ }
+
+ buf := make([]byte, 0, 16)
+ for i := 0; i < len(src); i += 4 {
+ r := Reverse(src[i : i+4])
+ buf = append(buf, r...)
+ }
+ return net.IP(buf), nil
+}
+
+func processInet(file string, kind netConnectionKindType, inodes map[string][]inodeMap, filterPid int32) ([]connTmp, error) {
+
+ if strings.HasSuffix(file, "6") && !common.PathExists(file) {
+ // IPv6 not supported, return empty.
+ return []connTmp{}, nil
+ }
+
+ // Read the contents of the /proc file with a single read sys call.
+ // This minimizes duplicates in the returned connections
+ // For more info:
+ // https://github.com/shirou/gopsutil/pull/361
+ contents, err := ioutil.ReadFile(file)
+ if err != nil {
+ return nil, err
+ }
+
+ lines := bytes.Split(contents, []byte("\n"))
+
+ var ret []connTmp
+ // skip first line
+ for _, line := range lines[1:] {
+ l := strings.Fields(string(line))
+ if len(l) < 10 {
+ continue
+ }
+ laddr := l[1]
+ raddr := l[2]
+ status := l[3]
+ inode := l[9]
+ pid := int32(0)
+ fd := uint32(0)
+ i, exists := inodes[inode]
+ if exists {
+ pid = i[0].pid
+ fd = i[0].fd
+ }
+ if filterPid > 0 && filterPid != pid {
+ continue
+ }
+ if kind.sockType == syscall.SOCK_STREAM {
+ status = TCPStatuses[status]
+ } else {
+ status = "NONE"
+ }
+ la, err := decodeAddress(kind.family, laddr)
+ if err != nil {
+ continue
+ }
+ ra, err := decodeAddress(kind.family, raddr)
+ if err != nil {
+ continue
+ }
+
+ ret = append(ret, connTmp{
+ fd: fd,
+ family: kind.family,
+ sockType: kind.sockType,
+ laddr: la,
+ raddr: ra,
+ status: status,
+ pid: pid,
+ })
+ }
+
+ return ret, nil
+}
+
+func processUnix(file string, kind netConnectionKindType, inodes map[string][]inodeMap, filterPid int32) ([]connTmp, error) {
+ // Read the contents of the /proc file with a single read sys call.
+ // This minimizes duplicates in the returned connections
+ // For more info:
+ // https://github.com/shirou/gopsutil/pull/361
+ contents, err := ioutil.ReadFile(file)
+ if err != nil {
+ return nil, err
+ }
+
+ lines := bytes.Split(contents, []byte("\n"))
+
+ var ret []connTmp
+ // skip first line
+ for _, line := range lines[1:] {
+ tokens := strings.Fields(string(line))
+ if len(tokens) < 6 {
+ continue
+ }
+ st, err := strconv.Atoi(tokens[4])
+ if err != nil {
+ return nil, err
+ }
+
+ inode := tokens[6]
+
+ var pairs []inodeMap
+ pairs, exists := inodes[inode]
+ if !exists {
+ pairs = []inodeMap{
+ {},
+ }
+ }
+ for _, pair := range pairs {
+ if filterPid > 0 && filterPid != pair.pid {
+ continue
+ }
+ var path string
+ if len(tokens) == 8 {
+ path = tokens[len(tokens)-1]
+ }
+ ret = append(ret, connTmp{
+ fd: pair.fd,
+ family: kind.family,
+ sockType: uint32(st),
+ laddr: Addr{
+ IP: path,
+ },
+ pid: pair.pid,
+ status: "NONE",
+ path: path,
+ })
+ }
+ }
+
+ return ret, nil
+}
+
+func updateMap(src map[string][]inodeMap, add map[string][]inodeMap) map[string][]inodeMap {
+ for key, value := range add {
+ a, exists := src[key]
+ if !exists {
+ src[key] = value
+ continue
+ }
+ src[key] = append(a, value...)
+ }
+ return src
+}
diff --git a/vendor/github.com/shirou/gopsutil/net/net_openbsd.go b/vendor/github.com/shirou/gopsutil/net/net_openbsd.go
new file mode 100644
index 0000000..3e74e8f
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/net/net_openbsd.go
@@ -0,0 +1,312 @@
+// +build openbsd
+
+package net
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "os/exec"
+ "regexp"
+ "strconv"
+ "strings"
+ "syscall"
+
+ "github.com/shirou/gopsutil/internal/common"
+)
+
+var portMatch = regexp.MustCompile(`(.*)\.(\d+)$`)
+
+func ParseNetstat(output string, mode string,
+ iocs map[string]IOCountersStat) error {
+ lines := strings.Split(output, "\n")
+
+ exists := make([]string, 0, len(lines)-1)
+
+ columns := 6
+ if mode == "ind" {
+ columns = 10
+ }
+ for _, line := range lines {
+ values := strings.Fields(line)
+ if len(values) < 1 || values[0] == "Name" {
+ continue
+ }
+ if common.StringsHas(exists, values[0]) {
+ // skip if already get
+ continue
+ }
+
+ if len(values) < columns {
+ continue
+ }
+ base := 1
+ // sometimes Address is ommitted
+ if len(values) < columns {
+ base = 0
+ }
+
+ parsed := make([]uint64, 0, 8)
+ var vv []string
+ if mode == "inb" {
+ vv = []string{
+ values[base+3], // BytesRecv
+ values[base+4], // BytesSent
+ }
+ } else {
+ vv = []string{
+ values[base+3], // Ipkts
+ values[base+4], // Ierrs
+ values[base+5], // Opkts
+ values[base+6], // Oerrs
+ values[base+8], // Drops
+ }
+ }
+ for _, target := range vv {
+ if target == "-" {
+ parsed = append(parsed, 0)
+ continue
+ }
+
+ t, err := strconv.ParseUint(target, 10, 64)
+ if err != nil {
+ return err
+ }
+ parsed = append(parsed, t)
+ }
+ exists = append(exists, values[0])
+
+ n, present := iocs[values[0]]
+ if !present {
+ n = IOCountersStat{Name: values[0]}
+ }
+ if mode == "inb" {
+ n.BytesRecv = parsed[0]
+ n.BytesSent = parsed[1]
+ } else {
+ n.PacketsRecv = parsed[0]
+ n.Errin = parsed[1]
+ n.PacketsSent = parsed[2]
+ n.Errout = parsed[3]
+ n.Dropin = parsed[4]
+ n.Dropout = parsed[4]
+ }
+
+ iocs[n.Name] = n
+ }
+ return nil
+}
+
+func IOCounters(pernic bool) ([]IOCountersStat, error) {
+ return IOCountersWithContext(context.Background(), pernic)
+}
+
+func IOCountersWithContext(ctx context.Context, pernic bool) ([]IOCountersStat, error) {
+ netstat, err := exec.LookPath("netstat")
+ if err != nil {
+ return nil, err
+ }
+ out, err := invoke.CommandWithContext(ctx, netstat, "-inb")
+ if err != nil {
+ return nil, err
+ }
+ out2, err := invoke.CommandWithContext(ctx, netstat, "-ind")
+ if err != nil {
+ return nil, err
+ }
+ iocs := make(map[string]IOCountersStat)
+
+ lines := strings.Split(string(out), "\n")
+ ret := make([]IOCountersStat, 0, len(lines)-1)
+
+ err = ParseNetstat(string(out), "inb", iocs)
+ if err != nil {
+ return nil, err
+ }
+ err = ParseNetstat(string(out2), "ind", iocs)
+ if err != nil {
+ return nil, err
+ }
+
+ for _, ioc := range iocs {
+ ret = append(ret, ioc)
+ }
+
+ if pernic == false {
+ return getIOCountersAll(ret)
+ }
+
+ return ret, nil
+}
+
+// NetIOCountersByFile is an method which is added just a compatibility for linux.
+func IOCountersByFile(pernic bool, filename string) ([]IOCountersStat, error) {
+ return IOCountersByFileWithContext(context.Background(), pernic, filename)
+}
+
+func IOCountersByFileWithContext(ctx context.Context, pernic bool, filename string) ([]IOCountersStat, error) {
+ return IOCounters(pernic)
+}
+
+func FilterCounters() ([]FilterStat, error) {
+ return FilterCountersWithContext(context.Background())
+}
+
+func FilterCountersWithContext(ctx context.Context) ([]FilterStat, error) {
+ return nil, errors.New("NetFilterCounters not implemented for openbsd")
+}
+
+// NetProtoCounters returns network statistics for the entire system
+// If protocols is empty then all protocols are returned, otherwise
+// just the protocols in the list are returned.
+// Not Implemented for OpenBSD
+func ProtoCounters(protocols []string) ([]ProtoCountersStat, error) {
+ return ProtoCountersWithContext(context.Background(), protocols)
+}
+
+func ProtoCountersWithContext(ctx context.Context, protocols []string) ([]ProtoCountersStat, error) {
+ return nil, errors.New("NetProtoCounters not implemented for openbsd")
+}
+
+func parseNetstatLine(line string) (ConnectionStat, error) {
+ f := strings.Fields(line)
+ if len(f) < 5 {
+ return ConnectionStat{}, fmt.Errorf("wrong line,%s", line)
+ }
+
+ var netType, netFamily uint32
+ switch f[0] {
+ case "tcp":
+ netType = syscall.SOCK_STREAM
+ netFamily = syscall.AF_INET
+ case "udp":
+ netType = syscall.SOCK_DGRAM
+ netFamily = syscall.AF_INET
+ case "tcp6":
+ netType = syscall.SOCK_STREAM
+ netFamily = syscall.AF_INET6
+ case "udp6":
+ netType = syscall.SOCK_DGRAM
+ netFamily = syscall.AF_INET6
+ default:
+ return ConnectionStat{}, fmt.Errorf("unknown type, %s", f[0])
+ }
+
+ laddr, raddr, err := parseNetstatAddr(f[3], f[4], netFamily)
+ if err != nil {
+ return ConnectionStat{}, fmt.Errorf("failed to parse netaddr, %s %s", f[3], f[4])
+ }
+
+ n := ConnectionStat{
+ Fd: uint32(0), // not supported
+ Family: uint32(netFamily),
+ Type: uint32(netType),
+ Laddr: laddr,
+ Raddr: raddr,
+ Pid: int32(0), // not supported
+ }
+ if len(f) == 6 {
+ n.Status = f[5]
+ }
+
+ return n, nil
+}
+
+func parseNetstatAddr(local string, remote string, family uint32) (laddr Addr, raddr Addr, err error) {
+ parse := func(l string) (Addr, error) {
+ matches := portMatch.FindStringSubmatch(l)
+ if matches == nil {
+ return Addr{}, fmt.Errorf("wrong addr, %s", l)
+ }
+ host := matches[1]
+ port := matches[2]
+ if host == "*" {
+ switch family {
+ case syscall.AF_INET:
+ host = "0.0.0.0"
+ case syscall.AF_INET6:
+ host = "::"
+ default:
+ return Addr{}, fmt.Errorf("unknown family, %d", family)
+ }
+ }
+ lport, err := strconv.Atoi(port)
+ if err != nil {
+ return Addr{}, err
+ }
+ return Addr{IP: host, Port: uint32(lport)}, nil
+ }
+
+ laddr, err = parse(local)
+ if remote != "*.*" { // remote addr exists
+ raddr, err = parse(remote)
+ if err != nil {
+ return laddr, raddr, err
+ }
+ }
+
+ return laddr, raddr, err
+}
+
+// Return a list of network connections opened.
+func Connections(kind string) ([]ConnectionStat, error) {
+ return ConnectionsWithContext(context.Background(), kind)
+}
+
+func ConnectionsWithContext(ctx context.Context, kind string) ([]ConnectionStat, error) {
+ var ret []ConnectionStat
+
+ args := []string{"-na"}
+ switch strings.ToLower(kind) {
+ default:
+ fallthrough
+ case "":
+ fallthrough
+ case "all":
+ fallthrough
+ case "inet":
+ // nothing to add
+ case "inet4":
+ args = append(args, "-finet")
+ case "inet6":
+ args = append(args, "-finet6")
+ case "tcp":
+ args = append(args, "-ptcp")
+ case "tcp4":
+ args = append(args, "-ptcp", "-finet")
+ case "tcp6":
+ args = append(args, "-ptcp", "-finet6")
+ case "udp":
+ args = append(args, "-pudp")
+ case "udp4":
+ args = append(args, "-pudp", "-finet")
+ case "udp6":
+ args = append(args, "-pudp", "-finet6")
+ case "unix":
+ return ret, common.ErrNotImplementedError
+ }
+
+ netstat, err := exec.LookPath("netstat")
+ if err != nil {
+ return nil, err
+ }
+ out, err := invoke.CommandWithContext(ctx, netstat, args...)
+
+ if err != nil {
+ return nil, err
+ }
+ lines := strings.Split(string(out), "\n")
+ for _, line := range lines {
+ if !(strings.HasPrefix(line, "tcp") || strings.HasPrefix(line, "udp")) {
+ continue
+ }
+ n, err := parseNetstatLine(line)
+ if err != nil {
+ continue
+ }
+
+ ret = append(ret, n)
+ }
+
+ return ret, nil
+}
diff --git a/vendor/github.com/shirou/gopsutil/net/net_unix.go b/vendor/github.com/shirou/gopsutil/net/net_unix.go
new file mode 100644
index 0000000..4451b54
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/net/net_unix.go
@@ -0,0 +1,96 @@
+// +build freebsd darwin
+
+package net
+
+import (
+ "context"
+ "strings"
+
+ "github.com/shirou/gopsutil/internal/common"
+)
+
+// Return a list of network connections opened.
+func Connections(kind string) ([]ConnectionStat, error) {
+ return ConnectionsWithContext(context.Background(), kind)
+}
+
+func ConnectionsWithContext(ctx context.Context, kind string) ([]ConnectionStat, error) {
+ return ConnectionsPid(kind, 0)
+}
+
+// Return a list of network connections opened returning at most `max`
+// connections for each running process.
+func ConnectionsMax(kind string, max int) ([]ConnectionStat, error) {
+ return ConnectionsMaxWithContext(context.Background(), kind, max)
+}
+
+func ConnectionsMaxWithContext(ctx context.Context, kind string, max int) ([]ConnectionStat, error) {
+ return []ConnectionStat{}, common.ErrNotImplementedError
+}
+
+// Return a list of network connections opened by a process.
+func ConnectionsPid(kind string, pid int32) ([]ConnectionStat, error) {
+ return ConnectionsPidWithContext(context.Background(), kind, pid)
+}
+
+func ConnectionsPidWithContext(ctx context.Context, kind string, pid int32) ([]ConnectionStat, error) {
+ var ret []ConnectionStat
+
+ args := []string{"-i"}
+ switch strings.ToLower(kind) {
+ default:
+ fallthrough
+ case "":
+ fallthrough
+ case "all":
+ fallthrough
+ case "inet":
+ args = append(args, "tcp", "-i", "udp")
+ case "inet4":
+ args = append(args, "4")
+ case "inet6":
+ args = append(args, "6")
+ case "tcp":
+ args = append(args, "tcp")
+ case "tcp4":
+ args = append(args, "4tcp")
+ case "tcp6":
+ args = append(args, "6tcp")
+ case "udp":
+ args = append(args, "udp")
+ case "udp4":
+ args = append(args, "6udp")
+ case "udp6":
+ args = append(args, "6udp")
+ case "unix":
+ args = []string{"-U"}
+ }
+
+ r, err := common.CallLsofWithContext(ctx, invoke, pid, args...)
+ if err != nil {
+ return nil, err
+ }
+ for _, rr := range r {
+ if strings.HasPrefix(rr, "COMMAND") {
+ continue
+ }
+ n, err := parseNetLine(rr)
+ if err != nil {
+
+ continue
+ }
+
+ ret = append(ret, n)
+ }
+
+ return ret, nil
+}
+
+// Return up to `max` network connections opened by a process.
+func ConnectionsPidMax(kind string, pid int32, max int) ([]ConnectionStat, error) {
+ return ConnectionsPidMaxWithContext(context.Background(), kind, pid, max)
+}
+
+func ConnectionsPidMaxWithContext(ctx context.Context, kind string, pid int32, max int) ([]ConnectionStat, error) {
+ return []ConnectionStat{}, common.ErrNotImplementedError
+}
diff --git a/vendor/github.com/shirou/gopsutil/net/net_windows.go b/vendor/github.com/shirou/gopsutil/net/net_windows.go
new file mode 100644
index 0000000..61eb6ec
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/net/net_windows.go
@@ -0,0 +1,645 @@
+// +build windows
+
+package net
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "net"
+ "os"
+ "syscall"
+ "unsafe"
+
+ "github.com/shirou/gopsutil/internal/common"
+ "golang.org/x/sys/windows"
+)
+
+var (
+ modiphlpapi = windows.NewLazySystemDLL("iphlpapi.dll")
+ procGetExtendedTCPTable = modiphlpapi.NewProc("GetExtendedTcpTable")
+ procGetExtendedUDPTable = modiphlpapi.NewProc("GetExtendedUdpTable")
+)
+
+const (
+ TCPTableBasicListener = iota
+ TCPTableBasicConnections
+ TCPTableBasicAll
+ TCPTableOwnerPIDListener
+ TCPTableOwnerPIDConnections
+ TCPTableOwnerPIDAll
+ TCPTableOwnerModuleListener
+ TCPTableOwnerModuleConnections
+ TCPTableOwnerModuleAll
+)
+
+type netConnectionKindType struct {
+ family uint32
+ sockType uint32
+ filename string
+}
+
+var kindTCP4 = netConnectionKindType{
+ family: syscall.AF_INET,
+ sockType: syscall.SOCK_STREAM,
+ filename: "tcp",
+}
+var kindTCP6 = netConnectionKindType{
+ family: syscall.AF_INET6,
+ sockType: syscall.SOCK_STREAM,
+ filename: "tcp6",
+}
+var kindUDP4 = netConnectionKindType{
+ family: syscall.AF_INET,
+ sockType: syscall.SOCK_DGRAM,
+ filename: "udp",
+}
+var kindUDP6 = netConnectionKindType{
+ family: syscall.AF_INET6,
+ sockType: syscall.SOCK_DGRAM,
+ filename: "udp6",
+}
+
+var netConnectionKindMap = map[string][]netConnectionKindType{
+ "all": {kindTCP4, kindTCP6, kindUDP4, kindUDP6},
+ "tcp": {kindTCP4, kindTCP6},
+ "tcp4": {kindTCP4},
+ "tcp6": {kindTCP6},
+ "udp": {kindUDP4, kindUDP6},
+ "udp4": {kindUDP4},
+ "udp6": {kindUDP6},
+ "inet": {kindTCP4, kindTCP6, kindUDP4, kindUDP6},
+ "inet4": {kindTCP4, kindUDP4},
+ "inet6": {kindTCP6, kindUDP6},
+}
+
+func IOCounters(pernic bool) ([]IOCountersStat, error) {
+ return IOCountersWithContext(context.Background(), pernic)
+}
+
+func IOCountersWithContext(ctx context.Context, pernic bool) ([]IOCountersStat, error) {
+ ifs, err := net.Interfaces()
+ if err != nil {
+ return nil, err
+ }
+ var ret []IOCountersStat
+
+ for _, ifi := range ifs {
+ c := IOCountersStat{
+ Name: ifi.Name,
+ }
+
+ row := windows.MibIfRow{Index: uint32(ifi.Index)}
+ e := windows.GetIfEntry(&row)
+ if e != nil {
+ return nil, os.NewSyscallError("GetIfEntry", e)
+ }
+ c.BytesSent = uint64(row.OutOctets)
+ c.BytesRecv = uint64(row.InOctets)
+ c.PacketsSent = uint64(row.OutUcastPkts)
+ c.PacketsRecv = uint64(row.InUcastPkts)
+ c.Errin = uint64(row.InErrors)
+ c.Errout = uint64(row.OutErrors)
+ c.Dropin = uint64(row.InDiscards)
+ c.Dropout = uint64(row.OutDiscards)
+
+ ret = append(ret, c)
+ }
+
+ if pernic == false {
+ return getIOCountersAll(ret)
+ }
+ return ret, nil
+}
+
+// NetIOCountersByFile is an method which is added just a compatibility for linux.
+func IOCountersByFile(pernic bool, filename string) ([]IOCountersStat, error) {
+ return IOCountersByFileWithContext(context.Background(), pernic, filename)
+}
+
+func IOCountersByFileWithContext(ctx context.Context, pernic bool, filename string) ([]IOCountersStat, error) {
+ return IOCounters(pernic)
+}
+
+// Return a list of network connections
+// Available kind:
+// reference to netConnectionKindMap
+func Connections(kind string) ([]ConnectionStat, error) {
+ return ConnectionsWithContext(context.Background(), kind)
+}
+
+func ConnectionsWithContext(ctx context.Context, kind string) ([]ConnectionStat, error) {
+ return ConnectionsPidWithContext(ctx, kind, 0)
+}
+
+// ConnectionsPid Return a list of network connections opened by a process
+func ConnectionsPid(kind string, pid int32) ([]ConnectionStat, error) {
+ return ConnectionsPidWithContext(context.Background(), kind, pid)
+}
+
+func ConnectionsPidWithContext(ctx context.Context, kind string, pid int32) ([]ConnectionStat, error) {
+ tmap, ok := netConnectionKindMap[kind]
+ if !ok {
+ return nil, fmt.Errorf("invalid kind, %s", kind)
+ }
+ return getProcInet(tmap, pid)
+}
+
+func getProcInet(kinds []netConnectionKindType, pid int32) ([]ConnectionStat, error) {
+ stats := make([]ConnectionStat, 0)
+
+ for _, kind := range kinds {
+ s, err := getNetStatWithKind(kind)
+ if err != nil {
+ continue
+ }
+
+ if pid == 0 {
+ stats = append(stats, s...)
+ } else {
+ for _, ns := range s {
+ if ns.Pid != pid {
+ continue
+ }
+ stats = append(stats, ns)
+ }
+ }
+ }
+
+ return stats, nil
+}
+
+func getNetStatWithKind(kindType netConnectionKindType) ([]ConnectionStat, error) {
+ if kindType.filename == "" {
+ return nil, fmt.Errorf("kind filename must be required")
+ }
+
+ switch kindType.filename {
+ case kindTCP4.filename:
+ return getTCPConnections(kindTCP4.family)
+ case kindTCP6.filename:
+ return getTCPConnections(kindTCP6.family)
+ case kindUDP4.filename:
+ return getUDPConnections(kindUDP4.family)
+ case kindUDP6.filename:
+ return getUDPConnections(kindUDP6.family)
+ }
+
+ return nil, fmt.Errorf("invalid kind filename, %s", kindType.filename)
+}
+
+// Return a list of network connections opened returning at most `max`
+// connections for each running process.
+func ConnectionsMax(kind string, max int) ([]ConnectionStat, error) {
+ return ConnectionsMaxWithContext(context.Background(), kind, max)
+}
+
+func ConnectionsMaxWithContext(ctx context.Context, kind string, max int) ([]ConnectionStat, error) {
+ return []ConnectionStat{}, common.ErrNotImplementedError
+}
+
+func FilterCounters() ([]FilterStat, error) {
+ return FilterCountersWithContext(context.Background())
+}
+
+func FilterCountersWithContext(ctx context.Context) ([]FilterStat, error) {
+ return nil, errors.New("NetFilterCounters not implemented for windows")
+}
+
+// NetProtoCounters returns network statistics for the entire system
+// If protocols is empty then all protocols are returned, otherwise
+// just the protocols in the list are returned.
+// Not Implemented for Windows
+func ProtoCounters(protocols []string) ([]ProtoCountersStat, error) {
+ return ProtoCountersWithContext(context.Background(), protocols)
+}
+
+func ProtoCountersWithContext(ctx context.Context, protocols []string) ([]ProtoCountersStat, error) {
+ return nil, errors.New("NetProtoCounters not implemented for windows")
+}
+
+func getTableUintptr(family uint32, buf []byte) uintptr {
+ var (
+ pmibTCPTable pmibTCPTableOwnerPidAll
+ pmibTCP6Table pmibTCP6TableOwnerPidAll
+
+ p uintptr
+ )
+ switch family {
+ case kindTCP4.family:
+ if len(buf) > 0 {
+ pmibTCPTable = (*mibTCPTableOwnerPid)(unsafe.Pointer(&buf[0]))
+ p = uintptr(unsafe.Pointer(pmibTCPTable))
+ } else {
+ p = uintptr(unsafe.Pointer(pmibTCPTable))
+ }
+ case kindTCP6.family:
+ if len(buf) > 0 {
+ pmibTCP6Table = (*mibTCP6TableOwnerPid)(unsafe.Pointer(&buf[0]))
+ p = uintptr(unsafe.Pointer(pmibTCP6Table))
+ } else {
+ p = uintptr(unsafe.Pointer(pmibTCP6Table))
+ }
+ }
+ return p
+}
+
+func getTableInfo(filename string, table interface{}) (index, step, length int) {
+ switch filename {
+ case kindTCP4.filename:
+ index = int(unsafe.Sizeof(table.(pmibTCPTableOwnerPidAll).DwNumEntries))
+ step = int(unsafe.Sizeof(table.(pmibTCPTableOwnerPidAll).Table))
+ length = int(table.(pmibTCPTableOwnerPidAll).DwNumEntries)
+ case kindTCP6.filename:
+ index = int(unsafe.Sizeof(table.(pmibTCP6TableOwnerPidAll).DwNumEntries))
+ step = int(unsafe.Sizeof(table.(pmibTCP6TableOwnerPidAll).Table))
+ length = int(table.(pmibTCP6TableOwnerPidAll).DwNumEntries)
+ case kindUDP4.filename:
+ index = int(unsafe.Sizeof(table.(pmibUDPTableOwnerPid).DwNumEntries))
+ step = int(unsafe.Sizeof(table.(pmibUDPTableOwnerPid).Table))
+ length = int(table.(pmibUDPTableOwnerPid).DwNumEntries)
+ case kindUDP6.filename:
+ index = int(unsafe.Sizeof(table.(pmibUDP6TableOwnerPid).DwNumEntries))
+ step = int(unsafe.Sizeof(table.(pmibUDP6TableOwnerPid).Table))
+ length = int(table.(pmibUDP6TableOwnerPid).DwNumEntries)
+ }
+
+ return
+}
+
+func getTCPConnections(family uint32) ([]ConnectionStat, error) {
+ var (
+ p uintptr
+ buf []byte
+ size uint32
+
+ pmibTCPTable pmibTCPTableOwnerPidAll
+ pmibTCP6Table pmibTCP6TableOwnerPidAll
+ )
+
+ if family == 0 {
+ return nil, fmt.Errorf("faimly must be required")
+ }
+
+ for {
+ switch family {
+ case kindTCP4.family:
+ if len(buf) > 0 {
+ pmibTCPTable = (*mibTCPTableOwnerPid)(unsafe.Pointer(&buf[0]))
+ p = uintptr(unsafe.Pointer(pmibTCPTable))
+ } else {
+ p = uintptr(unsafe.Pointer(pmibTCPTable))
+ }
+ case kindTCP6.family:
+ if len(buf) > 0 {
+ pmibTCP6Table = (*mibTCP6TableOwnerPid)(unsafe.Pointer(&buf[0]))
+ p = uintptr(unsafe.Pointer(pmibTCP6Table))
+ } else {
+ p = uintptr(unsafe.Pointer(pmibTCP6Table))
+ }
+ }
+
+ err := getExtendedTcpTable(p,
+ &size,
+ true,
+ family,
+ tcpTableOwnerPidAll,
+ 0)
+ if err == nil {
+ break
+ }
+ if err != windows.ERROR_INSUFFICIENT_BUFFER {
+ return nil, err
+ }
+ buf = make([]byte, size)
+ }
+
+ var (
+ index, step int
+ length int
+ )
+
+ stats := make([]ConnectionStat, 0)
+ switch family {
+ case kindTCP4.family:
+ index, step, length = getTableInfo(kindTCP4.filename, pmibTCPTable)
+ case kindTCP6.family:
+ index, step, length = getTableInfo(kindTCP6.filename, pmibTCP6Table)
+ }
+
+ if length == 0 {
+ return nil, nil
+ }
+
+ for i := 0; i < length; i++ {
+ switch family {
+ case kindTCP4.family:
+ mibs := (*mibTCPRowOwnerPid)(unsafe.Pointer(&buf[index]))
+ ns := mibs.convertToConnectionStat()
+ stats = append(stats, ns)
+ case kindTCP6.family:
+ mibs := (*mibTCP6RowOwnerPid)(unsafe.Pointer(&buf[index]))
+ ns := mibs.convertToConnectionStat()
+ stats = append(stats, ns)
+ }
+
+ index += step
+ }
+ return stats, nil
+}
+
+func getUDPConnections(family uint32) ([]ConnectionStat, error) {
+ var (
+ p uintptr
+ buf []byte
+ size uint32
+
+ pmibUDPTable pmibUDPTableOwnerPid
+ pmibUDP6Table pmibUDP6TableOwnerPid
+ )
+
+ if family == 0 {
+ return nil, fmt.Errorf("faimly must be required")
+ }
+
+ for {
+ switch family {
+ case kindUDP4.family:
+ if len(buf) > 0 {
+ pmibUDPTable = (*mibUDPTableOwnerPid)(unsafe.Pointer(&buf[0]))
+ p = uintptr(unsafe.Pointer(pmibUDPTable))
+ } else {
+ p = uintptr(unsafe.Pointer(pmibUDPTable))
+ }
+ case kindUDP6.family:
+ if len(buf) > 0 {
+ pmibUDP6Table = (*mibUDP6TableOwnerPid)(unsafe.Pointer(&buf[0]))
+ p = uintptr(unsafe.Pointer(pmibUDP6Table))
+ } else {
+ p = uintptr(unsafe.Pointer(pmibUDP6Table))
+ }
+ }
+
+ err := getExtendedUdpTable(
+ p,
+ &size,
+ true,
+ family,
+ udpTableOwnerPid,
+ 0,
+ )
+ if err == nil {
+ break
+ }
+ if err != windows.ERROR_INSUFFICIENT_BUFFER {
+ return nil, err
+ }
+ buf = make([]byte, size)
+ }
+
+ var (
+ index, step, length int
+ )
+
+ stats := make([]ConnectionStat, 0)
+ switch family {
+ case kindUDP4.family:
+ index, step, length = getTableInfo(kindUDP4.filename, pmibUDPTable)
+ case kindUDP6.family:
+ index, step, length = getTableInfo(kindUDP6.filename, pmibUDP6Table)
+ }
+
+ if length == 0 {
+ return nil, nil
+ }
+
+ for i := 0; i < length; i++ {
+ switch family {
+ case kindUDP4.family:
+ mibs := (*mibUDPRowOwnerPid)(unsafe.Pointer(&buf[index]))
+ ns := mibs.convertToConnectionStat()
+ stats = append(stats, ns)
+ case kindUDP4.family:
+ mibs := (*mibUDP6RowOwnerPid)(unsafe.Pointer(&buf[index]))
+ ns := mibs.convertToConnectionStat()
+ stats = append(stats, ns)
+ }
+
+ index += step
+ }
+ return stats, nil
+}
+
+// tcpStatuses https://msdn.microsoft.com/en-us/library/windows/desktop/bb485761(v=vs.85).aspx
+var tcpStatuses = map[mibTCPState]string{
+ 1: "CLOSED",
+ 2: "LISTEN",
+ 3: "SYN_SENT",
+ 4: "SYN_RECEIVED",
+ 5: "ESTABLISHED",
+ 6: "FIN_WAIT_1",
+ 7: "FIN_WAIT_2",
+ 8: "CLOSE_WAIT",
+ 9: "CLOSING",
+ 10: "LAST_ACK",
+ 11: "TIME_WAIT",
+ 12: "DELETE",
+}
+
+func getExtendedTcpTable(pTcpTable uintptr, pdwSize *uint32, bOrder bool, ulAf uint32, tableClass tcpTableClass, reserved uint32) (errcode error) {
+ r1, _, _ := syscall.Syscall6(procGetExtendedTCPTable.Addr(), 6, pTcpTable, uintptr(unsafe.Pointer(pdwSize)), getUintptrFromBool(bOrder), uintptr(ulAf), uintptr(tableClass), uintptr(reserved))
+ if r1 != 0 {
+ errcode = syscall.Errno(r1)
+ }
+ return
+}
+
+func getExtendedUdpTable(pUdpTable uintptr, pdwSize *uint32, bOrder bool, ulAf uint32, tableClass udpTableClass, reserved uint32) (errcode error) {
+ r1, _, _ := syscall.Syscall6(procGetExtendedUDPTable.Addr(), 6, pUdpTable, uintptr(unsafe.Pointer(pdwSize)), getUintptrFromBool(bOrder), uintptr(ulAf), uintptr(tableClass), uintptr(reserved))
+ if r1 != 0 {
+ errcode = syscall.Errno(r1)
+ }
+ return
+}
+
+func getUintptrFromBool(b bool) uintptr {
+ if b {
+ return 1
+ }
+ return 0
+}
+
+const anySize = 1
+
+// type MIB_TCP_STATE int32
+type mibTCPState int32
+
+type tcpTableClass int32
+
+const (
+ tcpTableBasicListener tcpTableClass = iota
+ tcpTableBasicConnections
+ tcpTableBasicAll
+ tcpTableOwnerPidListener
+ tcpTableOwnerPidConnections
+ tcpTableOwnerPidAll
+ tcpTableOwnerModuleListener
+ tcpTableOwnerModuleConnections
+ tcpTableOwnerModuleAll
+)
+
+type udpTableClass int32
+
+const (
+ udpTableBasic udpTableClass = iota
+ udpTableOwnerPid
+ udpTableOwnerModule
+)
+
+// TCP
+
+type mibTCPRowOwnerPid struct {
+ DwState uint32
+ DwLocalAddr uint32
+ DwLocalPort uint32
+ DwRemoteAddr uint32
+ DwRemotePort uint32
+ DwOwningPid uint32
+}
+
+func (m *mibTCPRowOwnerPid) convertToConnectionStat() ConnectionStat {
+ ns := ConnectionStat{
+ Family: kindTCP4.family,
+ Type: kindTCP4.sockType,
+ Laddr: Addr{
+ IP: parseIPv4HexString(m.DwLocalAddr),
+ Port: uint32(decodePort(m.DwLocalPort)),
+ },
+ Raddr: Addr{
+ IP: parseIPv4HexString(m.DwRemoteAddr),
+ Port: uint32(decodePort(m.DwRemotePort)),
+ },
+ Pid: int32(m.DwOwningPid),
+ Status: tcpStatuses[mibTCPState(m.DwState)],
+ }
+
+ return ns
+}
+
+type mibTCPTableOwnerPid struct {
+ DwNumEntries uint32
+ Table [anySize]mibTCPRowOwnerPid
+}
+
+type mibTCP6RowOwnerPid struct {
+ UcLocalAddr [16]byte
+ DwLocalScopeId uint32
+ DwLocalPort uint32
+ UcRemoteAddr [16]byte
+ DwRemoteScopeId uint32
+ DwRemotePort uint32
+ DwState uint32
+ DwOwningPid uint32
+}
+
+func (m *mibTCP6RowOwnerPid) convertToConnectionStat() ConnectionStat {
+ ns := ConnectionStat{
+ Family: kindTCP6.family,
+ Type: kindTCP6.sockType,
+ Laddr: Addr{
+ IP: parseIPv6HexString(m.UcLocalAddr),
+ Port: uint32(decodePort(m.DwLocalPort)),
+ },
+ Raddr: Addr{
+ IP: parseIPv6HexString(m.UcRemoteAddr),
+ Port: uint32(decodePort(m.DwRemotePort)),
+ },
+ Pid: int32(m.DwOwningPid),
+ Status: tcpStatuses[mibTCPState(m.DwState)],
+ }
+
+ return ns
+}
+
+type mibTCP6TableOwnerPid struct {
+ DwNumEntries uint32
+ Table [anySize]mibTCP6RowOwnerPid
+}
+
+type pmibTCPTableOwnerPidAll *mibTCPTableOwnerPid
+type pmibTCP6TableOwnerPidAll *mibTCP6TableOwnerPid
+
+// UDP
+
+type mibUDPRowOwnerPid struct {
+ DwLocalAddr uint32
+ DwLocalPort uint32
+ DwOwningPid uint32
+}
+
+func (m *mibUDPRowOwnerPid) convertToConnectionStat() ConnectionStat {
+ ns := ConnectionStat{
+ Family: kindUDP4.family,
+ Type: kindUDP4.sockType,
+ Laddr: Addr{
+ IP: parseIPv4HexString(m.DwLocalAddr),
+ Port: uint32(decodePort(m.DwLocalPort)),
+ },
+ Pid: int32(m.DwOwningPid),
+ }
+
+ return ns
+}
+
+type mibUDPTableOwnerPid struct {
+ DwNumEntries uint32
+ Table [anySize]mibUDPRowOwnerPid
+}
+
+type mibUDP6RowOwnerPid struct {
+ UcLocalAddr [16]byte
+ DwLocalScopeId uint32
+ DwLocalPort uint32
+ DwOwningPid uint32
+}
+
+func (m *mibUDP6RowOwnerPid) convertToConnectionStat() ConnectionStat {
+ ns := ConnectionStat{
+ Family: kindUDP6.family,
+ Type: kindUDP6.sockType,
+ Laddr: Addr{
+ IP: parseIPv6HexString(m.UcLocalAddr),
+ Port: uint32(decodePort(m.DwLocalPort)),
+ },
+ Pid: int32(m.DwOwningPid),
+ }
+
+ return ns
+}
+
+type mibUDP6TableOwnerPid struct {
+ DwNumEntries uint32
+ Table [anySize]mibUDP6RowOwnerPid
+}
+
+type pmibUDPTableOwnerPid *mibUDPTableOwnerPid
+type pmibUDP6TableOwnerPid *mibUDP6TableOwnerPid
+
+func decodePort(port uint32) uint16 {
+ return syscall.Ntohs(uint16(port))
+}
+
+func parseIPv4HexString(addr uint32) string {
+ return fmt.Sprintf("%d.%d.%d.%d", addr&255, addr>>8&255, addr>>16&255, addr>>24&255)
+}
+
+func parseIPv6HexString(addr [16]byte) string {
+ var ret [16]byte
+ for i := 0; i < 16; i++ {
+ ret[i] = uint8(addr[i])
+ }
+
+ // convert []byte to net.IP
+ ip := net.IP(ret[:])
+ return ip.String()
+}
diff --git a/vendor/github.com/shirou/gopsutil/process/process.go b/vendor/github.com/shirou/gopsutil/process/process.go
new file mode 100644
index 0000000..036ad91
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/process/process.go
@@ -0,0 +1,254 @@
+package process
+
+import (
+ "context"
+ "encoding/json"
+ "errors"
+ "runtime"
+ "time"
+
+ "github.com/shirou/gopsutil/cpu"
+ "github.com/shirou/gopsutil/internal/common"
+ "github.com/shirou/gopsutil/mem"
+)
+
+var (
+ invoke common.Invoker = common.Invoke{}
+ ErrorNoChildren = errors.New("process does not have children")
+)
+
+type Process struct {
+ Pid int32 `json:"pid"`
+ name string
+ status string
+ parent int32
+ numCtxSwitches *NumCtxSwitchesStat
+ uids []int32
+ gids []int32
+ numThreads int32
+ memInfo *MemoryInfoStat
+ sigInfo *SignalInfoStat
+
+ lastCPUTimes *cpu.TimesStat
+ lastCPUTime time.Time
+
+ tgid int32
+}
+
+type OpenFilesStat struct {
+ Path string `json:"path"`
+ Fd uint64 `json:"fd"`
+}
+
+type MemoryInfoStat struct {
+ RSS uint64 `json:"rss"` // bytes
+ VMS uint64 `json:"vms"` // bytes
+ Data uint64 `json:"data"` // bytes
+ Stack uint64 `json:"stack"` // bytes
+ Locked uint64 `json:"locked"` // bytes
+ Swap uint64 `json:"swap"` // bytes
+}
+
+type SignalInfoStat struct {
+ PendingProcess uint64 `json:"pending_process"`
+ PendingThread uint64 `json:"pending_thread"`
+ Blocked uint64 `json:"blocked"`
+ Ignored uint64 `json:"ignored"`
+ Caught uint64 `json:"caught"`
+}
+
+type RlimitStat struct {
+ Resource int32 `json:"resource"`
+ Soft int32 `json:"soft"` //TODO too small. needs to be uint64
+ Hard int32 `json:"hard"` //TODO too small. needs to be uint64
+ Used uint64 `json:"used"`
+}
+
+type IOCountersStat struct {
+ ReadCount uint64 `json:"readCount"`
+ WriteCount uint64 `json:"writeCount"`
+ ReadBytes uint64 `json:"readBytes"`
+ WriteBytes uint64 `json:"writeBytes"`
+}
+
+type NumCtxSwitchesStat struct {
+ Voluntary int64 `json:"voluntary"`
+ Involuntary int64 `json:"involuntary"`
+}
+
+// Resource limit constants are from /usr/include/x86_64-linux-gnu/bits/resource.h
+// from libc6-dev package in Ubuntu 16.10
+const (
+ RLIMIT_CPU int32 = 0
+ RLIMIT_FSIZE int32 = 1
+ RLIMIT_DATA int32 = 2
+ RLIMIT_STACK int32 = 3
+ RLIMIT_CORE int32 = 4
+ RLIMIT_RSS int32 = 5
+ RLIMIT_NPROC int32 = 6
+ RLIMIT_NOFILE int32 = 7
+ RLIMIT_MEMLOCK int32 = 8
+ RLIMIT_AS int32 = 9
+ RLIMIT_LOCKS int32 = 10
+ RLIMIT_SIGPENDING int32 = 11
+ RLIMIT_MSGQUEUE int32 = 12
+ RLIMIT_NICE int32 = 13
+ RLIMIT_RTPRIO int32 = 14
+ RLIMIT_RTTIME int32 = 15
+)
+
+func (p Process) String() string {
+ s, _ := json.Marshal(p)
+ return string(s)
+}
+
+func (o OpenFilesStat) String() string {
+ s, _ := json.Marshal(o)
+ return string(s)
+}
+
+func (m MemoryInfoStat) String() string {
+ s, _ := json.Marshal(m)
+ return string(s)
+}
+
+func (r RlimitStat) String() string {
+ s, _ := json.Marshal(r)
+ return string(s)
+}
+
+func (i IOCountersStat) String() string {
+ s, _ := json.Marshal(i)
+ return string(s)
+}
+
+func (p NumCtxSwitchesStat) String() string {
+ s, _ := json.Marshal(p)
+ return string(s)
+}
+
+func PidExists(pid int32) (bool, error) {
+ return PidExistsWithContext(context.Background(), pid)
+}
+
+func PidExistsWithContext(ctx context.Context, pid int32) (bool, error) {
+ pids, err := Pids()
+ if err != nil {
+ return false, err
+ }
+
+ for _, i := range pids {
+ if i == pid {
+ return true, err
+ }
+ }
+
+ return false, err
+}
+
+// Background returns true if the process is in background, false otherwise.
+func (p *Process) Background() (bool, error) {
+ return p.BackgroundWithContext(context.Background())
+}
+
+func (p *Process) BackgroundWithContext(ctx context.Context) (bool, error) {
+ fg, err := p.ForegroundWithContext(ctx)
+ if err != nil {
+ return false, err
+ }
+ return !fg, err
+}
+
+// If interval is 0, return difference from last call(non-blocking).
+// If interval > 0, wait interval sec and return diffrence between start and end.
+func (p *Process) Percent(interval time.Duration) (float64, error) {
+ return p.PercentWithContext(context.Background(), interval)
+}
+
+func (p *Process) PercentWithContext(ctx context.Context, interval time.Duration) (float64, error) {
+ cpuTimes, err := p.Times()
+ if err != nil {
+ return 0, err
+ }
+ now := time.Now()
+
+ if interval > 0 {
+ p.lastCPUTimes = cpuTimes
+ p.lastCPUTime = now
+ time.Sleep(interval)
+ cpuTimes, err = p.Times()
+ now = time.Now()
+ if err != nil {
+ return 0, err
+ }
+ } else {
+ if p.lastCPUTimes == nil {
+ // invoked first time
+ p.lastCPUTimes = cpuTimes
+ p.lastCPUTime = now
+ return 0, nil
+ }
+ }
+
+ numcpu := runtime.NumCPU()
+ delta := (now.Sub(p.lastCPUTime).Seconds()) * float64(numcpu)
+ ret := calculatePercent(p.lastCPUTimes, cpuTimes, delta, numcpu)
+ p.lastCPUTimes = cpuTimes
+ p.lastCPUTime = now
+ return ret, nil
+}
+
+func calculatePercent(t1, t2 *cpu.TimesStat, delta float64, numcpu int) float64 {
+ if delta == 0 {
+ return 0
+ }
+ delta_proc := t2.Total() - t1.Total()
+ overall_percent := ((delta_proc / delta) * 100) * float64(numcpu)
+ return overall_percent
+}
+
+// MemoryPercent returns how many percent of the total RAM this process uses
+func (p *Process) MemoryPercent() (float32, error) {
+ return p.MemoryPercentWithContext(context.Background())
+}
+
+func (p *Process) MemoryPercentWithContext(ctx context.Context) (float32, error) {
+ machineMemory, err := mem.VirtualMemory()
+ if err != nil {
+ return 0, err
+ }
+ total := machineMemory.Total
+
+ processMemory, err := p.MemoryInfo()
+ if err != nil {
+ return 0, err
+ }
+ used := processMemory.RSS
+
+ return (100 * float32(used) / float32(total)), nil
+}
+
+// CPU_Percent returns how many percent of the CPU time this process uses
+func (p *Process) CPUPercent() (float64, error) {
+ return p.CPUPercentWithContext(context.Background())
+}
+
+func (p *Process) CPUPercentWithContext(ctx context.Context) (float64, error) {
+ crt_time, err := p.CreateTime()
+ if err != nil {
+ return 0, err
+ }
+
+ cput, err := p.Times()
+ if err != nil {
+ return 0, err
+ }
+
+ created := time.Unix(0, crt_time*int64(time.Millisecond))
+ totalTime := time.Since(created).Seconds()
+ if totalTime <= 0 {
+ return 0, nil
+ }
+
+ return 100 * cput.Total() / totalTime, nil
+}
diff --git a/vendor/github.com/shirou/gopsutil/process/process_darwin.go b/vendor/github.com/shirou/gopsutil/process/process_darwin.go
new file mode 100644
index 0000000..ca0f187
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/process/process_darwin.go
@@ -0,0 +1,654 @@
+// +build darwin
+
+package process
+
+import (
+ "bytes"
+ "context"
+ "encoding/binary"
+ "fmt"
+ "os/exec"
+ "strconv"
+ "strings"
+ "time"
+ "unsafe"
+
+ "github.com/shirou/gopsutil/cpu"
+ "github.com/shirou/gopsutil/internal/common"
+ "github.com/shirou/gopsutil/net"
+ "golang.org/x/sys/unix"
+)
+
+// copied from sys/sysctl.h
+const (
+ CTLKern = 1 // "high kernel": proc, limits
+ KernProc = 14 // struct: process entries
+ KernProcPID = 1 // by process id
+ KernProcProc = 8 // only return procs
+ KernProcAll = 0 // everything
+ KernProcPathname = 12 // path to executable
+)
+
+const (
+ ClockTicks = 100 // C.sysconf(C._SC_CLK_TCK)
+)
+
+type _Ctype_struct___0 struct {
+ Pad uint64
+}
+
+// MemoryInfoExStat is different between OSes
+type MemoryInfoExStat struct {
+}
+
+type MemoryMapsStat struct {
+}
+
+func Pids() ([]int32, error) {
+ return PidsWithContext(context.Background())
+}
+
+func PidsWithContext(ctx context.Context) ([]int32, error) {
+ var ret []int32
+
+ pids, err := callPsWithContext(ctx, "pid", 0, false)
+ if err != nil {
+ return ret, err
+ }
+
+ for _, pid := range pids {
+ v, err := strconv.Atoi(pid[0])
+ if err != nil {
+ return ret, err
+ }
+ ret = append(ret, int32(v))
+ }
+
+ return ret, nil
+}
+
+func (p *Process) Ppid() (int32, error) {
+ return p.PpidWithContext(context.Background())
+}
+
+func (p *Process) PpidWithContext(ctx context.Context) (int32, error) {
+ r, err := callPsWithContext(ctx, "ppid", p.Pid, false)
+ if err != nil {
+ return 0, err
+ }
+
+ v, err := strconv.Atoi(r[0][0])
+ if err != nil {
+ return 0, err
+ }
+
+ return int32(v), err
+}
+func (p *Process) Name() (string, error) {
+ return p.NameWithContext(context.Background())
+}
+
+func (p *Process) NameWithContext(ctx context.Context) (string, error) {
+ k, err := p.getKProc()
+ if err != nil {
+ return "", err
+ }
+
+ return common.IntToString(k.Proc.P_comm[:]), nil
+}
+func (p *Process) Tgid() (int32, error) {
+ return 0, common.ErrNotImplementedError
+}
+func (p *Process) Exe() (string, error) {
+ return p.ExeWithContext(context.Background())
+}
+
+func (p *Process) ExeWithContext(ctx context.Context) (string, error) {
+ lsof_bin, err := exec.LookPath("lsof")
+ if err != nil {
+ return "", err
+ }
+
+ awk_bin, err := exec.LookPath("awk")
+ if err != nil {
+ return "", err
+ }
+
+ sed_bin, err := exec.LookPath("sed")
+ if err != nil {
+ return "", err
+ }
+
+ lsof := exec.CommandContext(ctx, lsof_bin, "-p", strconv.Itoa(int(p.Pid)), "-Fpfn")
+ awk := exec.CommandContext(ctx, awk_bin, "NR==5{print}")
+ sed := exec.CommandContext(ctx, sed_bin, "s/n\\//\\//")
+
+ output, _, err := common.Pipeline(lsof, awk, sed)
+
+ if err != nil {
+ return "", err
+ }
+
+ ret := strings.TrimSpace(string(output))
+
+ return ret, nil
+}
+
+// Cmdline returns the command line arguments of the process as a string with
+// each argument separated by 0x20 ascii character.
+func (p *Process) Cmdline() (string, error) {
+ return p.CmdlineWithContext(context.Background())
+}
+
+func (p *Process) CmdlineWithContext(ctx context.Context) (string, error) {
+ r, err := callPsWithContext(ctx, "command", p.Pid, false)
+ if err != nil {
+ return "", err
+ }
+ return strings.Join(r[0], " "), err
+}
+
+// CmdlineSlice returns the command line arguments of the process as a slice with each
+// element being an argument. Because of current deficiencies in the way that the command
+// line arguments are found, single arguments that have spaces in the will actually be
+// reported as two separate items. In order to do something better CGO would be needed
+// to use the native darwin functions.
+func (p *Process) CmdlineSlice() ([]string, error) {
+ return p.CmdlineSliceWithContext(context.Background())
+}
+
+func (p *Process) CmdlineSliceWithContext(ctx context.Context) ([]string, error) {
+ r, err := callPsWithContext(ctx, "command", p.Pid, false)
+ if err != nil {
+ return nil, err
+ }
+ return r[0], err
+}
+func (p *Process) CreateTime() (int64, error) {
+ return p.CreateTimeWithContext(context.Background())
+}
+
+func (p *Process) CreateTimeWithContext(ctx context.Context) (int64, error) {
+ r, err := callPsWithContext(ctx, "etime", p.Pid, false)
+ if err != nil {
+ return 0, err
+ }
+
+ elapsedSegments := strings.Split(strings.Replace(r[0][0], "-", ":", 1), ":")
+ var elapsedDurations []time.Duration
+ for i := len(elapsedSegments) - 1; i >= 0; i-- {
+ p, err := strconv.ParseInt(elapsedSegments[i], 10, 0)
+ if err != nil {
+ return 0, err
+ }
+ elapsedDurations = append(elapsedDurations, time.Duration(p))
+ }
+
+ var elapsed = time.Duration(elapsedDurations[0]) * time.Second
+ if len(elapsedDurations) > 1 {
+ elapsed += time.Duration(elapsedDurations[1]) * time.Minute
+ }
+ if len(elapsedDurations) > 2 {
+ elapsed += time.Duration(elapsedDurations[2]) * time.Hour
+ }
+ if len(elapsedDurations) > 3 {
+ elapsed += time.Duration(elapsedDurations[3]) * time.Hour * 24
+ }
+
+ start := time.Now().Add(-elapsed)
+ return start.Unix() * 1000, nil
+}
+func (p *Process) Cwd() (string, error) {
+ return p.CwdWithContext(context.Background())
+}
+
+func (p *Process) CwdWithContext(ctx context.Context) (string, error) {
+ return "", common.ErrNotImplementedError
+}
+func (p *Process) Parent() (*Process, error) {
+ return p.ParentWithContext(context.Background())
+}
+
+func (p *Process) ParentWithContext(ctx context.Context) (*Process, error) {
+ rr, err := common.CallLsofWithContext(ctx, invoke, p.Pid, "-FR")
+ if err != nil {
+ return nil, err
+ }
+ for _, r := range rr {
+ if strings.HasPrefix(r, "p") { // skip if process
+ continue
+ }
+ l := string(r)
+ v, err := strconv.Atoi(strings.Replace(l, "R", "", 1))
+ if err != nil {
+ return nil, err
+ }
+ return NewProcess(int32(v))
+ }
+ return nil, fmt.Errorf("could not find parent line")
+}
+func (p *Process) Status() (string, error) {
+ return p.StatusWithContext(context.Background())
+}
+
+func (p *Process) StatusWithContext(ctx context.Context) (string, error) {
+ r, err := callPsWithContext(ctx, "state", p.Pid, false)
+ if err != nil {
+ return "", err
+ }
+
+ return r[0][0], err
+}
+
+func (p *Process) Foreground() (bool, error) {
+ return p.ForegroundWithContext(context.Background())
+}
+
+func (p *Process) ForegroundWithContext(ctx context.Context) (bool, error) {
+ // see https://github.com/shirou/gopsutil/issues/596#issuecomment-432707831 for implementation details
+ pid := p.Pid
+ ps, err := exec.LookPath("ps")
+ if err != nil {
+ return false, err
+ }
+ out, err := invoke.CommandWithContext(ctx, ps, "-o", "stat=", "-p", strconv.Itoa(int(pid)))
+ if err != nil {
+ return false, err
+ }
+ return strings.IndexByte(string(out), '+') != -1, nil
+}
+
+func (p *Process) Uids() ([]int32, error) {
+ return p.UidsWithContext(context.Background())
+}
+
+func (p *Process) UidsWithContext(ctx context.Context) ([]int32, error) {
+ k, err := p.getKProc()
+ if err != nil {
+ return nil, err
+ }
+
+ // See: http://unix.superglobalmegacorp.com/Net2/newsrc/sys/ucred.h.html
+ userEffectiveUID := int32(k.Eproc.Ucred.UID)
+
+ return []int32{userEffectiveUID}, nil
+}
+func (p *Process) Gids() ([]int32, error) {
+ return p.GidsWithContext(context.Background())
+}
+
+func (p *Process) GidsWithContext(ctx context.Context) ([]int32, error) {
+ k, err := p.getKProc()
+ if err != nil {
+ return nil, err
+ }
+
+ gids := make([]int32, 0, 3)
+ gids = append(gids, int32(k.Eproc.Pcred.P_rgid), int32(k.Eproc.Ucred.Ngroups), int32(k.Eproc.Pcred.P_svgid))
+
+ return gids, nil
+}
+func (p *Process) Terminal() (string, error) {
+ return p.TerminalWithContext(context.Background())
+}
+
+func (p *Process) TerminalWithContext(ctx context.Context) (string, error) {
+ return "", common.ErrNotImplementedError
+ /*
+ k, err := p.getKProc()
+ if err != nil {
+ return "", err
+ }
+
+ ttyNr := uint64(k.Eproc.Tdev)
+ termmap, err := getTerminalMap()
+ if err != nil {
+ return "", err
+ }
+
+ return termmap[ttyNr], nil
+ */
+}
+func (p *Process) Nice() (int32, error) {
+ return p.NiceWithContext(context.Background())
+}
+
+func (p *Process) NiceWithContext(ctx context.Context) (int32, error) {
+ k, err := p.getKProc()
+ if err != nil {
+ return 0, err
+ }
+ return int32(k.Proc.P_nice), nil
+}
+func (p *Process) IOnice() (int32, error) {
+ return p.IOniceWithContext(context.Background())
+}
+
+func (p *Process) IOniceWithContext(ctx context.Context) (int32, error) {
+ return 0, common.ErrNotImplementedError
+}
+func (p *Process) Rlimit() ([]RlimitStat, error) {
+ return p.RlimitWithContext(context.Background())
+}
+
+func (p *Process) RlimitWithContext(ctx context.Context) ([]RlimitStat, error) {
+ var rlimit []RlimitStat
+ return rlimit, common.ErrNotImplementedError
+}
+func (p *Process) RlimitUsage(gatherUsed bool) ([]RlimitStat, error) {
+ return p.RlimitUsageWithContext(context.Background(), gatherUsed)
+}
+
+func (p *Process) RlimitUsageWithContext(ctx context.Context, gatherUsed bool) ([]RlimitStat, error) {
+ var rlimit []RlimitStat
+ return rlimit, common.ErrNotImplementedError
+}
+func (p *Process) IOCounters() (*IOCountersStat, error) {
+ return p.IOCountersWithContext(context.Background())
+}
+
+func (p *Process) IOCountersWithContext(ctx context.Context) (*IOCountersStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+func (p *Process) NumCtxSwitches() (*NumCtxSwitchesStat, error) {
+ return p.NumCtxSwitchesWithContext(context.Background())
+}
+
+func (p *Process) NumCtxSwitchesWithContext(ctx context.Context) (*NumCtxSwitchesStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+func (p *Process) NumFDs() (int32, error) {
+ return p.NumFDsWithContext(context.Background())
+}
+
+func (p *Process) NumFDsWithContext(ctx context.Context) (int32, error) {
+ return 0, common.ErrNotImplementedError
+}
+func (p *Process) NumThreads() (int32, error) {
+ return p.NumThreadsWithContext(context.Background())
+}
+
+func (p *Process) NumThreadsWithContext(ctx context.Context) (int32, error) {
+ r, err := callPsWithContext(ctx, "utime,stime", p.Pid, true)
+ if err != nil {
+ return 0, err
+ }
+ return int32(len(r)), nil
+}
+func (p *Process) Threads() (map[int32]*cpu.TimesStat, error) {
+ return p.ThreadsWithContext(context.Background())
+}
+
+func (p *Process) ThreadsWithContext(ctx context.Context) (map[int32]*cpu.TimesStat, error) {
+ ret := make(map[int32]*cpu.TimesStat)
+ return ret, common.ErrNotImplementedError
+}
+
+func convertCPUTimes(s string) (ret float64, err error) {
+ var t int
+ var _tmp string
+ if strings.Contains(s, ":") {
+ _t := strings.Split(s, ":")
+ hour, err := strconv.Atoi(_t[0])
+ if err != nil {
+ return ret, err
+ }
+ t += hour * 60 * 100
+ _tmp = _t[1]
+ } else {
+ _tmp = s
+ }
+
+ _t := strings.Split(_tmp, ".")
+ if err != nil {
+ return ret, err
+ }
+ h, err := strconv.Atoi(_t[0])
+ t += h * 100
+ h, err = strconv.Atoi(_t[1])
+ t += h
+ return float64(t) / ClockTicks, nil
+}
+func (p *Process) Times() (*cpu.TimesStat, error) {
+ return p.TimesWithContext(context.Background())
+}
+
+func (p *Process) TimesWithContext(ctx context.Context) (*cpu.TimesStat, error) {
+ r, err := callPsWithContext(ctx, "utime,stime", p.Pid, false)
+
+ if err != nil {
+ return nil, err
+ }
+
+ utime, err := convertCPUTimes(r[0][0])
+ if err != nil {
+ return nil, err
+ }
+ stime, err := convertCPUTimes(r[0][1])
+ if err != nil {
+ return nil, err
+ }
+
+ ret := &cpu.TimesStat{
+ CPU: "cpu",
+ User: utime,
+ System: stime,
+ }
+ return ret, nil
+}
+func (p *Process) CPUAffinity() ([]int32, error) {
+ return p.CPUAffinityWithContext(context.Background())
+}
+
+func (p *Process) CPUAffinityWithContext(ctx context.Context) ([]int32, error) {
+ return nil, common.ErrNotImplementedError
+}
+func (p *Process) MemoryInfo() (*MemoryInfoStat, error) {
+ return p.MemoryInfoWithContext(context.Background())
+}
+
+func (p *Process) MemoryInfoWithContext(ctx context.Context) (*MemoryInfoStat, error) {
+ r, err := callPsWithContext(ctx, "rss,vsize,pagein", p.Pid, false)
+ if err != nil {
+ return nil, err
+ }
+ rss, err := strconv.Atoi(r[0][0])
+ if err != nil {
+ return nil, err
+ }
+ vms, err := strconv.Atoi(r[0][1])
+ if err != nil {
+ return nil, err
+ }
+ pagein, err := strconv.Atoi(r[0][2])
+ if err != nil {
+ return nil, err
+ }
+
+ ret := &MemoryInfoStat{
+ RSS: uint64(rss) * 1024,
+ VMS: uint64(vms) * 1024,
+ Swap: uint64(pagein),
+ }
+
+ return ret, nil
+}
+func (p *Process) MemoryInfoEx() (*MemoryInfoExStat, error) {
+ return p.MemoryInfoExWithContext(context.Background())
+}
+
+func (p *Process) MemoryInfoExWithContext(ctx context.Context) (*MemoryInfoExStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) Children() ([]*Process, error) {
+ return p.ChildrenWithContext(context.Background())
+}
+
+func (p *Process) ChildrenWithContext(ctx context.Context) ([]*Process, error) {
+ pids, err := common.CallPgrepWithContext(ctx, invoke, p.Pid)
+ if err != nil {
+ return nil, err
+ }
+ ret := make([]*Process, 0, len(pids))
+ for _, pid := range pids {
+ np, err := NewProcess(pid)
+ if err != nil {
+ return nil, err
+ }
+ ret = append(ret, np)
+ }
+ return ret, nil
+}
+
+func (p *Process) OpenFiles() ([]OpenFilesStat, error) {
+ return p.OpenFilesWithContext(context.Background())
+}
+
+func (p *Process) OpenFilesWithContext(ctx context.Context) ([]OpenFilesStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) Connections() ([]net.ConnectionStat, error) {
+ return p.ConnectionsWithContext(context.Background())
+}
+
+func (p *Process) ConnectionsWithContext(ctx context.Context) ([]net.ConnectionStat, error) {
+ return net.ConnectionsPid("all", p.Pid)
+}
+
+func (p *Process) NetIOCounters(pernic bool) ([]net.IOCountersStat, error) {
+ return p.NetIOCountersWithContext(context.Background(), pernic)
+}
+
+func (p *Process) NetIOCountersWithContext(ctx context.Context, pernic bool) ([]net.IOCountersStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) IsRunning() (bool, error) {
+ return p.IsRunningWithContext(context.Background())
+}
+
+func (p *Process) IsRunningWithContext(ctx context.Context) (bool, error) {
+ return true, common.ErrNotImplementedError
+}
+func (p *Process) MemoryMaps(grouped bool) (*[]MemoryMapsStat, error) {
+ return p.MemoryMapsWithContext(context.Background(), grouped)
+}
+
+func (p *Process) MemoryMapsWithContext(ctx context.Context, grouped bool) (*[]MemoryMapsStat, error) {
+ var ret []MemoryMapsStat
+ return &ret, common.ErrNotImplementedError
+}
+
+func Processes() ([]*Process, error) {
+ return ProcessesWithContext(context.Background())
+}
+
+func ProcessesWithContext(ctx context.Context) ([]*Process, error) {
+ out := []*Process{}
+
+ pids, err := PidsWithContext(ctx)
+ if err != nil {
+ return out, err
+ }
+
+ for _, pid := range pids {
+ p, err := NewProcess(pid)
+ if err != nil {
+ continue
+ }
+ out = append(out, p)
+ }
+
+ return out, nil
+}
+
+func parseKinfoProc(buf []byte) (KinfoProc, error) {
+ var k KinfoProc
+ br := bytes.NewReader(buf)
+
+ err := common.Read(br, binary.LittleEndian, &k)
+ if err != nil {
+ return k, err
+ }
+
+ return k, nil
+}
+
+// Returns a proc as defined here:
+// http://unix.superglobalmegacorp.com/Net2/newsrc/sys/kinfo_proc.h.html
+func (p *Process) getKProc() (*KinfoProc, error) {
+ return p.getKProcWithContext(context.Background())
+}
+
+func (p *Process) getKProcWithContext(ctx context.Context) (*KinfoProc, error) {
+ mib := []int32{CTLKern, KernProc, KernProcPID, p.Pid}
+ procK := KinfoProc{}
+ length := uint64(unsafe.Sizeof(procK))
+ buf := make([]byte, length)
+ _, _, syserr := unix.Syscall6(
+ unix.SYS___SYSCTL,
+ uintptr(unsafe.Pointer(&mib[0])),
+ uintptr(len(mib)),
+ uintptr(unsafe.Pointer(&buf[0])),
+ uintptr(unsafe.Pointer(&length)),
+ 0,
+ 0)
+ if syserr != 0 {
+ return nil, syserr
+ }
+ k, err := parseKinfoProc(buf)
+ if err != nil {
+ return nil, err
+ }
+
+ return &k, nil
+}
+
+func NewProcess(pid int32) (*Process, error) {
+ p := &Process{Pid: pid}
+
+ return p, nil
+}
+
+// call ps command.
+// Return value deletes Header line(you must not input wrong arg).
+// And splited by Space. Caller have responsibility to manage.
+// If passed arg pid is 0, get information from all process.
+func callPsWithContext(ctx context.Context, arg string, pid int32, threadOption bool) ([][]string, error) {
+ bin, err := exec.LookPath("ps")
+ if err != nil {
+ return [][]string{}, err
+ }
+
+ var cmd []string
+ if pid == 0 { // will get from all processes.
+ cmd = []string{"-ax", "-o", arg}
+ } else if threadOption {
+ cmd = []string{"-x", "-o", arg, "-M", "-p", strconv.Itoa(int(pid))}
+ } else {
+ cmd = []string{"-x", "-o", arg, "-p", strconv.Itoa(int(pid))}
+ }
+ out, err := invoke.CommandWithContext(ctx, bin, cmd...)
+ if err != nil {
+ return [][]string{}, err
+ }
+ lines := strings.Split(string(out), "\n")
+
+ var ret [][]string
+ for _, l := range lines[1:] {
+ var lr []string
+ for _, r := range strings.Split(l, " ") {
+ if r == "" {
+ continue
+ }
+ lr = append(lr, strings.TrimSpace(r))
+ }
+ if len(lr) != 0 {
+ ret = append(ret, lr)
+ }
+ }
+
+ return ret, nil
+}
diff --git a/vendor/github.com/shirou/gopsutil/process/process_darwin_386.go b/vendor/github.com/shirou/gopsutil/process/process_darwin_386.go
new file mode 100644
index 0000000..f8e9223
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/process/process_darwin_386.go
@@ -0,0 +1,234 @@
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs types_darwin.go
+
+package process
+
+const (
+ sizeofPtr = 0x8
+ sizeofShort = 0x2
+ sizeofInt = 0x4
+ sizeofLong = 0x8
+ sizeofLongLong = 0x8
+)
+
+type (
+ _C_short int16
+ _C_int int32
+ _C_long int64
+ _C_long_long int64
+)
+
+type Timespec struct {
+ Sec int64
+ Nsec int64
+}
+
+type Timeval struct {
+ Sec int64
+ Usec int32
+ Pad_cgo_0 [4]byte
+}
+
+type Rusage struct {
+ Utime Timeval
+ Stime Timeval
+ Maxrss int64
+ Ixrss int64
+ Idrss int64
+ Isrss int64
+ Minflt int64
+ Majflt int64
+ Nswap int64
+ Inblock int64
+ Oublock int64
+ Msgsnd int64
+ Msgrcv int64
+ Nsignals int64
+ Nvcsw int64
+ Nivcsw int64
+}
+
+type Rlimit struct {
+ Cur uint64
+ Max uint64
+}
+
+type UGid_t uint32
+
+type KinfoProc struct {
+ Proc ExternProc
+ Eproc Eproc
+}
+
+type Eproc struct {
+ Paddr *uint64
+ Sess *Session
+ Pcred Upcred
+ Ucred Uucred
+ Pad_cgo_0 [4]byte
+ Vm Vmspace
+ Ppid int32
+ Pgid int32
+ Jobc int16
+ Pad_cgo_1 [2]byte
+ Tdev int32
+ Tpgid int32
+ Pad_cgo_2 [4]byte
+ Tsess *Session
+ Wmesg [8]int8
+ Xsize int32
+ Xrssize int16
+ Xccount int16
+ Xswrss int16
+ Pad_cgo_3 [2]byte
+ Flag int32
+ Login [12]int8
+ Spare [4]int32
+ Pad_cgo_4 [4]byte
+}
+
+type Proc struct{}
+
+type Session struct{}
+
+type ucred struct {
+ Link _Ctype_struct___0
+ Ref uint64
+ Posix Posix_cred
+ Label *Label
+ Audit Au_session
+}
+
+type Uucred struct {
+ Ref int32
+ UID uint32
+ Ngroups int16
+ Pad_cgo_0 [2]byte
+ Groups [16]uint32
+}
+
+type Upcred struct {
+ Pc_lock [72]int8
+ Pc_ucred *ucred
+ P_ruid uint32
+ P_svuid uint32
+ P_rgid uint32
+ P_svgid uint32
+ P_refcnt int32
+ Pad_cgo_0 [4]byte
+}
+
+type Vmspace struct {
+ Dummy int32
+ Pad_cgo_0 [4]byte
+ Dummy2 *int8
+ Dummy3 [5]int32
+ Pad_cgo_1 [4]byte
+ Dummy4 [3]*int8
+}
+
+type Sigacts struct{}
+
+type ExternProc struct {
+ P_un [16]byte
+ P_vmspace uint64
+ P_sigacts uint64
+ Pad_cgo_0 [3]byte
+ P_flag int32
+ P_stat int8
+ P_pid int32
+ P_oppid int32
+ P_dupfd int32
+ Pad_cgo_1 [4]byte
+ User_stack uint64
+ Exit_thread uint64
+ P_debugger int32
+ Sigwait int32
+ P_estcpu uint32
+ P_cpticks int32
+ P_pctcpu uint32
+ Pad_cgo_2 [4]byte
+ P_wchan uint64
+ P_wmesg uint64
+ P_swtime uint32
+ P_slptime uint32
+ P_realtimer Itimerval
+ P_rtime Timeval
+ P_uticks uint64
+ P_sticks uint64
+ P_iticks uint64
+ P_traceflag int32
+ Pad_cgo_3 [4]byte
+ P_tracep uint64
+ P_siglist int32
+ Pad_cgo_4 [4]byte
+ P_textvp uint64
+ P_holdcnt int32
+ P_sigmask uint32
+ P_sigignore uint32
+ P_sigcatch uint32
+ P_priority uint8
+ P_usrpri uint8
+ P_nice int8
+ P_comm [17]int8
+ Pad_cgo_5 [4]byte
+ P_pgrp uint64
+ P_addr uint64
+ P_xstat uint16
+ P_acflag uint16
+ Pad_cgo_6 [4]byte
+ P_ru uint64
+}
+
+type Itimerval struct {
+ Interval Timeval
+ Value Timeval
+}
+
+type Vnode struct{}
+
+type Pgrp struct{}
+
+type UserStruct struct{}
+
+type Au_session struct {
+ Aia_p *AuditinfoAddr
+ Mask AuMask
+}
+
+type Posix_cred struct {
+ UID uint32
+ Ruid uint32
+ Svuid uint32
+ Ngroups int16
+ Pad_cgo_0 [2]byte
+ Groups [16]uint32
+ Rgid uint32
+ Svgid uint32
+ Gmuid uint32
+ Flags int32
+}
+
+type Label struct{}
+
+type AuditinfoAddr struct {
+ Auid uint32
+ Mask AuMask
+ Termid AuTidAddr
+ Asid int32
+ Flags uint64
+}
+type AuMask struct {
+ Success uint32
+ Failure uint32
+}
+type AuTidAddr struct {
+ Port int32
+ Type uint32
+ Addr [4]uint32
+}
+
+type UcredQueue struct {
+ Next *ucred
+ Prev **ucred
+}
diff --git a/vendor/github.com/shirou/gopsutil/process/process_darwin_amd64.go b/vendor/github.com/shirou/gopsutil/process/process_darwin_amd64.go
new file mode 100644
index 0000000..f8e9223
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/process/process_darwin_amd64.go
@@ -0,0 +1,234 @@
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs types_darwin.go
+
+package process
+
+const (
+ sizeofPtr = 0x8
+ sizeofShort = 0x2
+ sizeofInt = 0x4
+ sizeofLong = 0x8
+ sizeofLongLong = 0x8
+)
+
+type (
+ _C_short int16
+ _C_int int32
+ _C_long int64
+ _C_long_long int64
+)
+
+type Timespec struct {
+ Sec int64
+ Nsec int64
+}
+
+type Timeval struct {
+ Sec int64
+ Usec int32
+ Pad_cgo_0 [4]byte
+}
+
+type Rusage struct {
+ Utime Timeval
+ Stime Timeval
+ Maxrss int64
+ Ixrss int64
+ Idrss int64
+ Isrss int64
+ Minflt int64
+ Majflt int64
+ Nswap int64
+ Inblock int64
+ Oublock int64
+ Msgsnd int64
+ Msgrcv int64
+ Nsignals int64
+ Nvcsw int64
+ Nivcsw int64
+}
+
+type Rlimit struct {
+ Cur uint64
+ Max uint64
+}
+
+type UGid_t uint32
+
+type KinfoProc struct {
+ Proc ExternProc
+ Eproc Eproc
+}
+
+type Eproc struct {
+ Paddr *uint64
+ Sess *Session
+ Pcred Upcred
+ Ucred Uucred
+ Pad_cgo_0 [4]byte
+ Vm Vmspace
+ Ppid int32
+ Pgid int32
+ Jobc int16
+ Pad_cgo_1 [2]byte
+ Tdev int32
+ Tpgid int32
+ Pad_cgo_2 [4]byte
+ Tsess *Session
+ Wmesg [8]int8
+ Xsize int32
+ Xrssize int16
+ Xccount int16
+ Xswrss int16
+ Pad_cgo_3 [2]byte
+ Flag int32
+ Login [12]int8
+ Spare [4]int32
+ Pad_cgo_4 [4]byte
+}
+
+type Proc struct{}
+
+type Session struct{}
+
+type ucred struct {
+ Link _Ctype_struct___0
+ Ref uint64
+ Posix Posix_cred
+ Label *Label
+ Audit Au_session
+}
+
+type Uucred struct {
+ Ref int32
+ UID uint32
+ Ngroups int16
+ Pad_cgo_0 [2]byte
+ Groups [16]uint32
+}
+
+type Upcred struct {
+ Pc_lock [72]int8
+ Pc_ucred *ucred
+ P_ruid uint32
+ P_svuid uint32
+ P_rgid uint32
+ P_svgid uint32
+ P_refcnt int32
+ Pad_cgo_0 [4]byte
+}
+
+type Vmspace struct {
+ Dummy int32
+ Pad_cgo_0 [4]byte
+ Dummy2 *int8
+ Dummy3 [5]int32
+ Pad_cgo_1 [4]byte
+ Dummy4 [3]*int8
+}
+
+type Sigacts struct{}
+
+type ExternProc struct {
+ P_un [16]byte
+ P_vmspace uint64
+ P_sigacts uint64
+ Pad_cgo_0 [3]byte
+ P_flag int32
+ P_stat int8
+ P_pid int32
+ P_oppid int32
+ P_dupfd int32
+ Pad_cgo_1 [4]byte
+ User_stack uint64
+ Exit_thread uint64
+ P_debugger int32
+ Sigwait int32
+ P_estcpu uint32
+ P_cpticks int32
+ P_pctcpu uint32
+ Pad_cgo_2 [4]byte
+ P_wchan uint64
+ P_wmesg uint64
+ P_swtime uint32
+ P_slptime uint32
+ P_realtimer Itimerval
+ P_rtime Timeval
+ P_uticks uint64
+ P_sticks uint64
+ P_iticks uint64
+ P_traceflag int32
+ Pad_cgo_3 [4]byte
+ P_tracep uint64
+ P_siglist int32
+ Pad_cgo_4 [4]byte
+ P_textvp uint64
+ P_holdcnt int32
+ P_sigmask uint32
+ P_sigignore uint32
+ P_sigcatch uint32
+ P_priority uint8
+ P_usrpri uint8
+ P_nice int8
+ P_comm [17]int8
+ Pad_cgo_5 [4]byte
+ P_pgrp uint64
+ P_addr uint64
+ P_xstat uint16
+ P_acflag uint16
+ Pad_cgo_6 [4]byte
+ P_ru uint64
+}
+
+type Itimerval struct {
+ Interval Timeval
+ Value Timeval
+}
+
+type Vnode struct{}
+
+type Pgrp struct{}
+
+type UserStruct struct{}
+
+type Au_session struct {
+ Aia_p *AuditinfoAddr
+ Mask AuMask
+}
+
+type Posix_cred struct {
+ UID uint32
+ Ruid uint32
+ Svuid uint32
+ Ngroups int16
+ Pad_cgo_0 [2]byte
+ Groups [16]uint32
+ Rgid uint32
+ Svgid uint32
+ Gmuid uint32
+ Flags int32
+}
+
+type Label struct{}
+
+type AuditinfoAddr struct {
+ Auid uint32
+ Mask AuMask
+ Termid AuTidAddr
+ Asid int32
+ Flags uint64
+}
+type AuMask struct {
+ Success uint32
+ Failure uint32
+}
+type AuTidAddr struct {
+ Port int32
+ Type uint32
+ Addr [4]uint32
+}
+
+type UcredQueue struct {
+ Next *ucred
+ Prev **ucred
+}
diff --git a/vendor/github.com/shirou/gopsutil/process/process_fallback.go b/vendor/github.com/shirou/gopsutil/process/process_fallback.go
new file mode 100644
index 0000000..8772440
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/process/process_fallback.go
@@ -0,0 +1,319 @@
+// +build !darwin,!linux,!freebsd,!openbsd,!windows
+
+package process
+
+import (
+ "context"
+ "syscall"
+
+ "github.com/shirou/gopsutil/cpu"
+ "github.com/shirou/gopsutil/internal/common"
+ "github.com/shirou/gopsutil/net"
+)
+
+type MemoryMapsStat struct {
+ Path string `json:"path"`
+ Rss uint64 `json:"rss"`
+ Size uint64 `json:"size"`
+ Pss uint64 `json:"pss"`
+ SharedClean uint64 `json:"sharedClean"`
+ SharedDirty uint64 `json:"sharedDirty"`
+ PrivateClean uint64 `json:"privateClean"`
+ PrivateDirty uint64 `json:"privateDirty"`
+ Referenced uint64 `json:"referenced"`
+ Anonymous uint64 `json:"anonymous"`
+ Swap uint64 `json:"swap"`
+}
+
+type MemoryInfoExStat struct {
+}
+
+func Pids() ([]int32, error) {
+ return PidsWithContext(context.Background())
+}
+
+func PidsWithContext(ctx context.Context) ([]int32, error) {
+ return []int32{}, common.ErrNotImplementedError
+}
+
+func Processes() ([]*Process, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func ProcessesWithContext(ctx context.Context) ([]*Process, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func NewProcess(pid int32) (*Process, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) Ppid() (int32, error) {
+ return p.PpidWithContext(context.Background())
+}
+
+func (p *Process) PpidWithContext(ctx context.Context) (int32, error) {
+ return 0, common.ErrNotImplementedError
+}
+func (p *Process) Name() (string, error) {
+ return p.NameWithContext(context.Background())
+}
+
+func (p *Process) NameWithContext(ctx context.Context) (string, error) {
+ return "", common.ErrNotImplementedError
+}
+func (p *Process) Tgid() (int32, error) {
+ return 0, common.ErrNotImplementedError
+}
+func (p *Process) Exe() (string, error) {
+ return p.ExeWithContext(context.Background())
+}
+
+func (p *Process) ExeWithContext(ctx context.Context) (string, error) {
+ return "", common.ErrNotImplementedError
+}
+func (p *Process) Cmdline() (string, error) {
+ return p.CmdlineWithContext(context.Background())
+}
+
+func (p *Process) CmdlineWithContext(ctx context.Context) (string, error) {
+ return "", common.ErrNotImplementedError
+}
+func (p *Process) CmdlineSlice() ([]string, error) {
+ return p.CmdlineSliceWithContext(context.Background())
+}
+
+func (p *Process) CmdlineSliceWithContext(ctx context.Context) ([]string, error) {
+ return []string{}, common.ErrNotImplementedError
+}
+func (p *Process) CreateTime() (int64, error) {
+ return p.CreateTimeWithContext(context.Background())
+}
+
+func (p *Process) CreateTimeWithContext(ctx context.Context) (int64, error) {
+ return 0, common.ErrNotImplementedError
+}
+func (p *Process) Cwd() (string, error) {
+ return p.CwdWithContext(context.Background())
+}
+
+func (p *Process) CwdWithContext(ctx context.Context) (string, error) {
+ return "", common.ErrNotImplementedError
+}
+func (p *Process) Parent() (*Process, error) {
+ return p.ParentWithContext(context.Background())
+}
+
+func (p *Process) ParentWithContext(ctx context.Context) (*Process, error) {
+ return nil, common.ErrNotImplementedError
+}
+func (p *Process) Status() (string, error) {
+ return p.StatusWithContext(context.Background())
+}
+
+func (p *Process) StatusWithContext(ctx context.Context) (string, error) {
+ return "", common.ErrNotImplementedError
+}
+func (p *Process) Foreground() (bool, error) {
+ return p.ForegroundWithContext(context.Background())
+}
+
+func (p *Process) ForegroundWithContext(ctx context.Context) (bool, error) {
+ return false, common.ErrNotImplementedError
+}
+func (p *Process) Uids() ([]int32, error) {
+ return p.UidsWithContext(context.Background())
+}
+
+func (p *Process) UidsWithContext(ctx context.Context) ([]int32, error) {
+ return []int32{}, common.ErrNotImplementedError
+}
+func (p *Process) Gids() ([]int32, error) {
+ return p.GidsWithContext(context.Background())
+}
+
+func (p *Process) GidsWithContext(ctx context.Context) ([]int32, error) {
+ return []int32{}, common.ErrNotImplementedError
+}
+func (p *Process) Terminal() (string, error) {
+ return p.TerminalWithContext(context.Background())
+}
+
+func (p *Process) TerminalWithContext(ctx context.Context) (string, error) {
+ return "", common.ErrNotImplementedError
+}
+func (p *Process) Nice() (int32, error) {
+ return p.NiceWithContext(context.Background())
+}
+
+func (p *Process) NiceWithContext(ctx context.Context) (int32, error) {
+ return 0, common.ErrNotImplementedError
+}
+func (p *Process) IOnice() (int32, error) {
+ return p.IOniceWithContext(context.Background())
+}
+
+func (p *Process) IOniceWithContext(ctx context.Context) (int32, error) {
+ return 0, common.ErrNotImplementedError
+}
+func (p *Process) Rlimit() ([]RlimitStat, error) {
+ return p.RlimitWithContext(context.Background())
+}
+
+func (p *Process) RlimitWithContext(ctx context.Context) ([]RlimitStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+func (p *Process) RlimitUsage(gatherUsed bool) ([]RlimitStat, error) {
+ return p.RlimitUsageWithContext(context.Background(), gatherUsed)
+}
+
+func (p *Process) RlimitUsageWithContext(ctx context.Context, gatherUsed bool) ([]RlimitStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+func (p *Process) IOCounters() (*IOCountersStat, error) {
+ return p.IOCountersWithContext(context.Background())
+}
+
+func (p *Process) IOCountersWithContext(ctx context.Context) (*IOCountersStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+func (p *Process) NumCtxSwitches() (*NumCtxSwitchesStat, error) {
+ return p.NumCtxSwitchesWithContext(context.Background())
+}
+
+func (p *Process) NumCtxSwitchesWithContext(ctx context.Context) (*NumCtxSwitchesStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+func (p *Process) NumFDs() (int32, error) {
+ return p.NumFDsWithContext(context.Background())
+}
+
+func (p *Process) NumFDsWithContext(ctx context.Context) (int32, error) {
+ return 0, common.ErrNotImplementedError
+}
+func (p *Process) NumThreads() (int32, error) {
+ return p.NumThreadsWithContext(context.Background())
+}
+
+func (p *Process) NumThreadsWithContext(ctx context.Context) (int32, error) {
+ return 0, common.ErrNotImplementedError
+}
+func (p *Process) Threads() (map[int32]*cpu.TimesStat, error) {
+ return p.ThreadsWithContext(context.Background())
+}
+
+func (p *Process) ThreadsWithContext(ctx context.Context) (map[int32]*cpu.TimesStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+func (p *Process) Times() (*cpu.TimesStat, error) {
+ return p.TimesWithContext(context.Background())
+}
+
+func (p *Process) TimesWithContext(ctx context.Context) (*cpu.TimesStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+func (p *Process) CPUAffinity() ([]int32, error) {
+ return p.CPUAffinityWithContext(context.Background())
+}
+
+func (p *Process) CPUAffinityWithContext(ctx context.Context) ([]int32, error) {
+ return nil, common.ErrNotImplementedError
+}
+func (p *Process) MemoryInfo() (*MemoryInfoStat, error) {
+ return p.MemoryInfoWithContext(context.Background())
+}
+
+func (p *Process) MemoryInfoWithContext(ctx context.Context) (*MemoryInfoStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+func (p *Process) MemoryInfoEx() (*MemoryInfoExStat, error) {
+ return p.MemoryInfoExWithContext(context.Background())
+}
+
+func (p *Process) MemoryInfoExWithContext(ctx context.Context) (*MemoryInfoExStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+func (p *Process) Children() ([]*Process, error) {
+ return p.ChildrenWithContext(context.Background())
+}
+
+func (p *Process) ChildrenWithContext(ctx context.Context) ([]*Process, error) {
+ return nil, common.ErrNotImplementedError
+}
+func (p *Process) OpenFiles() ([]OpenFilesStat, error) {
+ return p.OpenFilesWithContext(context.Background())
+}
+
+func (p *Process) OpenFilesWithContext(ctx context.Context) ([]OpenFilesStat, error) {
+ return []OpenFilesStat{}, common.ErrNotImplementedError
+}
+func (p *Process) Connections() ([]net.ConnectionStat, error) {
+ return p.ConnectionsWithContext(context.Background())
+}
+
+func (p *Process) ConnectionsWithContext(ctx context.Context) ([]net.ConnectionStat, error) {
+ return []net.ConnectionStat{}, common.ErrNotImplementedError
+}
+func (p *Process) NetIOCounters(pernic bool) ([]net.IOCountersStat, error) {
+ return p.NetIOCountersWithContext(context.Background(), pernic)
+}
+
+func (p *Process) NetIOCountersWithContext(ctx context.Context, pernic bool) ([]net.IOCountersStat, error) {
+ return []net.IOCountersStat{}, common.ErrNotImplementedError
+}
+func (p *Process) IsRunning() (bool, error) {
+ return p.IsRunningWithContext(context.Background())
+}
+
+func (p *Process) IsRunningWithContext(ctx context.Context) (bool, error) {
+ return true, common.ErrNotImplementedError
+}
+func (p *Process) MemoryMaps(grouped bool) (*[]MemoryMapsStat, error) {
+ return p.MemoryMapsWithContext(context.Background(), grouped)
+}
+
+func (p *Process) MemoryMapsWithContext(ctx context.Context, grouped bool) (*[]MemoryMapsStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+func (p *Process) SendSignal(sig syscall.Signal) error {
+ return p.SendSignalWithContext(context.Background(), sig)
+}
+
+func (p *Process) SendSignalWithContext(ctx context.Context, sig syscall.Signal) error {
+ return common.ErrNotImplementedError
+}
+func (p *Process) Suspend() error {
+ return p.SuspendWithContext(context.Background())
+}
+
+func (p *Process) SuspendWithContext(ctx context.Context) error {
+ return common.ErrNotImplementedError
+}
+func (p *Process) Resume() error {
+ return p.ResumeWithContext(context.Background())
+}
+
+func (p *Process) ResumeWithContext(ctx context.Context) error {
+ return common.ErrNotImplementedError
+}
+func (p *Process) Terminate() error {
+ return p.TerminateWithContext(context.Background())
+}
+
+func (p *Process) TerminateWithContext(ctx context.Context) error {
+ return common.ErrNotImplementedError
+}
+func (p *Process) Kill() error {
+ return p.KillWithContext(context.Background())
+}
+
+func (p *Process) KillWithContext(ctx context.Context) error {
+ return common.ErrNotImplementedError
+}
+func (p *Process) Username() (string, error) {
+ return p.UsernameWithContext(context.Background())
+}
+
+func (p *Process) UsernameWithContext(ctx context.Context) (string, error) {
+ return "", common.ErrNotImplementedError
+}
diff --git a/vendor/github.com/shirou/gopsutil/process/process_freebsd.go b/vendor/github.com/shirou/gopsutil/process/process_freebsd.go
new file mode 100644
index 0000000..fd98a8c
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/process/process_freebsd.go
@@ -0,0 +1,501 @@
+// +build freebsd
+
+package process
+
+import (
+ "bytes"
+ "context"
+ "encoding/binary"
+ "os/exec"
+ "strconv"
+ "strings"
+
+ cpu "github.com/shirou/gopsutil/cpu"
+ "github.com/shirou/gopsutil/internal/common"
+ net "github.com/shirou/gopsutil/net"
+ "golang.org/x/sys/unix"
+)
+
+// MemoryInfoExStat is different between OSes
+type MemoryInfoExStat struct {
+}
+
+type MemoryMapsStat struct {
+}
+
+func Pids() ([]int32, error) {
+ return PidsWithContext(context.Background())
+}
+
+func PidsWithContext(ctx context.Context) ([]int32, error) {
+ var ret []int32
+ procs, err := Processes()
+ if err != nil {
+ return ret, nil
+ }
+
+ for _, p := range procs {
+ ret = append(ret, p.Pid)
+ }
+
+ return ret, nil
+}
+
+func (p *Process) Ppid() (int32, error) {
+ return p.PpidWithContext(context.Background())
+}
+
+func (p *Process) PpidWithContext(ctx context.Context) (int32, error) {
+ k, err := p.getKProc()
+ if err != nil {
+ return 0, err
+ }
+
+ return k.Ppid, nil
+}
+func (p *Process) Name() (string, error) {
+ return p.NameWithContext(context.Background())
+}
+
+func (p *Process) NameWithContext(ctx context.Context) (string, error) {
+ k, err := p.getKProc()
+ if err != nil {
+ return "", err
+ }
+
+ return common.IntToString(k.Comm[:]), nil
+}
+func (p *Process) Tgid() (int32, error) {
+ return 0, common.ErrNotImplementedError
+}
+func (p *Process) Exe() (string, error) {
+ return p.ExeWithContext(context.Background())
+}
+
+func (p *Process) ExeWithContext(ctx context.Context) (string, error) {
+ return "", common.ErrNotImplementedError
+}
+
+func (p *Process) Cmdline() (string, error) {
+ return p.CmdlineWithContext(context.Background())
+}
+
+func (p *Process) CmdlineWithContext(ctx context.Context) (string, error) {
+ mib := []int32{CTLKern, KernProc, KernProcArgs, p.Pid}
+ buf, _, err := common.CallSyscall(mib)
+ if err != nil {
+ return "", err
+ }
+ ret := strings.FieldsFunc(string(buf), func(r rune) bool {
+ if r == '\u0000' {
+ return true
+ }
+ return false
+ })
+
+ return strings.Join(ret, " "), nil
+}
+
+func (p *Process) CmdlineSlice() ([]string, error) {
+ return p.CmdlineSliceWithContext(context.Background())
+}
+
+func (p *Process) CmdlineSliceWithContext(ctx context.Context) ([]string, error) {
+ mib := []int32{CTLKern, KernProc, KernProcArgs, p.Pid}
+ buf, _, err := common.CallSyscall(mib)
+ if err != nil {
+ return nil, err
+ }
+ if len(buf) == 0 {
+ return nil, nil
+ }
+ if buf[len(buf)-1] == 0 {
+ buf = buf[:len(buf)-1]
+ }
+ parts := bytes.Split(buf, []byte{0})
+ var strParts []string
+ for _, p := range parts {
+ strParts = append(strParts, string(p))
+ }
+
+ return strParts, nil
+}
+func (p *Process) CreateTime() (int64, error) {
+ return p.CreateTimeWithContext(context.Background())
+}
+
+func (p *Process) CreateTimeWithContext(ctx context.Context) (int64, error) {
+ return 0, common.ErrNotImplementedError
+}
+func (p *Process) Cwd() (string, error) {
+ return p.CwdWithContext(context.Background())
+}
+
+func (p *Process) CwdWithContext(ctx context.Context) (string, error) {
+ return "", common.ErrNotImplementedError
+}
+func (p *Process) Parent() (*Process, error) {
+ return p.ParentWithContext(context.Background())
+}
+
+func (p *Process) ParentWithContext(ctx context.Context) (*Process, error) {
+ return p, common.ErrNotImplementedError
+}
+func (p *Process) Status() (string, error) {
+ return p.StatusWithContext(context.Background())
+}
+
+func (p *Process) StatusWithContext(ctx context.Context) (string, error) {
+ k, err := p.getKProc()
+ if err != nil {
+ return "", err
+ }
+ var s string
+ switch k.Stat {
+ case SIDL:
+ s = "I"
+ case SRUN:
+ s = "R"
+ case SSLEEP:
+ s = "S"
+ case SSTOP:
+ s = "T"
+ case SZOMB:
+ s = "Z"
+ case SWAIT:
+ s = "W"
+ case SLOCK:
+ s = "L"
+ }
+
+ return s, nil
+}
+
+func (p *Process) Foreground() (bool, error) {
+ return p.ForegroundWithContext(context.Background())
+}
+
+func (p *Process) ForegroundWithContext(ctx context.Context) (bool, error) {
+ // see https://github.com/shirou/gopsutil/issues/596#issuecomment-432707831 for implementation details
+ pid := p.Pid
+ ps, err := exec.LookPath("ps")
+ if err != nil {
+ return false, err
+ }
+ out, err := invoke.CommandWithContext(ctx, ps, "-o", "stat=", "-p", strconv.Itoa(int(pid)))
+ if err != nil {
+ return false, err
+ }
+ return strings.IndexByte(string(out), '+') != -1, nil
+}
+
+func (p *Process) Uids() ([]int32, error) {
+ return p.UidsWithContext(context.Background())
+}
+
+func (p *Process) UidsWithContext(ctx context.Context) ([]int32, error) {
+ k, err := p.getKProc()
+ if err != nil {
+ return nil, err
+ }
+
+ uids := make([]int32, 0, 3)
+
+ uids = append(uids, int32(k.Ruid), int32(k.Uid), int32(k.Svuid))
+
+ return uids, nil
+}
+func (p *Process) Gids() ([]int32, error) {
+ return p.GidsWithContext(context.Background())
+}
+
+func (p *Process) GidsWithContext(ctx context.Context) ([]int32, error) {
+ k, err := p.getKProc()
+ if err != nil {
+ return nil, err
+ }
+
+ gids := make([]int32, 0, 3)
+ gids = append(gids, int32(k.Rgid), int32(k.Ngroups), int32(k.Svgid))
+
+ return gids, nil
+}
+func (p *Process) Terminal() (string, error) {
+ return p.TerminalWithContext(context.Background())
+}
+
+func (p *Process) TerminalWithContext(ctx context.Context) (string, error) {
+ k, err := p.getKProc()
+ if err != nil {
+ return "", err
+ }
+
+ ttyNr := uint64(k.Tdev)
+
+ termmap, err := getTerminalMap()
+ if err != nil {
+ return "", err
+ }
+
+ return termmap[ttyNr], nil
+}
+func (p *Process) Nice() (int32, error) {
+ return p.NiceWithContext(context.Background())
+}
+
+func (p *Process) NiceWithContext(ctx context.Context) (int32, error) {
+ k, err := p.getKProc()
+ if err != nil {
+ return 0, err
+ }
+ return int32(k.Nice), nil
+}
+func (p *Process) IOnice() (int32, error) {
+ return p.IOniceWithContext(context.Background())
+}
+
+func (p *Process) IOniceWithContext(ctx context.Context) (int32, error) {
+ return 0, common.ErrNotImplementedError
+}
+func (p *Process) Rlimit() ([]RlimitStat, error) {
+ return p.RlimitWithContext(context.Background())
+}
+
+func (p *Process) RlimitWithContext(ctx context.Context) ([]RlimitStat, error) {
+ var rlimit []RlimitStat
+ return rlimit, common.ErrNotImplementedError
+}
+func (p *Process) RlimitUsage(gatherUsed bool) ([]RlimitStat, error) {
+ return p.RlimitUsageWithContext(context.Background(), gatherUsed)
+}
+
+func (p *Process) RlimitUsageWithContext(ctx context.Context, gatherUsed bool) ([]RlimitStat, error) {
+ var rlimit []RlimitStat
+ return rlimit, common.ErrNotImplementedError
+}
+func (p *Process) IOCounters() (*IOCountersStat, error) {
+ return p.IOCountersWithContext(context.Background())
+}
+
+func (p *Process) IOCountersWithContext(ctx context.Context) (*IOCountersStat, error) {
+ k, err := p.getKProc()
+ if err != nil {
+ return nil, err
+ }
+ return &IOCountersStat{
+ ReadCount: uint64(k.Rusage.Inblock),
+ WriteCount: uint64(k.Rusage.Oublock),
+ }, nil
+}
+func (p *Process) NumCtxSwitches() (*NumCtxSwitchesStat, error) {
+ return p.NumCtxSwitchesWithContext(context.Background())
+}
+
+func (p *Process) NumCtxSwitchesWithContext(ctx context.Context) (*NumCtxSwitchesStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+func (p *Process) NumFDs() (int32, error) {
+ return p.NumFDsWithContext(context.Background())
+}
+
+func (p *Process) NumFDsWithContext(ctx context.Context) (int32, error) {
+ return 0, common.ErrNotImplementedError
+}
+func (p *Process) NumThreads() (int32, error) {
+ return p.NumThreadsWithContext(context.Background())
+}
+
+func (p *Process) NumThreadsWithContext(ctx context.Context) (int32, error) {
+ k, err := p.getKProc()
+ if err != nil {
+ return 0, err
+ }
+
+ return k.Numthreads, nil
+}
+func (p *Process) Threads() (map[int32]*cpu.TimesStat, error) {
+ return p.ThreadsWithContext(context.Background())
+}
+
+func (p *Process) ThreadsWithContext(ctx context.Context) (map[int32]*cpu.TimesStat, error) {
+ ret := make(map[int32]*cpu.TimesStat)
+ return ret, common.ErrNotImplementedError
+}
+func (p *Process) Times() (*cpu.TimesStat, error) {
+ return p.TimesWithContext(context.Background())
+}
+
+func (p *Process) TimesWithContext(ctx context.Context) (*cpu.TimesStat, error) {
+ k, err := p.getKProc()
+ if err != nil {
+ return nil, err
+ }
+ return &cpu.TimesStat{
+ CPU: "cpu",
+ User: float64(k.Rusage.Utime.Sec) + float64(k.Rusage.Utime.Usec)/1000000,
+ System: float64(k.Rusage.Stime.Sec) + float64(k.Rusage.Stime.Usec)/1000000,
+ }, nil
+}
+func (p *Process) CPUAffinity() ([]int32, error) {
+ return p.CPUAffinityWithContext(context.Background())
+}
+
+func (p *Process) CPUAffinityWithContext(ctx context.Context) ([]int32, error) {
+ return nil, common.ErrNotImplementedError
+}
+func (p *Process) MemoryInfo() (*MemoryInfoStat, error) {
+ return p.MemoryInfoWithContext(context.Background())
+}
+
+func (p *Process) MemoryInfoWithContext(ctx context.Context) (*MemoryInfoStat, error) {
+ k, err := p.getKProc()
+ if err != nil {
+ return nil, err
+ }
+ v, err := unix.Sysctl("vm.stats.vm.v_page_size")
+ if err != nil {
+ return nil, err
+ }
+ pageSize := common.LittleEndian.Uint16([]byte(v))
+
+ return &MemoryInfoStat{
+ RSS: uint64(k.Rssize) * uint64(pageSize),
+ VMS: uint64(k.Size),
+ }, nil
+}
+func (p *Process) MemoryInfoEx() (*MemoryInfoExStat, error) {
+ return p.MemoryInfoExWithContext(context.Background())
+}
+
+func (p *Process) MemoryInfoExWithContext(ctx context.Context) (*MemoryInfoExStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) Children() ([]*Process, error) {
+ return p.ChildrenWithContext(context.Background())
+}
+
+func (p *Process) ChildrenWithContext(ctx context.Context) ([]*Process, error) {
+ pids, err := common.CallPgrepWithContext(ctx, invoke, p.Pid)
+ if err != nil {
+ return nil, err
+ }
+ ret := make([]*Process, 0, len(pids))
+ for _, pid := range pids {
+ np, err := NewProcess(pid)
+ if err != nil {
+ return nil, err
+ }
+ ret = append(ret, np)
+ }
+ return ret, nil
+}
+
+func (p *Process) OpenFiles() ([]OpenFilesStat, error) {
+ return p.OpenFilesWithContext(context.Background())
+}
+
+func (p *Process) OpenFilesWithContext(ctx context.Context) ([]OpenFilesStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) Connections() ([]net.ConnectionStat, error) {
+ return p.ConnectionsWithContext(context.Background())
+}
+
+func (p *Process) ConnectionsWithContext(ctx context.Context) ([]net.ConnectionStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) NetIOCounters(pernic bool) ([]net.IOCountersStat, error) {
+ return p.NetIOCountersWithContext(context.Background(), pernic)
+}
+
+func (p *Process) NetIOCountersWithContext(ctx context.Context, pernic bool) ([]net.IOCountersStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) IsRunning() (bool, error) {
+ return p.IsRunningWithContext(context.Background())
+}
+
+func (p *Process) IsRunningWithContext(ctx context.Context) (bool, error) {
+ return true, common.ErrNotImplementedError
+}
+func (p *Process) MemoryMaps(grouped bool) (*[]MemoryMapsStat, error) {
+ return p.MemoryMapsWithContext(context.Background(), grouped)
+}
+
+func (p *Process) MemoryMapsWithContext(ctx context.Context, grouped bool) (*[]MemoryMapsStat, error) {
+ var ret []MemoryMapsStat
+ return &ret, common.ErrNotImplementedError
+}
+
+func Processes() ([]*Process, error) {
+ return ProcessesWithContext(context.Background())
+}
+
+func ProcessesWithContext(ctx context.Context) ([]*Process, error) {
+ results := []*Process{}
+
+ mib := []int32{CTLKern, KernProc, KernProcProc, 0}
+ buf, length, err := common.CallSyscall(mib)
+ if err != nil {
+ return results, err
+ }
+
+ // get kinfo_proc size
+ count := int(length / uint64(sizeOfKinfoProc))
+
+ // parse buf to procs
+ for i := 0; i < count; i++ {
+ b := buf[i*sizeOfKinfoProc : (i+1)*sizeOfKinfoProc]
+ k, err := parseKinfoProc(b)
+ if err != nil {
+ continue
+ }
+ p, err := NewProcess(int32(k.Pid))
+ if err != nil {
+ continue
+ }
+
+ results = append(results, p)
+ }
+
+ return results, nil
+}
+
+func parseKinfoProc(buf []byte) (KinfoProc, error) {
+ var k KinfoProc
+ br := bytes.NewReader(buf)
+ err := common.Read(br, binary.LittleEndian, &k)
+ return k, err
+}
+
+func (p *Process) getKProc() (*KinfoProc, error) {
+ return p.getKProcWithContext(context.Background())
+}
+
+func (p *Process) getKProcWithContext(ctx context.Context) (*KinfoProc, error) {
+ mib := []int32{CTLKern, KernProc, KernProcPID, p.Pid}
+
+ buf, length, err := common.CallSyscall(mib)
+ if err != nil {
+ return nil, err
+ }
+ if length != sizeOfKinfoProc {
+ return nil, err
+ }
+
+ k, err := parseKinfoProc(buf)
+ if err != nil {
+ return nil, err
+ }
+ return &k, nil
+}
+
+func NewProcess(pid int32) (*Process, error) {
+ p := &Process{Pid: pid}
+
+ return p, nil
+}
diff --git a/vendor/github.com/shirou/gopsutil/process/process_freebsd_386.go b/vendor/github.com/shirou/gopsutil/process/process_freebsd_386.go
new file mode 100644
index 0000000..08ab333
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/process/process_freebsd_386.go
@@ -0,0 +1,192 @@
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs types_freebsd.go
+
+package process
+
+const (
+ CTLKern = 1
+ KernProc = 14
+ KernProcPID = 1
+ KernProcProc = 8
+ KernProcPathname = 12
+ KernProcArgs = 7
+)
+
+const (
+ sizeofPtr = 0x4
+ sizeofShort = 0x2
+ sizeofInt = 0x4
+ sizeofLong = 0x4
+ sizeofLongLong = 0x8
+)
+
+const (
+ sizeOfKinfoVmentry = 0x488
+ sizeOfKinfoProc = 0x300
+)
+
+const (
+ SIDL = 1
+ SRUN = 2
+ SSLEEP = 3
+ SSTOP = 4
+ SZOMB = 5
+ SWAIT = 6
+ SLOCK = 7
+)
+
+type (
+ _C_short int16
+ _C_int int32
+ _C_long int32
+ _C_long_long int64
+)
+
+type Timespec struct {
+ Sec int32
+ Nsec int32
+}
+
+type Timeval struct {
+ Sec int32
+ Usec int32
+}
+
+type Rusage struct {
+ Utime Timeval
+ Stime Timeval
+ Maxrss int32
+ Ixrss int32
+ Idrss int32
+ Isrss int32
+ Minflt int32
+ Majflt int32
+ Nswap int32
+ Inblock int32
+ Oublock int32
+ Msgsnd int32
+ Msgrcv int32
+ Nsignals int32
+ Nvcsw int32
+ Nivcsw int32
+}
+
+type Rlimit struct {
+ Cur int64
+ Max int64
+}
+
+type KinfoProc struct {
+ Structsize int32
+ Layout int32
+ Args int32 /* pargs */
+ Paddr int32 /* proc */
+ Addr int32 /* user */
+ Tracep int32 /* vnode */
+ Textvp int32 /* vnode */
+ Fd int32 /* filedesc */
+ Vmspace int32 /* vmspace */
+ Wchan int32
+ Pid int32
+ Ppid int32
+ Pgid int32
+ Tpgid int32
+ Sid int32
+ Tsid int32
+ Jobc int16
+ Spare_short1 int16
+ Tdev uint32
+ Siglist [16]byte /* sigset */
+ Sigmask [16]byte /* sigset */
+ Sigignore [16]byte /* sigset */
+ Sigcatch [16]byte /* sigset */
+ Uid uint32
+ Ruid uint32
+ Svuid uint32
+ Rgid uint32
+ Svgid uint32
+ Ngroups int16
+ Spare_short2 int16
+ Groups [16]uint32
+ Size uint32
+ Rssize int32
+ Swrss int32
+ Tsize int32
+ Dsize int32
+ Ssize int32
+ Xstat uint16
+ Acflag uint16
+ Pctcpu uint32
+ Estcpu uint32
+ Slptime uint32
+ Swtime uint32
+ Cow uint32
+ Runtime uint64
+ Start Timeval
+ Childtime Timeval
+ Flag int32
+ Kiflag int32
+ Traceflag int32
+ Stat int8
+ Nice int8
+ Lock int8
+ Rqindex int8
+ Oncpu uint8
+ Lastcpu uint8
+ Tdname [17]int8
+ Wmesg [9]int8
+ Login [18]int8
+ Lockname [9]int8
+ Comm [20]int8
+ Emul [17]int8
+ Loginclass [18]int8
+ Sparestrings [50]int8
+ Spareints [7]int32
+ Flag2 int32
+ Fibnum int32
+ Cr_flags uint32
+ Jid int32
+ Numthreads int32
+ Tid int32
+ Pri Priority
+ Rusage Rusage
+ Rusage_ch Rusage
+ Pcb int32 /* pcb */
+ Kstack int32
+ Udata int32
+ Tdaddr int32 /* thread */
+ Spareptrs [6]int32
+ Sparelongs [12]int32
+ Sflag int32
+ Tdflags int32
+}
+
+type Priority struct {
+ Class uint8
+ Level uint8
+ Native uint8
+ User uint8
+}
+
+type KinfoVmentry struct {
+ Structsize int32
+ Type int32
+ Start uint64
+ End uint64
+ Offset uint64
+ Vn_fileid uint64
+ Vn_fsid uint32
+ Flags int32
+ Resident int32
+ Private_resident int32
+ Protection int32
+ Ref_count int32
+ Shadow_count int32
+ Vn_type int32
+ Vn_size uint64
+ Vn_rdev uint32
+ Vn_mode uint16
+ Status uint16
+ X_kve_ispare [12]int32
+ Path [1024]int8
+}
diff --git a/vendor/github.com/shirou/gopsutil/process/process_freebsd_amd64.go b/vendor/github.com/shirou/gopsutil/process/process_freebsd_amd64.go
new file mode 100644
index 0000000..560e627
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/process/process_freebsd_amd64.go
@@ -0,0 +1,192 @@
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs types_freebsd.go
+
+package process
+
+const (
+ CTLKern = 1
+ KernProc = 14
+ KernProcPID = 1
+ KernProcProc = 8
+ KernProcPathname = 12
+ KernProcArgs = 7
+)
+
+const (
+ sizeofPtr = 0x8
+ sizeofShort = 0x2
+ sizeofInt = 0x4
+ sizeofLong = 0x8
+ sizeofLongLong = 0x8
+)
+
+const (
+ sizeOfKinfoVmentry = 0x488
+ sizeOfKinfoProc = 0x440
+)
+
+const (
+ SIDL = 1
+ SRUN = 2
+ SSLEEP = 3
+ SSTOP = 4
+ SZOMB = 5
+ SWAIT = 6
+ SLOCK = 7
+)
+
+type (
+ _C_short int16
+ _C_int int32
+ _C_long int64
+ _C_long_long int64
+)
+
+type Timespec struct {
+ Sec int64
+ Nsec int64
+}
+
+type Timeval struct {
+ Sec int64
+ Usec int64
+}
+
+type Rusage struct {
+ Utime Timeval
+ Stime Timeval
+ Maxrss int64
+ Ixrss int64
+ Idrss int64
+ Isrss int64
+ Minflt int64
+ Majflt int64
+ Nswap int64
+ Inblock int64
+ Oublock int64
+ Msgsnd int64
+ Msgrcv int64
+ Nsignals int64
+ Nvcsw int64
+ Nivcsw int64
+}
+
+type Rlimit struct {
+ Cur int64
+ Max int64
+}
+
+type KinfoProc struct {
+ Structsize int32
+ Layout int32
+ Args int64 /* pargs */
+ Paddr int64 /* proc */
+ Addr int64 /* user */
+ Tracep int64 /* vnode */
+ Textvp int64 /* vnode */
+ Fd int64 /* filedesc */
+ Vmspace int64 /* vmspace */
+ Wchan int64
+ Pid int32
+ Ppid int32
+ Pgid int32
+ Tpgid int32
+ Sid int32
+ Tsid int32
+ Jobc int16
+ Spare_short1 int16
+ Tdev uint32
+ Siglist [16]byte /* sigset */
+ Sigmask [16]byte /* sigset */
+ Sigignore [16]byte /* sigset */
+ Sigcatch [16]byte /* sigset */
+ Uid uint32
+ Ruid uint32
+ Svuid uint32
+ Rgid uint32
+ Svgid uint32
+ Ngroups int16
+ Spare_short2 int16
+ Groups [16]uint32
+ Size uint64
+ Rssize int64
+ Swrss int64
+ Tsize int64
+ Dsize int64
+ Ssize int64
+ Xstat uint16
+ Acflag uint16
+ Pctcpu uint32
+ Estcpu uint32
+ Slptime uint32
+ Swtime uint32
+ Cow uint32
+ Runtime uint64
+ Start Timeval
+ Childtime Timeval
+ Flag int64
+ Kiflag int64
+ Traceflag int32
+ Stat int8
+ Nice int8
+ Lock int8
+ Rqindex int8
+ Oncpu uint8
+ Lastcpu uint8
+ Tdname [17]int8
+ Wmesg [9]int8
+ Login [18]int8
+ Lockname [9]int8
+ Comm [20]int8
+ Emul [17]int8
+ Loginclass [18]int8
+ Sparestrings [50]int8
+ Spareints [7]int32
+ Flag2 int32
+ Fibnum int32
+ Cr_flags uint32
+ Jid int32
+ Numthreads int32
+ Tid int32
+ Pri Priority
+ Rusage Rusage
+ Rusage_ch Rusage
+ Pcb int64 /* pcb */
+ Kstack int64
+ Udata int64
+ Tdaddr int64 /* thread */
+ Spareptrs [6]int64
+ Sparelongs [12]int64
+ Sflag int64
+ Tdflags int64
+}
+
+type Priority struct {
+ Class uint8
+ Level uint8
+ Native uint8
+ User uint8
+}
+
+type KinfoVmentry struct {
+ Structsize int32
+ Type int32
+ Start uint64
+ End uint64
+ Offset uint64
+ Vn_fileid uint64
+ Vn_fsid uint32
+ Flags int32
+ Resident int32
+ Private_resident int32
+ Protection int32
+ Ref_count int32
+ Shadow_count int32
+ Vn_type int32
+ Vn_size uint64
+ Vn_rdev uint32
+ Vn_mode uint16
+ Status uint16
+ X_kve_ispare [12]int32
+ Path [1024]int8
+}
diff --git a/vendor/github.com/shirou/gopsutil/process/process_freebsd_arm.go b/vendor/github.com/shirou/gopsutil/process/process_freebsd_arm.go
new file mode 100644
index 0000000..81ae0b9
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/process/process_freebsd_arm.go
@@ -0,0 +1,192 @@
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs types_freebsd.go
+
+package process
+
+const (
+ CTLKern = 1
+ KernProc = 14
+ KernProcPID = 1
+ KernProcProc = 8
+ KernProcPathname = 12
+ KernProcArgs = 7
+)
+
+const (
+ sizeofPtr = 0x4
+ sizeofShort = 0x2
+ sizeofInt = 0x4
+ sizeofLong = 0x4
+ sizeofLongLong = 0x8
+)
+
+const (
+ sizeOfKinfoVmentry = 0x488
+ sizeOfKinfoProc = 0x440
+)
+
+const (
+ SIDL = 1
+ SRUN = 2
+ SSLEEP = 3
+ SSTOP = 4
+ SZOMB = 5
+ SWAIT = 6
+ SLOCK = 7
+)
+
+type (
+ _C_short int16
+ _C_int int32
+ _C_long int32
+ _C_long_long int64
+)
+
+type Timespec struct {
+ Sec int64
+ Nsec int64
+}
+
+type Timeval struct {
+ Sec int64
+ Usec int64
+}
+
+type Rusage struct {
+ Utime Timeval
+ Stime Timeval
+ Maxrss int32
+ Ixrss int32
+ Idrss int32
+ Isrss int32
+ Minflt int32
+ Majflt int32
+ Nswap int32
+ Inblock int32
+ Oublock int32
+ Msgsnd int32
+ Msgrcv int32
+ Nsignals int32
+ Nvcsw int32
+ Nivcsw int32
+}
+
+type Rlimit struct {
+ Cur int32
+ Max int32
+}
+
+type KinfoProc struct {
+ Structsize int32
+ Layout int32
+ Args int32 /* pargs */
+ Paddr int32 /* proc */
+ Addr int32 /* user */
+ Tracep int32 /* vnode */
+ Textvp int32 /* vnode */
+ Fd int32 /* filedesc */
+ Vmspace int32 /* vmspace */
+ Wchan int32
+ Pid int32
+ Ppid int32
+ Pgid int32
+ Tpgid int32
+ Sid int32
+ Tsid int32
+ Jobc int16
+ Spare_short1 int16
+ Tdev uint32
+ Siglist [16]byte /* sigset */
+ Sigmask [16]byte /* sigset */
+ Sigignore [16]byte /* sigset */
+ Sigcatch [16]byte /* sigset */
+ Uid uint32
+ Ruid uint32
+ Svuid uint32
+ Rgid uint32
+ Svgid uint32
+ Ngroups int16
+ Spare_short2 int16
+ Groups [16]uint32
+ Size uint32
+ Rssize int32
+ Swrss int32
+ Tsize int32
+ Dsize int32
+ Ssize int32
+ Xstat uint16
+ Acflag uint16
+ Pctcpu uint32
+ Estcpu uint32
+ Slptime uint32
+ Swtime uint32
+ Cow uint32
+ Runtime uint64
+ Start Timeval
+ Childtime Timeval
+ Flag int32
+ Kiflag int32
+ Traceflag int32
+ Stat int8
+ Nice int8
+ Lock int8
+ Rqindex int8
+ Oncpu uint8
+ Lastcpu uint8
+ Tdname [17]int8
+ Wmesg [9]int8
+ Login [18]int8
+ Lockname [9]int8
+ Comm [20]int8
+ Emul [17]int8
+ Loginclass [18]int8
+ Sparestrings [50]int8
+ Spareints [4]int32
+ Flag2 int32
+ Fibnum int32
+ Cr_flags uint32
+ Jid int32
+ Numthreads int32
+ Tid int32
+ Pri Priority
+ Rusage Rusage
+ Rusage_ch Rusage
+ Pcb int32 /* pcb */
+ Kstack int32
+ Udata int32
+ Tdaddr int32 /* thread */
+ Spareptrs [6]int64
+ Sparelongs [12]int64
+ Sflag int64
+ Tdflags int64
+}
+
+type Priority struct {
+ Class uint8
+ Level uint8
+ Native uint8
+ User uint8
+}
+
+type KinfoVmentry struct {
+ Structsize int32
+ Type int32
+ Start uint64
+ End uint64
+ Offset uint64
+ Vn_fileid uint64
+ Vn_fsid uint32
+ Flags int32
+ Resident int32
+ Private_resident int32
+ Protection int32
+ Ref_count int32
+ Shadow_count int32
+ Vn_type int32
+ Vn_size uint64
+ Vn_rdev uint32
+ Vn_mode uint16
+ Status uint16
+ X_kve_ispare [12]int32
+ Path [1024]int8
+}
diff --git a/vendor/github.com/shirou/gopsutil/process/process_linux.go b/vendor/github.com/shirou/gopsutil/process/process_linux.go
new file mode 100644
index 0000000..ecdd7b4
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/process/process_linux.go
@@ -0,0 +1,1284 @@
+// +build linux
+
+package process
+
+import (
+ "bufio"
+ "bytes"
+ "context"
+ "encoding/json"
+ "fmt"
+ "io/ioutil"
+ "math"
+ "os"
+ "path/filepath"
+ "strconv"
+ "strings"
+
+ "github.com/shirou/gopsutil/cpu"
+ "github.com/shirou/gopsutil/host"
+ "github.com/shirou/gopsutil/internal/common"
+ "github.com/shirou/gopsutil/net"
+ "golang.org/x/sys/unix"
+)
+
+var PageSize = uint64(os.Getpagesize())
+
+const (
+ PrioProcess = 0 // linux/resource.h
+ ClockTicks = 100 // C.sysconf(C._SC_CLK_TCK)
+)
+
+// MemoryInfoExStat is different between OSes
+type MemoryInfoExStat struct {
+ RSS uint64 `json:"rss"` // bytes
+ VMS uint64 `json:"vms"` // bytes
+ Shared uint64 `json:"shared"` // bytes
+ Text uint64 `json:"text"` // bytes
+ Lib uint64 `json:"lib"` // bytes
+ Data uint64 `json:"data"` // bytes
+ Dirty uint64 `json:"dirty"` // bytes
+}
+
+func (m MemoryInfoExStat) String() string {
+ s, _ := json.Marshal(m)
+ return string(s)
+}
+
+type MemoryMapsStat struct {
+ Path string `json:"path"`
+ Rss uint64 `json:"rss"`
+ Size uint64 `json:"size"`
+ Pss uint64 `json:"pss"`
+ SharedClean uint64 `json:"sharedClean"`
+ SharedDirty uint64 `json:"sharedDirty"`
+ PrivateClean uint64 `json:"privateClean"`
+ PrivateDirty uint64 `json:"privateDirty"`
+ Referenced uint64 `json:"referenced"`
+ Anonymous uint64 `json:"anonymous"`
+ Swap uint64 `json:"swap"`
+}
+
+// String returns JSON value of the process.
+func (m MemoryMapsStat) String() string {
+ s, _ := json.Marshal(m)
+ return string(s)
+}
+
+// NewProcess creates a new Process instance, it only stores the pid and
+// checks that the process exists. Other method on Process can be used
+// to get more information about the process. An error will be returned
+// if the process does not exist.
+func NewProcess(pid int32) (*Process, error) {
+ p := &Process{
+ Pid: int32(pid),
+ }
+ file, err := os.Open(common.HostProc(strconv.Itoa(int(p.Pid))))
+ defer file.Close()
+ return p, err
+}
+
+// Ppid returns Parent Process ID of the process.
+func (p *Process) Ppid() (int32, error) {
+ return p.PpidWithContext(context.Background())
+}
+
+func (p *Process) PpidWithContext(ctx context.Context) (int32, error) {
+ _, ppid, _, _, _, _, err := p.fillFromStat()
+ if err != nil {
+ return -1, err
+ }
+ return ppid, nil
+}
+
+// Name returns name of the process.
+func (p *Process) Name() (string, error) {
+ return p.NameWithContext(context.Background())
+}
+
+func (p *Process) NameWithContext(ctx context.Context) (string, error) {
+ if p.name == "" {
+ if err := p.fillFromStatus(); err != nil {
+ return "", err
+ }
+ }
+ return p.name, nil
+}
+
+// Tgid returns tgid, a Linux-synonym for user-space Pid
+func (p *Process) Tgid() (int32, error) {
+ if p.tgid == 0 {
+ if err := p.fillFromStatus(); err != nil {
+ return 0, err
+ }
+ }
+ return p.tgid, nil
+}
+
+// Exe returns executable path of the process.
+func (p *Process) Exe() (string, error) {
+ return p.ExeWithContext(context.Background())
+}
+
+func (p *Process) ExeWithContext(ctx context.Context) (string, error) {
+ return p.fillFromExe()
+}
+
+// Cmdline returns the command line arguments of the process as a string with
+// each argument separated by 0x20 ascii character.
+func (p *Process) Cmdline() (string, error) {
+ return p.CmdlineWithContext(context.Background())
+}
+
+func (p *Process) CmdlineWithContext(ctx context.Context) (string, error) {
+ return p.fillFromCmdline()
+}
+
+// CmdlineSlice returns the command line arguments of the process as a slice with each
+// element being an argument.
+func (p *Process) CmdlineSlice() ([]string, error) {
+ return p.CmdlineSliceWithContext(context.Background())
+}
+
+func (p *Process) CmdlineSliceWithContext(ctx context.Context) ([]string, error) {
+ return p.fillSliceFromCmdline()
+}
+
+// CreateTime returns created time of the process in milliseconds since the epoch, in UTC.
+func (p *Process) CreateTime() (int64, error) {
+ return p.CreateTimeWithContext(context.Background())
+}
+
+func (p *Process) CreateTimeWithContext(ctx context.Context) (int64, error) {
+ _, _, _, createTime, _, _, err := p.fillFromStat()
+ if err != nil {
+ return 0, err
+ }
+ return createTime, nil
+}
+
+// Cwd returns current working directory of the process.
+func (p *Process) Cwd() (string, error) {
+ return p.CwdWithContext(context.Background())
+}
+
+func (p *Process) CwdWithContext(ctx context.Context) (string, error) {
+ return p.fillFromCwd()
+}
+
+// Parent returns parent Process of the process.
+func (p *Process) Parent() (*Process, error) {
+ return p.ParentWithContext(context.Background())
+}
+
+func (p *Process) ParentWithContext(ctx context.Context) (*Process, error) {
+ err := p.fillFromStatus()
+ if err != nil {
+ return nil, err
+ }
+ if p.parent == 0 {
+ return nil, fmt.Errorf("wrong number of parents")
+ }
+ return NewProcess(p.parent)
+}
+
+// Status returns the process status.
+// Return value could be one of these.
+// R: Running S: Sleep T: Stop I: Idle
+// Z: Zombie W: Wait L: Lock
+// The charactor is same within all supported platforms.
+func (p *Process) Status() (string, error) {
+ return p.StatusWithContext(context.Background())
+}
+
+func (p *Process) StatusWithContext(ctx context.Context) (string, error) {
+ err := p.fillFromStatus()
+ if err != nil {
+ return "", err
+ }
+ return p.status, nil
+}
+
+// Foreground returns true if the process is in foreground, false otherwise.
+func (p *Process) Foreground() (bool, error) {
+ return p.ForegroundWithContext(context.Background())
+}
+
+func (p *Process) ForegroundWithContext(ctx context.Context) (bool, error) {
+ // see https://github.com/shirou/gopsutil/issues/596#issuecomment-432707831 for implementation details
+ pid := p.Pid
+ statPath := common.HostProc(strconv.Itoa(int(pid)), "stat")
+ contents, err := ioutil.ReadFile(statPath)
+ if err != nil {
+ return false, err
+ }
+ fields := strings.Fields(string(contents))
+ if len(fields) < 8 {
+ return false, fmt.Errorf("insufficient data in %s", statPath)
+ }
+ pgid := fields[4]
+ tpgid := fields[7]
+ return pgid == tpgid, nil
+}
+
+// Uids returns user ids of the process as a slice of the int
+func (p *Process) Uids() ([]int32, error) {
+ return p.UidsWithContext(context.Background())
+}
+
+func (p *Process) UidsWithContext(ctx context.Context) ([]int32, error) {
+ err := p.fillFromStatus()
+ if err != nil {
+ return []int32{}, err
+ }
+ return p.uids, nil
+}
+
+// Gids returns group ids of the process as a slice of the int
+func (p *Process) Gids() ([]int32, error) {
+ return p.GidsWithContext(context.Background())
+}
+
+func (p *Process) GidsWithContext(ctx context.Context) ([]int32, error) {
+ err := p.fillFromStatus()
+ if err != nil {
+ return []int32{}, err
+ }
+ return p.gids, nil
+}
+
+// Terminal returns a terminal which is associated with the process.
+func (p *Process) Terminal() (string, error) {
+ return p.TerminalWithContext(context.Background())
+}
+
+func (p *Process) TerminalWithContext(ctx context.Context) (string, error) {
+ t, _, _, _, _, _, err := p.fillFromStat()
+ if err != nil {
+ return "", err
+ }
+ termmap, err := getTerminalMap()
+ if err != nil {
+ return "", err
+ }
+ terminal := termmap[t]
+ return terminal, nil
+}
+
+// Nice returns a nice value (priority).
+// Notice: gopsutil can not set nice value.
+func (p *Process) Nice() (int32, error) {
+ return p.NiceWithContext(context.Background())
+}
+
+func (p *Process) NiceWithContext(ctx context.Context) (int32, error) {
+ _, _, _, _, _, nice, err := p.fillFromStat()
+ if err != nil {
+ return 0, err
+ }
+ return nice, nil
+}
+
+// IOnice returns process I/O nice value (priority).
+func (p *Process) IOnice() (int32, error) {
+ return p.IOniceWithContext(context.Background())
+}
+
+func (p *Process) IOniceWithContext(ctx context.Context) (int32, error) {
+ return 0, common.ErrNotImplementedError
+}
+
+// Rlimit returns Resource Limits.
+func (p *Process) Rlimit() ([]RlimitStat, error) {
+ return p.RlimitWithContext(context.Background())
+}
+
+func (p *Process) RlimitWithContext(ctx context.Context) ([]RlimitStat, error) {
+ return p.RlimitUsage(false)
+}
+
+// RlimitUsage returns Resource Limits.
+// If gatherUsed is true, the currently used value will be gathered and added
+// to the resulting RlimitStat.
+func (p *Process) RlimitUsage(gatherUsed bool) ([]RlimitStat, error) {
+ return p.RlimitUsageWithContext(context.Background(), gatherUsed)
+}
+
+func (p *Process) RlimitUsageWithContext(ctx context.Context, gatherUsed bool) ([]RlimitStat, error) {
+ rlimits, err := p.fillFromLimits()
+ if !gatherUsed || err != nil {
+ return rlimits, err
+ }
+
+ _, _, _, _, rtprio, nice, err := p.fillFromStat()
+ if err != nil {
+ return nil, err
+ }
+ if err := p.fillFromStatus(); err != nil {
+ return nil, err
+ }
+
+ for i := range rlimits {
+ rs := &rlimits[i]
+ switch rs.Resource {
+ case RLIMIT_CPU:
+ times, err := p.Times()
+ if err != nil {
+ return nil, err
+ }
+ rs.Used = uint64(times.User + times.System)
+ case RLIMIT_DATA:
+ rs.Used = uint64(p.memInfo.Data)
+ case RLIMIT_STACK:
+ rs.Used = uint64(p.memInfo.Stack)
+ case RLIMIT_RSS:
+ rs.Used = uint64(p.memInfo.RSS)
+ case RLIMIT_NOFILE:
+ n, err := p.NumFDs()
+ if err != nil {
+ return nil, err
+ }
+ rs.Used = uint64(n)
+ case RLIMIT_MEMLOCK:
+ rs.Used = uint64(p.memInfo.Locked)
+ case RLIMIT_AS:
+ rs.Used = uint64(p.memInfo.VMS)
+ case RLIMIT_LOCKS:
+ //TODO we can get the used value from /proc/$pid/locks. But linux doesn't enforce it, so not a high priority.
+ case RLIMIT_SIGPENDING:
+ rs.Used = p.sigInfo.PendingProcess
+ case RLIMIT_NICE:
+ // The rlimit for nice is a little unusual, in that 0 means the niceness cannot be decreased beyond the current value, but it can be increased.
+ // So effectively: if rs.Soft == 0 { rs.Soft = rs.Used }
+ rs.Used = uint64(nice)
+ case RLIMIT_RTPRIO:
+ rs.Used = uint64(rtprio)
+ }
+ }
+
+ return rlimits, err
+}
+
+// IOCounters returns IO Counters.
+func (p *Process) IOCounters() (*IOCountersStat, error) {
+ return p.IOCountersWithContext(context.Background())
+}
+
+func (p *Process) IOCountersWithContext(ctx context.Context) (*IOCountersStat, error) {
+ return p.fillFromIO()
+}
+
+// NumCtxSwitches returns the number of the context switches of the process.
+func (p *Process) NumCtxSwitches() (*NumCtxSwitchesStat, error) {
+ return p.NumCtxSwitchesWithContext(context.Background())
+}
+
+func (p *Process) NumCtxSwitchesWithContext(ctx context.Context) (*NumCtxSwitchesStat, error) {
+ err := p.fillFromStatus()
+ if err != nil {
+ return nil, err
+ }
+ return p.numCtxSwitches, nil
+}
+
+// NumFDs returns the number of File Descriptors used by the process.
+func (p *Process) NumFDs() (int32, error) {
+ return p.NumFDsWithContext(context.Background())
+}
+
+func (p *Process) NumFDsWithContext(ctx context.Context) (int32, error) {
+ _, fnames, err := p.fillFromfdList()
+ return int32(len(fnames)), err
+}
+
+// NumThreads returns the number of threads used by the process.
+func (p *Process) NumThreads() (int32, error) {
+ return p.NumThreadsWithContext(context.Background())
+}
+
+func (p *Process) NumThreadsWithContext(ctx context.Context) (int32, error) {
+ err := p.fillFromStatus()
+ if err != nil {
+ return 0, err
+ }
+ return p.numThreads, nil
+}
+
+func (p *Process) Threads() (map[int32]*cpu.TimesStat, error) {
+ return p.ThreadsWithContext(context.Background())
+}
+
+func (p *Process) ThreadsWithContext(ctx context.Context) (map[int32]*cpu.TimesStat, error) {
+ ret := make(map[int32]*cpu.TimesStat)
+ taskPath := common.HostProc(strconv.Itoa(int(p.Pid)), "task")
+
+ tids, err := readPidsFromDir(taskPath)
+ if err != nil {
+ return nil, err
+ }
+
+ for _, tid := range tids {
+ _, _, cpuTimes, _, _, _, err := p.fillFromTIDStat(tid)
+ if err != nil {
+ return nil, err
+ }
+ ret[tid] = cpuTimes
+ }
+
+ return ret, nil
+}
+
+// Times returns CPU times of the process.
+func (p *Process) Times() (*cpu.TimesStat, error) {
+ return p.TimesWithContext(context.Background())
+}
+
+func (p *Process) TimesWithContext(ctx context.Context) (*cpu.TimesStat, error) {
+ _, _, cpuTimes, _, _, _, err := p.fillFromStat()
+ if err != nil {
+ return nil, err
+ }
+ return cpuTimes, nil
+}
+
+// CPUAffinity returns CPU affinity of the process.
+//
+// Notice: Not implemented yet.
+func (p *Process) CPUAffinity() ([]int32, error) {
+ return p.CPUAffinityWithContext(context.Background())
+}
+
+func (p *Process) CPUAffinityWithContext(ctx context.Context) ([]int32, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+// MemoryInfo returns platform in-dependend memory information, such as RSS, VMS and Swap
+func (p *Process) MemoryInfo() (*MemoryInfoStat, error) {
+ return p.MemoryInfoWithContext(context.Background())
+}
+
+func (p *Process) MemoryInfoWithContext(ctx context.Context) (*MemoryInfoStat, error) {
+ meminfo, _, err := p.fillFromStatm()
+ if err != nil {
+ return nil, err
+ }
+ return meminfo, nil
+}
+
+// MemoryInfoEx returns platform dependend memory information.
+func (p *Process) MemoryInfoEx() (*MemoryInfoExStat, error) {
+ return p.MemoryInfoExWithContext(context.Background())
+}
+
+func (p *Process) MemoryInfoExWithContext(ctx context.Context) (*MemoryInfoExStat, error) {
+ _, memInfoEx, err := p.fillFromStatm()
+ if err != nil {
+ return nil, err
+ }
+ return memInfoEx, nil
+}
+
+// Children returns a slice of Process of the process.
+func (p *Process) Children() ([]*Process, error) {
+ return p.ChildrenWithContext(context.Background())
+}
+
+func (p *Process) ChildrenWithContext(ctx context.Context) ([]*Process, error) {
+ pids, err := common.CallPgrepWithContext(ctx, invoke, p.Pid)
+ if err != nil {
+ if pids == nil || len(pids) == 0 {
+ return nil, ErrorNoChildren
+ }
+ return nil, err
+ }
+ ret := make([]*Process, 0, len(pids))
+ for _, pid := range pids {
+ np, err := NewProcess(pid)
+ if err != nil {
+ return nil, err
+ }
+ ret = append(ret, np)
+ }
+ return ret, nil
+}
+
+// OpenFiles returns a slice of OpenFilesStat opend by the process.
+// OpenFilesStat includes a file path and file descriptor.
+func (p *Process) OpenFiles() ([]OpenFilesStat, error) {
+ return p.OpenFilesWithContext(context.Background())
+}
+
+func (p *Process) OpenFilesWithContext(ctx context.Context) ([]OpenFilesStat, error) {
+ _, ofs, err := p.fillFromfd()
+ if err != nil {
+ return nil, err
+ }
+ ret := make([]OpenFilesStat, len(ofs))
+ for i, o := range ofs {
+ ret[i] = *o
+ }
+
+ return ret, nil
+}
+
+// Connections returns a slice of net.ConnectionStat used by the process.
+// This returns all kind of the connection. This measn TCP, UDP or UNIX.
+func (p *Process) Connections() ([]net.ConnectionStat, error) {
+ return p.ConnectionsWithContext(context.Background())
+}
+
+func (p *Process) ConnectionsWithContext(ctx context.Context) ([]net.ConnectionStat, error) {
+ return net.ConnectionsPid("all", p.Pid)
+}
+
+// NetIOCounters returns NetIOCounters of the process.
+func (p *Process) NetIOCounters(pernic bool) ([]net.IOCountersStat, error) {
+ return p.NetIOCountersWithContext(context.Background(), pernic)
+}
+
+func (p *Process) NetIOCountersWithContext(ctx context.Context, pernic bool) ([]net.IOCountersStat, error) {
+ filename := common.HostProc(strconv.Itoa(int(p.Pid)), "net/dev")
+ return net.IOCountersByFile(pernic, filename)
+}
+
+// IsRunning returns whether the process is running or not.
+// Not implemented yet.
+func (p *Process) IsRunning() (bool, error) {
+ return p.IsRunningWithContext(context.Background())
+}
+
+func (p *Process) IsRunningWithContext(ctx context.Context) (bool, error) {
+ return true, common.ErrNotImplementedError
+}
+
+// MemoryMaps get memory maps from /proc/(pid)/smaps
+func (p *Process) MemoryMaps(grouped bool) (*[]MemoryMapsStat, error) {
+ return p.MemoryMapsWithContext(context.Background(), grouped)
+}
+
+func (p *Process) MemoryMapsWithContext(ctx context.Context, grouped bool) (*[]MemoryMapsStat, error) {
+ pid := p.Pid
+ var ret []MemoryMapsStat
+ smapsPath := common.HostProc(strconv.Itoa(int(pid)), "smaps")
+ contents, err := ioutil.ReadFile(smapsPath)
+ if err != nil {
+ return nil, err
+ }
+ lines := strings.Split(string(contents), "\n")
+
+ // function of parsing a block
+ getBlock := func(first_line []string, block []string) (MemoryMapsStat, error) {
+ m := MemoryMapsStat{}
+ m.Path = first_line[len(first_line)-1]
+
+ for _, line := range block {
+ if strings.Contains(line, "VmFlags") {
+ continue
+ }
+ field := strings.Split(line, ":")
+ if len(field) < 2 {
+ continue
+ }
+ v := strings.Trim(field[1], " kB") // remove last "kB"
+ t, err := strconv.ParseUint(v, 10, 64)
+ if err != nil {
+ return m, err
+ }
+
+ switch field[0] {
+ case "Size":
+ m.Size = t
+ case "Rss":
+ m.Rss = t
+ case "Pss":
+ m.Pss = t
+ case "Shared_Clean":
+ m.SharedClean = t
+ case "Shared_Dirty":
+ m.SharedDirty = t
+ case "Private_Clean":
+ m.PrivateClean = t
+ case "Private_Dirty":
+ m.PrivateDirty = t
+ case "Referenced":
+ m.Referenced = t
+ case "Anonymous":
+ m.Anonymous = t
+ case "Swap":
+ m.Swap = t
+ }
+ }
+ return m, nil
+ }
+
+ blocks := make([]string, 16)
+ for _, line := range lines {
+ field := strings.Split(line, " ")
+ if strings.HasSuffix(field[0], ":") == false {
+ // new block section
+ if len(blocks) > 0 {
+ g, err := getBlock(field, blocks)
+ if err != nil {
+ return &ret, err
+ }
+ ret = append(ret, g)
+ }
+ // starts new block
+ blocks = make([]string, 16)
+ } else {
+ blocks = append(blocks, line)
+ }
+ }
+
+ return &ret, nil
+}
+
+/**
+** Internal functions
+**/
+
+func limitToInt(val string) (int32, error) {
+ if val == "unlimited" {
+ return math.MaxInt32, nil
+ } else {
+ res, err := strconv.ParseInt(val, 10, 32)
+ if err != nil {
+ return 0, err
+ }
+ return int32(res), nil
+ }
+}
+
+// Get num_fds from /proc/(pid)/limits
+func (p *Process) fillFromLimits() ([]RlimitStat, error) {
+ return p.fillFromLimitsWithContext(context.Background())
+}
+
+func (p *Process) fillFromLimitsWithContext(ctx context.Context) ([]RlimitStat, error) {
+ pid := p.Pid
+ limitsFile := common.HostProc(strconv.Itoa(int(pid)), "limits")
+ d, err := os.Open(limitsFile)
+ if err != nil {
+ return nil, err
+ }
+ defer d.Close()
+
+ var limitStats []RlimitStat
+
+ limitsScanner := bufio.NewScanner(d)
+ for limitsScanner.Scan() {
+ var statItem RlimitStat
+
+ str := strings.Fields(limitsScanner.Text())
+
+ // Remove the header line
+ if strings.Contains(str[len(str)-1], "Units") {
+ continue
+ }
+
+ // Assert that last item is a Hard limit
+ statItem.Hard, err = limitToInt(str[len(str)-1])
+ if err != nil {
+ // On error remove last item an try once again since it can be unit or header line
+ str = str[:len(str)-1]
+ statItem.Hard, err = limitToInt(str[len(str)-1])
+ if err != nil {
+ return nil, err
+ }
+ }
+ // Remove last item from string
+ str = str[:len(str)-1]
+
+ //Now last item is a Soft limit
+ statItem.Soft, err = limitToInt(str[len(str)-1])
+ if err != nil {
+ return nil, err
+ }
+ // Remove last item from string
+ str = str[:len(str)-1]
+
+ //The rest is a stats name
+ resourceName := strings.Join(str, " ")
+ switch resourceName {
+ case "Max cpu time":
+ statItem.Resource = RLIMIT_CPU
+ case "Max file size":
+ statItem.Resource = RLIMIT_FSIZE
+ case "Max data size":
+ statItem.Resource = RLIMIT_DATA
+ case "Max stack size":
+ statItem.Resource = RLIMIT_STACK
+ case "Max core file size":
+ statItem.Resource = RLIMIT_CORE
+ case "Max resident set":
+ statItem.Resource = RLIMIT_RSS
+ case "Max processes":
+ statItem.Resource = RLIMIT_NPROC
+ case "Max open files":
+ statItem.Resource = RLIMIT_NOFILE
+ case "Max locked memory":
+ statItem.Resource = RLIMIT_MEMLOCK
+ case "Max address space":
+ statItem.Resource = RLIMIT_AS
+ case "Max file locks":
+ statItem.Resource = RLIMIT_LOCKS
+ case "Max pending signals":
+ statItem.Resource = RLIMIT_SIGPENDING
+ case "Max msgqueue size":
+ statItem.Resource = RLIMIT_MSGQUEUE
+ case "Max nice priority":
+ statItem.Resource = RLIMIT_NICE
+ case "Max realtime priority":
+ statItem.Resource = RLIMIT_RTPRIO
+ case "Max realtime timeout":
+ statItem.Resource = RLIMIT_RTTIME
+ default:
+ continue
+ }
+
+ limitStats = append(limitStats, statItem)
+ }
+
+ if err := limitsScanner.Err(); err != nil {
+ return nil, err
+ }
+
+ return limitStats, nil
+}
+
+// Get list of /proc/(pid)/fd files
+func (p *Process) fillFromfdList() (string, []string, error) {
+ return p.fillFromfdListWithContext(context.Background())
+}
+
+func (p *Process) fillFromfdListWithContext(ctx context.Context) (string, []string, error) {
+ pid := p.Pid
+ statPath := common.HostProc(strconv.Itoa(int(pid)), "fd")
+ d, err := os.Open(statPath)
+ if err != nil {
+ return statPath, []string{}, err
+ }
+ defer d.Close()
+ fnames, err := d.Readdirnames(-1)
+ return statPath, fnames, err
+}
+
+// Get num_fds from /proc/(pid)/fd
+func (p *Process) fillFromfd() (int32, []*OpenFilesStat, error) {
+ return p.fillFromfdWithContext(context.Background())
+}
+
+func (p *Process) fillFromfdWithContext(ctx context.Context) (int32, []*OpenFilesStat, error) {
+ statPath, fnames, err := p.fillFromfdList()
+ if err != nil {
+ return 0, nil, err
+ }
+ numFDs := int32(len(fnames))
+
+ var openfiles []*OpenFilesStat
+ for _, fd := range fnames {
+ fpath := filepath.Join(statPath, fd)
+ filepath, err := os.Readlink(fpath)
+ if err != nil {
+ continue
+ }
+ t, err := strconv.ParseUint(fd, 10, 64)
+ if err != nil {
+ return numFDs, openfiles, err
+ }
+ o := &OpenFilesStat{
+ Path: filepath,
+ Fd: t,
+ }
+ openfiles = append(openfiles, o)
+ }
+
+ return numFDs, openfiles, nil
+}
+
+// Get cwd from /proc/(pid)/cwd
+func (p *Process) fillFromCwd() (string, error) {
+ return p.fillFromCwdWithContext(context.Background())
+}
+
+func (p *Process) fillFromCwdWithContext(ctx context.Context) (string, error) {
+ pid := p.Pid
+ cwdPath := common.HostProc(strconv.Itoa(int(pid)), "cwd")
+ cwd, err := os.Readlink(cwdPath)
+ if err != nil {
+ return "", err
+ }
+ return string(cwd), nil
+}
+
+// Get exe from /proc/(pid)/exe
+func (p *Process) fillFromExe() (string, error) {
+ return p.fillFromExeWithContext(context.Background())
+}
+
+func (p *Process) fillFromExeWithContext(ctx context.Context) (string, error) {
+ pid := p.Pid
+ exePath := common.HostProc(strconv.Itoa(int(pid)), "exe")
+ exe, err := os.Readlink(exePath)
+ if err != nil {
+ return "", err
+ }
+ return string(exe), nil
+}
+
+// Get cmdline from /proc/(pid)/cmdline
+func (p *Process) fillFromCmdline() (string, error) {
+ return p.fillFromCmdlineWithContext(context.Background())
+}
+
+func (p *Process) fillFromCmdlineWithContext(ctx context.Context) (string, error) {
+ pid := p.Pid
+ cmdPath := common.HostProc(strconv.Itoa(int(pid)), "cmdline")
+ cmdline, err := ioutil.ReadFile(cmdPath)
+ if err != nil {
+ return "", err
+ }
+ ret := strings.FieldsFunc(string(cmdline), func(r rune) bool {
+ if r == '\u0000' {
+ return true
+ }
+ return false
+ })
+
+ return strings.Join(ret, " "), nil
+}
+
+func (p *Process) fillSliceFromCmdline() ([]string, error) {
+ return p.fillSliceFromCmdlineWithContext(context.Background())
+}
+
+func (p *Process) fillSliceFromCmdlineWithContext(ctx context.Context) ([]string, error) {
+ pid := p.Pid
+ cmdPath := common.HostProc(strconv.Itoa(int(pid)), "cmdline")
+ cmdline, err := ioutil.ReadFile(cmdPath)
+ if err != nil {
+ return nil, err
+ }
+ if len(cmdline) == 0 {
+ return nil, nil
+ }
+ if cmdline[len(cmdline)-1] == 0 {
+ cmdline = cmdline[:len(cmdline)-1]
+ }
+ parts := bytes.Split(cmdline, []byte{0})
+ var strParts []string
+ for _, p := range parts {
+ strParts = append(strParts, string(p))
+ }
+
+ return strParts, nil
+}
+
+// Get IO status from /proc/(pid)/io
+func (p *Process) fillFromIO() (*IOCountersStat, error) {
+ return p.fillFromIOWithContext(context.Background())
+}
+
+func (p *Process) fillFromIOWithContext(ctx context.Context) (*IOCountersStat, error) {
+ pid := p.Pid
+ ioPath := common.HostProc(strconv.Itoa(int(pid)), "io")
+ ioline, err := ioutil.ReadFile(ioPath)
+ if err != nil {
+ return nil, err
+ }
+ lines := strings.Split(string(ioline), "\n")
+ ret := &IOCountersStat{}
+
+ for _, line := range lines {
+ field := strings.Fields(line)
+ if len(field) < 2 {
+ continue
+ }
+ t, err := strconv.ParseUint(field[1], 10, 64)
+ if err != nil {
+ return nil, err
+ }
+ param := field[0]
+ if strings.HasSuffix(param, ":") {
+ param = param[:len(param)-1]
+ }
+ switch param {
+ case "syscr":
+ ret.ReadCount = t
+ case "syscw":
+ ret.WriteCount = t
+ case "read_bytes":
+ ret.ReadBytes = t
+ case "write_bytes":
+ ret.WriteBytes = t
+ }
+ }
+
+ return ret, nil
+}
+
+// Get memory info from /proc/(pid)/statm
+func (p *Process) fillFromStatm() (*MemoryInfoStat, *MemoryInfoExStat, error) {
+ return p.fillFromStatmWithContext(context.Background())
+}
+
+func (p *Process) fillFromStatmWithContext(ctx context.Context) (*MemoryInfoStat, *MemoryInfoExStat, error) {
+ pid := p.Pid
+ memPath := common.HostProc(strconv.Itoa(int(pid)), "statm")
+ contents, err := ioutil.ReadFile(memPath)
+ if err != nil {
+ return nil, nil, err
+ }
+ fields := strings.Split(string(contents), " ")
+
+ vms, err := strconv.ParseUint(fields[0], 10, 64)
+ if err != nil {
+ return nil, nil, err
+ }
+ rss, err := strconv.ParseUint(fields[1], 10, 64)
+ if err != nil {
+ return nil, nil, err
+ }
+ memInfo := &MemoryInfoStat{
+ RSS: rss * PageSize,
+ VMS: vms * PageSize,
+ }
+
+ shared, err := strconv.ParseUint(fields[2], 10, 64)
+ if err != nil {
+ return nil, nil, err
+ }
+ text, err := strconv.ParseUint(fields[3], 10, 64)
+ if err != nil {
+ return nil, nil, err
+ }
+ lib, err := strconv.ParseUint(fields[4], 10, 64)
+ if err != nil {
+ return nil, nil, err
+ }
+ dirty, err := strconv.ParseUint(fields[5], 10, 64)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ memInfoEx := &MemoryInfoExStat{
+ RSS: rss * PageSize,
+ VMS: vms * PageSize,
+ Shared: shared * PageSize,
+ Text: text * PageSize,
+ Lib: lib * PageSize,
+ Dirty: dirty * PageSize,
+ }
+
+ return memInfo, memInfoEx, nil
+}
+
+// Get various status from /proc/(pid)/status
+func (p *Process) fillFromStatus() error {
+ return p.fillFromStatusWithContext(context.Background())
+}
+
+func (p *Process) fillFromStatusWithContext(ctx context.Context) error {
+ pid := p.Pid
+ statPath := common.HostProc(strconv.Itoa(int(pid)), "status")
+ contents, err := ioutil.ReadFile(statPath)
+ if err != nil {
+ return err
+ }
+ lines := strings.Split(string(contents), "\n")
+ p.numCtxSwitches = &NumCtxSwitchesStat{}
+ p.memInfo = &MemoryInfoStat{}
+ p.sigInfo = &SignalInfoStat{}
+ for _, line := range lines {
+ tabParts := strings.SplitN(line, "\t", 2)
+ if len(tabParts) < 2 {
+ continue
+ }
+ value := tabParts[1]
+ switch strings.TrimRight(tabParts[0], ":") {
+ case "Name":
+ p.name = strings.Trim(value, " \t")
+ if len(p.name) >= 15 {
+ cmdlineSlice, err := p.CmdlineSlice()
+ if err != nil {
+ return err
+ }
+ if len(cmdlineSlice) > 0 {
+ extendedName := filepath.Base(cmdlineSlice[0])
+ if strings.HasPrefix(extendedName, p.name) {
+ p.name = extendedName
+ } else {
+ p.name = cmdlineSlice[0]
+ }
+ }
+ }
+ case "State":
+ p.status = value[0:1]
+ case "PPid", "Ppid":
+ pval, err := strconv.ParseInt(value, 10, 32)
+ if err != nil {
+ return err
+ }
+ p.parent = int32(pval)
+ case "Tgid":
+ pval, err := strconv.ParseInt(value, 10, 32)
+ if err != nil {
+ return err
+ }
+ p.tgid = int32(pval)
+ case "Uid":
+ p.uids = make([]int32, 0, 4)
+ for _, i := range strings.Split(value, "\t") {
+ v, err := strconv.ParseInt(i, 10, 32)
+ if err != nil {
+ return err
+ }
+ p.uids = append(p.uids, int32(v))
+ }
+ case "Gid":
+ p.gids = make([]int32, 0, 4)
+ for _, i := range strings.Split(value, "\t") {
+ v, err := strconv.ParseInt(i, 10, 32)
+ if err != nil {
+ return err
+ }
+ p.gids = append(p.gids, int32(v))
+ }
+ case "Threads":
+ v, err := strconv.ParseInt(value, 10, 32)
+ if err != nil {
+ return err
+ }
+ p.numThreads = int32(v)
+ case "voluntary_ctxt_switches":
+ v, err := strconv.ParseInt(value, 10, 64)
+ if err != nil {
+ return err
+ }
+ p.numCtxSwitches.Voluntary = v
+ case "nonvoluntary_ctxt_switches":
+ v, err := strconv.ParseInt(value, 10, 64)
+ if err != nil {
+ return err
+ }
+ p.numCtxSwitches.Involuntary = v
+ case "VmRSS":
+ value := strings.Trim(value, " kB") // remove last "kB"
+ v, err := strconv.ParseUint(value, 10, 64)
+ if err != nil {
+ return err
+ }
+ p.memInfo.RSS = v * 1024
+ case "VmSize":
+ value := strings.Trim(value, " kB") // remove last "kB"
+ v, err := strconv.ParseUint(value, 10, 64)
+ if err != nil {
+ return err
+ }
+ p.memInfo.VMS = v * 1024
+ case "VmSwap":
+ value := strings.Trim(value, " kB") // remove last "kB"
+ v, err := strconv.ParseUint(value, 10, 64)
+ if err != nil {
+ return err
+ }
+ p.memInfo.Swap = v * 1024
+ case "VmData":
+ value := strings.Trim(value, " kB") // remove last "kB"
+ v, err := strconv.ParseUint(value, 10, 64)
+ if err != nil {
+ return err
+ }
+ p.memInfo.Data = v * 1024
+ case "VmStk":
+ value := strings.Trim(value, " kB") // remove last "kB"
+ v, err := strconv.ParseUint(value, 10, 64)
+ if err != nil {
+ return err
+ }
+ p.memInfo.Stack = v * 1024
+ case "VmLck":
+ value := strings.Trim(value, " kB") // remove last "kB"
+ v, err := strconv.ParseUint(value, 10, 64)
+ if err != nil {
+ return err
+ }
+ p.memInfo.Locked = v * 1024
+ case "SigPnd":
+ v, err := strconv.ParseUint(value, 16, 64)
+ if err != nil {
+ return err
+ }
+ p.sigInfo.PendingThread = v
+ case "ShdPnd":
+ v, err := strconv.ParseUint(value, 16, 64)
+ if err != nil {
+ return err
+ }
+ p.sigInfo.PendingProcess = v
+ case "SigBlk":
+ v, err := strconv.ParseUint(value, 16, 64)
+ if err != nil {
+ return err
+ }
+ p.sigInfo.Blocked = v
+ case "SigIgn":
+ v, err := strconv.ParseUint(value, 16, 64)
+ if err != nil {
+ return err
+ }
+ p.sigInfo.Ignored = v
+ case "SigCgt":
+ v, err := strconv.ParseUint(value, 16, 64)
+ if err != nil {
+ return err
+ }
+ p.sigInfo.Caught = v
+ }
+
+ }
+ return nil
+}
+
+func (p *Process) fillFromTIDStat(tid int32) (uint64, int32, *cpu.TimesStat, int64, uint32, int32, error) {
+ return p.fillFromTIDStatWithContext(context.Background(), tid)
+}
+
+func (p *Process) fillFromTIDStatWithContext(ctx context.Context, tid int32) (uint64, int32, *cpu.TimesStat, int64, uint32, int32, error) {
+ pid := p.Pid
+ var statPath string
+
+ if tid == -1 {
+ statPath = common.HostProc(strconv.Itoa(int(pid)), "stat")
+ } else {
+ statPath = common.HostProc(strconv.Itoa(int(pid)), "task", strconv.Itoa(int(tid)), "stat")
+ }
+
+ contents, err := ioutil.ReadFile(statPath)
+ if err != nil {
+ return 0, 0, nil, 0, 0, 0, err
+ }
+ fields := strings.Fields(string(contents))
+
+ i := 1
+ for !strings.HasSuffix(fields[i], ")") {
+ i++
+ }
+
+ terminal, err := strconv.ParseUint(fields[i+5], 10, 64)
+ if err != nil {
+ return 0, 0, nil, 0, 0, 0, err
+ }
+
+ ppid, err := strconv.ParseInt(fields[i+2], 10, 32)
+ if err != nil {
+ return 0, 0, nil, 0, 0, 0, err
+ }
+ utime, err := strconv.ParseFloat(fields[i+12], 64)
+ if err != nil {
+ return 0, 0, nil, 0, 0, 0, err
+ }
+
+ stime, err := strconv.ParseFloat(fields[i+13], 64)
+ if err != nil {
+ return 0, 0, nil, 0, 0, 0, err
+ }
+
+ cpuTimes := &cpu.TimesStat{
+ CPU: "cpu",
+ User: float64(utime / ClockTicks),
+ System: float64(stime / ClockTicks),
+ }
+
+ bootTime, _ := host.BootTime()
+ t, err := strconv.ParseUint(fields[i+20], 10, 64)
+ if err != nil {
+ return 0, 0, nil, 0, 0, 0, err
+ }
+ ctime := (t / uint64(ClockTicks)) + uint64(bootTime)
+ createTime := int64(ctime * 1000)
+
+ rtpriority, err := strconv.ParseInt(fields[i+16], 10, 32)
+ if err != nil {
+ return 0, 0, nil, 0, 0, 0, err
+ }
+ if rtpriority < 0 {
+ rtpriority = rtpriority*-1 - 1
+ } else {
+ rtpriority = 0
+ }
+
+ // p.Nice = mustParseInt32(fields[18])
+ // use syscall instead of parse Stat file
+ snice, _ := unix.Getpriority(PrioProcess, int(pid))
+ nice := int32(snice) // FIXME: is this true?
+
+ return terminal, int32(ppid), cpuTimes, createTime, uint32(rtpriority), nice, nil
+}
+
+func (p *Process) fillFromStat() (uint64, int32, *cpu.TimesStat, int64, uint32, int32, error) {
+ return p.fillFromStatWithContext(context.Background())
+}
+
+func (p *Process) fillFromStatWithContext(ctx context.Context) (uint64, int32, *cpu.TimesStat, int64, uint32, int32, error) {
+ return p.fillFromTIDStat(-1)
+}
+
+// Pids returns a slice of process ID list which are running now.
+func Pids() ([]int32, error) {
+ return PidsWithContext(context.Background())
+}
+
+func PidsWithContext(ctx context.Context) ([]int32, error) {
+ return readPidsFromDir(common.HostProc())
+}
+
+// Process returns a slice of pointers to Process structs for all
+// currently running processes.
+func Processes() ([]*Process, error) {
+ return ProcessesWithContext(context.Background())
+}
+
+func ProcessesWithContext(ctx context.Context) ([]*Process, error) {
+ out := []*Process{}
+
+ pids, err := PidsWithContext(ctx)
+ if err != nil {
+ return out, err
+ }
+
+ for _, pid := range pids {
+ p, err := NewProcess(pid)
+ if err != nil {
+ continue
+ }
+ out = append(out, p)
+ }
+
+ return out, nil
+}
+
+func readPidsFromDir(path string) ([]int32, error) {
+ var ret []int32
+
+ d, err := os.Open(path)
+ if err != nil {
+ return nil, err
+ }
+ defer d.Close()
+
+ fnames, err := d.Readdirnames(-1)
+ if err != nil {
+ return nil, err
+ }
+ for _, fname := range fnames {
+ pid, err := strconv.ParseInt(fname, 10, 32)
+ if err != nil {
+ // if not numeric name, just skip
+ continue
+ }
+ ret = append(ret, int32(pid))
+ }
+
+ return ret, nil
+}
diff --git a/vendor/github.com/shirou/gopsutil/process/process_openbsd.go b/vendor/github.com/shirou/gopsutil/process/process_openbsd.go
new file mode 100644
index 0000000..f9e0a08
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/process/process_openbsd.go
@@ -0,0 +1,527 @@
+// +build openbsd
+
+package process
+
+import (
+ "C"
+ "bytes"
+ "context"
+ "encoding/binary"
+ "strings"
+ "unsafe"
+
+ cpu "github.com/shirou/gopsutil/cpu"
+ "github.com/shirou/gopsutil/internal/common"
+ mem "github.com/shirou/gopsutil/mem"
+ net "github.com/shirou/gopsutil/net"
+ "golang.org/x/sys/unix"
+)
+
+// MemoryInfoExStat is different between OSes
+type MemoryInfoExStat struct {
+}
+
+type MemoryMapsStat struct {
+}
+
+func Pids() ([]int32, error) {
+ return PidsWithContext(context.Background())
+}
+
+func PidsWithContext(ctx context.Context) ([]int32, error) {
+ var ret []int32
+ procs, err := Processes()
+ if err != nil {
+ return ret, nil
+ }
+
+ for _, p := range procs {
+ ret = append(ret, p.Pid)
+ }
+
+ return ret, nil
+}
+
+func (p *Process) Ppid() (int32, error) {
+ return p.PpidWithContext(context.Background())
+}
+
+func (p *Process) PpidWithContext(ctx context.Context) (int32, error) {
+ k, err := p.getKProc()
+ if err != nil {
+ return 0, err
+ }
+
+ return k.Ppid, nil
+}
+func (p *Process) Name() (string, error) {
+ return p.NameWithContext(context.Background())
+}
+
+func (p *Process) NameWithContext(ctx context.Context) (string, error) {
+ k, err := p.getKProc()
+ if err != nil {
+ return "", err
+ }
+
+ return common.IntToString(k.Comm[:]), nil
+}
+func (p *Process) Tgid() (int32, error) {
+ return 0, common.ErrNotImplementedError
+}
+func (p *Process) Exe() (string, error) {
+ return p.ExeWithContext(context.Background())
+}
+
+func (p *Process) ExeWithContext(ctx context.Context) (string, error) {
+ return "", common.ErrNotImplementedError
+}
+
+func (p *Process) CmdlineSlice() ([]string, error) {
+ return p.CmdlineSliceWithContext(context.Background())
+}
+
+func (p *Process) CmdlineSliceWithContext(ctx context.Context) ([]string, error) {
+ mib := []int32{CTLKern, KernProcArgs, p.Pid, KernProcArgv}
+ buf, _, err := common.CallSyscall(mib)
+
+ if err != nil {
+ return nil, err
+ }
+
+ argc := 0
+ argvp := unsafe.Pointer(&buf[0])
+ argv := *(**C.char)(unsafe.Pointer(argvp))
+ size := unsafe.Sizeof(argv)
+ var strParts []string
+
+ for argv != nil {
+ strParts = append(strParts, C.GoString(argv))
+
+ argc++
+ argv = *(**C.char)(unsafe.Pointer(uintptr(argvp) + uintptr(argc)*size))
+ }
+ return strParts, nil
+}
+
+func (p *Process) Cmdline() (string, error) {
+ return p.CmdlineWithContext(context.Background())
+}
+
+func (p *Process) CmdlineWithContext(ctx context.Context) (string, error) {
+ argv, err := p.CmdlineSlice()
+ if err != nil {
+ return "", err
+ }
+ return strings.Join(argv, " "), nil
+}
+
+func (p *Process) CreateTime() (int64, error) {
+ return p.CreateTimeWithContext(context.Background())
+}
+
+func (p *Process) CreateTimeWithContext(ctx context.Context) (int64, error) {
+ return 0, common.ErrNotImplementedError
+}
+func (p *Process) Cwd() (string, error) {
+ return p.CwdWithContext(context.Background())
+}
+
+func (p *Process) CwdWithContext(ctx context.Context) (string, error) {
+ return "", common.ErrNotImplementedError
+}
+func (p *Process) Parent() (*Process, error) {
+ return p.ParentWithContext(context.Background())
+}
+
+func (p *Process) ParentWithContext(ctx context.Context) (*Process, error) {
+ return p, common.ErrNotImplementedError
+}
+func (p *Process) Status() (string, error) {
+ return p.StatusWithContext(context.Background())
+}
+
+func (p *Process) StatusWithContext(ctx context.Context) (string, error) {
+ k, err := p.getKProc()
+ if err != nil {
+ return "", err
+ }
+ var s string
+ switch k.Stat {
+ case SIDL:
+ case SRUN:
+ case SONPROC:
+ s = "R"
+ case SSLEEP:
+ s = "S"
+ case SSTOP:
+ s = "T"
+ case SDEAD:
+ s = "Z"
+ }
+
+ return s, nil
+}
+func (p *Process) Foreground() (bool, error) {
+ return p.ForegroundWithContext(context.Background())
+}
+
+func (p *Process) ForegroundWithContext(ctx context.Context) (bool, error) {
+ // see https://github.com/shirou/gopsutil/issues/596#issuecomment-432707831 for implementation details
+ pid := p.Pid
+ ps, err := exec.LookPath("ps")
+ if err != nil {
+ return false, err
+ }
+ out, err := invoke.CommandWithContext(ctx, ps, "-o", "stat=", "-p", strconv.Itoa(int(pid)))
+ if err != nil {
+ return false, err
+ }
+ return strings.IndexByte(string(out), '+') != -1, nil
+}
+func (p *Process) Uids() ([]int32, error) {
+ return p.UidsWithContext(context.Background())
+}
+
+func (p *Process) UidsWithContext(ctx context.Context) ([]int32, error) {
+ k, err := p.getKProc()
+ if err != nil {
+ return nil, err
+ }
+
+ uids := make([]int32, 0, 3)
+
+ uids = append(uids, int32(k.Ruid), int32(k.Uid), int32(k.Svuid))
+
+ return uids, nil
+}
+func (p *Process) Gids() ([]int32, error) {
+ return p.GidsWithContext(context.Background())
+}
+
+func (p *Process) GidsWithContext(ctx context.Context) ([]int32, error) {
+ k, err := p.getKProc()
+ if err != nil {
+ return nil, err
+ }
+
+ gids := make([]int32, 0, 3)
+ gids = append(gids, int32(k.Rgid), int32(k.Ngroups), int32(k.Svgid))
+
+ return gids, nil
+}
+func (p *Process) Terminal() (string, error) {
+ return p.TerminalWithContext(context.Background())
+}
+
+func (p *Process) TerminalWithContext(ctx context.Context) (string, error) {
+ k, err := p.getKProc()
+ if err != nil {
+ return "", err
+ }
+
+ ttyNr := uint64(k.Tdev)
+
+ termmap, err := getTerminalMap()
+ if err != nil {
+ return "", err
+ }
+
+ return termmap[ttyNr], nil
+}
+func (p *Process) Nice() (int32, error) {
+ return p.NiceWithContext(context.Background())
+}
+
+func (p *Process) NiceWithContext(ctx context.Context) (int32, error) {
+ k, err := p.getKProc()
+ if err != nil {
+ return 0, err
+ }
+ return int32(k.Nice), nil
+}
+func (p *Process) IOnice() (int32, error) {
+ return p.IOniceWithContext(context.Background())
+}
+
+func (p *Process) IOniceWithContext(ctx context.Context) (int32, error) {
+ return 0, common.ErrNotImplementedError
+}
+func (p *Process) Rlimit() ([]RlimitStat, error) {
+ return p.RlimitWithContext(context.Background())
+}
+
+func (p *Process) RlimitWithContext(ctx context.Context) ([]RlimitStat, error) {
+ var rlimit []RlimitStat
+ return rlimit, common.ErrNotImplementedError
+}
+func (p *Process) RlimitUsage(gatherUsed bool) ([]RlimitStat, error) {
+ return p.RlimitUsageWithContext(context.Background(), gatherUsed)
+}
+
+func (p *Process) RlimitUsageWithContext(ctx context.Context, gatherUsed bool) ([]RlimitStat, error) {
+ var rlimit []RlimitStat
+ return rlimit, common.ErrNotImplementedError
+}
+func (p *Process) IOCounters() (*IOCountersStat, error) {
+ return p.IOCountersWithContext(context.Background())
+}
+
+func (p *Process) IOCountersWithContext(ctx context.Context) (*IOCountersStat, error) {
+ k, err := p.getKProc()
+ if err != nil {
+ return nil, err
+ }
+ return &IOCountersStat{
+ ReadCount: uint64(k.Uru_inblock),
+ WriteCount: uint64(k.Uru_oublock),
+ }, nil
+}
+func (p *Process) NumCtxSwitches() (*NumCtxSwitchesStat, error) {
+ return p.NumCtxSwitchesWithContext(context.Background())
+}
+
+func (p *Process) NumCtxSwitchesWithContext(ctx context.Context) (*NumCtxSwitchesStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+func (p *Process) NumFDs() (int32, error) {
+ return p.NumFDsWithContext(context.Background())
+}
+
+func (p *Process) NumFDsWithContext(ctx context.Context) (int32, error) {
+ return 0, common.ErrNotImplementedError
+}
+func (p *Process) NumThreads() (int32, error) {
+ return p.NumThreadsWithContext(context.Background())
+}
+
+func (p *Process) NumThreadsWithContext(ctx context.Context) (int32, error) {
+ /* not supported, just return 1 */
+ return 1, nil
+}
+func (p *Process) Threads() (map[int32]*cpu.TimesStat, error) {
+ return p.ThreadsWithContext(context.Background())
+}
+
+func (p *Process) ThreadsWithContext(ctx context.Context) (map[int32]*cpu.TimesStat, error) {
+ ret := make(map[int32]*cpu.TimesStat)
+ return ret, common.ErrNotImplementedError
+}
+func (p *Process) Times() (*cpu.TimesStat, error) {
+ return p.TimesWithContext(context.Background())
+}
+
+func (p *Process) TimesWithContext(ctx context.Context) (*cpu.TimesStat, error) {
+ k, err := p.getKProc()
+ if err != nil {
+ return nil, err
+ }
+ return &cpu.TimesStat{
+ CPU: "cpu",
+ User: float64(k.Uutime_sec) + float64(k.Uutime_usec)/1000000,
+ System: float64(k.Ustime_sec) + float64(k.Ustime_usec)/1000000,
+ }, nil
+}
+func (p *Process) CPUAffinity() ([]int32, error) {
+ return p.CPUAffinityWithContext(context.Background())
+}
+
+func (p *Process) CPUAffinityWithContext(ctx context.Context) ([]int32, error) {
+ return nil, common.ErrNotImplementedError
+}
+func (p *Process) MemoryInfo() (*MemoryInfoStat, error) {
+ return p.MemoryInfoWithContext(context.Background())
+}
+
+func (p *Process) MemoryInfoWithContext(ctx context.Context) (*MemoryInfoStat, error) {
+ k, err := p.getKProc()
+ if err != nil {
+ return nil, err
+ }
+ pageSize, err := mem.GetPageSize()
+ if err != nil {
+ return nil, err
+ }
+
+ return &MemoryInfoStat{
+ RSS: uint64(k.Vm_rssize) * pageSize,
+ VMS: uint64(k.Vm_tsize) + uint64(k.Vm_dsize) +
+ uint64(k.Vm_ssize),
+ }, nil
+}
+func (p *Process) MemoryInfoEx() (*MemoryInfoExStat, error) {
+ return p.MemoryInfoExWithContext(context.Background())
+}
+
+func (p *Process) MemoryInfoExWithContext(ctx context.Context) (*MemoryInfoExStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) Children() ([]*Process, error) {
+ return p.ChildrenWithContext(context.Background())
+}
+
+func (p *Process) ChildrenWithContext(ctx context.Context) ([]*Process, error) {
+ pids, err := common.CallPgrepWithContext(ctx, invoke, p.Pid)
+ if err != nil {
+ return nil, err
+ }
+ ret := make([]*Process, 0, len(pids))
+ for _, pid := range pids {
+ np, err := NewProcess(pid)
+ if err != nil {
+ return nil, err
+ }
+ ret = append(ret, np)
+ }
+ return ret, nil
+}
+
+func (p *Process) OpenFiles() ([]OpenFilesStat, error) {
+ return p.OpenFilesWithContext(context.Background())
+}
+
+func (p *Process) OpenFilesWithContext(ctx context.Context) ([]OpenFilesStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) Connections() ([]net.ConnectionStat, error) {
+ return p.ConnectionsWithContext(context.Background())
+}
+
+func (p *Process) ConnectionsWithContext(ctx context.Context) ([]net.ConnectionStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) NetIOCounters(pernic bool) ([]net.IOCountersStat, error) {
+ return p.NetIOCountersWithContext(context.Background(), pernic)
+}
+
+func (p *Process) NetIOCountersWithContext(ctx context.Context, pernic bool) ([]net.IOCountersStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) IsRunning() (bool, error) {
+ return p.IsRunningWithContext(context.Background())
+}
+
+func (p *Process) IsRunningWithContext(ctx context.Context) (bool, error) {
+ return true, common.ErrNotImplementedError
+}
+func (p *Process) MemoryMaps(grouped bool) (*[]MemoryMapsStat, error) {
+ return p.MemoryMapsWithContext(context.Background(), grouped)
+}
+
+func (p *Process) MemoryMapsWithContext(ctx context.Context, grouped bool) (*[]MemoryMapsStat, error) {
+ var ret []MemoryMapsStat
+ return &ret, common.ErrNotImplementedError
+}
+
+func Processes() ([]*Process, error) {
+ return ProcessesWithContext(context.Background())
+}
+
+func ProcessesWithContext(ctx context.Context) ([]*Process, error) {
+ results := []*Process{}
+
+ buf, length, err := CallKernProcSyscall(KernProcAll, 0)
+
+ if err != nil {
+ return results, err
+ }
+
+ // get kinfo_proc size
+ count := int(length / uint64(sizeOfKinfoProc))
+
+ // parse buf to procs
+ for i := 0; i < count; i++ {
+ b := buf[i*sizeOfKinfoProc : (i+1)*sizeOfKinfoProc]
+ k, err := parseKinfoProc(b)
+ if err != nil {
+ continue
+ }
+ p, err := NewProcess(int32(k.Pid))
+ if err != nil {
+ continue
+ }
+
+ results = append(results, p)
+ }
+
+ return results, nil
+}
+
+func parseKinfoProc(buf []byte) (KinfoProc, error) {
+ var k KinfoProc
+ br := bytes.NewReader(buf)
+ err := common.Read(br, binary.LittleEndian, &k)
+ return k, err
+}
+
+func (p *Process) getKProc() (*KinfoProc, error) {
+ return p.getKProcWithContext(context.Background())
+}
+
+func (p *Process) getKProcWithContext(ctx context.Context) (*KinfoProc, error) {
+ buf, length, err := CallKernProcSyscall(KernProcPID, p.Pid)
+ if err != nil {
+ return nil, err
+ }
+ if length != sizeOfKinfoProc {
+ return nil, err
+ }
+
+ k, err := parseKinfoProc(buf)
+ if err != nil {
+ return nil, err
+ }
+ return &k, nil
+}
+
+func NewProcess(pid int32) (*Process, error) {
+ p := &Process{Pid: pid}
+
+ return p, nil
+}
+
+func CallKernProcSyscall(op int32, arg int32) ([]byte, uint64, error) {
+ return CallKernProcSyscallWithContext(context.Background(), op, arg)
+}
+
+func CallKernProcSyscallWithContext(ctx context.Context, op int32, arg int32) ([]byte, uint64, error) {
+ mib := []int32{CTLKern, KernProc, op, arg, sizeOfKinfoProc, 0}
+ mibptr := unsafe.Pointer(&mib[0])
+ miblen := uint64(len(mib))
+ length := uint64(0)
+ _, _, err := unix.Syscall6(
+ unix.SYS___SYSCTL,
+ uintptr(mibptr),
+ uintptr(miblen),
+ 0,
+ uintptr(unsafe.Pointer(&length)),
+ 0,
+ 0)
+ if err != 0 {
+ return nil, length, err
+ }
+
+ count := int32(length / uint64(sizeOfKinfoProc))
+ mib = []int32{CTLKern, KernProc, op, arg, sizeOfKinfoProc, count}
+ mibptr = unsafe.Pointer(&mib[0])
+ miblen = uint64(len(mib))
+ // get proc info itself
+ buf := make([]byte, length)
+ _, _, err = unix.Syscall6(
+ unix.SYS___SYSCTL,
+ uintptr(mibptr),
+ uintptr(miblen),
+ uintptr(unsafe.Pointer(&buf[0])),
+ uintptr(unsafe.Pointer(&length)),
+ 0,
+ 0)
+ if err != 0 {
+ return buf, length, err
+ }
+
+ return buf, length, nil
+}
diff --git a/vendor/github.com/shirou/gopsutil/process/process_openbsd_amd64.go b/vendor/github.com/shirou/gopsutil/process/process_openbsd_amd64.go
new file mode 100644
index 0000000..8607422
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/process/process_openbsd_amd64.go
@@ -0,0 +1,200 @@
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs types_openbsd.go
+
+package process
+
+const (
+ CTLKern = 1
+ KernProc = 66
+ KernProcAll = 0
+ KernProcPID = 1
+ KernProcProc = 8
+ KernProcPathname = 12
+ KernProcArgs = 55
+ KernProcArgv = 1
+ KernProcEnv = 3
+)
+
+const (
+ ArgMax = 256 * 1024
+)
+
+const (
+ sizeofPtr = 0x8
+ sizeofShort = 0x2
+ sizeofInt = 0x4
+ sizeofLong = 0x8
+ sizeofLongLong = 0x8
+)
+
+const (
+ sizeOfKinfoVmentry = 0x50
+ sizeOfKinfoProc = 0x268
+)
+
+const (
+ SIDL = 1
+ SRUN = 2
+ SSLEEP = 3
+ SSTOP = 4
+ SZOMB = 5
+ SDEAD = 6
+ SONPROC = 7
+)
+
+type (
+ _C_short int16
+ _C_int int32
+ _C_long int64
+ _C_long_long int64
+)
+
+type Timespec struct {
+ Sec int64
+ Nsec int64
+}
+
+type Timeval struct {
+ Sec int64
+ Usec int64
+}
+
+type Rusage struct {
+ Utime Timeval
+ Stime Timeval
+ Maxrss int64
+ Ixrss int64
+ Idrss int64
+ Isrss int64
+ Minflt int64
+ Majflt int64
+ Nswap int64
+ Inblock int64
+ Oublock int64
+ Msgsnd int64
+ Msgrcv int64
+ Nsignals int64
+ Nvcsw int64
+ Nivcsw int64
+}
+
+type Rlimit struct {
+ Cur uint64
+ Max uint64
+}
+
+type KinfoProc struct {
+ Forw uint64
+ Back uint64
+ Paddr uint64
+ Addr uint64
+ Fd uint64
+ Stats uint64
+ Limit uint64
+ Vmspace uint64
+ Sigacts uint64
+ Sess uint64
+ Tsess uint64
+ Ru uint64
+ Eflag int32
+ Exitsig int32
+ Flag int32
+ Pid int32
+ Ppid int32
+ Sid int32
+ X_pgid int32
+ Tpgid int32
+ Uid uint32
+ Ruid uint32
+ Gid uint32
+ Rgid uint32
+ Groups [16]uint32
+ Ngroups int16
+ Jobc int16
+ Tdev uint32
+ Estcpu uint32
+ Rtime_sec uint32
+ Rtime_usec uint32
+ Cpticks int32
+ Pctcpu uint32
+ Swtime uint32
+ Slptime uint32
+ Schedflags int32
+ Uticks uint64
+ Sticks uint64
+ Iticks uint64
+ Tracep uint64
+ Traceflag int32
+ Holdcnt int32
+ Siglist int32
+ Sigmask uint32
+ Sigignore uint32
+ Sigcatch uint32
+ Stat int8
+ Priority uint8
+ Usrpri uint8
+ Nice uint8
+ Xstat uint16
+ Acflag uint16
+ Comm [24]int8
+ Wmesg [8]int8
+ Wchan uint64
+ Login [32]int8
+ Vm_rssize int32
+ Vm_tsize int32
+ Vm_dsize int32
+ Vm_ssize int32
+ Uvalid int64
+ Ustart_sec uint64
+ Ustart_usec uint32
+ Uutime_sec uint32
+ Uutime_usec uint32
+ Ustime_sec uint32
+ Ustime_usec uint32
+ Pad_cgo_0 [4]byte
+ Uru_maxrss uint64
+ Uru_ixrss uint64
+ Uru_idrss uint64
+ Uru_isrss uint64
+ Uru_minflt uint64
+ Uru_majflt uint64
+ Uru_nswap uint64
+ Uru_inblock uint64
+ Uru_oublock uint64
+ Uru_msgsnd uint64
+ Uru_msgrcv uint64
+ Uru_nsignals uint64
+ Uru_nvcsw uint64
+ Uru_nivcsw uint64
+ Uctime_sec uint32
+ Uctime_usec uint32
+ Psflags int32
+ Spare int32
+ Svuid uint32
+ Svgid uint32
+ Emul [8]int8
+ Rlim_rss_cur uint64
+ Cpuid uint64
+ Vm_map_size uint64
+ Tid int32
+ Rtableid uint32
+}
+
+type Priority struct{}
+
+type KinfoVmentry struct {
+ Start uint64
+ End uint64
+ Guard uint64
+ Fspace uint64
+ Fspace_augment uint64
+ Offset uint64
+ Wired_count int32
+ Etype int32
+ Protection int32
+ Max_protection int32
+ Advice int32
+ Inheritance int32
+ Flags uint8
+ Pad_cgo_0 [7]byte
+}
diff --git a/vendor/github.com/shirou/gopsutil/process/process_posix.go b/vendor/github.com/shirou/gopsutil/process/process_posix.go
new file mode 100644
index 0000000..8ffb6b7
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/process/process_posix.go
@@ -0,0 +1,146 @@
+// +build linux freebsd openbsd darwin
+
+package process
+
+import (
+ "context"
+ "os"
+ "os/user"
+ "path/filepath"
+ "strconv"
+ "strings"
+ "syscall"
+
+ "golang.org/x/sys/unix"
+)
+
+// POSIX
+func getTerminalMap() (map[uint64]string, error) {
+ ret := make(map[uint64]string)
+ var termfiles []string
+
+ d, err := os.Open("/dev")
+ if err != nil {
+ return nil, err
+ }
+ defer d.Close()
+
+ devnames, err := d.Readdirnames(-1)
+ if err != nil {
+ return nil, err
+ }
+ for _, devname := range devnames {
+ if strings.HasPrefix(devname, "/dev/tty") {
+ termfiles = append(termfiles, "/dev/tty/"+devname)
+ }
+ }
+
+ var ptsnames []string
+ ptsd, err := os.Open("/dev/pts")
+ if err != nil {
+ ptsnames, _ = filepath.Glob("/dev/ttyp*")
+ if ptsnames == nil {
+ return nil, err
+ }
+ }
+ defer ptsd.Close()
+
+ if ptsnames == nil {
+ defer ptsd.Close()
+ ptsnames, err = ptsd.Readdirnames(-1)
+ if err != nil {
+ return nil, err
+ }
+ for _, ptsname := range ptsnames {
+ termfiles = append(termfiles, "/dev/pts/"+ptsname)
+ }
+ } else {
+ termfiles = ptsnames
+ }
+
+ for _, name := range termfiles {
+ stat := unix.Stat_t{}
+ if err = unix.Stat(name, &stat); err != nil {
+ return nil, err
+ }
+ rdev := uint64(stat.Rdev)
+ ret[rdev] = strings.Replace(name, "/dev", "", -1)
+ }
+ return ret, nil
+}
+
+// SendSignal sends a unix.Signal to the process.
+// Currently, SIGSTOP, SIGCONT, SIGTERM and SIGKILL are supported.
+func (p *Process) SendSignal(sig syscall.Signal) error {
+ return p.SendSignalWithContext(context.Background(), sig)
+}
+
+func (p *Process) SendSignalWithContext(ctx context.Context, sig syscall.Signal) error {
+ process, err := os.FindProcess(int(p.Pid))
+ if err != nil {
+ return err
+ }
+
+ err = process.Signal(sig)
+ if err != nil {
+ return err
+ }
+
+ return nil
+}
+
+// Suspend sends SIGSTOP to the process.
+func (p *Process) Suspend() error {
+ return p.SuspendWithContext(context.Background())
+}
+
+func (p *Process) SuspendWithContext(ctx context.Context) error {
+ return p.SendSignal(unix.SIGSTOP)
+}
+
+// Resume sends SIGCONT to the process.
+func (p *Process) Resume() error {
+ return p.ResumeWithContext(context.Background())
+}
+
+func (p *Process) ResumeWithContext(ctx context.Context) error {
+ return p.SendSignal(unix.SIGCONT)
+}
+
+// Terminate sends SIGTERM to the process.
+func (p *Process) Terminate() error {
+ return p.TerminateWithContext(context.Background())
+}
+
+func (p *Process) TerminateWithContext(ctx context.Context) error {
+ return p.SendSignal(unix.SIGTERM)
+}
+
+// Kill sends SIGKILL to the process.
+func (p *Process) Kill() error {
+ return p.KillWithContext(context.Background())
+}
+
+func (p *Process) KillWithContext(ctx context.Context) error {
+ return p.SendSignal(unix.SIGKILL)
+}
+
+// Username returns a username of the process.
+func (p *Process) Username() (string, error) {
+ return p.UsernameWithContext(context.Background())
+}
+
+func (p *Process) UsernameWithContext(ctx context.Context) (string, error) {
+ uids, err := p.Uids()
+ if err != nil {
+ return "", err
+ }
+ if len(uids) > 0 {
+ u, err := user.LookupId(strconv.Itoa(int(uids[0])))
+ if err != nil {
+ return "", err
+ }
+ return u.Username, nil
+ }
+ return "", nil
+}
diff --git a/vendor/github.com/shirou/gopsutil/process/process_windows.go b/vendor/github.com/shirou/gopsutil/process/process_windows.go
new file mode 100644
index 0000000..48a1213
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/process/process_windows.go
@@ -0,0 +1,801 @@
+// +build windows
+
+package process
+
+import (
+ "context"
+ "fmt"
+ "os"
+ "strings"
+ "syscall"
+ "time"
+ "unsafe"
+
+ "github.com/StackExchange/wmi"
+ cpu "github.com/shirou/gopsutil/cpu"
+ "github.com/shirou/gopsutil/internal/common"
+ net "github.com/shirou/gopsutil/net"
+ "github.com/shirou/w32"
+ "golang.org/x/sys/windows"
+)
+
+const (
+ NoMoreFiles = 0x12
+ MaxPathLength = 260
+)
+
+var (
+ modpsapi = windows.NewLazySystemDLL("psapi.dll")
+ procGetProcessMemoryInfo = modpsapi.NewProc("GetProcessMemoryInfo")
+
+ advapi32 = windows.NewLazySystemDLL("advapi32.dll")
+ procLookupPrivilegeValue = advapi32.NewProc("LookupPrivilegeValueW")
+ procAdjustTokenPrivileges = advapi32.NewProc("AdjustTokenPrivileges")
+)
+
+type SystemProcessInformation struct {
+ NextEntryOffset uint64
+ NumberOfThreads uint64
+ Reserved1 [48]byte
+ Reserved2 [3]byte
+ UniqueProcessID uintptr
+ Reserved3 uintptr
+ HandleCount uint64
+ Reserved4 [4]byte
+ Reserved5 [11]byte
+ PeakPagefileUsage uint64
+ PrivatePageCount uint64
+ Reserved6 [6]uint64
+}
+
+// Memory_info_ex is different between OSes
+type MemoryInfoExStat struct {
+}
+
+type MemoryMapsStat struct {
+}
+
+type Win32_Process struct {
+ Name string
+ ExecutablePath *string
+ CommandLine *string
+ Priority uint32
+ CreationDate *time.Time
+ ProcessID uint32
+ ThreadCount uint32
+ Status *string
+ ReadOperationCount uint64
+ ReadTransferCount uint64
+ WriteOperationCount uint64
+ WriteTransferCount uint64
+ CSCreationClassName string
+ CSName string
+ Caption *string
+ CreationClassName string
+ Description *string
+ ExecutionState *uint16
+ HandleCount uint32
+ KernelModeTime uint64
+ MaximumWorkingSetSize *uint32
+ MinimumWorkingSetSize *uint32
+ OSCreationClassName string
+ OSName string
+ OtherOperationCount uint64
+ OtherTransferCount uint64
+ PageFaults uint32
+ PageFileUsage uint32
+ ParentProcessID uint32
+ PeakPageFileUsage uint32
+ PeakVirtualSize uint64
+ PeakWorkingSetSize uint32
+ PrivatePageCount uint64
+ TerminationDate *time.Time
+ UserModeTime uint64
+ WorkingSetSize uint64
+}
+
+type winLUID struct {
+ LowPart winDWord
+ HighPart winLong
+}
+
+// LUID_AND_ATTRIBUTES
+type winLUIDAndAttributes struct {
+ Luid winLUID
+ Attributes winDWord
+}
+
+// TOKEN_PRIVILEGES
+type winTokenPriviledges struct {
+ PrivilegeCount winDWord
+ Privileges [1]winLUIDAndAttributes
+}
+
+type winLong int32
+type winDWord uint32
+
+func init() {
+ wmi.DefaultClient.AllowMissingFields = true
+
+ // enable SeDebugPrivilege https://github.com/midstar/proci/blob/6ec79f57b90ba3d9efa2a7b16ef9c9369d4be875/proci_windows.go#L80-L119
+ handle, err := syscall.GetCurrentProcess()
+ if err != nil {
+ return
+ }
+
+ var token syscall.Token
+ err = syscall.OpenProcessToken(handle, 0x0028, &token)
+ if err != nil {
+ return
+ }
+ defer token.Close()
+
+ tokenPriviledges := winTokenPriviledges{PrivilegeCount: 1}
+ lpName := syscall.StringToUTF16("SeDebugPrivilege")
+ ret, _, _ := procLookupPrivilegeValue.Call(
+ 0,
+ uintptr(unsafe.Pointer(&lpName[0])),
+ uintptr(unsafe.Pointer(&tokenPriviledges.Privileges[0].Luid)))
+ if ret == 0 {
+ return
+ }
+
+ tokenPriviledges.Privileges[0].Attributes = 0x00000002 // SE_PRIVILEGE_ENABLED
+
+ procAdjustTokenPrivileges.Call(
+ uintptr(token),
+ 0,
+ uintptr(unsafe.Pointer(&tokenPriviledges)),
+ uintptr(unsafe.Sizeof(tokenPriviledges)),
+ 0,
+ 0)
+}
+
+func Pids() ([]int32, error) {
+ return PidsWithContext(context.Background())
+}
+
+func PidsWithContext(ctx context.Context) ([]int32, error) {
+ // inspired by https://gist.github.com/henkman/3083408
+ // and https://github.com/giampaolo/psutil/blob/1c3a15f637521ba5c0031283da39c733fda53e4c/psutil/arch/windows/process_info.c#L315-L329
+ var ret []int32
+ var read uint32 = 0
+ var psSize uint32 = 1024
+ const dwordSize uint32 = 4
+
+ for {
+ ps := make([]uint32, psSize)
+ if !w32.EnumProcesses(ps, uint32(len(ps)), &read) {
+ return nil, fmt.Errorf("could not get w32.EnumProcesses")
+ }
+ if uint32(len(ps)) == read { // ps buffer was too small to host every results, retry with a bigger one
+ psSize += 1024
+ continue
+ }
+ for _, pid := range ps[:read/dwordSize] {
+ ret = append(ret, int32(pid))
+ }
+ return ret, nil
+
+ }
+
+}
+
+func (p *Process) Ppid() (int32, error) {
+ return p.PpidWithContext(context.Background())
+}
+
+func (p *Process) PpidWithContext(ctx context.Context) (int32, error) {
+ ppid, _, _, err := getFromSnapProcess(p.Pid)
+ if err != nil {
+ return 0, err
+ }
+ return ppid, nil
+}
+
+func GetWin32Proc(pid int32) ([]Win32_Process, error) {
+ return GetWin32ProcWithContext(context.Background(), pid)
+}
+
+func GetWin32ProcWithContext(ctx context.Context, pid int32) ([]Win32_Process, error) {
+ var dst []Win32_Process
+ query := fmt.Sprintf("WHERE ProcessId = %d", pid)
+ q := wmi.CreateQuery(&dst, query)
+ err := common.WMIQueryWithContext(ctx, q, &dst)
+ if err != nil {
+ return []Win32_Process{}, fmt.Errorf("could not get win32Proc: %s", err)
+ }
+
+ if len(dst) == 0 {
+ return []Win32_Process{}, fmt.Errorf("could not get win32Proc: empty")
+ }
+
+ return dst, nil
+}
+
+func (p *Process) Name() (string, error) {
+ return p.NameWithContext(context.Background())
+}
+
+func (p *Process) NameWithContext(ctx context.Context) (string, error) {
+ _, _, name, err := getFromSnapProcess(p.Pid)
+ if err != nil {
+ return "", fmt.Errorf("could not get Name: %s", err)
+ }
+ return name, nil
+}
+
+func (p *Process) Tgid() (int32, error) {
+ return 0, common.ErrNotImplementedError
+}
+
+func (p *Process) Exe() (string, error) {
+ return p.ExeWithContext(context.Background())
+}
+
+func (p *Process) ExeWithContext(ctx context.Context) (string, error) {
+ if p.Pid != 0 { // 0 or null is the current process for CreateToolhelp32Snapshot
+ snap := w32.CreateToolhelp32Snapshot(w32.TH32CS_SNAPMODULE|w32.TH32CS_SNAPMODULE32, uint32(p.Pid))
+ if snap != 0 { // don't report errors here, fallback to WMI instead
+ defer w32.CloseHandle(snap)
+ var me32 w32.MODULEENTRY32
+ me32.Size = uint32(unsafe.Sizeof(me32))
+
+ if w32.Module32First(snap, &me32) {
+ szexepath := windows.UTF16ToString(me32.SzExePath[:])
+ return szexepath, nil
+ }
+ }
+ }
+ dst, err := GetWin32ProcWithContext(ctx, p.Pid)
+ if err != nil {
+ return "", fmt.Errorf("could not get ExecutablePath: %s", err)
+ }
+ return *dst[0].ExecutablePath, nil
+}
+
+func (p *Process) Cmdline() (string, error) {
+ return p.CmdlineWithContext(context.Background())
+}
+
+func (p *Process) CmdlineWithContext(ctx context.Context) (string, error) {
+ dst, err := GetWin32ProcWithContext(ctx, p.Pid)
+ if err != nil {
+ return "", fmt.Errorf("could not get CommandLine: %s", err)
+ }
+ return *dst[0].CommandLine, nil
+}
+
+// CmdlineSlice returns the command line arguments of the process as a slice with each
+// element being an argument. This merely returns the CommandLine informations passed
+// to the process split on the 0x20 ASCII character.
+func (p *Process) CmdlineSlice() ([]string, error) {
+ return p.CmdlineSliceWithContext(context.Background())
+}
+
+func (p *Process) CmdlineSliceWithContext(ctx context.Context) ([]string, error) {
+ cmdline, err := p.CmdlineWithContext(ctx)
+ if err != nil {
+ return nil, err
+ }
+ return strings.Split(cmdline, " "), nil
+}
+
+func (p *Process) CreateTime() (int64, error) {
+ return p.CreateTimeWithContext(context.Background())
+}
+
+func (p *Process) CreateTimeWithContext(ctx context.Context) (int64, error) {
+ ru, err := getRusage(p.Pid)
+ if err != nil {
+ return 0, fmt.Errorf("could not get CreationDate: %s", err)
+ }
+
+ return ru.CreationTime.Nanoseconds() / 1000000, nil
+}
+
+func (p *Process) Cwd() (string, error) {
+ return p.CwdWithContext(context.Background())
+}
+
+func (p *Process) CwdWithContext(ctx context.Context) (string, error) {
+ return "", common.ErrNotImplementedError
+}
+func (p *Process) Parent() (*Process, error) {
+ return p.ParentWithContext(context.Background())
+}
+
+func (p *Process) ParentWithContext(ctx context.Context) (*Process, error) {
+ ppid, err := p.PpidWithContext(ctx)
+ if err != nil {
+ return nil, fmt.Errorf("could not get ParentProcessID: %s", err)
+ }
+
+ return NewProcess(ppid)
+}
+func (p *Process) Status() (string, error) {
+ return p.StatusWithContext(context.Background())
+}
+
+func (p *Process) StatusWithContext(ctx context.Context) (string, error) {
+ return "", common.ErrNotImplementedError
+}
+
+func (p *Process) Foreground() (bool, error) {
+ return p.ForegroundWithContext(context.Background())
+}
+
+func (p *Process) ForegroundWithContext(ctx context.Context) (bool, error) {
+ return false, common.ErrNotImplementedError
+}
+
+func (p *Process) Username() (string, error) {
+ return p.UsernameWithContext(context.Background())
+}
+
+func (p *Process) UsernameWithContext(ctx context.Context) (string, error) {
+ pid := p.Pid
+ // 0x1000 is PROCESS_QUERY_LIMITED_INFORMATION
+ c, err := syscall.OpenProcess(0x1000, false, uint32(pid))
+ if err != nil {
+ return "", err
+ }
+ defer syscall.CloseHandle(c)
+
+ var token syscall.Token
+ err = syscall.OpenProcessToken(c, syscall.TOKEN_QUERY, &token)
+ if err != nil {
+ return "", err
+ }
+ defer token.Close()
+ tokenUser, err := token.GetTokenUser()
+ if err != nil {
+ return "", err
+ }
+
+ user, domain, _, err := tokenUser.User.Sid.LookupAccount("")
+ return domain + "\\" + user, err
+}
+
+func (p *Process) Uids() ([]int32, error) {
+ return p.UidsWithContext(context.Background())
+}
+
+func (p *Process) UidsWithContext(ctx context.Context) ([]int32, error) {
+ var uids []int32
+
+ return uids, common.ErrNotImplementedError
+}
+func (p *Process) Gids() ([]int32, error) {
+ return p.GidsWithContext(context.Background())
+}
+
+func (p *Process) GidsWithContext(ctx context.Context) ([]int32, error) {
+ var gids []int32
+ return gids, common.ErrNotImplementedError
+}
+func (p *Process) Terminal() (string, error) {
+ return p.TerminalWithContext(context.Background())
+}
+
+func (p *Process) TerminalWithContext(ctx context.Context) (string, error) {
+ return "", common.ErrNotImplementedError
+}
+
+// Nice returns priority in Windows
+func (p *Process) Nice() (int32, error) {
+ return p.NiceWithContext(context.Background())
+}
+
+func (p *Process) NiceWithContext(ctx context.Context) (int32, error) {
+ dst, err := GetWin32ProcWithContext(ctx, p.Pid)
+ if err != nil {
+ return 0, fmt.Errorf("could not get Priority: %s", err)
+ }
+ return int32(dst[0].Priority), nil
+}
+func (p *Process) IOnice() (int32, error) {
+ return p.IOniceWithContext(context.Background())
+}
+
+func (p *Process) IOniceWithContext(ctx context.Context) (int32, error) {
+ return 0, common.ErrNotImplementedError
+}
+func (p *Process) Rlimit() ([]RlimitStat, error) {
+ return p.RlimitWithContext(context.Background())
+}
+
+func (p *Process) RlimitWithContext(ctx context.Context) ([]RlimitStat, error) {
+ var rlimit []RlimitStat
+
+ return rlimit, common.ErrNotImplementedError
+}
+func (p *Process) RlimitUsage(gatherUsed bool) ([]RlimitStat, error) {
+ return p.RlimitUsageWithContext(context.Background(), gatherUsed)
+}
+
+func (p *Process) RlimitUsageWithContext(ctx context.Context, gatherUsed bool) ([]RlimitStat, error) {
+ var rlimit []RlimitStat
+
+ return rlimit, common.ErrNotImplementedError
+}
+
+func (p *Process) IOCounters() (*IOCountersStat, error) {
+ return p.IOCountersWithContext(context.Background())
+}
+
+func (p *Process) IOCountersWithContext(ctx context.Context) (*IOCountersStat, error) {
+ dst, err := GetWin32ProcWithContext(ctx, p.Pid)
+ if err != nil || len(dst) == 0 {
+ return nil, fmt.Errorf("could not get Win32Proc: %s", err)
+ }
+ ret := &IOCountersStat{
+ ReadCount: uint64(dst[0].ReadOperationCount),
+ ReadBytes: uint64(dst[0].ReadTransferCount),
+ WriteCount: uint64(dst[0].WriteOperationCount),
+ WriteBytes: uint64(dst[0].WriteTransferCount),
+ }
+
+ return ret, nil
+}
+func (p *Process) NumCtxSwitches() (*NumCtxSwitchesStat, error) {
+ return p.NumCtxSwitchesWithContext(context.Background())
+}
+
+func (p *Process) NumCtxSwitchesWithContext(ctx context.Context) (*NumCtxSwitchesStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+func (p *Process) NumFDs() (int32, error) {
+ return p.NumFDsWithContext(context.Background())
+}
+
+func (p *Process) NumFDsWithContext(ctx context.Context) (int32, error) {
+ return 0, common.ErrNotImplementedError
+}
+func (p *Process) NumThreads() (int32, error) {
+ return p.NumThreadsWithContext(context.Background())
+}
+
+func (p *Process) NumThreadsWithContext(ctx context.Context) (int32, error) {
+ dst, err := GetWin32ProcWithContext(ctx, p.Pid)
+ if err != nil {
+ return 0, fmt.Errorf("could not get ThreadCount: %s", err)
+ }
+ return int32(dst[0].ThreadCount), nil
+}
+func (p *Process) Threads() (map[int32]*cpu.TimesStat, error) {
+ return p.ThreadsWithContext(context.Background())
+}
+
+func (p *Process) ThreadsWithContext(ctx context.Context) (map[int32]*cpu.TimesStat, error) {
+ ret := make(map[int32]*cpu.TimesStat)
+ return ret, common.ErrNotImplementedError
+}
+func (p *Process) Times() (*cpu.TimesStat, error) {
+ return p.TimesWithContext(context.Background())
+}
+
+func (p *Process) TimesWithContext(ctx context.Context) (*cpu.TimesStat, error) {
+ sysTimes, err := getProcessCPUTimes(p.Pid)
+ if err != nil {
+ return nil, err
+ }
+
+ // User and kernel times are represented as a FILETIME structure
+ // which contains a 64-bit value representing the number of
+ // 100-nanosecond intervals since January 1, 1601 (UTC):
+ // http://msdn.microsoft.com/en-us/library/ms724284(VS.85).aspx
+ // To convert it into a float representing the seconds that the
+ // process has executed in user/kernel mode I borrowed the code
+ // below from psutil's _psutil_windows.c, and in turn from Python's
+ // Modules/posixmodule.c
+
+ user := float64(sysTimes.UserTime.HighDateTime)*429.4967296 + float64(sysTimes.UserTime.LowDateTime)*1e-7
+ kernel := float64(sysTimes.KernelTime.HighDateTime)*429.4967296 + float64(sysTimes.KernelTime.LowDateTime)*1e-7
+
+ return &cpu.TimesStat{
+ User: user,
+ System: kernel,
+ }, nil
+}
+func (p *Process) CPUAffinity() ([]int32, error) {
+ return p.CPUAffinityWithContext(context.Background())
+}
+
+func (p *Process) CPUAffinityWithContext(ctx context.Context) ([]int32, error) {
+ return nil, common.ErrNotImplementedError
+}
+func (p *Process) MemoryInfo() (*MemoryInfoStat, error) {
+ return p.MemoryInfoWithContext(context.Background())
+}
+
+func (p *Process) MemoryInfoWithContext(ctx context.Context) (*MemoryInfoStat, error) {
+ mem, err := getMemoryInfo(p.Pid)
+ if err != nil {
+ return nil, err
+ }
+
+ ret := &MemoryInfoStat{
+ RSS: uint64(mem.WorkingSetSize),
+ VMS: uint64(mem.PagefileUsage),
+ }
+
+ return ret, nil
+}
+func (p *Process) MemoryInfoEx() (*MemoryInfoExStat, error) {
+ return p.MemoryInfoExWithContext(context.Background())
+}
+
+func (p *Process) MemoryInfoExWithContext(ctx context.Context) (*MemoryInfoExStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) Children() ([]*Process, error) {
+ return p.ChildrenWithContext(context.Background())
+}
+
+func (p *Process) ChildrenWithContext(ctx context.Context) ([]*Process, error) {
+ out := []*Process{}
+ snap := w32.CreateToolhelp32Snapshot(w32.TH32CS_SNAPPROCESS, uint32(0))
+ if snap == 0 {
+ return out, windows.GetLastError()
+ }
+ defer w32.CloseHandle(snap)
+ var pe32 w32.PROCESSENTRY32
+ pe32.DwSize = uint32(unsafe.Sizeof(pe32))
+ if w32.Process32First(snap, &pe32) == false {
+ return out, windows.GetLastError()
+ }
+
+ if pe32.Th32ParentProcessID == uint32(p.Pid) {
+ p, err := NewProcess(int32(pe32.Th32ProcessID))
+ if err == nil {
+ out = append(out, p)
+ }
+ }
+
+ for w32.Process32Next(snap, &pe32) {
+ if pe32.Th32ParentProcessID == uint32(p.Pid) {
+ p, err := NewProcess(int32(pe32.Th32ProcessID))
+ if err == nil {
+ out = append(out, p)
+ }
+ }
+ }
+ return out, nil
+}
+
+func (p *Process) OpenFiles() ([]OpenFilesStat, error) {
+ return p.OpenFilesWithContext(context.Background())
+}
+
+func (p *Process) OpenFilesWithContext(ctx context.Context) ([]OpenFilesStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) Connections() ([]net.ConnectionStat, error) {
+ return p.ConnectionsWithContext(context.Background())
+}
+
+func (p *Process) ConnectionsWithContext(ctx context.Context) ([]net.ConnectionStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) NetIOCounters(pernic bool) ([]net.IOCountersStat, error) {
+ return p.NetIOCountersWithContext(context.Background(), pernic)
+}
+
+func (p *Process) NetIOCountersWithContext(ctx context.Context, pernic bool) ([]net.IOCountersStat, error) {
+ return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) IsRunning() (bool, error) {
+ return p.IsRunningWithContext(context.Background())
+}
+
+func (p *Process) IsRunningWithContext(ctx context.Context) (bool, error) {
+ return true, common.ErrNotImplementedError
+}
+
+func (p *Process) MemoryMaps(grouped bool) (*[]MemoryMapsStat, error) {
+ return p.MemoryMapsWithContext(context.Background(), grouped)
+}
+
+func (p *Process) MemoryMapsWithContext(ctx context.Context, grouped bool) (*[]MemoryMapsStat, error) {
+ var ret []MemoryMapsStat
+ return &ret, common.ErrNotImplementedError
+}
+
+func NewProcess(pid int32) (*Process, error) {
+ p := &Process{Pid: pid}
+
+ return p, nil
+}
+
+func (p *Process) SendSignal(sig windows.Signal) error {
+ return p.SendSignalWithContext(context.Background(), sig)
+}
+
+func (p *Process) SendSignalWithContext(ctx context.Context, sig windows.Signal) error {
+ return common.ErrNotImplementedError
+}
+
+func (p *Process) Suspend() error {
+ return p.SuspendWithContext(context.Background())
+}
+
+func (p *Process) SuspendWithContext(ctx context.Context) error {
+ return common.ErrNotImplementedError
+}
+func (p *Process) Resume() error {
+ return p.ResumeWithContext(context.Background())
+}
+
+func (p *Process) ResumeWithContext(ctx context.Context) error {
+ return common.ErrNotImplementedError
+}
+
+func (p *Process) Terminate() error {
+ return p.TerminateWithContext(context.Background())
+}
+
+func (p *Process) TerminateWithContext(ctx context.Context) error {
+ // PROCESS_TERMINATE = 0x0001
+ proc := w32.OpenProcess(0x0001, false, uint32(p.Pid))
+ ret := w32.TerminateProcess(proc, 0)
+ w32.CloseHandle(proc)
+
+ if ret == false {
+ return windows.GetLastError()
+ } else {
+ return nil
+ }
+}
+
+func (p *Process) Kill() error {
+ return p.KillWithContext(context.Background())
+}
+
+func (p *Process) KillWithContext(ctx context.Context) error {
+ process := os.Process{Pid: int(p.Pid)}
+ return process.Kill()
+}
+
+func getFromSnapProcess(pid int32) (int32, int32, string, error) {
+ snap := w32.CreateToolhelp32Snapshot(w32.TH32CS_SNAPPROCESS, uint32(pid))
+ if snap == 0 {
+ return 0, 0, "", windows.GetLastError()
+ }
+ defer w32.CloseHandle(snap)
+ var pe32 w32.PROCESSENTRY32
+ pe32.DwSize = uint32(unsafe.Sizeof(pe32))
+ if w32.Process32First(snap, &pe32) == false {
+ return 0, 0, "", windows.GetLastError()
+ }
+
+ if pe32.Th32ProcessID == uint32(pid) {
+ szexe := windows.UTF16ToString(pe32.SzExeFile[:])
+ return int32(pe32.Th32ParentProcessID), int32(pe32.CntThreads), szexe, nil
+ }
+
+ for w32.Process32Next(snap, &pe32) {
+ if pe32.Th32ProcessID == uint32(pid) {
+ szexe := windows.UTF16ToString(pe32.SzExeFile[:])
+ return int32(pe32.Th32ParentProcessID), int32(pe32.CntThreads), szexe, nil
+ }
+ }
+ return 0, 0, "", fmt.Errorf("Couldn't find pid: %d", pid)
+}
+
+// Get processes
+func Processes() ([]*Process, error) {
+ return ProcessesWithContext(context.Background())
+}
+
+func ProcessesWithContext(ctx context.Context) ([]*Process, error) {
+ out := []*Process{}
+
+ pids, err := PidsWithContext(ctx)
+ if err != nil {
+ return out, fmt.Errorf("could not get Processes %s", err)
+ }
+
+ for _, pid := range pids {
+ p, err := NewProcess(pid)
+ if err != nil {
+ continue
+ }
+ out = append(out, p)
+ }
+
+ return out, nil
+}
+
+func getProcInfo(pid int32) (*SystemProcessInformation, error) {
+ initialBufferSize := uint64(0x4000)
+ bufferSize := initialBufferSize
+ buffer := make([]byte, bufferSize)
+
+ var sysProcInfo SystemProcessInformation
+ ret, _, _ := common.ProcNtQuerySystemInformation.Call(
+ uintptr(unsafe.Pointer(&sysProcInfo)),
+ uintptr(unsafe.Pointer(&buffer[0])),
+ uintptr(unsafe.Pointer(&bufferSize)),
+ uintptr(unsafe.Pointer(&bufferSize)))
+ if ret != 0 {
+ return nil, windows.GetLastError()
+ }
+
+ return &sysProcInfo, nil
+}
+
+func getRusage(pid int32) (*windows.Rusage, error) {
+ var CPU windows.Rusage
+
+ c, err := windows.OpenProcess(windows.PROCESS_QUERY_INFORMATION, false, uint32(pid))
+ if err != nil {
+ return nil, err
+ }
+ defer windows.CloseHandle(c)
+
+ if err := windows.GetProcessTimes(c, &CPU.CreationTime, &CPU.ExitTime, &CPU.KernelTime, &CPU.UserTime); err != nil {
+ return nil, err
+ }
+
+ return &CPU, nil
+}
+
+func getMemoryInfo(pid int32) (PROCESS_MEMORY_COUNTERS, error) {
+ var mem PROCESS_MEMORY_COUNTERS
+ // PROCESS_QUERY_LIMITED_INFORMATION is 0x1000
+ c, err := windows.OpenProcess(0x1000, false, uint32(pid))
+ if err != nil {
+ return mem, err
+ }
+ defer windows.CloseHandle(c)
+ if err := getProcessMemoryInfo(c, &mem); err != nil {
+ return mem, err
+ }
+
+ return mem, err
+}
+
+func getProcessMemoryInfo(h windows.Handle, mem *PROCESS_MEMORY_COUNTERS) (err error) {
+ r1, _, e1 := syscall.Syscall(procGetProcessMemoryInfo.Addr(), 3, uintptr(h), uintptr(unsafe.Pointer(mem)), uintptr(unsafe.Sizeof(*mem)))
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+type SYSTEM_TIMES struct {
+ CreateTime syscall.Filetime
+ ExitTime syscall.Filetime
+ KernelTime syscall.Filetime
+ UserTime syscall.Filetime
+}
+
+func getProcessCPUTimes(pid int32) (SYSTEM_TIMES, error) {
+ var times SYSTEM_TIMES
+
+ // PROCESS_QUERY_LIMITED_INFORMATION is 0x1000
+ h, err := windows.OpenProcess(0x1000, false, uint32(pid))
+ if err != nil {
+ return times, err
+ }
+ defer windows.CloseHandle(h)
+
+ err = syscall.GetProcessTimes(
+ syscall.Handle(h),
+ ×.CreateTime,
+ ×.ExitTime,
+ ×.KernelTime,
+ ×.UserTime,
+ )
+
+ return times, err
+}
diff --git a/vendor/github.com/shirou/gopsutil/process/process_windows_386.go b/vendor/github.com/shirou/gopsutil/process/process_windows_386.go
new file mode 100644
index 0000000..68f3153
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/process/process_windows_386.go
@@ -0,0 +1,16 @@
+// +build windows
+
+package process
+
+type PROCESS_MEMORY_COUNTERS struct {
+ CB uint32
+ PageFaultCount uint32
+ PeakWorkingSetSize uint32
+ WorkingSetSize uint32
+ QuotaPeakPagedPoolUsage uint32
+ QuotaPagedPoolUsage uint32
+ QuotaPeakNonPagedPoolUsage uint32
+ QuotaNonPagedPoolUsage uint32
+ PagefileUsage uint32
+ PeakPagefileUsage uint32
+}
diff --git a/vendor/github.com/shirou/gopsutil/process/process_windows_amd64.go b/vendor/github.com/shirou/gopsutil/process/process_windows_amd64.go
new file mode 100644
index 0000000..df286df
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/process/process_windows_amd64.go
@@ -0,0 +1,16 @@
+// +build windows
+
+package process
+
+type PROCESS_MEMORY_COUNTERS struct {
+ CB uint32
+ PageFaultCount uint32
+ PeakWorkingSetSize uint64
+ WorkingSetSize uint64
+ QuotaPeakPagedPoolUsage uint64
+ QuotaPagedPoolUsage uint64
+ QuotaPeakNonPagedPoolUsage uint64
+ QuotaNonPagedPoolUsage uint64
+ PagefileUsage uint64
+ PeakPagefileUsage uint64
+}
diff --git a/vendor/github.com/shirou/w32/AUTHORS b/vendor/github.com/shirou/w32/AUTHORS
new file mode 100644
index 0000000..c0785e8
--- /dev/null
+++ b/vendor/github.com/shirou/w32/AUTHORS
@@ -0,0 +1,16 @@
+# This is the official list of 'w32' authors for copyright purposes.
+
+# Names should be added to this file as
+# Name or Organization
+# The email address is not required for organizations.
+
+# Please keep the list sorted.
+
+# Contributors
+# ============
+
+Allen Dang
+Benny Siegert
+Bruno Bigras
+Gerald Rosenberg
+Michael Henke
\ No newline at end of file
diff --git a/vendor/github.com/shirou/w32/LICENSE b/vendor/github.com/shirou/w32/LICENSE
new file mode 100644
index 0000000..9f36608
--- /dev/null
+++ b/vendor/github.com/shirou/w32/LICENSE
@@ -0,0 +1,23 @@
+Copyright (c) 2010-2012 The w32 Authors. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+3. The names of the authors may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/vendor/github.com/shirou/w32/README.md b/vendor/github.com/shirou/w32/README.md
new file mode 100644
index 0000000..ed196e7
--- /dev/null
+++ b/vendor/github.com/shirou/w32/README.md
@@ -0,0 +1,33 @@
+About w32
+==========
+
+w32 is a wrapper of windows apis for the Go Programming Language.
+
+It wraps win32 apis to "Go style" to make them easier to use.
+
+Setup
+=====
+
+1. Make sure you have a working Go installation and build environment,
+ see this go-nuts post for details:
+ http://groups.google.com/group/golang-nuts/msg/5c87630a84f4fd0c
+
+ Updated versions of the Windows Go build are available here:
+ http://code.google.com/p/gomingw/downloads/list
+
+2. Create a "gopath" directory if you do not have one yet and set the
+ GOPATH variable accordingly. For example:
+ mkdir -p go-externals/src
+ export GOPATH=${PWD}/go-externals
+
+3. go get github.com/AllenDang/w32
+
+4. go install github.com/AllenDang/w32...
+
+Contribute
+==========
+
+Contributions in form of design, code, documentation, bug reporting or other
+ways you see fit are very welcome.
+
+Thank You!
diff --git a/vendor/github.com/shirou/w32/advapi32.go b/vendor/github.com/shirou/w32/advapi32.go
new file mode 100644
index 0000000..35fd35a
--- /dev/null
+++ b/vendor/github.com/shirou/w32/advapi32.go
@@ -0,0 +1,301 @@
+// Copyright 2010-2012 The W32 Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build windows
+
+package w32
+
+import (
+ "errors"
+ "fmt"
+ "syscall"
+ "unsafe"
+)
+
+var (
+ modadvapi32 = syscall.NewLazyDLL("advapi32.dll")
+
+ procRegCreateKeyEx = modadvapi32.NewProc("RegCreateKeyExW")
+ procRegOpenKeyEx = modadvapi32.NewProc("RegOpenKeyExW")
+ procRegCloseKey = modadvapi32.NewProc("RegCloseKey")
+ procRegGetValue = modadvapi32.NewProc("RegGetValueW")
+ procRegEnumKeyEx = modadvapi32.NewProc("RegEnumKeyExW")
+ // procRegSetKeyValue = modadvapi32.NewProc("RegSetKeyValueW")
+ procRegSetValueEx = modadvapi32.NewProc("RegSetValueExW")
+ procOpenEventLog = modadvapi32.NewProc("OpenEventLogW")
+ procReadEventLog = modadvapi32.NewProc("ReadEventLogW")
+ procCloseEventLog = modadvapi32.NewProc("CloseEventLog")
+ procOpenSCManager = modadvapi32.NewProc("OpenSCManagerW")
+ procCloseServiceHandle = modadvapi32.NewProc("CloseServiceHandle")
+ procOpenService = modadvapi32.NewProc("OpenServiceW")
+ procStartService = modadvapi32.NewProc("StartServiceW")
+ procControlService = modadvapi32.NewProc("ControlService")
+)
+
+func RegCreateKey(hKey HKEY, subKey string) HKEY {
+ var result HKEY
+ ret, _, _ := procRegCreateKeyEx.Call(
+ uintptr(hKey),
+ uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(subKey))),
+ uintptr(0),
+ uintptr(0),
+ uintptr(0),
+ uintptr(KEY_ALL_ACCESS),
+ uintptr(0),
+ uintptr(unsafe.Pointer(&result)),
+ uintptr(0))
+ _ = ret
+ return result
+}
+
+func RegOpenKeyEx(hKey HKEY, subKey string, samDesired uint32) HKEY {
+ var result HKEY
+ ret, _, _ := procRegOpenKeyEx.Call(
+ uintptr(hKey),
+ uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(subKey))),
+ uintptr(0),
+ uintptr(samDesired),
+ uintptr(unsafe.Pointer(&result)))
+
+ if ret != ERROR_SUCCESS {
+ panic(fmt.Sprintf("RegOpenKeyEx(%d, %s, %d) failed", hKey, subKey, samDesired))
+ }
+ return result
+}
+
+func RegCloseKey(hKey HKEY) error {
+ var err error
+ ret, _, _ := procRegCloseKey.Call(
+ uintptr(hKey))
+
+ if ret != ERROR_SUCCESS {
+ err = errors.New("RegCloseKey failed")
+ }
+ return err
+}
+
+func RegGetRaw(hKey HKEY, subKey string, value string) []byte {
+ var bufLen uint32
+ var valptr unsafe.Pointer
+ if len(value) > 0 {
+ valptr = unsafe.Pointer(syscall.StringToUTF16Ptr(value))
+ }
+ procRegGetValue.Call(
+ uintptr(hKey),
+ uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(subKey))),
+ uintptr(valptr),
+ uintptr(RRF_RT_ANY),
+ 0,
+ 0,
+ uintptr(unsafe.Pointer(&bufLen)))
+
+ if bufLen == 0 {
+ return nil
+ }
+
+ buf := make([]byte, bufLen)
+ ret, _, _ := procRegGetValue.Call(
+ uintptr(hKey),
+ uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(subKey))),
+ uintptr(valptr),
+ uintptr(RRF_RT_ANY),
+ 0,
+ uintptr(unsafe.Pointer(&buf[0])),
+ uintptr(unsafe.Pointer(&bufLen)))
+
+ if ret != ERROR_SUCCESS {
+ return nil
+ }
+
+ return buf
+}
+
+func RegSetBinary(hKey HKEY, subKey string, value []byte) (errno int) {
+ var lptr, vptr unsafe.Pointer
+ if len(subKey) > 0 {
+ lptr = unsafe.Pointer(syscall.StringToUTF16Ptr(subKey))
+ }
+ if len(value) > 0 {
+ vptr = unsafe.Pointer(&value[0])
+ }
+ ret, _, _ := procRegSetValueEx.Call(
+ uintptr(hKey),
+ uintptr(lptr),
+ uintptr(0),
+ uintptr(REG_BINARY),
+ uintptr(vptr),
+ uintptr(len(value)))
+
+ return int(ret)
+}
+
+func RegGetString(hKey HKEY, subKey string, value string) string {
+ var bufLen uint32
+ procRegGetValue.Call(
+ uintptr(hKey),
+ uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(subKey))),
+ uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(value))),
+ uintptr(RRF_RT_REG_SZ),
+ 0,
+ 0,
+ uintptr(unsafe.Pointer(&bufLen)))
+
+ if bufLen == 0 {
+ return ""
+ }
+
+ buf := make([]uint16, bufLen)
+ ret, _, _ := procRegGetValue.Call(
+ uintptr(hKey),
+ uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(subKey))),
+ uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(value))),
+ uintptr(RRF_RT_REG_SZ),
+ 0,
+ uintptr(unsafe.Pointer(&buf[0])),
+ uintptr(unsafe.Pointer(&bufLen)))
+
+ if ret != ERROR_SUCCESS {
+ return ""
+ }
+
+ return syscall.UTF16ToString(buf)
+}
+
+/*
+func RegSetKeyValue(hKey HKEY, subKey string, valueName string, dwType uint32, data uintptr, cbData uint16) (errno int) {
+ ret, _, _ := procRegSetKeyValue.Call(
+ uintptr(hKey),
+ uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(subKey))),
+ uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(valueName))),
+ uintptr(dwType),
+ data,
+ uintptr(cbData))
+
+ return int(ret)
+}
+*/
+
+func RegEnumKeyEx(hKey HKEY, index uint32) string {
+ var bufLen uint32 = 255
+ buf := make([]uint16, bufLen)
+ procRegEnumKeyEx.Call(
+ uintptr(hKey),
+ uintptr(index),
+ uintptr(unsafe.Pointer(&buf[0])),
+ uintptr(unsafe.Pointer(&bufLen)),
+ 0,
+ 0,
+ 0,
+ 0)
+ return syscall.UTF16ToString(buf)
+}
+
+func OpenEventLog(servername string, sourcename string) HANDLE {
+ ret, _, _ := procOpenEventLog.Call(
+ uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(servername))),
+ uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(sourcename))))
+
+ return HANDLE(ret)
+}
+
+func ReadEventLog(eventlog HANDLE, readflags, recordoffset uint32, buffer []byte, numberofbytestoread uint32, bytesread, minnumberofbytesneeded *uint32) bool {
+ ret, _, _ := procReadEventLog.Call(
+ uintptr(eventlog),
+ uintptr(readflags),
+ uintptr(recordoffset),
+ uintptr(unsafe.Pointer(&buffer[0])),
+ uintptr(numberofbytestoread),
+ uintptr(unsafe.Pointer(bytesread)),
+ uintptr(unsafe.Pointer(minnumberofbytesneeded)))
+
+ return ret != 0
+}
+
+func CloseEventLog(eventlog HANDLE) bool {
+ ret, _, _ := procCloseEventLog.Call(
+ uintptr(eventlog))
+
+ return ret != 0
+}
+
+func OpenSCManager(lpMachineName, lpDatabaseName string, dwDesiredAccess uint32) (HANDLE, error) {
+ var p1, p2 uintptr
+ if len(lpMachineName) > 0 {
+ p1 = uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(lpMachineName)))
+ }
+ if len(lpDatabaseName) > 0 {
+ p2 = uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(lpDatabaseName)))
+ }
+ ret, _, _ := procOpenSCManager.Call(
+ p1,
+ p2,
+ uintptr(dwDesiredAccess))
+
+ if ret == 0 {
+ return 0, syscall.GetLastError()
+ }
+
+ return HANDLE(ret), nil
+}
+
+func CloseServiceHandle(hSCObject HANDLE) error {
+ ret, _, _ := procCloseServiceHandle.Call(uintptr(hSCObject))
+ if ret == 0 {
+ return syscall.GetLastError()
+ }
+ return nil
+}
+
+func OpenService(hSCManager HANDLE, lpServiceName string, dwDesiredAccess uint32) (HANDLE, error) {
+ ret, _, _ := procOpenService.Call(
+ uintptr(hSCManager),
+ uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(lpServiceName))),
+ uintptr(dwDesiredAccess))
+
+ if ret == 0 {
+ return 0, syscall.GetLastError()
+ }
+
+ return HANDLE(ret), nil
+}
+
+func StartService(hService HANDLE, lpServiceArgVectors []string) error {
+ l := len(lpServiceArgVectors)
+ var ret uintptr
+ if l == 0 {
+ ret, _, _ = procStartService.Call(
+ uintptr(hService),
+ 0,
+ 0)
+ } else {
+ lpArgs := make([]uintptr, l)
+ for i := 0; i < l; i++ {
+ lpArgs[i] = uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(lpServiceArgVectors[i])))
+ }
+
+ ret, _, _ = procStartService.Call(
+ uintptr(hService),
+ uintptr(l),
+ uintptr(unsafe.Pointer(&lpArgs[0])))
+ }
+
+ if ret == 0 {
+ return syscall.GetLastError()
+ }
+
+ return nil
+}
+
+func ControlService(hService HANDLE, dwControl uint32, lpServiceStatus *SERVICE_STATUS) bool {
+ if lpServiceStatus == nil {
+ panic("ControlService:lpServiceStatus cannot be nil")
+ }
+
+ ret, _, _ := procControlService.Call(
+ uintptr(hService),
+ uintptr(dwControl),
+ uintptr(unsafe.Pointer(lpServiceStatus)))
+
+ return ret != 0
+}
diff --git a/vendor/github.com/shirou/w32/comctl32.go b/vendor/github.com/shirou/w32/comctl32.go
new file mode 100644
index 0000000..5139558
--- /dev/null
+++ b/vendor/github.com/shirou/w32/comctl32.go
@@ -0,0 +1,111 @@
+// Copyright 2010-2012 The W32 Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build windows
+
+package w32
+
+import (
+ "syscall"
+ "unsafe"
+)
+
+var (
+ modcomctl32 = syscall.NewLazyDLL("comctl32.dll")
+
+ procInitCommonControlsEx = modcomctl32.NewProc("InitCommonControlsEx")
+ procImageList_Create = modcomctl32.NewProc("ImageList_Create")
+ procImageList_Destroy = modcomctl32.NewProc("ImageList_Destroy")
+ procImageList_GetImageCount = modcomctl32.NewProc("ImageList_GetImageCount")
+ procImageList_SetImageCount = modcomctl32.NewProc("ImageList_SetImageCount")
+ procImageList_Add = modcomctl32.NewProc("ImageList_Add")
+ procImageList_ReplaceIcon = modcomctl32.NewProc("ImageList_ReplaceIcon")
+ procImageList_Remove = modcomctl32.NewProc("ImageList_Remove")
+ procTrackMouseEvent = modcomctl32.NewProc("_TrackMouseEvent")
+)
+
+func InitCommonControlsEx(lpInitCtrls *INITCOMMONCONTROLSEX) bool {
+ ret, _, _ := procInitCommonControlsEx.Call(
+ uintptr(unsafe.Pointer(lpInitCtrls)))
+
+ return ret != 0
+}
+
+func ImageList_Create(cx, cy int, flags uint, cInitial, cGrow int) HIMAGELIST {
+ ret, _, _ := procImageList_Create.Call(
+ uintptr(cx),
+ uintptr(cy),
+ uintptr(flags),
+ uintptr(cInitial),
+ uintptr(cGrow))
+
+ if ret == 0 {
+ panic("Create image list failed")
+ }
+
+ return HIMAGELIST(ret)
+}
+
+func ImageList_Destroy(himl HIMAGELIST) bool {
+ ret, _, _ := procImageList_Destroy.Call(
+ uintptr(himl))
+
+ return ret != 0
+}
+
+func ImageList_GetImageCount(himl HIMAGELIST) int {
+ ret, _, _ := procImageList_GetImageCount.Call(
+ uintptr(himl))
+
+ return int(ret)
+}
+
+func ImageList_SetImageCount(himl HIMAGELIST, uNewCount uint) bool {
+ ret, _, _ := procImageList_SetImageCount.Call(
+ uintptr(himl),
+ uintptr(uNewCount))
+
+ return ret != 0
+}
+
+func ImageList_Add(himl HIMAGELIST, hbmImage, hbmMask HBITMAP) int {
+ ret, _, _ := procImageList_Add.Call(
+ uintptr(himl),
+ uintptr(hbmImage),
+ uintptr(hbmMask))
+
+ return int(ret)
+}
+
+func ImageList_ReplaceIcon(himl HIMAGELIST, i int, hicon HICON) int {
+ ret, _, _ := procImageList_ReplaceIcon.Call(
+ uintptr(himl),
+ uintptr(i),
+ uintptr(hicon))
+
+ return int(ret)
+}
+
+func ImageList_AddIcon(himl HIMAGELIST, hicon HICON) int {
+ return ImageList_ReplaceIcon(himl, -1, hicon)
+}
+
+func ImageList_Remove(himl HIMAGELIST, i int) bool {
+ ret, _, _ := procImageList_Remove.Call(
+ uintptr(himl),
+ uintptr(i))
+
+ return ret != 0
+}
+
+func ImageList_RemoveAll(himl HIMAGELIST) bool {
+ return ImageList_Remove(himl, -1)
+}
+
+func TrackMouseEvent(tme *TRACKMOUSEEVENT) bool {
+ ret, _, _ := procTrackMouseEvent.Call(
+ uintptr(unsafe.Pointer(tme)))
+
+ return ret != 0
+}
diff --git a/vendor/github.com/shirou/w32/comdlg32.go b/vendor/github.com/shirou/w32/comdlg32.go
new file mode 100644
index 0000000..ad9f776
--- /dev/null
+++ b/vendor/github.com/shirou/w32/comdlg32.go
@@ -0,0 +1,40 @@
+// Copyright 2010-2012 The W32 Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build windows
+
+package w32
+
+import (
+ "syscall"
+ "unsafe"
+)
+
+var (
+ modcomdlg32 = syscall.NewLazyDLL("comdlg32.dll")
+
+ procGetSaveFileName = modcomdlg32.NewProc("GetSaveFileNameW")
+ procGetOpenFileName = modcomdlg32.NewProc("GetOpenFileNameW")
+ procCommDlgExtendedError = modcomdlg32.NewProc("CommDlgExtendedError")
+)
+
+func GetOpenFileName(ofn *OPENFILENAME) bool {
+ ret, _, _ := procGetOpenFileName.Call(
+ uintptr(unsafe.Pointer(ofn)))
+
+ return ret != 0
+}
+
+func GetSaveFileName(ofn *OPENFILENAME) bool {
+ ret, _, _ := procGetSaveFileName.Call(
+ uintptr(unsafe.Pointer(ofn)))
+
+ return ret != 0
+}
+
+func CommDlgExtendedError() uint {
+ ret, _, _ := procCommDlgExtendedError.Call()
+
+ return uint(ret)
+}
diff --git a/vendor/github.com/shirou/w32/constants.go b/vendor/github.com/shirou/w32/constants.go
new file mode 100644
index 0000000..62d2d4b
--- /dev/null
+++ b/vendor/github.com/shirou/w32/constants.go
@@ -0,0 +1,2661 @@
+// Copyright 2010-2012 The W32 Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package w32
+
+const (
+ FALSE = 0
+ TRUE = 1
+)
+
+const (
+ NO_ERROR = 0
+ ERROR_SUCCESS = 0
+ ERROR_FILE_NOT_FOUND = 2
+ ERROR_PATH_NOT_FOUND = 3
+ ERROR_ACCESS_DENIED = 5
+ ERROR_INVALID_HANDLE = 6
+ ERROR_BAD_FORMAT = 11
+ ERROR_INVALID_NAME = 123
+ ERROR_MORE_DATA = 234
+ ERROR_NO_MORE_ITEMS = 259
+ ERROR_INVALID_SERVICE_CONTROL = 1052
+ ERROR_SERVICE_REQUEST_TIMEOUT = 1053
+ ERROR_SERVICE_NO_THREAD = 1054
+ ERROR_SERVICE_DATABASE_LOCKED = 1055
+ ERROR_SERVICE_ALREADY_RUNNING = 1056
+ ERROR_SERVICE_DISABLED = 1058
+ ERROR_SERVICE_DOES_NOT_EXIST = 1060
+ ERROR_SERVICE_CANNOT_ACCEPT_CTRL = 1061
+ ERROR_SERVICE_NOT_ACTIVE = 1062
+ ERROR_DATABASE_DOES_NOT_EXIST = 1065
+ ERROR_SERVICE_DEPENDENCY_FAIL = 1068
+ ERROR_SERVICE_LOGON_FAILED = 1069
+ ERROR_SERVICE_MARKED_FOR_DELETE = 1072
+ ERROR_SERVICE_DEPENDENCY_DELETED = 1075
+)
+
+const (
+ SE_ERR_FNF = 2
+ SE_ERR_PNF = 3
+ SE_ERR_ACCESSDENIED = 5
+ SE_ERR_OOM = 8
+ SE_ERR_DLLNOTFOUND = 32
+ SE_ERR_SHARE = 26
+ SE_ERR_ASSOCINCOMPLETE = 27
+ SE_ERR_DDETIMEOUT = 28
+ SE_ERR_DDEFAIL = 29
+ SE_ERR_DDEBUSY = 30
+ SE_ERR_NOASSOC = 31
+)
+
+const (
+ CW_USEDEFAULT = ^0x7fffffff
+)
+
+// ShowWindow constants
+const (
+ SW_HIDE = 0
+ SW_NORMAL = 1
+ SW_SHOWNORMAL = 1
+ SW_SHOWMINIMIZED = 2
+ SW_MAXIMIZE = 3
+ SW_SHOWMAXIMIZED = 3
+ SW_SHOWNOACTIVATE = 4
+ SW_SHOW = 5
+ SW_MINIMIZE = 6
+ SW_SHOWMINNOACTIVE = 7
+ SW_SHOWNA = 8
+ SW_RESTORE = 9
+ SW_SHOWDEFAULT = 10
+ SW_FORCEMINIMIZE = 11
+)
+
+// Window class styles
+const (
+ CS_VREDRAW = 0x00000001
+ CS_HREDRAW = 0x00000002
+ CS_KEYCVTWINDOW = 0x00000004
+ CS_DBLCLKS = 0x00000008
+ CS_OWNDC = 0x00000020
+ CS_CLASSDC = 0x00000040
+ CS_PARENTDC = 0x00000080
+ CS_NOKEYCVT = 0x00000100
+ CS_NOCLOSE = 0x00000200
+ CS_SAVEBITS = 0x00000800
+ CS_BYTEALIGNCLIENT = 0x00001000
+ CS_BYTEALIGNWINDOW = 0x00002000
+ CS_GLOBALCLASS = 0x00004000
+ CS_IME = 0x00010000
+ CS_DROPSHADOW = 0x00020000
+)
+
+// Predefined cursor constants
+const (
+ IDC_ARROW = 32512
+ IDC_IBEAM = 32513
+ IDC_WAIT = 32514
+ IDC_CROSS = 32515
+ IDC_UPARROW = 32516
+ IDC_SIZENWSE = 32642
+ IDC_SIZENESW = 32643
+ IDC_SIZEWE = 32644
+ IDC_SIZENS = 32645
+ IDC_SIZEALL = 32646
+ IDC_NO = 32648
+ IDC_HAND = 32649
+ IDC_APPSTARTING = 32650
+ IDC_HELP = 32651
+ IDC_ICON = 32641
+ IDC_SIZE = 32640
+)
+
+// Predefined icon constants
+const (
+ IDI_APPLICATION = 32512
+ IDI_HAND = 32513
+ IDI_QUESTION = 32514
+ IDI_EXCLAMATION = 32515
+ IDI_ASTERISK = 32516
+ IDI_WINLOGO = 32517
+ IDI_WARNING = IDI_EXCLAMATION
+ IDI_ERROR = IDI_HAND
+ IDI_INFORMATION = IDI_ASTERISK
+)
+
+// Button style constants
+const (
+ BS_3STATE = 5
+ BS_AUTO3STATE = 6
+ BS_AUTOCHECKBOX = 3
+ BS_AUTORADIOBUTTON = 9
+ BS_BITMAP = 128
+ BS_BOTTOM = 0X800
+ BS_CENTER = 0X300
+ BS_CHECKBOX = 2
+ BS_DEFPUSHBUTTON = 1
+ BS_GROUPBOX = 7
+ BS_ICON = 64
+ BS_LEFT = 256
+ BS_LEFTTEXT = 32
+ BS_MULTILINE = 0X2000
+ BS_NOTIFY = 0X4000
+ BS_OWNERDRAW = 0XB
+ BS_PUSHBUTTON = 0
+ BS_PUSHLIKE = 4096
+ BS_RADIOBUTTON = 4
+ BS_RIGHT = 512
+ BS_RIGHTBUTTON = 32
+ BS_TEXT = 0
+ BS_TOP = 0X400
+ BS_USERBUTTON = 8
+ BS_VCENTER = 0XC00
+ BS_FLAT = 0X8000
+)
+
+// Button state constants
+const (
+ BST_CHECKED = 1
+ BST_INDETERMINATE = 2
+ BST_UNCHECKED = 0
+ BST_FOCUS = 8
+ BST_PUSHED = 4
+)
+
+// Predefined brushes constants
+const (
+ COLOR_3DDKSHADOW = 21
+ COLOR_3DFACE = 15
+ COLOR_3DHILIGHT = 20
+ COLOR_3DHIGHLIGHT = 20
+ COLOR_3DLIGHT = 22
+ COLOR_BTNHILIGHT = 20
+ COLOR_3DSHADOW = 16
+ COLOR_ACTIVEBORDER = 10
+ COLOR_ACTIVECAPTION = 2
+ COLOR_APPWORKSPACE = 12
+ COLOR_BACKGROUND = 1
+ COLOR_DESKTOP = 1
+ COLOR_BTNFACE = 15
+ COLOR_BTNHIGHLIGHT = 20
+ COLOR_BTNSHADOW = 16
+ COLOR_BTNTEXT = 18
+ COLOR_CAPTIONTEXT = 9
+ COLOR_GRAYTEXT = 17
+ COLOR_HIGHLIGHT = 13
+ COLOR_HIGHLIGHTTEXT = 14
+ COLOR_INACTIVEBORDER = 11
+ COLOR_INACTIVECAPTION = 3
+ COLOR_INACTIVECAPTIONTEXT = 19
+ COLOR_INFOBK = 24
+ COLOR_INFOTEXT = 23
+ COLOR_MENU = 4
+ COLOR_MENUTEXT = 7
+ COLOR_SCROLLBAR = 0
+ COLOR_WINDOW = 5
+ COLOR_WINDOWFRAME = 6
+ COLOR_WINDOWTEXT = 8
+ COLOR_HOTLIGHT = 26
+ COLOR_GRADIENTACTIVECAPTION = 27
+ COLOR_GRADIENTINACTIVECAPTION = 28
+)
+
+// Button message constants
+const (
+ BM_CLICK = 245
+ BM_GETCHECK = 240
+ BM_GETIMAGE = 246
+ BM_GETSTATE = 242
+ BM_SETCHECK = 241
+ BM_SETIMAGE = 247
+ BM_SETSTATE = 243
+ BM_SETSTYLE = 244
+)
+
+// Button notifications
+const (
+ BN_CLICKED = 0
+ BN_PAINT = 1
+ BN_HILITE = 2
+ BN_PUSHED = BN_HILITE
+ BN_UNHILITE = 3
+ BN_UNPUSHED = BN_UNHILITE
+ BN_DISABLE = 4
+ BN_DOUBLECLICKED = 5
+ BN_DBLCLK = BN_DOUBLECLICKED
+ BN_SETFOCUS = 6
+ BN_KILLFOCUS = 7
+)
+
+// GetWindowLong and GetWindowLongPtr constants
+const (
+ GWL_EXSTYLE = -20
+ GWL_STYLE = -16
+ GWL_WNDPROC = -4
+ GWLP_WNDPROC = -4
+ GWL_HINSTANCE = -6
+ GWLP_HINSTANCE = -6
+ GWL_HWNDPARENT = -8
+ GWLP_HWNDPARENT = -8
+ GWL_ID = -12
+ GWLP_ID = -12
+ GWL_USERDATA = -21
+ GWLP_USERDATA = -21
+)
+
+// Window style constants
+const (
+ WS_OVERLAPPED = 0X00000000
+ WS_POPUP = 0X80000000
+ WS_CHILD = 0X40000000
+ WS_MINIMIZE = 0X20000000
+ WS_VISIBLE = 0X10000000
+ WS_DISABLED = 0X08000000
+ WS_CLIPSIBLINGS = 0X04000000
+ WS_CLIPCHILDREN = 0X02000000
+ WS_MAXIMIZE = 0X01000000
+ WS_CAPTION = 0X00C00000
+ WS_BORDER = 0X00800000
+ WS_DLGFRAME = 0X00400000
+ WS_VSCROLL = 0X00200000
+ WS_HSCROLL = 0X00100000
+ WS_SYSMENU = 0X00080000
+ WS_THICKFRAME = 0X00040000
+ WS_GROUP = 0X00020000
+ WS_TABSTOP = 0X00010000
+ WS_MINIMIZEBOX = 0X00020000
+ WS_MAXIMIZEBOX = 0X00010000
+ WS_TILED = 0X00000000
+ WS_ICONIC = 0X20000000
+ WS_SIZEBOX = 0X00040000
+ WS_OVERLAPPEDWINDOW = 0X00000000 | 0X00C00000 | 0X00080000 | 0X00040000 | 0X00020000 | 0X00010000
+ WS_POPUPWINDOW = 0X80000000 | 0X00800000 | 0X00080000
+ WS_CHILDWINDOW = 0X40000000
+)
+
+// Extended window style constants
+const (
+ WS_EX_DLGMODALFRAME = 0X00000001
+ WS_EX_NOPARENTNOTIFY = 0X00000004
+ WS_EX_TOPMOST = 0X00000008
+ WS_EX_ACCEPTFILES = 0X00000010
+ WS_EX_TRANSPARENT = 0X00000020
+ WS_EX_MDICHILD = 0X00000040
+ WS_EX_TOOLWINDOW = 0X00000080
+ WS_EX_WINDOWEDGE = 0X00000100
+ WS_EX_CLIENTEDGE = 0X00000200
+ WS_EX_CONTEXTHELP = 0X00000400
+ WS_EX_RIGHT = 0X00001000
+ WS_EX_LEFT = 0X00000000
+ WS_EX_RTLREADING = 0X00002000
+ WS_EX_LTRREADING = 0X00000000
+ WS_EX_LEFTSCROLLBAR = 0X00004000
+ WS_EX_RIGHTSCROLLBAR = 0X00000000
+ WS_EX_CONTROLPARENT = 0X00010000
+ WS_EX_STATICEDGE = 0X00020000
+ WS_EX_APPWINDOW = 0X00040000
+ WS_EX_OVERLAPPEDWINDOW = 0X00000100 | 0X00000200
+ WS_EX_PALETTEWINDOW = 0X00000100 | 0X00000080 | 0X00000008
+ WS_EX_LAYERED = 0X00080000
+ WS_EX_NOINHERITLAYOUT = 0X00100000
+ WS_EX_LAYOUTRTL = 0X00400000
+ WS_EX_NOACTIVATE = 0X08000000
+)
+
+// Window message constants
+const (
+ WM_APP = 32768
+ WM_ACTIVATE = 6
+ WM_ACTIVATEAPP = 28
+ WM_AFXFIRST = 864
+ WM_AFXLAST = 895
+ WM_ASKCBFORMATNAME = 780
+ WM_CANCELJOURNAL = 75
+ WM_CANCELMODE = 31
+ WM_CAPTURECHANGED = 533
+ WM_CHANGECBCHAIN = 781
+ WM_CHAR = 258
+ WM_CHARTOITEM = 47
+ WM_CHILDACTIVATE = 34
+ WM_CLEAR = 771
+ WM_CLOSE = 16
+ WM_COMMAND = 273
+ WM_COMMNOTIFY = 68 /* OBSOLETE */
+ WM_COMPACTING = 65
+ WM_COMPAREITEM = 57
+ WM_CONTEXTMENU = 123
+ WM_COPY = 769
+ WM_COPYDATA = 74
+ WM_CREATE = 1
+ WM_CTLCOLORBTN = 309
+ WM_CTLCOLORDLG = 310
+ WM_CTLCOLOREDIT = 307
+ WM_CTLCOLORLISTBOX = 308
+ WM_CTLCOLORMSGBOX = 306
+ WM_CTLCOLORSCROLLBAR = 311
+ WM_CTLCOLORSTATIC = 312
+ WM_CUT = 768
+ WM_DEADCHAR = 259
+ WM_DELETEITEM = 45
+ WM_DESTROY = 2
+ WM_DESTROYCLIPBOARD = 775
+ WM_DEVICECHANGE = 537
+ WM_DEVMODECHANGE = 27
+ WM_DISPLAYCHANGE = 126
+ WM_DRAWCLIPBOARD = 776
+ WM_DRAWITEM = 43
+ WM_DROPFILES = 563
+ WM_ENABLE = 10
+ WM_ENDSESSION = 22
+ WM_ENTERIDLE = 289
+ WM_ENTERMENULOOP = 529
+ WM_ENTERSIZEMOVE = 561
+ WM_ERASEBKGND = 20
+ WM_EXITMENULOOP = 530
+ WM_EXITSIZEMOVE = 562
+ WM_FONTCHANGE = 29
+ WM_GETDLGCODE = 135
+ WM_GETFONT = 49
+ WM_GETHOTKEY = 51
+ WM_GETICON = 127
+ WM_GETMINMAXINFO = 36
+ WM_GETTEXT = 13
+ WM_GETTEXTLENGTH = 14
+ WM_HANDHELDFIRST = 856
+ WM_HANDHELDLAST = 863
+ WM_HELP = 83
+ WM_HOTKEY = 786
+ WM_HSCROLL = 276
+ WM_HSCROLLCLIPBOARD = 782
+ WM_ICONERASEBKGND = 39
+ WM_INITDIALOG = 272
+ WM_INITMENU = 278
+ WM_INITMENUPOPUP = 279
+ WM_INPUT = 0X00FF
+ WM_INPUTLANGCHANGE = 81
+ WM_INPUTLANGCHANGEREQUEST = 80
+ WM_KEYDOWN = 256
+ WM_KEYUP = 257
+ WM_KILLFOCUS = 8
+ WM_MDIACTIVATE = 546
+ WM_MDICASCADE = 551
+ WM_MDICREATE = 544
+ WM_MDIDESTROY = 545
+ WM_MDIGETACTIVE = 553
+ WM_MDIICONARRANGE = 552
+ WM_MDIMAXIMIZE = 549
+ WM_MDINEXT = 548
+ WM_MDIREFRESHMENU = 564
+ WM_MDIRESTORE = 547
+ WM_MDISETMENU = 560
+ WM_MDITILE = 550
+ WM_MEASUREITEM = 44
+ WM_GETOBJECT = 0X003D
+ WM_CHANGEUISTATE = 0X0127
+ WM_UPDATEUISTATE = 0X0128
+ WM_QUERYUISTATE = 0X0129
+ WM_UNINITMENUPOPUP = 0X0125
+ WM_MENURBUTTONUP = 290
+ WM_MENUCOMMAND = 0X0126
+ WM_MENUGETOBJECT = 0X0124
+ WM_MENUDRAG = 0X0123
+ WM_APPCOMMAND = 0X0319
+ WM_MENUCHAR = 288
+ WM_MENUSELECT = 287
+ WM_MOVE = 3
+ WM_MOVING = 534
+ WM_NCACTIVATE = 134
+ WM_NCCALCSIZE = 131
+ WM_NCCREATE = 129
+ WM_NCDESTROY = 130
+ WM_NCHITTEST = 132
+ WM_NCLBUTTONDBLCLK = 163
+ WM_NCLBUTTONDOWN = 161
+ WM_NCLBUTTONUP = 162
+ WM_NCMBUTTONDBLCLK = 169
+ WM_NCMBUTTONDOWN = 167
+ WM_NCMBUTTONUP = 168
+ WM_NCXBUTTONDOWN = 171
+ WM_NCXBUTTONUP = 172
+ WM_NCXBUTTONDBLCLK = 173
+ WM_NCMOUSEHOVER = 0X02A0
+ WM_NCMOUSELEAVE = 0X02A2
+ WM_NCMOUSEMOVE = 160
+ WM_NCPAINT = 133
+ WM_NCRBUTTONDBLCLK = 166
+ WM_NCRBUTTONDOWN = 164
+ WM_NCRBUTTONUP = 165
+ WM_NEXTDLGCTL = 40
+ WM_NEXTMENU = 531
+ WM_NOTIFY = 78
+ WM_NOTIFYFORMAT = 85
+ WM_NULL = 0
+ WM_PAINT = 15
+ WM_PAINTCLIPBOARD = 777
+ WM_PAINTICON = 38
+ WM_PALETTECHANGED = 785
+ WM_PALETTEISCHANGING = 784
+ WM_PARENTNOTIFY = 528
+ WM_PASTE = 770
+ WM_PENWINFIRST = 896
+ WM_PENWINLAST = 911
+ WM_POWER = 72
+ WM_POWERBROADCAST = 536
+ WM_PRINT = 791
+ WM_PRINTCLIENT = 792
+ WM_QUERYDRAGICON = 55
+ WM_QUERYENDSESSION = 17
+ WM_QUERYNEWPALETTE = 783
+ WM_QUERYOPEN = 19
+ WM_QUEUESYNC = 35
+ WM_QUIT = 18
+ WM_RENDERALLFORMATS = 774
+ WM_RENDERFORMAT = 773
+ WM_SETCURSOR = 32
+ WM_SETFOCUS = 7
+ WM_SETFONT = 48
+ WM_SETHOTKEY = 50
+ WM_SETICON = 128
+ WM_SETREDRAW = 11
+ WM_SETTEXT = 12
+ WM_SETTINGCHANGE = 26
+ WM_SHOWWINDOW = 24
+ WM_SIZE = 5
+ WM_SIZECLIPBOARD = 779
+ WM_SIZING = 532
+ WM_SPOOLERSTATUS = 42
+ WM_STYLECHANGED = 125
+ WM_STYLECHANGING = 124
+ WM_SYSCHAR = 262
+ WM_SYSCOLORCHANGE = 21
+ WM_SYSCOMMAND = 274
+ WM_SYSDEADCHAR = 263
+ WM_SYSKEYDOWN = 260
+ WM_SYSKEYUP = 261
+ WM_TCARD = 82
+ WM_THEMECHANGED = 794
+ WM_TIMECHANGE = 30
+ WM_TIMER = 275
+ WM_UNDO = 772
+ WM_USER = 1024
+ WM_USERCHANGED = 84
+ WM_VKEYTOITEM = 46
+ WM_VSCROLL = 277
+ WM_VSCROLLCLIPBOARD = 778
+ WM_WINDOWPOSCHANGED = 71
+ WM_WINDOWPOSCHANGING = 70
+ WM_WININICHANGE = 26
+ WM_KEYFIRST = 256
+ WM_KEYLAST = 264
+ WM_SYNCPAINT = 136
+ WM_MOUSEACTIVATE = 33
+ WM_MOUSEMOVE = 512
+ WM_LBUTTONDOWN = 513
+ WM_LBUTTONUP = 514
+ WM_LBUTTONDBLCLK = 515
+ WM_RBUTTONDOWN = 516
+ WM_RBUTTONUP = 517
+ WM_RBUTTONDBLCLK = 518
+ WM_MBUTTONDOWN = 519
+ WM_MBUTTONUP = 520
+ WM_MBUTTONDBLCLK = 521
+ WM_MOUSEWHEEL = 522
+ WM_MOUSEFIRST = 512
+ WM_XBUTTONDOWN = 523
+ WM_XBUTTONUP = 524
+ WM_XBUTTONDBLCLK = 525
+ WM_MOUSELAST = 525
+ WM_MOUSEHOVER = 0X2A1
+ WM_MOUSELEAVE = 0X2A3
+ WM_CLIPBOARDUPDATE = 0x031D
+)
+
+// WM_ACTIVATE
+const (
+ WA_INACTIVE = 0
+ WA_ACTIVE = 1
+ WA_CLICKACTIVE = 2
+)
+
+const LF_FACESIZE = 32
+
+// Font weight constants
+const (
+ FW_DONTCARE = 0
+ FW_THIN = 100
+ FW_EXTRALIGHT = 200
+ FW_ULTRALIGHT = FW_EXTRALIGHT
+ FW_LIGHT = 300
+ FW_NORMAL = 400
+ FW_REGULAR = 400
+ FW_MEDIUM = 500
+ FW_SEMIBOLD = 600
+ FW_DEMIBOLD = FW_SEMIBOLD
+ FW_BOLD = 700
+ FW_EXTRABOLD = 800
+ FW_ULTRABOLD = FW_EXTRABOLD
+ FW_HEAVY = 900
+ FW_BLACK = FW_HEAVY
+)
+
+// Charset constants
+const (
+ ANSI_CHARSET = 0
+ DEFAULT_CHARSET = 1
+ SYMBOL_CHARSET = 2
+ SHIFTJIS_CHARSET = 128
+ HANGEUL_CHARSET = 129
+ HANGUL_CHARSET = 129
+ GB2312_CHARSET = 134
+ CHINESEBIG5_CHARSET = 136
+ GREEK_CHARSET = 161
+ TURKISH_CHARSET = 162
+ HEBREW_CHARSET = 177
+ ARABIC_CHARSET = 178
+ BALTIC_CHARSET = 186
+ RUSSIAN_CHARSET = 204
+ THAI_CHARSET = 222
+ EASTEUROPE_CHARSET = 238
+ OEM_CHARSET = 255
+ JOHAB_CHARSET = 130
+ VIETNAMESE_CHARSET = 163
+ MAC_CHARSET = 77
+)
+
+// Font output precision constants
+const (
+ OUT_DEFAULT_PRECIS = 0
+ OUT_STRING_PRECIS = 1
+ OUT_CHARACTER_PRECIS = 2
+ OUT_STROKE_PRECIS = 3
+ OUT_TT_PRECIS = 4
+ OUT_DEVICE_PRECIS = 5
+ OUT_RASTER_PRECIS = 6
+ OUT_TT_ONLY_PRECIS = 7
+ OUT_OUTLINE_PRECIS = 8
+ OUT_PS_ONLY_PRECIS = 10
+)
+
+// Font clipping precision constants
+const (
+ CLIP_DEFAULT_PRECIS = 0
+ CLIP_CHARACTER_PRECIS = 1
+ CLIP_STROKE_PRECIS = 2
+ CLIP_MASK = 15
+ CLIP_LH_ANGLES = 16
+ CLIP_TT_ALWAYS = 32
+ CLIP_EMBEDDED = 128
+)
+
+// Font output quality constants
+const (
+ DEFAULT_QUALITY = 0
+ DRAFT_QUALITY = 1
+ PROOF_QUALITY = 2
+ NONANTIALIASED_QUALITY = 3
+ ANTIALIASED_QUALITY = 4
+ CLEARTYPE_QUALITY = 5
+)
+
+// Font pitch constants
+const (
+ DEFAULT_PITCH = 0
+ FIXED_PITCH = 1
+ VARIABLE_PITCH = 2
+)
+
+// Font family constants
+const (
+ FF_DECORATIVE = 80
+ FF_DONTCARE = 0
+ FF_MODERN = 48
+ FF_ROMAN = 16
+ FF_SCRIPT = 64
+ FF_SWISS = 32
+)
+
+// DeviceCapabilities capabilities
+const (
+ DC_FIELDS = 1
+ DC_PAPERS = 2
+ DC_PAPERSIZE = 3
+ DC_MINEXTENT = 4
+ DC_MAXEXTENT = 5
+ DC_BINS = 6
+ DC_DUPLEX = 7
+ DC_SIZE = 8
+ DC_EXTRA = 9
+ DC_VERSION = 10
+ DC_DRIVER = 11
+ DC_BINNAMES = 12
+ DC_ENUMRESOLUTIONS = 13
+ DC_FILEDEPENDENCIES = 14
+ DC_TRUETYPE = 15
+ DC_PAPERNAMES = 16
+ DC_ORIENTATION = 17
+ DC_COPIES = 18
+ DC_BINADJUST = 19
+ DC_EMF_COMPLIANT = 20
+ DC_DATATYPE_PRODUCED = 21
+ DC_COLLATE = 22
+ DC_MANUFACTURER = 23
+ DC_MODEL = 24
+ DC_PERSONALITY = 25
+ DC_PRINTRATE = 26
+ DC_PRINTRATEUNIT = 27
+ DC_PRINTERMEM = 28
+ DC_MEDIAREADY = 29
+ DC_STAPLE = 30
+ DC_PRINTRATEPPM = 31
+ DC_COLORDEVICE = 32
+ DC_NUP = 33
+ DC_MEDIATYPENAMES = 34
+ DC_MEDIATYPES = 35
+)
+
+// GetDeviceCaps index constants
+const (
+ DRIVERVERSION = 0
+ TECHNOLOGY = 2
+ HORZSIZE = 4
+ VERTSIZE = 6
+ HORZRES = 8
+ VERTRES = 10
+ LOGPIXELSX = 88
+ LOGPIXELSY = 90
+ BITSPIXEL = 12
+ PLANES = 14
+ NUMBRUSHES = 16
+ NUMPENS = 18
+ NUMFONTS = 22
+ NUMCOLORS = 24
+ NUMMARKERS = 20
+ ASPECTX = 40
+ ASPECTY = 42
+ ASPECTXY = 44
+ PDEVICESIZE = 26
+ CLIPCAPS = 36
+ SIZEPALETTE = 104
+ NUMRESERVED = 106
+ COLORRES = 108
+ PHYSICALWIDTH = 110
+ PHYSICALHEIGHT = 111
+ PHYSICALOFFSETX = 112
+ PHYSICALOFFSETY = 113
+ SCALINGFACTORX = 114
+ SCALINGFACTORY = 115
+ VREFRESH = 116
+ DESKTOPHORZRES = 118
+ DESKTOPVERTRES = 117
+ BLTALIGNMENT = 119
+ SHADEBLENDCAPS = 120
+ COLORMGMTCAPS = 121
+ RASTERCAPS = 38
+ CURVECAPS = 28
+ LINECAPS = 30
+ POLYGONALCAPS = 32
+ TEXTCAPS = 34
+)
+
+// GetDeviceCaps TECHNOLOGY constants
+const (
+ DT_PLOTTER = 0
+ DT_RASDISPLAY = 1
+ DT_RASPRINTER = 2
+ DT_RASCAMERA = 3
+ DT_CHARSTREAM = 4
+ DT_METAFILE = 5
+ DT_DISPFILE = 6
+)
+
+// GetDeviceCaps SHADEBLENDCAPS constants
+const (
+ SB_NONE = 0x00
+ SB_CONST_ALPHA = 0x01
+ SB_PIXEL_ALPHA = 0x02
+ SB_PREMULT_ALPHA = 0x04
+ SB_GRAD_RECT = 0x10
+ SB_GRAD_TRI = 0x20
+)
+
+// GetDeviceCaps COLORMGMTCAPS constants
+const (
+ CM_NONE = 0x00
+ CM_DEVICE_ICM = 0x01
+ CM_GAMMA_RAMP = 0x02
+ CM_CMYK_COLOR = 0x04
+)
+
+// GetDeviceCaps RASTERCAPS constants
+const (
+ RC_BANDING = 2
+ RC_BITBLT = 1
+ RC_BITMAP64 = 8
+ RC_DI_BITMAP = 128
+ RC_DIBTODEV = 512
+ RC_FLOODFILL = 4096
+ RC_GDI20_OUTPUT = 16
+ RC_PALETTE = 256
+ RC_SCALING = 4
+ RC_STRETCHBLT = 2048
+ RC_STRETCHDIB = 8192
+ RC_DEVBITS = 0x8000
+ RC_OP_DX_OUTPUT = 0x4000
+)
+
+// GetDeviceCaps CURVECAPS constants
+const (
+ CC_NONE = 0
+ CC_CIRCLES = 1
+ CC_PIE = 2
+ CC_CHORD = 4
+ CC_ELLIPSES = 8
+ CC_WIDE = 16
+ CC_STYLED = 32
+ CC_WIDESTYLED = 64
+ CC_INTERIORS = 128
+ CC_ROUNDRECT = 256
+)
+
+// GetDeviceCaps LINECAPS constants
+const (
+ LC_NONE = 0
+ LC_POLYLINE = 2
+ LC_MARKER = 4
+ LC_POLYMARKER = 8
+ LC_WIDE = 16
+ LC_STYLED = 32
+ LC_WIDESTYLED = 64
+ LC_INTERIORS = 128
+)
+
+// GetDeviceCaps POLYGONALCAPS constants
+const (
+ PC_NONE = 0
+ PC_POLYGON = 1
+ PC_POLYPOLYGON = 256
+ PC_PATHS = 512
+ PC_RECTANGLE = 2
+ PC_WINDPOLYGON = 4
+ PC_SCANLINE = 8
+ PC_TRAPEZOID = 4
+ PC_WIDE = 16
+ PC_STYLED = 32
+ PC_WIDESTYLED = 64
+ PC_INTERIORS = 128
+)
+
+// GetDeviceCaps TEXTCAPS constants
+const (
+ TC_OP_CHARACTER = 1
+ TC_OP_STROKE = 2
+ TC_CP_STROKE = 4
+ TC_CR_90 = 8
+ TC_CR_ANY = 16
+ TC_SF_X_YINDEP = 32
+ TC_SA_DOUBLE = 64
+ TC_SA_INTEGER = 128
+ TC_SA_CONTIN = 256
+ TC_EA_DOUBLE = 512
+ TC_IA_ABLE = 1024
+ TC_UA_ABLE = 2048
+ TC_SO_ABLE = 4096
+ TC_RA_ABLE = 8192
+ TC_VA_ABLE = 16384
+ TC_RESERVED = 32768
+ TC_SCROLLBLT = 65536
+)
+
+// Static control styles
+const (
+ SS_BITMAP = 14
+ SS_BLACKFRAME = 7
+ SS_BLACKRECT = 4
+ SS_CENTER = 1
+ SS_CENTERIMAGE = 512
+ SS_EDITCONTROL = 0x2000
+ SS_ENHMETAFILE = 15
+ SS_ETCHEDFRAME = 18
+ SS_ETCHEDHORZ = 16
+ SS_ETCHEDVERT = 17
+ SS_GRAYFRAME = 8
+ SS_GRAYRECT = 5
+ SS_ICON = 3
+ SS_LEFT = 0
+ SS_LEFTNOWORDWRAP = 0xc
+ SS_NOPREFIX = 128
+ SS_NOTIFY = 256
+ SS_OWNERDRAW = 0xd
+ SS_REALSIZECONTROL = 0x040
+ SS_REALSIZEIMAGE = 0x800
+ SS_RIGHT = 2
+ SS_RIGHTJUST = 0x400
+ SS_SIMPLE = 11
+ SS_SUNKEN = 4096
+ SS_WHITEFRAME = 9
+ SS_WHITERECT = 6
+ SS_USERITEM = 10
+ SS_TYPEMASK = 0x0000001F
+ SS_ENDELLIPSIS = 0x00004000
+ SS_PATHELLIPSIS = 0x00008000
+ SS_WORDELLIPSIS = 0x0000C000
+ SS_ELLIPSISMASK = 0x0000C000
+)
+
+// Edit styles
+const (
+ ES_LEFT = 0x0000
+ ES_CENTER = 0x0001
+ ES_RIGHT = 0x0002
+ ES_MULTILINE = 0x0004
+ ES_UPPERCASE = 0x0008
+ ES_LOWERCASE = 0x0010
+ ES_PASSWORD = 0x0020
+ ES_AUTOVSCROLL = 0x0040
+ ES_AUTOHSCROLL = 0x0080
+ ES_NOHIDESEL = 0x0100
+ ES_OEMCONVERT = 0x0400
+ ES_READONLY = 0x0800
+ ES_WANTRETURN = 0x1000
+ ES_NUMBER = 0x2000
+)
+
+// Edit notifications
+const (
+ EN_SETFOCUS = 0x0100
+ EN_KILLFOCUS = 0x0200
+ EN_CHANGE = 0x0300
+ EN_UPDATE = 0x0400
+ EN_ERRSPACE = 0x0500
+ EN_MAXTEXT = 0x0501
+ EN_HSCROLL = 0x0601
+ EN_VSCROLL = 0x0602
+ EN_ALIGN_LTR_EC = 0x0700
+ EN_ALIGN_RTL_EC = 0x0701
+)
+
+// Edit messages
+const (
+ EM_GETSEL = 0x00B0
+ EM_SETSEL = 0x00B1
+ EM_GETRECT = 0x00B2
+ EM_SETRECT = 0x00B3
+ EM_SETRECTNP = 0x00B4
+ EM_SCROLL = 0x00B5
+ EM_LINESCROLL = 0x00B6
+ EM_SCROLLCARET = 0x00B7
+ EM_GETMODIFY = 0x00B8
+ EM_SETMODIFY = 0x00B9
+ EM_GETLINECOUNT = 0x00BA
+ EM_LINEINDEX = 0x00BB
+ EM_SETHANDLE = 0x00BC
+ EM_GETHANDLE = 0x00BD
+ EM_GETTHUMB = 0x00BE
+ EM_LINELENGTH = 0x00C1
+ EM_REPLACESEL = 0x00C2
+ EM_GETLINE = 0x00C4
+ EM_LIMITTEXT = 0x00C5
+ EM_CANUNDO = 0x00C6
+ EM_UNDO = 0x00C7
+ EM_FMTLINES = 0x00C8
+ EM_LINEFROMCHAR = 0x00C9
+ EM_SETTABSTOPS = 0x00CB
+ EM_SETPASSWORDCHAR = 0x00CC
+ EM_EMPTYUNDOBUFFER = 0x00CD
+ EM_GETFIRSTVISIBLELINE = 0x00CE
+ EM_SETREADONLY = 0x00CF
+ EM_SETWORDBREAKPROC = 0x00D0
+ EM_GETWORDBREAKPROC = 0x00D1
+ EM_GETPASSWORDCHAR = 0x00D2
+ EM_SETMARGINS = 0x00D3
+ EM_GETMARGINS = 0x00D4
+ EM_SETLIMITTEXT = EM_LIMITTEXT
+ EM_GETLIMITTEXT = 0x00D5
+ EM_POSFROMCHAR = 0x00D6
+ EM_CHARFROMPOS = 0x00D7
+ EM_SETIMESTATUS = 0x00D8
+ EM_GETIMESTATUS = 0x00D9
+ EM_SETCUEBANNER = 0x1501
+ EM_GETCUEBANNER = 0x1502
+)
+
+const (
+ CCM_FIRST = 0x2000
+ CCM_LAST = CCM_FIRST + 0x200
+ CCM_SETBKCOLOR = 8193
+ CCM_SETCOLORSCHEME = 8194
+ CCM_GETCOLORSCHEME = 8195
+ CCM_GETDROPTARGET = 8196
+ CCM_SETUNICODEFORMAT = 8197
+ CCM_GETUNICODEFORMAT = 8198
+ CCM_SETVERSION = 0x2007
+ CCM_GETVERSION = 0x2008
+ CCM_SETNOTIFYWINDOW = 0x2009
+ CCM_SETWINDOWTHEME = 0x200b
+ CCM_DPISCALE = 0x200c
+)
+
+// Common controls styles
+const (
+ CCS_TOP = 1
+ CCS_NOMOVEY = 2
+ CCS_BOTTOM = 3
+ CCS_NORESIZE = 4
+ CCS_NOPARENTALIGN = 8
+ CCS_ADJUSTABLE = 32
+ CCS_NODIVIDER = 64
+ CCS_VERT = 128
+ CCS_LEFT = 129
+ CCS_NOMOVEX = 130
+ CCS_RIGHT = 131
+)
+
+// ProgressBar messages
+const (
+ PROGRESS_CLASS = "msctls_progress32"
+ PBM_SETPOS = WM_USER + 2
+ PBM_DELTAPOS = WM_USER + 3
+ PBM_SETSTEP = WM_USER + 4
+ PBM_STEPIT = WM_USER + 5
+ PBM_SETRANGE32 = 1030
+ PBM_GETRANGE = 1031
+ PBM_GETPOS = 1032
+ PBM_SETBARCOLOR = 1033
+ PBM_SETBKCOLOR = CCM_SETBKCOLOR
+ PBS_SMOOTH = 1
+ PBS_VERTICAL = 4
+)
+
+// GetOpenFileName and GetSaveFileName extended flags
+const (
+ OFN_EX_NOPLACESBAR = 0x00000001
+)
+
+// GetOpenFileName and GetSaveFileName flags
+const (
+ OFN_ALLOWMULTISELECT = 0x00000200
+ OFN_CREATEPROMPT = 0x00002000
+ OFN_DONTADDTORECENT = 0x02000000
+ OFN_ENABLEHOOK = 0x00000020
+ OFN_ENABLEINCLUDENOTIFY = 0x00400000
+ OFN_ENABLESIZING = 0x00800000
+ OFN_ENABLETEMPLATE = 0x00000040
+ OFN_ENABLETEMPLATEHANDLE = 0x00000080
+ OFN_EXPLORER = 0x00080000
+ OFN_EXTENSIONDIFFERENT = 0x00000400
+ OFN_FILEMUSTEXIST = 0x00001000
+ OFN_FORCESHOWHIDDEN = 0x10000000
+ OFN_HIDEREADONLY = 0x00000004
+ OFN_LONGNAMES = 0x00200000
+ OFN_NOCHANGEDIR = 0x00000008
+ OFN_NODEREFERENCELINKS = 0x00100000
+ OFN_NOLONGNAMES = 0x00040000
+ OFN_NONETWORKBUTTON = 0x00020000
+ OFN_NOREADONLYRETURN = 0x00008000
+ OFN_NOTESTFILECREATE = 0x00010000
+ OFN_NOVALIDATE = 0x00000100
+ OFN_OVERWRITEPROMPT = 0x00000002
+ OFN_PATHMUSTEXIST = 0x00000800
+ OFN_READONLY = 0x00000001
+ OFN_SHAREAWARE = 0x00004000
+ OFN_SHOWHELP = 0x00000010
+)
+
+//SHBrowseForFolder flags
+const (
+ BIF_RETURNONLYFSDIRS = 0x00000001
+ BIF_DONTGOBELOWDOMAIN = 0x00000002
+ BIF_STATUSTEXT = 0x00000004
+ BIF_RETURNFSANCESTORS = 0x00000008
+ BIF_EDITBOX = 0x00000010
+ BIF_VALIDATE = 0x00000020
+ BIF_NEWDIALOGSTYLE = 0x00000040
+ BIF_BROWSEINCLUDEURLS = 0x00000080
+ BIF_USENEWUI = BIF_EDITBOX | BIF_NEWDIALOGSTYLE
+ BIF_UAHINT = 0x00000100
+ BIF_NONEWFOLDERBUTTON = 0x00000200
+ BIF_NOTRANSLATETARGETS = 0x00000400
+ BIF_BROWSEFORCOMPUTER = 0x00001000
+ BIF_BROWSEFORPRINTER = 0x00002000
+ BIF_BROWSEINCLUDEFILES = 0x00004000
+ BIF_SHAREABLE = 0x00008000
+ BIF_BROWSEFILEJUNCTIONS = 0x00010000
+)
+
+//MessageBox flags
+const (
+ MB_OK = 0x00000000
+ MB_OKCANCEL = 0x00000001
+ MB_ABORTRETRYIGNORE = 0x00000002
+ MB_YESNOCANCEL = 0x00000003
+ MB_YESNO = 0x00000004
+ MB_RETRYCANCEL = 0x00000005
+ MB_CANCELTRYCONTINUE = 0x00000006
+ MB_ICONHAND = 0x00000010
+ MB_ICONQUESTION = 0x00000020
+ MB_ICONEXCLAMATION = 0x00000030
+ MB_ICONASTERISK = 0x00000040
+ MB_USERICON = 0x00000080
+ MB_ICONWARNING = MB_ICONEXCLAMATION
+ MB_ICONERROR = MB_ICONHAND
+ MB_ICONINFORMATION = MB_ICONASTERISK
+ MB_ICONSTOP = MB_ICONHAND
+ MB_DEFBUTTON1 = 0x00000000
+ MB_DEFBUTTON2 = 0x00000100
+ MB_DEFBUTTON3 = 0x00000200
+ MB_DEFBUTTON4 = 0x00000300
+)
+
+//COM
+const (
+ E_INVALIDARG = 0x80070057
+ E_OUTOFMEMORY = 0x8007000E
+ E_UNEXPECTED = 0x8000FFFF
+)
+
+const (
+ S_OK = 0
+ S_FALSE = 0x0001
+ RPC_E_CHANGED_MODE = 0x80010106
+)
+
+// GetSystemMetrics constants
+const (
+ SM_CXSCREEN = 0
+ SM_CYSCREEN = 1
+ SM_CXVSCROLL = 2
+ SM_CYHSCROLL = 3
+ SM_CYCAPTION = 4
+ SM_CXBORDER = 5
+ SM_CYBORDER = 6
+ SM_CXDLGFRAME = 7
+ SM_CYDLGFRAME = 8
+ SM_CYVTHUMB = 9
+ SM_CXHTHUMB = 10
+ SM_CXICON = 11
+ SM_CYICON = 12
+ SM_CXCURSOR = 13
+ SM_CYCURSOR = 14
+ SM_CYMENU = 15
+ SM_CXFULLSCREEN = 16
+ SM_CYFULLSCREEN = 17
+ SM_CYKANJIWINDOW = 18
+ SM_MOUSEPRESENT = 19
+ SM_CYVSCROLL = 20
+ SM_CXHSCROLL = 21
+ SM_DEBUG = 22
+ SM_SWAPBUTTON = 23
+ SM_RESERVED1 = 24
+ SM_RESERVED2 = 25
+ SM_RESERVED3 = 26
+ SM_RESERVED4 = 27
+ SM_CXMIN = 28
+ SM_CYMIN = 29
+ SM_CXSIZE = 30
+ SM_CYSIZE = 31
+ SM_CXFRAME = 32
+ SM_CYFRAME = 33
+ SM_CXMINTRACK = 34
+ SM_CYMINTRACK = 35
+ SM_CXDOUBLECLK = 36
+ SM_CYDOUBLECLK = 37
+ SM_CXICONSPACING = 38
+ SM_CYICONSPACING = 39
+ SM_MENUDROPALIGNMENT = 40
+ SM_PENWINDOWS = 41
+ SM_DBCSENABLED = 42
+ SM_CMOUSEBUTTONS = 43
+ SM_CXFIXEDFRAME = SM_CXDLGFRAME
+ SM_CYFIXEDFRAME = SM_CYDLGFRAME
+ SM_CXSIZEFRAME = SM_CXFRAME
+ SM_CYSIZEFRAME = SM_CYFRAME
+ SM_SECURE = 44
+ SM_CXEDGE = 45
+ SM_CYEDGE = 46
+ SM_CXMINSPACING = 47
+ SM_CYMINSPACING = 48
+ SM_CXSMICON = 49
+ SM_CYSMICON = 50
+ SM_CYSMCAPTION = 51
+ SM_CXSMSIZE = 52
+ SM_CYSMSIZE = 53
+ SM_CXMENUSIZE = 54
+ SM_CYMENUSIZE = 55
+ SM_ARRANGE = 56
+ SM_CXMINIMIZED = 57
+ SM_CYMINIMIZED = 58
+ SM_CXMAXTRACK = 59
+ SM_CYMAXTRACK = 60
+ SM_CXMAXIMIZED = 61
+ SM_CYMAXIMIZED = 62
+ SM_NETWORK = 63
+ SM_CLEANBOOT = 67
+ SM_CXDRAG = 68
+ SM_CYDRAG = 69
+ SM_SHOWSOUNDS = 70
+ SM_CXMENUCHECK = 71
+ SM_CYMENUCHECK = 72
+ SM_SLOWMACHINE = 73
+ SM_MIDEASTENABLED = 74
+ SM_MOUSEWHEELPRESENT = 75
+ SM_XVIRTUALSCREEN = 76
+ SM_YVIRTUALSCREEN = 77
+ SM_CXVIRTUALSCREEN = 78
+ SM_CYVIRTUALSCREEN = 79
+ SM_CMONITORS = 80
+ SM_SAMEDISPLAYFORMAT = 81
+ SM_IMMENABLED = 82
+ SM_CXFOCUSBORDER = 83
+ SM_CYFOCUSBORDER = 84
+ SM_TABLETPC = 86
+ SM_MEDIACENTER = 87
+ SM_STARTER = 88
+ SM_SERVERR2 = 89
+ SM_CMETRICS = 91
+ SM_REMOTESESSION = 0x1000
+ SM_SHUTTINGDOWN = 0x2000
+ SM_REMOTECONTROL = 0x2001
+ SM_CARETBLINKINGENABLED = 0x2002
+)
+
+const (
+ CLSCTX_INPROC_SERVER = 1
+ CLSCTX_INPROC_HANDLER = 2
+ CLSCTX_LOCAL_SERVER = 4
+ CLSCTX_INPROC_SERVER16 = 8
+ CLSCTX_REMOTE_SERVER = 16
+ CLSCTX_ALL = CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER | CLSCTX_LOCAL_SERVER
+ CLSCTX_INPROC = CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER
+ CLSCTX_SERVER = CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER
+)
+
+const (
+ COINIT_APARTMENTTHREADED = 0x2
+ COINIT_MULTITHREADED = 0x0
+ COINIT_DISABLE_OLE1DDE = 0x4
+ COINIT_SPEED_OVER_MEMORY = 0x8
+)
+
+const (
+ DISPATCH_METHOD = 1
+ DISPATCH_PROPERTYGET = 2
+ DISPATCH_PROPERTYPUT = 4
+ DISPATCH_PROPERTYPUTREF = 8
+)
+
+const (
+ CC_FASTCALL = iota
+ CC_CDECL
+ CC_MSCPASCAL
+ CC_PASCAL = CC_MSCPASCAL
+ CC_MACPASCAL
+ CC_STDCALL
+ CC_FPFASTCALL
+ CC_SYSCALL
+ CC_MPWCDECL
+ CC_MPWPASCAL
+ CC_MAX = CC_MPWPASCAL
+)
+
+const (
+ VT_EMPTY = 0x0
+ VT_NULL = 0x1
+ VT_I2 = 0x2
+ VT_I4 = 0x3
+ VT_R4 = 0x4
+ VT_R8 = 0x5
+ VT_CY = 0x6
+ VT_DATE = 0x7
+ VT_BSTR = 0x8
+ VT_DISPATCH = 0x9
+ VT_ERROR = 0xa
+ VT_BOOL = 0xb
+ VT_VARIANT = 0xc
+ VT_UNKNOWN = 0xd
+ VT_DECIMAL = 0xe
+ VT_I1 = 0x10
+ VT_UI1 = 0x11
+ VT_UI2 = 0x12
+ VT_UI4 = 0x13
+ VT_I8 = 0x14
+ VT_UI8 = 0x15
+ VT_INT = 0x16
+ VT_UINT = 0x17
+ VT_VOID = 0x18
+ VT_HRESULT = 0x19
+ VT_PTR = 0x1a
+ VT_SAFEARRAY = 0x1b
+ VT_CARRAY = 0x1c
+ VT_USERDEFINED = 0x1d
+ VT_LPSTR = 0x1e
+ VT_LPWSTR = 0x1f
+ VT_RECORD = 0x24
+ VT_INT_PTR = 0x25
+ VT_UINT_PTR = 0x26
+ VT_FILETIME = 0x40
+ VT_BLOB = 0x41
+ VT_STREAM = 0x42
+ VT_STORAGE = 0x43
+ VT_STREAMED_OBJECT = 0x44
+ VT_STORED_OBJECT = 0x45
+ VT_BLOB_OBJECT = 0x46
+ VT_CF = 0x47
+ VT_CLSID = 0x48
+ VT_BSTR_BLOB = 0xfff
+ VT_VECTOR = 0x1000
+ VT_ARRAY = 0x2000
+ VT_BYREF = 0x4000
+ VT_RESERVED = 0x8000
+ VT_ILLEGAL = 0xffff
+ VT_ILLEGALMASKED = 0xfff
+ VT_TYPEMASK = 0xfff
+)
+
+const (
+ DISPID_UNKNOWN = -1
+ DISPID_VALUE = 0
+ DISPID_PROPERTYPUT = -3
+ DISPID_NEWENUM = -4
+ DISPID_EVALUATE = -5
+ DISPID_CONSTRUCTOR = -6
+ DISPID_DESTRUCTOR = -7
+ DISPID_COLLECT = -8
+)
+
+const (
+ MONITOR_DEFAULTTONULL = 0x00000000
+ MONITOR_DEFAULTTOPRIMARY = 0x00000001
+ MONITOR_DEFAULTTONEAREST = 0x00000002
+
+ MONITORINFOF_PRIMARY = 0x00000001
+)
+
+const (
+ CCHDEVICENAME = 32
+ CCHFORMNAME = 32
+)
+
+const (
+ IDOK = 1
+ IDCANCEL = 2
+ IDABORT = 3
+ IDRETRY = 4
+ IDIGNORE = 5
+ IDYES = 6
+ IDNO = 7
+ IDCLOSE = 8
+ IDHELP = 9
+ IDTRYAGAIN = 10
+ IDCONTINUE = 11
+ IDTIMEOUT = 32000
+)
+
+// Generic WM_NOTIFY notification codes
+const (
+ NM_FIRST = 0
+ NM_OUTOFMEMORY = NM_FIRST - 1
+ NM_CLICK = NM_FIRST - 2
+ NM_DBLCLK = NM_FIRST - 3
+ NM_RETURN = NM_FIRST - 4
+ NM_RCLICK = NM_FIRST - 5
+ NM_RDBLCLK = NM_FIRST - 6
+ NM_SETFOCUS = NM_FIRST - 7
+ NM_KILLFOCUS = NM_FIRST - 8
+ NM_CUSTOMDRAW = NM_FIRST - 12
+ NM_HOVER = NM_FIRST - 13
+ NM_NCHITTEST = NM_FIRST - 14
+ NM_KEYDOWN = NM_FIRST - 15
+ NM_RELEASEDCAPTURE = NM_FIRST - 16
+ NM_SETCURSOR = NM_FIRST - 17
+ NM_CHAR = NM_FIRST - 18
+ NM_TOOLTIPSCREATED = NM_FIRST - 19
+ NM_LAST = NM_FIRST - 99
+)
+
+// ListView messages
+const (
+ LVM_FIRST = 0x1000
+ LVM_GETITEMCOUNT = LVM_FIRST + 4
+ LVM_SETIMAGELIST = LVM_FIRST + 3
+ LVM_GETIMAGELIST = LVM_FIRST + 2
+ LVM_GETITEM = LVM_FIRST + 75
+ LVM_SETITEM = LVM_FIRST + 76
+ LVM_INSERTITEM = LVM_FIRST + 77
+ LVM_DELETEITEM = LVM_FIRST + 8
+ LVM_DELETEALLITEMS = LVM_FIRST + 9
+ LVM_GETCALLBACKMASK = LVM_FIRST + 10
+ LVM_SETCALLBACKMASK = LVM_FIRST + 11
+ LVM_SETUNICODEFORMAT = CCM_SETUNICODEFORMAT
+ LVM_GETNEXTITEM = LVM_FIRST + 12
+ LVM_FINDITEM = LVM_FIRST + 83
+ LVM_GETITEMRECT = LVM_FIRST + 14
+ LVM_GETSTRINGWIDTH = LVM_FIRST + 87
+ LVM_HITTEST = LVM_FIRST + 18
+ LVM_ENSUREVISIBLE = LVM_FIRST + 19
+ LVM_SCROLL = LVM_FIRST + 20
+ LVM_REDRAWITEMS = LVM_FIRST + 21
+ LVM_ARRANGE = LVM_FIRST + 22
+ LVM_EDITLABEL = LVM_FIRST + 118
+ LVM_GETEDITCONTROL = LVM_FIRST + 24
+ LVM_GETCOLUMN = LVM_FIRST + 95
+ LVM_SETCOLUMN = LVM_FIRST + 96
+ LVM_INSERTCOLUMN = LVM_FIRST + 97
+ LVM_DELETECOLUMN = LVM_FIRST + 28
+ LVM_GETCOLUMNWIDTH = LVM_FIRST + 29
+ LVM_SETCOLUMNWIDTH = LVM_FIRST + 30
+ LVM_GETHEADER = LVM_FIRST + 31
+ LVM_CREATEDRAGIMAGE = LVM_FIRST + 33
+ LVM_GETVIEWRECT = LVM_FIRST + 34
+ LVM_GETTEXTCOLOR = LVM_FIRST + 35
+ LVM_SETTEXTCOLOR = LVM_FIRST + 36
+ LVM_GETTEXTBKCOLOR = LVM_FIRST + 37
+ LVM_SETTEXTBKCOLOR = LVM_FIRST + 38
+ LVM_GETTOPINDEX = LVM_FIRST + 39
+ LVM_GETCOUNTPERPAGE = LVM_FIRST + 40
+ LVM_GETORIGIN = LVM_FIRST + 41
+ LVM_UPDATE = LVM_FIRST + 42
+ LVM_SETITEMSTATE = LVM_FIRST + 43
+ LVM_GETITEMSTATE = LVM_FIRST + 44
+ LVM_GETITEMTEXT = LVM_FIRST + 115
+ LVM_SETITEMTEXT = LVM_FIRST + 116
+ LVM_SETITEMCOUNT = LVM_FIRST + 47
+ LVM_SORTITEMS = LVM_FIRST + 48
+ LVM_SETITEMPOSITION32 = LVM_FIRST + 49
+ LVM_GETSELECTEDCOUNT = LVM_FIRST + 50
+ LVM_GETITEMSPACING = LVM_FIRST + 51
+ LVM_GETISEARCHSTRING = LVM_FIRST + 117
+ LVM_SETICONSPACING = LVM_FIRST + 53
+ LVM_SETEXTENDEDLISTVIEWSTYLE = LVM_FIRST + 54
+ LVM_GETEXTENDEDLISTVIEWSTYLE = LVM_FIRST + 55
+ LVM_GETSUBITEMRECT = LVM_FIRST + 56
+ LVM_SUBITEMHITTEST = LVM_FIRST + 57
+ LVM_SETCOLUMNORDERARRAY = LVM_FIRST + 58
+ LVM_GETCOLUMNORDERARRAY = LVM_FIRST + 59
+ LVM_SETHOTITEM = LVM_FIRST + 60
+ LVM_GETHOTITEM = LVM_FIRST + 61
+ LVM_SETHOTCURSOR = LVM_FIRST + 62
+ LVM_GETHOTCURSOR = LVM_FIRST + 63
+ LVM_APPROXIMATEVIEWRECT = LVM_FIRST + 64
+ LVM_SETWORKAREAS = LVM_FIRST + 65
+ LVM_GETWORKAREAS = LVM_FIRST + 70
+ LVM_GETNUMBEROFWORKAREAS = LVM_FIRST + 73
+ LVM_GETSELECTIONMARK = LVM_FIRST + 66
+ LVM_SETSELECTIONMARK = LVM_FIRST + 67
+ LVM_SETHOVERTIME = LVM_FIRST + 71
+ LVM_GETHOVERTIME = LVM_FIRST + 72
+ LVM_SETTOOLTIPS = LVM_FIRST + 74
+ LVM_GETTOOLTIPS = LVM_FIRST + 78
+ LVM_SORTITEMSEX = LVM_FIRST + 81
+ LVM_SETBKIMAGE = LVM_FIRST + 138
+ LVM_GETBKIMAGE = LVM_FIRST + 139
+ LVM_SETSELECTEDCOLUMN = LVM_FIRST + 140
+ LVM_SETVIEW = LVM_FIRST + 142
+ LVM_GETVIEW = LVM_FIRST + 143
+ LVM_INSERTGROUP = LVM_FIRST + 145
+ LVM_SETGROUPINFO = LVM_FIRST + 147
+ LVM_GETGROUPINFO = LVM_FIRST + 149
+ LVM_REMOVEGROUP = LVM_FIRST + 150
+ LVM_MOVEGROUP = LVM_FIRST + 151
+ LVM_GETGROUPCOUNT = LVM_FIRST + 152
+ LVM_GETGROUPINFOBYINDEX = LVM_FIRST + 153
+ LVM_MOVEITEMTOGROUP = LVM_FIRST + 154
+ LVM_GETGROUPRECT = LVM_FIRST + 98
+ LVM_SETGROUPMETRICS = LVM_FIRST + 155
+ LVM_GETGROUPMETRICS = LVM_FIRST + 156
+ LVM_ENABLEGROUPVIEW = LVM_FIRST + 157
+ LVM_SORTGROUPS = LVM_FIRST + 158
+ LVM_INSERTGROUPSORTED = LVM_FIRST + 159
+ LVM_REMOVEALLGROUPS = LVM_FIRST + 160
+ LVM_HASGROUP = LVM_FIRST + 161
+ LVM_GETGROUPSTATE = LVM_FIRST + 92
+ LVM_GETFOCUSEDGROUP = LVM_FIRST + 93
+ LVM_SETTILEVIEWINFO = LVM_FIRST + 162
+ LVM_GETTILEVIEWINFO = LVM_FIRST + 163
+ LVM_SETTILEINFO = LVM_FIRST + 164
+ LVM_GETTILEINFO = LVM_FIRST + 165
+ LVM_SETINSERTMARK = LVM_FIRST + 166
+ LVM_GETINSERTMARK = LVM_FIRST + 167
+ LVM_INSERTMARKHITTEST = LVM_FIRST + 168
+ LVM_GETINSERTMARKRECT = LVM_FIRST + 169
+ LVM_SETINSERTMARKCOLOR = LVM_FIRST + 170
+ LVM_GETINSERTMARKCOLOR = LVM_FIRST + 171
+ LVM_SETINFOTIP = LVM_FIRST + 173
+ LVM_GETSELECTEDCOLUMN = LVM_FIRST + 174
+ LVM_ISGROUPVIEWENABLED = LVM_FIRST + 175
+ LVM_GETOUTLINECOLOR = LVM_FIRST + 176
+ LVM_SETOUTLINECOLOR = LVM_FIRST + 177
+ LVM_CANCELEDITLABEL = LVM_FIRST + 179
+ LVM_MAPINDEXTOID = LVM_FIRST + 180
+ LVM_MAPIDTOINDEX = LVM_FIRST + 181
+ LVM_ISITEMVISIBLE = LVM_FIRST + 182
+ LVM_GETNEXTITEMINDEX = LVM_FIRST + 211
+)
+
+// ListView notifications
+const (
+ LVN_FIRST = -100
+
+ LVN_ITEMCHANGING = LVN_FIRST - 0
+ LVN_ITEMCHANGED = LVN_FIRST - 1
+ LVN_INSERTITEM = LVN_FIRST - 2
+ LVN_DELETEITEM = LVN_FIRST - 3
+ LVN_DELETEALLITEMS = LVN_FIRST - 4
+ LVN_BEGINLABELEDITA = LVN_FIRST - 5
+ LVN_BEGINLABELEDITW = LVN_FIRST - 75
+ LVN_ENDLABELEDITA = LVN_FIRST - 6
+ LVN_ENDLABELEDITW = LVN_FIRST - 76
+ LVN_COLUMNCLICK = LVN_FIRST - 8
+ LVN_BEGINDRAG = LVN_FIRST - 9
+ LVN_BEGINRDRAG = LVN_FIRST - 11
+ LVN_ODCACHEHINT = LVN_FIRST - 13
+ LVN_ODFINDITEMA = LVN_FIRST - 52
+ LVN_ODFINDITEMW = LVN_FIRST - 79
+ LVN_ITEMACTIVATE = LVN_FIRST - 14
+ LVN_ODSTATECHANGED = LVN_FIRST - 15
+ LVN_HOTTRACK = LVN_FIRST - 21
+ LVN_GETDISPINFO = LVN_FIRST - 77
+ LVN_SETDISPINFO = LVN_FIRST - 78
+ LVN_KEYDOWN = LVN_FIRST - 55
+ LVN_MARQUEEBEGIN = LVN_FIRST - 56
+ LVN_GETINFOTIP = LVN_FIRST - 58
+ LVN_INCREMENTALSEARCH = LVN_FIRST - 63
+ LVN_BEGINSCROLL = LVN_FIRST - 80
+ LVN_ENDSCROLL = LVN_FIRST - 81
+)
+
+// ListView LVNI constants
+const (
+ LVNI_ALL = 0
+ LVNI_FOCUSED = 1
+ LVNI_SELECTED = 2
+ LVNI_CUT = 4
+ LVNI_DROPHILITED = 8
+ LVNI_ABOVE = 256
+ LVNI_BELOW = 512
+ LVNI_TOLEFT = 1024
+ LVNI_TORIGHT = 2048
+)
+
+// ListView styles
+const (
+ LVS_ICON = 0x0000
+ LVS_REPORT = 0x0001
+ LVS_SMALLICON = 0x0002
+ LVS_LIST = 0x0003
+ LVS_TYPEMASK = 0x0003
+ LVS_SINGLESEL = 0x0004
+ LVS_SHOWSELALWAYS = 0x0008
+ LVS_SORTASCENDING = 0x0010
+ LVS_SORTDESCENDING = 0x0020
+ LVS_SHAREIMAGELISTS = 0x0040
+ LVS_NOLABELWRAP = 0x0080
+ LVS_AUTOARRANGE = 0x0100
+ LVS_EDITLABELS = 0x0200
+ LVS_OWNERDATA = 0x1000
+ LVS_NOSCROLL = 0x2000
+ LVS_TYPESTYLEMASK = 0xfc00
+ LVS_ALIGNTOP = 0x0000
+ LVS_ALIGNLEFT = 0x0800
+ LVS_ALIGNMASK = 0x0c00
+ LVS_OWNERDRAWFIXED = 0x0400
+ LVS_NOCOLUMNHEADER = 0x4000
+ LVS_NOSORTHEADER = 0x8000
+)
+
+// ListView extended styles
+const (
+ LVS_EX_GRIDLINES = 0x00000001
+ LVS_EX_SUBITEMIMAGES = 0x00000002
+ LVS_EX_CHECKBOXES = 0x00000004
+ LVS_EX_TRACKSELECT = 0x00000008
+ LVS_EX_HEADERDRAGDROP = 0x00000010
+ LVS_EX_FULLROWSELECT = 0x00000020
+ LVS_EX_ONECLICKACTIVATE = 0x00000040
+ LVS_EX_TWOCLICKACTIVATE = 0x00000080
+ LVS_EX_FLATSB = 0x00000100
+ LVS_EX_REGIONAL = 0x00000200
+ LVS_EX_INFOTIP = 0x00000400
+ LVS_EX_UNDERLINEHOT = 0x00000800
+ LVS_EX_UNDERLINECOLD = 0x00001000
+ LVS_EX_MULTIWORKAREAS = 0x00002000
+ LVS_EX_LABELTIP = 0x00004000
+ LVS_EX_BORDERSELECT = 0x00008000
+ LVS_EX_DOUBLEBUFFER = 0x00010000
+ LVS_EX_HIDELABELS = 0x00020000
+ LVS_EX_SINGLEROW = 0x00040000
+ LVS_EX_SNAPTOGRID = 0x00080000
+ LVS_EX_SIMPLESELECT = 0x00100000
+)
+
+// ListView column flags
+const (
+ LVCF_FMT = 0x0001
+ LVCF_WIDTH = 0x0002
+ LVCF_TEXT = 0x0004
+ LVCF_SUBITEM = 0x0008
+ LVCF_IMAGE = 0x0010
+ LVCF_ORDER = 0x0020
+)
+
+// ListView column format constants
+const (
+ LVCFMT_LEFT = 0x0000
+ LVCFMT_RIGHT = 0x0001
+ LVCFMT_CENTER = 0x0002
+ LVCFMT_JUSTIFYMASK = 0x0003
+ LVCFMT_IMAGE = 0x0800
+ LVCFMT_BITMAP_ON_RIGHT = 0x1000
+ LVCFMT_COL_HAS_IMAGES = 0x8000
+)
+
+// ListView item flags
+const (
+ LVIF_TEXT = 0x00000001
+ LVIF_IMAGE = 0x00000002
+ LVIF_PARAM = 0x00000004
+ LVIF_STATE = 0x00000008
+ LVIF_INDENT = 0x00000010
+ LVIF_NORECOMPUTE = 0x00000800
+ LVIF_GROUPID = 0x00000100
+ LVIF_COLUMNS = 0x00000200
+)
+
+// ListView item states
+const (
+ LVIS_FOCUSED = 1
+ LVIS_SELECTED = 2
+ LVIS_CUT = 4
+ LVIS_DROPHILITED = 8
+ LVIS_OVERLAYMASK = 0xF00
+ LVIS_STATEIMAGEMASK = 0xF000
+)
+
+// ListView hit test constants
+const (
+ LVHT_NOWHERE = 0x00000001
+ LVHT_ONITEMICON = 0x00000002
+ LVHT_ONITEMLABEL = 0x00000004
+ LVHT_ONITEMSTATEICON = 0x00000008
+ LVHT_ONITEM = LVHT_ONITEMICON | LVHT_ONITEMLABEL | LVHT_ONITEMSTATEICON
+
+ LVHT_ABOVE = 0x00000008
+ LVHT_BELOW = 0x00000010
+ LVHT_TORIGHT = 0x00000020
+ LVHT_TOLEFT = 0x00000040
+)
+
+// ListView image list types
+const (
+ LVSIL_NORMAL = 0
+ LVSIL_SMALL = 1
+ LVSIL_STATE = 2
+ LVSIL_GROUPHEADER = 3
+)
+
+// InitCommonControlsEx flags
+const (
+ ICC_LISTVIEW_CLASSES = 1
+ ICC_TREEVIEW_CLASSES = 2
+ ICC_BAR_CLASSES = 4
+ ICC_TAB_CLASSES = 8
+ ICC_UPDOWN_CLASS = 16
+ ICC_PROGRESS_CLASS = 32
+ ICC_HOTKEY_CLASS = 64
+ ICC_ANIMATE_CLASS = 128
+ ICC_WIN95_CLASSES = 255
+ ICC_DATE_CLASSES = 256
+ ICC_USEREX_CLASSES = 512
+ ICC_COOL_CLASSES = 1024
+ ICC_INTERNET_CLASSES = 2048
+ ICC_PAGESCROLLER_CLASS = 4096
+ ICC_NATIVEFNTCTL_CLASS = 8192
+ INFOTIPSIZE = 1024
+ ICC_STANDARD_CLASSES = 0x00004000
+ ICC_LINK_CLASS = 0x00008000
+)
+
+// Dialog Codes
+const (
+ DLGC_WANTARROWS = 0x0001
+ DLGC_WANTTAB = 0x0002
+ DLGC_WANTALLKEYS = 0x0004
+ DLGC_WANTMESSAGE = 0x0004
+ DLGC_HASSETSEL = 0x0008
+ DLGC_DEFPUSHBUTTON = 0x0010
+ DLGC_UNDEFPUSHBUTTON = 0x0020
+ DLGC_RADIOBUTTON = 0x0040
+ DLGC_WANTCHARS = 0x0080
+ DLGC_STATIC = 0x0100
+ DLGC_BUTTON = 0x2000
+)
+
+// Get/SetWindowWord/Long offsets for use with WC_DIALOG windows
+const (
+ DWL_MSGRESULT = 0
+ DWL_DLGPROC = 4
+ DWL_USER = 8
+)
+
+// Registry predefined keys
+const (
+ HKEY_CLASSES_ROOT HKEY = 0x80000000
+ HKEY_CURRENT_USER HKEY = 0x80000001
+ HKEY_LOCAL_MACHINE HKEY = 0x80000002
+ HKEY_USERS HKEY = 0x80000003
+ HKEY_PERFORMANCE_DATA HKEY = 0x80000004
+ HKEY_CURRENT_CONFIG HKEY = 0x80000005
+ HKEY_DYN_DATA HKEY = 0x80000006
+)
+
+// Registry Key Security and Access Rights
+const (
+ KEY_ALL_ACCESS = 0xF003F
+ KEY_CREATE_SUB_KEY = 0x0004
+ KEY_ENUMERATE_SUB_KEYS = 0x0008
+ KEY_NOTIFY = 0x0010
+ KEY_QUERY_VALUE = 0x0001
+ KEY_SET_VALUE = 0x0002
+ KEY_READ = 0x20019
+ KEY_WRITE = 0x20006
+)
+
+const (
+ NFR_ANSI = 1
+ NFR_UNICODE = 2
+ NF_QUERY = 3
+ NF_REQUERY = 4
+)
+
+// Registry value types
+const (
+ RRF_RT_REG_NONE = 0x00000001
+ RRF_RT_REG_SZ = 0x00000002
+ RRF_RT_REG_EXPAND_SZ = 0x00000004
+ RRF_RT_REG_BINARY = 0x00000008
+ RRF_RT_REG_DWORD = 0x00000010
+ RRF_RT_REG_MULTI_SZ = 0x00000020
+ RRF_RT_REG_QWORD = 0x00000040
+ RRF_RT_DWORD = (RRF_RT_REG_BINARY | RRF_RT_REG_DWORD)
+ RRF_RT_QWORD = (RRF_RT_REG_BINARY | RRF_RT_REG_QWORD)
+ RRF_RT_ANY = 0x0000ffff
+ RRF_NOEXPAND = 0x10000000
+ RRF_ZEROONFAILURE = 0x20000000
+ REG_PROCESS_APPKEY = 0x00000001
+ REG_MUI_STRING_TRUNCATE = 0x00000001
+)
+
+// PeekMessage wRemoveMsg value
+const (
+ PM_NOREMOVE = 0x000
+ PM_REMOVE = 0x001
+ PM_NOYIELD = 0x002
+)
+
+// ImageList flags
+const (
+ ILC_MASK = 0x00000001
+ ILC_COLOR = 0x00000000
+ ILC_COLORDDB = 0x000000FE
+ ILC_COLOR4 = 0x00000004
+ ILC_COLOR8 = 0x00000008
+ ILC_COLOR16 = 0x00000010
+ ILC_COLOR24 = 0x00000018
+ ILC_COLOR32 = 0x00000020
+ ILC_PALETTE = 0x00000800
+ ILC_MIRROR = 0x00002000
+ ILC_PERITEMMIRROR = 0x00008000
+ ILC_ORIGINALSIZE = 0x00010000
+ ILC_HIGHQUALITYSCALE = 0x00020000
+)
+
+// Keystroke Message Flags
+const (
+ KF_EXTENDED = 0x0100
+ KF_DLGMODE = 0x0800
+ KF_MENUMODE = 0x1000
+ KF_ALTDOWN = 0x2000
+ KF_REPEAT = 0x4000
+ KF_UP = 0x8000
+)
+
+// Virtual-Key Codes
+const (
+ VK_LBUTTON = 0x01
+ VK_RBUTTON = 0x02
+ VK_CANCEL = 0x03
+ VK_MBUTTON = 0x04
+ VK_XBUTTON1 = 0x05
+ VK_XBUTTON2 = 0x06
+ VK_BACK = 0x08
+ VK_TAB = 0x09
+ VK_CLEAR = 0x0C
+ VK_RETURN = 0x0D
+ VK_SHIFT = 0x10
+ VK_CONTROL = 0x11
+ VK_MENU = 0x12
+ VK_PAUSE = 0x13
+ VK_CAPITAL = 0x14
+ VK_KANA = 0x15
+ VK_HANGEUL = 0x15
+ VK_HANGUL = 0x15
+ VK_JUNJA = 0x17
+ VK_FINAL = 0x18
+ VK_HANJA = 0x19
+ VK_KANJI = 0x19
+ VK_ESCAPE = 0x1B
+ VK_CONVERT = 0x1C
+ VK_NONCONVERT = 0x1D
+ VK_ACCEPT = 0x1E
+ VK_MODECHANGE = 0x1F
+ VK_SPACE = 0x20
+ VK_PRIOR = 0x21
+ VK_NEXT = 0x22
+ VK_END = 0x23
+ VK_HOME = 0x24
+ VK_LEFT = 0x25
+ VK_UP = 0x26
+ VK_RIGHT = 0x27
+ VK_DOWN = 0x28
+ VK_SELECT = 0x29
+ VK_PRINT = 0x2A
+ VK_EXECUTE = 0x2B
+ VK_SNAPSHOT = 0x2C
+ VK_INSERT = 0x2D
+ VK_DELETE = 0x2E
+ VK_HELP = 0x2F
+ VK_LWIN = 0x5B
+ VK_RWIN = 0x5C
+ VK_APPS = 0x5D
+ VK_SLEEP = 0x5F
+ VK_NUMPAD0 = 0x60
+ VK_NUMPAD1 = 0x61
+ VK_NUMPAD2 = 0x62
+ VK_NUMPAD3 = 0x63
+ VK_NUMPAD4 = 0x64
+ VK_NUMPAD5 = 0x65
+ VK_NUMPAD6 = 0x66
+ VK_NUMPAD7 = 0x67
+ VK_NUMPAD8 = 0x68
+ VK_NUMPAD9 = 0x69
+ VK_MULTIPLY = 0x6A
+ VK_ADD = 0x6B
+ VK_SEPARATOR = 0x6C
+ VK_SUBTRACT = 0x6D
+ VK_DECIMAL = 0x6E
+ VK_DIVIDE = 0x6F
+ VK_F1 = 0x70
+ VK_F2 = 0x71
+ VK_F3 = 0x72
+ VK_F4 = 0x73
+ VK_F5 = 0x74
+ VK_F6 = 0x75
+ VK_F7 = 0x76
+ VK_F8 = 0x77
+ VK_F9 = 0x78
+ VK_F10 = 0x79
+ VK_F11 = 0x7A
+ VK_F12 = 0x7B
+ VK_F13 = 0x7C
+ VK_F14 = 0x7D
+ VK_F15 = 0x7E
+ VK_F16 = 0x7F
+ VK_F17 = 0x80
+ VK_F18 = 0x81
+ VK_F19 = 0x82
+ VK_F20 = 0x83
+ VK_F21 = 0x84
+ VK_F22 = 0x85
+ VK_F23 = 0x86
+ VK_F24 = 0x87
+ VK_NUMLOCK = 0x90
+ VK_SCROLL = 0x91
+ VK_OEM_NEC_EQUAL = 0x92
+ VK_OEM_FJ_JISHO = 0x92
+ VK_OEM_FJ_MASSHOU = 0x93
+ VK_OEM_FJ_TOUROKU = 0x94
+ VK_OEM_FJ_LOYA = 0x95
+ VK_OEM_FJ_ROYA = 0x96
+ VK_LSHIFT = 0xA0
+ VK_RSHIFT = 0xA1
+ VK_LCONTROL = 0xA2
+ VK_RCONTROL = 0xA3
+ VK_LMENU = 0xA4
+ VK_RMENU = 0xA5
+ VK_BROWSER_BACK = 0xA6
+ VK_BROWSER_FORWARD = 0xA7
+ VK_BROWSER_REFRESH = 0xA8
+ VK_BROWSER_STOP = 0xA9
+ VK_BROWSER_SEARCH = 0xAA
+ VK_BROWSER_FAVORITES = 0xAB
+ VK_BROWSER_HOME = 0xAC
+ VK_VOLUME_MUTE = 0xAD
+ VK_VOLUME_DOWN = 0xAE
+ VK_VOLUME_UP = 0xAF
+ VK_MEDIA_NEXT_TRACK = 0xB0
+ VK_MEDIA_PREV_TRACK = 0xB1
+ VK_MEDIA_STOP = 0xB2
+ VK_MEDIA_PLAY_PAUSE = 0xB3
+ VK_LAUNCH_MAIL = 0xB4
+ VK_LAUNCH_MEDIA_SELECT = 0xB5
+ VK_LAUNCH_APP1 = 0xB6
+ VK_LAUNCH_APP2 = 0xB7
+ VK_OEM_1 = 0xBA
+ VK_OEM_PLUS = 0xBB
+ VK_OEM_COMMA = 0xBC
+ VK_OEM_MINUS = 0xBD
+ VK_OEM_PERIOD = 0xBE
+ VK_OEM_2 = 0xBF
+ VK_OEM_3 = 0xC0
+ VK_OEM_4 = 0xDB
+ VK_OEM_5 = 0xDC
+ VK_OEM_6 = 0xDD
+ VK_OEM_7 = 0xDE
+ VK_OEM_8 = 0xDF
+ VK_OEM_AX = 0xE1
+ VK_OEM_102 = 0xE2
+ VK_ICO_HELP = 0xE3
+ VK_ICO_00 = 0xE4
+ VK_PROCESSKEY = 0xE5
+ VK_ICO_CLEAR = 0xE6
+ VK_OEM_RESET = 0xE9
+ VK_OEM_JUMP = 0xEA
+ VK_OEM_PA1 = 0xEB
+ VK_OEM_PA2 = 0xEC
+ VK_OEM_PA3 = 0xED
+ VK_OEM_WSCTRL = 0xEE
+ VK_OEM_CUSEL = 0xEF
+ VK_OEM_ATTN = 0xF0
+ VK_OEM_FINISH = 0xF1
+ VK_OEM_COPY = 0xF2
+ VK_OEM_AUTO = 0xF3
+ VK_OEM_ENLW = 0xF4
+ VK_OEM_BACKTAB = 0xF5
+ VK_ATTN = 0xF6
+ VK_CRSEL = 0xF7
+ VK_EXSEL = 0xF8
+ VK_EREOF = 0xF9
+ VK_PLAY = 0xFA
+ VK_ZOOM = 0xFB
+ VK_NONAME = 0xFC
+ VK_PA1 = 0xFD
+ VK_OEM_CLEAR = 0xFE
+)
+
+// Registry Value Types
+const (
+ REG_NONE = 0
+ REG_SZ = 1
+ REG_EXPAND_SZ = 2
+ REG_BINARY = 3
+ REG_DWORD = 4
+ REG_DWORD_LITTLE_ENDIAN = 4
+ REG_DWORD_BIG_ENDIAN = 5
+ REG_LINK = 6
+ REG_MULTI_SZ = 7
+ REG_RESOURCE_LIST = 8
+ REG_FULL_RESOURCE_DESCRIPTOR = 9
+ REG_RESOURCE_REQUIREMENTS_LIST = 10
+ REG_QWORD = 11
+ REG_QWORD_LITTLE_ENDIAN = 11
+)
+
+// Tooltip styles
+const (
+ TTS_ALWAYSTIP = 0x01
+ TTS_NOPREFIX = 0x02
+ TTS_NOANIMATE = 0x10
+ TTS_NOFADE = 0x20
+ TTS_BALLOON = 0x40
+ TTS_CLOSE = 0x80
+ TTS_USEVISUALSTYLE = 0x100
+)
+
+// Tooltip messages
+const (
+ TTM_ACTIVATE = (WM_USER + 1)
+ TTM_SETDELAYTIME = (WM_USER + 3)
+ TTM_ADDTOOL = (WM_USER + 50)
+ TTM_DELTOOL = (WM_USER + 51)
+ TTM_NEWTOOLRECT = (WM_USER + 52)
+ TTM_RELAYEVENT = (WM_USER + 7)
+ TTM_GETTOOLINFO = (WM_USER + 53)
+ TTM_SETTOOLINFO = (WM_USER + 54)
+ TTM_HITTEST = (WM_USER + 55)
+ TTM_GETTEXT = (WM_USER + 56)
+ TTM_UPDATETIPTEXT = (WM_USER + 57)
+ TTM_GETTOOLCOUNT = (WM_USER + 13)
+ TTM_ENUMTOOLS = (WM_USER + 58)
+ TTM_GETCURRENTTOOL = (WM_USER + 59)
+ TTM_WINDOWFROMPOINT = (WM_USER + 16)
+ TTM_TRACKACTIVATE = (WM_USER + 17)
+ TTM_TRACKPOSITION = (WM_USER + 18)
+ TTM_SETTIPBKCOLOR = (WM_USER + 19)
+ TTM_SETTIPTEXTCOLOR = (WM_USER + 20)
+ TTM_GETDELAYTIME = (WM_USER + 21)
+ TTM_GETTIPBKCOLOR = (WM_USER + 22)
+ TTM_GETTIPTEXTCOLOR = (WM_USER + 23)
+ TTM_SETMAXTIPWIDTH = (WM_USER + 24)
+ TTM_GETMAXTIPWIDTH = (WM_USER + 25)
+ TTM_SETMARGIN = (WM_USER + 26)
+ TTM_GETMARGIN = (WM_USER + 27)
+ TTM_POP = (WM_USER + 28)
+ TTM_UPDATE = (WM_USER + 29)
+ TTM_GETBUBBLESIZE = (WM_USER + 30)
+ TTM_ADJUSTRECT = (WM_USER + 31)
+ TTM_SETTITLE = (WM_USER + 33)
+ TTM_POPUP = (WM_USER + 34)
+ TTM_GETTITLE = (WM_USER + 35)
+)
+
+// Tooltip icons
+const (
+ TTI_NONE = 0
+ TTI_INFO = 1
+ TTI_WARNING = 2
+ TTI_ERROR = 3
+ TTI_INFO_LARGE = 4
+ TTI_WARNING_LARGE = 5
+ TTI_ERROR_LARGE = 6
+)
+
+// Tooltip notifications
+const (
+ TTN_FIRST = -520
+ TTN_LAST = -549
+ TTN_GETDISPINFO = (TTN_FIRST - 10)
+ TTN_SHOW = (TTN_FIRST - 1)
+ TTN_POP = (TTN_FIRST - 2)
+ TTN_LINKCLICK = (TTN_FIRST - 3)
+ TTN_NEEDTEXT = TTN_GETDISPINFO
+)
+
+const (
+ TTF_IDISHWND = 0x0001
+ TTF_CENTERTIP = 0x0002
+ TTF_RTLREADING = 0x0004
+ TTF_SUBCLASS = 0x0010
+ TTF_TRACK = 0x0020
+ TTF_ABSOLUTE = 0x0080
+ TTF_TRANSPARENT = 0x0100
+ TTF_PARSELINKS = 0x1000
+ TTF_DI_SETITEM = 0x8000
+)
+
+const (
+ SWP_NOSIZE = 0x0001
+ SWP_NOMOVE = 0x0002
+ SWP_NOZORDER = 0x0004
+ SWP_NOREDRAW = 0x0008
+ SWP_NOACTIVATE = 0x0010
+ SWP_FRAMECHANGED = 0x0020
+ SWP_SHOWWINDOW = 0x0040
+ SWP_HIDEWINDOW = 0x0080
+ SWP_NOCOPYBITS = 0x0100
+ SWP_NOOWNERZORDER = 0x0200
+ SWP_NOSENDCHANGING = 0x0400
+ SWP_DRAWFRAME = SWP_FRAMECHANGED
+ SWP_NOREPOSITION = SWP_NOOWNERZORDER
+ SWP_DEFERERASE = 0x2000
+ SWP_ASYNCWINDOWPOS = 0x4000
+)
+
+// Predefined window handles
+const (
+ HWND_BROADCAST = HWND(0xFFFF)
+ HWND_BOTTOM = HWND(1)
+ HWND_NOTOPMOST = ^HWND(1) // -2
+ HWND_TOP = HWND(0)
+ HWND_TOPMOST = ^HWND(0) // -1
+ HWND_DESKTOP = HWND(0)
+ HWND_MESSAGE = ^HWND(2) // -3
+)
+
+// Pen types
+const (
+ PS_COSMETIC = 0x00000000
+ PS_GEOMETRIC = 0x00010000
+ PS_TYPE_MASK = 0x000F0000
+)
+
+// Pen styles
+const (
+ PS_SOLID = 0
+ PS_DASH = 1
+ PS_DOT = 2
+ PS_DASHDOT = 3
+ PS_DASHDOTDOT = 4
+ PS_NULL = 5
+ PS_INSIDEFRAME = 6
+ PS_USERSTYLE = 7
+ PS_ALTERNATE = 8
+ PS_STYLE_MASK = 0x0000000F
+)
+
+// Pen cap types
+const (
+ PS_ENDCAP_ROUND = 0x00000000
+ PS_ENDCAP_SQUARE = 0x00000100
+ PS_ENDCAP_FLAT = 0x00000200
+ PS_ENDCAP_MASK = 0x00000F00
+)
+
+// Pen join types
+const (
+ PS_JOIN_ROUND = 0x00000000
+ PS_JOIN_BEVEL = 0x00001000
+ PS_JOIN_MITER = 0x00002000
+ PS_JOIN_MASK = 0x0000F000
+)
+
+// Hatch styles
+const (
+ HS_HORIZONTAL = 0
+ HS_VERTICAL = 1
+ HS_FDIAGONAL = 2
+ HS_BDIAGONAL = 3
+ HS_CROSS = 4
+ HS_DIAGCROSS = 5
+)
+
+// Stock Logical Objects
+const (
+ WHITE_BRUSH = 0
+ LTGRAY_BRUSH = 1
+ GRAY_BRUSH = 2
+ DKGRAY_BRUSH = 3
+ BLACK_BRUSH = 4
+ NULL_BRUSH = 5
+ HOLLOW_BRUSH = NULL_BRUSH
+ WHITE_PEN = 6
+ BLACK_PEN = 7
+ NULL_PEN = 8
+ OEM_FIXED_FONT = 10
+ ANSI_FIXED_FONT = 11
+ ANSI_VAR_FONT = 12
+ SYSTEM_FONT = 13
+ DEVICE_DEFAULT_FONT = 14
+ DEFAULT_PALETTE = 15
+ SYSTEM_FIXED_FONT = 16
+ DEFAULT_GUI_FONT = 17
+ DC_BRUSH = 18
+ DC_PEN = 19
+)
+
+// Brush styles
+const (
+ BS_SOLID = 0
+ BS_NULL = 1
+ BS_HOLLOW = BS_NULL
+ BS_HATCHED = 2
+ BS_PATTERN = 3
+ BS_INDEXED = 4
+ BS_DIBPATTERN = 5
+ BS_DIBPATTERNPT = 6
+ BS_PATTERN8X8 = 7
+ BS_DIBPATTERN8X8 = 8
+ BS_MONOPATTERN = 9
+)
+
+// TRACKMOUSEEVENT flags
+const (
+ TME_HOVER = 0x00000001
+ TME_LEAVE = 0x00000002
+ TME_NONCLIENT = 0x00000010
+ TME_QUERY = 0x40000000
+ TME_CANCEL = 0x80000000
+
+ HOVER_DEFAULT = 0xFFFFFFFF
+)
+
+// WM_NCHITTEST and MOUSEHOOKSTRUCT Mouse Position Codes
+const (
+ HTERROR = (-2)
+ HTTRANSPARENT = (-1)
+ HTNOWHERE = 0
+ HTCLIENT = 1
+ HTCAPTION = 2
+ HTSYSMENU = 3
+ HTGROWBOX = 4
+ HTSIZE = HTGROWBOX
+ HTMENU = 5
+ HTHSCROLL = 6
+ HTVSCROLL = 7
+ HTMINBUTTON = 8
+ HTMAXBUTTON = 9
+ HTLEFT = 10
+ HTRIGHT = 11
+ HTTOP = 12
+ HTTOPLEFT = 13
+ HTTOPRIGHT = 14
+ HTBOTTOM = 15
+ HTBOTTOMLEFT = 16
+ HTBOTTOMRIGHT = 17
+ HTBORDER = 18
+ HTREDUCE = HTMINBUTTON
+ HTZOOM = HTMAXBUTTON
+ HTSIZEFIRST = HTLEFT
+ HTSIZELAST = HTBOTTOMRIGHT
+ HTOBJECT = 19
+ HTCLOSE = 20
+ HTHELP = 21
+)
+
+// DrawText[Ex] format flags
+const (
+ DT_TOP = 0x00000000
+ DT_LEFT = 0x00000000
+ DT_CENTER = 0x00000001
+ DT_RIGHT = 0x00000002
+ DT_VCENTER = 0x00000004
+ DT_BOTTOM = 0x00000008
+ DT_WORDBREAK = 0x00000010
+ DT_SINGLELINE = 0x00000020
+ DT_EXPANDTABS = 0x00000040
+ DT_TABSTOP = 0x00000080
+ DT_NOCLIP = 0x00000100
+ DT_EXTERNALLEADING = 0x00000200
+ DT_CALCRECT = 0x00000400
+ DT_NOPREFIX = 0x00000800
+ DT_INTERNAL = 0x00001000
+ DT_EDITCONTROL = 0x00002000
+ DT_PATH_ELLIPSIS = 0x00004000
+ DT_END_ELLIPSIS = 0x00008000
+ DT_MODIFYSTRING = 0x00010000
+ DT_RTLREADING = 0x00020000
+ DT_WORD_ELLIPSIS = 0x00040000
+ DT_NOFULLWIDTHCHARBREAK = 0x00080000
+ DT_HIDEPREFIX = 0x00100000
+ DT_PREFIXONLY = 0x00200000
+)
+
+const CLR_INVALID = 0xFFFFFFFF
+
+// Background Modes
+const (
+ TRANSPARENT = 1
+ OPAQUE = 2
+ BKMODE_LAST = 2
+)
+
+// Global Memory Flags
+const (
+ GMEM_FIXED = 0x0000
+ GMEM_MOVEABLE = 0x0002
+ GMEM_NOCOMPACT = 0x0010
+ GMEM_NODISCARD = 0x0020
+ GMEM_ZEROINIT = 0x0040
+ GMEM_MODIFY = 0x0080
+ GMEM_DISCARDABLE = 0x0100
+ GMEM_NOT_BANKED = 0x1000
+ GMEM_SHARE = 0x2000
+ GMEM_DDESHARE = 0x2000
+ GMEM_NOTIFY = 0x4000
+ GMEM_LOWER = GMEM_NOT_BANKED
+ GMEM_VALID_FLAGS = 0x7F72
+ GMEM_INVALID_HANDLE = 0x8000
+ GHND = (GMEM_MOVEABLE | GMEM_ZEROINIT)
+ GPTR = (GMEM_FIXED | GMEM_ZEROINIT)
+)
+
+// Ternary raster operations
+const (
+ SRCCOPY = 0x00CC0020
+ SRCPAINT = 0x00EE0086
+ SRCAND = 0x008800C6
+ SRCINVERT = 0x00660046
+ SRCERASE = 0x00440328
+ NOTSRCCOPY = 0x00330008
+ NOTSRCERASE = 0x001100A6
+ MERGECOPY = 0x00C000CA
+ MERGEPAINT = 0x00BB0226
+ PATCOPY = 0x00F00021
+ PATPAINT = 0x00FB0A09
+ PATINVERT = 0x005A0049
+ DSTINVERT = 0x00550009
+ BLACKNESS = 0x00000042
+ WHITENESS = 0x00FF0062
+ NOMIRRORBITMAP = 0x80000000
+ CAPTUREBLT = 0x40000000
+)
+
+// Clipboard formats
+const (
+ CF_TEXT = 1
+ CF_BITMAP = 2
+ CF_METAFILEPICT = 3
+ CF_SYLK = 4
+ CF_DIF = 5
+ CF_TIFF = 6
+ CF_OEMTEXT = 7
+ CF_DIB = 8
+ CF_PALETTE = 9
+ CF_PENDATA = 10
+ CF_RIFF = 11
+ CF_WAVE = 12
+ CF_UNICODETEXT = 13
+ CF_ENHMETAFILE = 14
+ CF_HDROP = 15
+ CF_LOCALE = 16
+ CF_DIBV5 = 17
+ CF_MAX = 18
+ CF_OWNERDISPLAY = 0x0080
+ CF_DSPTEXT = 0x0081
+ CF_DSPBITMAP = 0x0082
+ CF_DSPMETAFILEPICT = 0x0083
+ CF_DSPENHMETAFILE = 0x008E
+ CF_PRIVATEFIRST = 0x0200
+ CF_PRIVATELAST = 0x02FF
+ CF_GDIOBJFIRST = 0x0300
+ CF_GDIOBJLAST = 0x03FF
+)
+
+// Bitmap compression formats
+const (
+ BI_RGB = 0
+ BI_RLE8 = 1
+ BI_RLE4 = 2
+ BI_BITFIELDS = 3
+ BI_JPEG = 4
+ BI_PNG = 5
+)
+
+// SetDIBitsToDevice fuColorUse
+const (
+ DIB_PAL_COLORS = 1
+ DIB_RGB_COLORS = 0
+)
+
+const (
+ STANDARD_RIGHTS_REQUIRED = 0x000F
+)
+
+// Service Control Manager object specific access types
+const (
+ SC_MANAGER_CONNECT = 0x0001
+ SC_MANAGER_CREATE_SERVICE = 0x0002
+ SC_MANAGER_ENUMERATE_SERVICE = 0x0004
+ SC_MANAGER_LOCK = 0x0008
+ SC_MANAGER_QUERY_LOCK_STATUS = 0x0010
+ SC_MANAGER_MODIFY_BOOT_CONFIG = 0x0020
+ SC_MANAGER_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED | SC_MANAGER_CONNECT | SC_MANAGER_CREATE_SERVICE | SC_MANAGER_ENUMERATE_SERVICE | SC_MANAGER_LOCK | SC_MANAGER_QUERY_LOCK_STATUS | SC_MANAGER_MODIFY_BOOT_CONFIG
+)
+
+// Service Types (Bit Mask)
+const (
+ SERVICE_KERNEL_DRIVER = 0x00000001
+ SERVICE_FILE_SYSTEM_DRIVER = 0x00000002
+ SERVICE_ADAPTER = 0x00000004
+ SERVICE_RECOGNIZER_DRIVER = 0x00000008
+ SERVICE_DRIVER = SERVICE_KERNEL_DRIVER | SERVICE_FILE_SYSTEM_DRIVER | SERVICE_RECOGNIZER_DRIVER
+ SERVICE_WIN32_OWN_PROCESS = 0x00000010
+ SERVICE_WIN32_SHARE_PROCESS = 0x00000020
+ SERVICE_WIN32 = SERVICE_WIN32_OWN_PROCESS | SERVICE_WIN32_SHARE_PROCESS
+ SERVICE_INTERACTIVE_PROCESS = 0x00000100
+ SERVICE_TYPE_ALL = SERVICE_WIN32 | SERVICE_ADAPTER | SERVICE_DRIVER | SERVICE_INTERACTIVE_PROCESS
+)
+
+// Service State -- for CurrentState
+const (
+ SERVICE_STOPPED = 0x00000001
+ SERVICE_START_PENDING = 0x00000002
+ SERVICE_STOP_PENDING = 0x00000003
+ SERVICE_RUNNING = 0x00000004
+ SERVICE_CONTINUE_PENDING = 0x00000005
+ SERVICE_PAUSE_PENDING = 0x00000006
+ SERVICE_PAUSED = 0x00000007
+)
+
+// Controls Accepted (Bit Mask)
+const (
+ SERVICE_ACCEPT_STOP = 0x00000001
+ SERVICE_ACCEPT_PAUSE_CONTINUE = 0x00000002
+ SERVICE_ACCEPT_SHUTDOWN = 0x00000004
+ SERVICE_ACCEPT_PARAMCHANGE = 0x00000008
+ SERVICE_ACCEPT_NETBINDCHANGE = 0x00000010
+ SERVICE_ACCEPT_HARDWAREPROFILECHANGE = 0x00000020
+ SERVICE_ACCEPT_POWEREVENT = 0x00000040
+ SERVICE_ACCEPT_SESSIONCHANGE = 0x00000080
+ SERVICE_ACCEPT_PRESHUTDOWN = 0x00000100
+ SERVICE_ACCEPT_TIMECHANGE = 0x00000200
+ SERVICE_ACCEPT_TRIGGEREVENT = 0x00000400
+)
+
+// Service object specific access type
+const (
+ SERVICE_QUERY_CONFIG = 0x0001
+ SERVICE_CHANGE_CONFIG = 0x0002
+ SERVICE_QUERY_STATUS = 0x0004
+ SERVICE_ENUMERATE_DEPENDENTS = 0x0008
+ SERVICE_START = 0x0010
+ SERVICE_STOP = 0x0020
+ SERVICE_PAUSE_CONTINUE = 0x0040
+ SERVICE_INTERROGATE = 0x0080
+ SERVICE_USER_DEFINED_CONTROL = 0x0100
+
+ SERVICE_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED |
+ SERVICE_QUERY_CONFIG |
+ SERVICE_CHANGE_CONFIG |
+ SERVICE_QUERY_STATUS |
+ SERVICE_ENUMERATE_DEPENDENTS |
+ SERVICE_START |
+ SERVICE_STOP |
+ SERVICE_PAUSE_CONTINUE |
+ SERVICE_INTERROGATE |
+ SERVICE_USER_DEFINED_CONTROL
+)
+
+// MapVirtualKey maptypes
+const (
+ MAPVK_VK_TO_CHAR = 2
+ MAPVK_VK_TO_VSC = 0
+ MAPVK_VSC_TO_VK = 1
+ MAPVK_VSC_TO_VK_EX = 3
+)
+
+// ReadEventLog Flags
+const (
+ EVENTLOG_SEEK_READ = 0x0002
+ EVENTLOG_SEQUENTIAL_READ = 0x0001
+ EVENTLOG_FORWARDS_READ = 0x0004
+ EVENTLOG_BACKWARDS_READ = 0x0008
+)
+
+// CreateToolhelp32Snapshot flags
+const (
+ TH32CS_SNAPHEAPLIST = 0x00000001
+ TH32CS_SNAPPROCESS = 0x00000002
+ TH32CS_SNAPTHREAD = 0x00000004
+ TH32CS_SNAPMODULE = 0x00000008
+ TH32CS_SNAPMODULE32 = 0x00000010
+ TH32CS_INHERIT = 0x80000000
+ TH32CS_SNAPALL = TH32CS_SNAPHEAPLIST | TH32CS_SNAPMODULE | TH32CS_SNAPPROCESS | TH32CS_SNAPTHREAD
+)
+
+const (
+ MAX_MODULE_NAME32 = 255
+ MAX_PATH = 260
+)
+
+const (
+ FOREGROUND_BLUE = 0x0001
+ FOREGROUND_GREEN = 0x0002
+ FOREGROUND_RED = 0x0004
+ FOREGROUND_INTENSITY = 0x0008
+ BACKGROUND_BLUE = 0x0010
+ BACKGROUND_GREEN = 0x0020
+ BACKGROUND_RED = 0x0040
+ BACKGROUND_INTENSITY = 0x0080
+ COMMON_LVB_LEADING_BYTE = 0x0100
+ COMMON_LVB_TRAILING_BYTE = 0x0200
+ COMMON_LVB_GRID_HORIZONTAL = 0x0400
+ COMMON_LVB_GRID_LVERTICAL = 0x0800
+ COMMON_LVB_GRID_RVERTICAL = 0x1000
+ COMMON_LVB_REVERSE_VIDEO = 0x4000
+ COMMON_LVB_UNDERSCORE = 0x8000
+)
+
+// Flags used by the DWM_BLURBEHIND structure to indicate
+// which of its members contain valid information.
+const (
+ DWM_BB_ENABLE = 0x00000001 // A value for the fEnable member has been specified.
+ DWM_BB_BLURREGION = 0x00000002 // A value for the hRgnBlur member has been specified.
+ DWM_BB_TRANSITIONONMAXIMIZED = 0x00000004 // A value for the fTransitionOnMaximized member has been specified.
+)
+
+// Flags used by the DwmEnableComposition function
+// to change the state of Desktop Window Manager (DWM) composition.
+const (
+ DWM_EC_DISABLECOMPOSITION = 0 // Disable composition
+ DWM_EC_ENABLECOMPOSITION = 1 // Enable composition
+)
+
+// enum-lite implementation for the following constant structure
+type DWM_SHOWCONTACT int32
+
+const (
+ DWMSC_DOWN = 0x00000001
+ DWMSC_UP = 0x00000002
+ DWMSC_DRAG = 0x00000004
+ DWMSC_HOLD = 0x00000008
+ DWMSC_PENBARREL = 0x00000010
+ DWMSC_NONE = 0x00000000
+ DWMSC_ALL = 0xFFFFFFFF
+)
+
+// enum-lite implementation for the following constant structure
+type DWM_SOURCE_FRAME_SAMPLING int32
+
+// TODO: need to verify this construction
+// Flags used by the DwmSetPresentParameters function
+// to specify the frame sampling type
+const (
+ DWM_SOURCE_FRAME_SAMPLING_POINT = iota + 1
+ DWM_SOURCE_FRAME_SAMPLING_COVERAGE
+ DWM_SOURCE_FRAME_SAMPLING_LAST
+)
+
+// Flags used by the DWM_THUMBNAIL_PROPERTIES structure to
+// indicate which of its members contain valid information.
+const (
+ DWM_TNP_RECTDESTINATION = 0x00000001 // A value for the rcDestination member has been specified
+ DWM_TNP_RECTSOURCE = 0x00000002 // A value for the rcSource member has been specified
+ DWM_TNP_OPACITY = 0x00000004 // A value for the opacity member has been specified
+ DWM_TNP_VISIBLE = 0x00000008 // A value for the fVisible member has been specified
+ DWM_TNP_SOURCECLIENTAREAONLY = 0x00000010 // A value for the fSourceClientAreaOnly member has been specified
+)
+
+// enum-lite implementation for the following constant structure
+type DWMFLIP3DWINDOWPOLICY int32
+
+// TODO: need to verify this construction
+// Flags used by the DwmSetWindowAttribute function
+// to specify the Flip3D window policy
+const (
+ DWMFLIP3D_DEFAULT = iota + 1
+ DWMFLIP3D_EXCLUDEBELOW
+ DWMFLIP3D_EXCLUDEABOVE
+ DWMFLIP3D_LAST
+)
+
+// enum-lite implementation for the following constant structure
+type DWMNCRENDERINGPOLICY int32
+
+// TODO: need to verify this construction
+// Flags used by the DwmSetWindowAttribute function
+// to specify the non-client area rendering policy
+const (
+ DWMNCRP_USEWINDOWSTYLE = iota + 1
+ DWMNCRP_DISABLED
+ DWMNCRP_ENABLED
+ DWMNCRP_LAST
+)
+
+// enum-lite implementation for the following constant structure
+type DWMTRANSITION_OWNEDWINDOW_TARGET int32
+
+const (
+ DWMTRANSITION_OWNEDWINDOW_NULL = -1
+ DWMTRANSITION_OWNEDWINDOW_REPOSITION = 0
+)
+
+// enum-lite implementation for the following constant structure
+type DWMWINDOWATTRIBUTE int32
+
+// TODO: need to verify this construction
+// Flags used by the DwmGetWindowAttribute and DwmSetWindowAttribute functions
+// to specify window attributes for non-client rendering
+const (
+ DWMWA_NCRENDERING_ENABLED = iota + 1
+ DWMWA_NCRENDERING_POLICY
+ DWMWA_TRANSITIONS_FORCEDISABLED
+ DWMWA_ALLOW_NCPAINT
+ DWMWA_CAPTION_BUTTON_BOUNDS
+ DWMWA_NONCLIENT_RTL_LAYOUT
+ DWMWA_FORCE_ICONIC_REPRESENTATION
+ DWMWA_FLIP3D_POLICY
+ DWMWA_EXTENDED_FRAME_BOUNDS
+ DWMWA_HAS_ICONIC_BITMAP
+ DWMWA_DISALLOW_PEEK
+ DWMWA_EXCLUDED_FROM_PEEK
+ DWMWA_CLOAK
+ DWMWA_CLOAKED
+ DWMWA_FREEZE_REPRESENTATION
+ DWMWA_LAST
+)
+
+// enum-lite implementation for the following constant structure
+type GESTURE_TYPE int32
+
+// TODO: use iota?
+// Identifies the gesture type
+const (
+ GT_PEN_TAP = 0
+ GT_PEN_DOUBLETAP = 1
+ GT_PEN_RIGHTTAP = 2
+ GT_PEN_PRESSANDHOLD = 3
+ GT_PEN_PRESSANDHOLDABORT = 4
+ GT_TOUCH_TAP = 5
+ GT_TOUCH_DOUBLETAP = 6
+ GT_TOUCH_RIGHTTAP = 7
+ GT_TOUCH_PRESSANDHOLD = 8
+ GT_TOUCH_PRESSANDHOLDABORT = 9
+ GT_TOUCH_PRESSANDTAP = 10
+)
+
+// Icons
+const (
+ ICON_SMALL = 0
+ ICON_BIG = 1
+ ICON_SMALL2 = 2
+)
+
+const (
+ SIZE_RESTORED = 0
+ SIZE_MINIMIZED = 1
+ SIZE_MAXIMIZED = 2
+ SIZE_MAXSHOW = 3
+ SIZE_MAXHIDE = 4
+)
+
+// XButton values
+const (
+ XBUTTON1 = 1
+ XBUTTON2 = 2
+)
+
+// Devmode
+const (
+ DM_SPECVERSION = 0x0401
+
+ DM_ORIENTATION = 0x00000001
+ DM_PAPERSIZE = 0x00000002
+ DM_PAPERLENGTH = 0x00000004
+ DM_PAPERWIDTH = 0x00000008
+ DM_SCALE = 0x00000010
+ DM_POSITION = 0x00000020
+ DM_NUP = 0x00000040
+ DM_DISPLAYORIENTATION = 0x00000080
+ DM_COPIES = 0x00000100
+ DM_DEFAULTSOURCE = 0x00000200
+ DM_PRINTQUALITY = 0x00000400
+ DM_COLOR = 0x00000800
+ DM_DUPLEX = 0x00001000
+ DM_YRESOLUTION = 0x00002000
+ DM_TTOPTION = 0x00004000
+ DM_COLLATE = 0x00008000
+ DM_FORMNAME = 0x00010000
+ DM_LOGPIXELS = 0x00020000
+ DM_BITSPERPEL = 0x00040000
+ DM_PELSWIDTH = 0x00080000
+ DM_PELSHEIGHT = 0x00100000
+ DM_DISPLAYFLAGS = 0x00200000
+ DM_DISPLAYFREQUENCY = 0x00400000
+ DM_ICMMETHOD = 0x00800000
+ DM_ICMINTENT = 0x01000000
+ DM_MEDIATYPE = 0x02000000
+ DM_DITHERTYPE = 0x04000000
+ DM_PANNINGWIDTH = 0x08000000
+ DM_PANNINGHEIGHT = 0x10000000
+ DM_DISPLAYFIXEDOUTPUT = 0x20000000
+)
+
+// ChangeDisplaySettings
+const (
+ CDS_UPDATEREGISTRY = 0x00000001
+ CDS_TEST = 0x00000002
+ CDS_FULLSCREEN = 0x00000004
+ CDS_GLOBAL = 0x00000008
+ CDS_SET_PRIMARY = 0x00000010
+ CDS_VIDEOPARAMETERS = 0x00000020
+ CDS_RESET = 0x40000000
+ CDS_NORESET = 0x10000000
+
+ DISP_CHANGE_SUCCESSFUL = 0
+ DISP_CHANGE_RESTART = 1
+ DISP_CHANGE_FAILED = -1
+ DISP_CHANGE_BADMODE = -2
+ DISP_CHANGE_NOTUPDATED = -3
+ DISP_CHANGE_BADFLAGS = -4
+ DISP_CHANGE_BADPARAM = -5
+ DISP_CHANGE_BADDUALVIEW = -6
+)
+
+const (
+ ENUM_CURRENT_SETTINGS = 0xFFFFFFFF
+ ENUM_REGISTRY_SETTINGS = 0xFFFFFFFE
+)
+
+// PIXELFORMATDESCRIPTOR
+const (
+ PFD_TYPE_RGBA = 0
+ PFD_TYPE_COLORINDEX = 1
+
+ PFD_MAIN_PLANE = 0
+ PFD_OVERLAY_PLANE = 1
+ PFD_UNDERLAY_PLANE = -1
+
+ PFD_DOUBLEBUFFER = 0x00000001
+ PFD_STEREO = 0x00000002
+ PFD_DRAW_TO_WINDOW = 0x00000004
+ PFD_DRAW_TO_BITMAP = 0x00000008
+ PFD_SUPPORT_GDI = 0x00000010
+ PFD_SUPPORT_OPENGL = 0x00000020
+ PFD_GENERIC_FORMAT = 0x00000040
+ PFD_NEED_PALETTE = 0x00000080
+ PFD_NEED_SYSTEM_PALETTE = 0x00000100
+ PFD_SWAP_EXCHANGE = 0x00000200
+ PFD_SWAP_COPY = 0x00000400
+ PFD_SWAP_LAYER_BUFFERS = 0x00000800
+ PFD_GENERIC_ACCELERATED = 0x00001000
+ PFD_SUPPORT_DIRECTDRAW = 0x00002000
+ PFD_DIRECT3D_ACCELERATED = 0x00004000
+ PFD_SUPPORT_COMPOSITION = 0x00008000
+
+ PFD_DEPTH_DONTCARE = 0x20000000
+ PFD_DOUBLEBUFFER_DONTCARE = 0x40000000
+ PFD_STEREO_DONTCARE = 0x80000000
+)
+
+const (
+ INPUT_MOUSE = 0
+ INPUT_KEYBOARD = 1
+ INPUT_HARDWARE = 2
+)
+
+const (
+ MOUSEEVENTF_ABSOLUTE = 0x8000
+ MOUSEEVENTF_HWHEEL = 0x01000
+ MOUSEEVENTF_MOVE = 0x0001
+ MOUSEEVENTF_MOVE_NOCOALESCE = 0x2000
+ MOUSEEVENTF_LEFTDOWN = 0x0002
+ MOUSEEVENTF_LEFTUP = 0x0004
+ MOUSEEVENTF_RIGHTDOWN = 0x0008
+ MOUSEEVENTF_RIGHTUP = 0x0010
+ MOUSEEVENTF_MIDDLEDOWN = 0x0020
+ MOUSEEVENTF_MIDDLEUP = 0x0040
+ MOUSEEVENTF_VIRTUALDESK = 0x4000
+ MOUSEEVENTF_WHEEL = 0x0800
+ MOUSEEVENTF_XDOWN = 0x0080
+ MOUSEEVENTF_XUP = 0x0100
+)
diff --git a/vendor/github.com/shirou/w32/dwmapi.go b/vendor/github.com/shirou/w32/dwmapi.go
new file mode 100644
index 0000000..139b937
--- /dev/null
+++ b/vendor/github.com/shirou/w32/dwmapi.go
@@ -0,0 +1,256 @@
+// Copyright 2010-2012 The W32 Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build windows
+
+package w32
+
+import (
+ "fmt"
+ "syscall"
+ "unsafe"
+)
+
+// DEFINED IN THE DWM API BUT NOT IMPLEMENTED BY MS:
+// DwmAttachMilContent
+// DwmDetachMilContent
+// DwmEnableComposition
+// DwmGetGraphicsStreamClient
+// DwmGetGraphicsStreamTransformHint
+
+var (
+ moddwmapi = syscall.NewLazyDLL("dwmapi.dll")
+
+ procDwmDefWindowProc = moddwmapi.NewProc("DwmDefWindowProc")
+ procDwmEnableBlurBehindWindow = moddwmapi.NewProc("DwmEnableBlurBehindWindow")
+ procDwmEnableMMCSS = moddwmapi.NewProc("DwmEnableMMCSS")
+ procDwmExtendFrameIntoClientArea = moddwmapi.NewProc("DwmExtendFrameIntoClientArea")
+ procDwmFlush = moddwmapi.NewProc("DwmFlush")
+ procDwmGetColorizationColor = moddwmapi.NewProc("DwmGetColorizationColor")
+ procDwmGetCompositionTimingInfo = moddwmapi.NewProc("DwmGetCompositionTimingInfo")
+ procDwmGetTransportAttributes = moddwmapi.NewProc("DwmGetTransportAttributes")
+ procDwmGetWindowAttribute = moddwmapi.NewProc("DwmGetWindowAttribute")
+ procDwmInvalidateIconicBitmaps = moddwmapi.NewProc("DwmInvalidateIconicBitmaps")
+ procDwmIsCompositionEnabled = moddwmapi.NewProc("DwmIsCompositionEnabled")
+ procDwmModifyPreviousDxFrameDuration = moddwmapi.NewProc("DwmModifyPreviousDxFrameDuration")
+ procDwmQueryThumbnailSourceSize = moddwmapi.NewProc("DwmQueryThumbnailSourceSize")
+ procDwmRegisterThumbnail = moddwmapi.NewProc("DwmRegisterThumbnail")
+ procDwmRenderGesture = moddwmapi.NewProc("DwmRenderGesture")
+ procDwmSetDxFrameDuration = moddwmapi.NewProc("DwmSetDxFrameDuration")
+ procDwmSetIconicLivePreviewBitmap = moddwmapi.NewProc("DwmSetIconicLivePreviewBitmap")
+ procDwmSetIconicThumbnail = moddwmapi.NewProc("DwmSetIconicThumbnail")
+ procDwmSetPresentParameters = moddwmapi.NewProc("DwmSetPresentParameters")
+ procDwmSetWindowAttribute = moddwmapi.NewProc("DwmSetWindowAttribute")
+ procDwmShowContact = moddwmapi.NewProc("DwmShowContact")
+ procDwmTetherContact = moddwmapi.NewProc("DwmTetherContact")
+ procDwmTransitionOwnedWindow = moddwmapi.NewProc("DwmTransitionOwnedWindow")
+ procDwmUnregisterThumbnail = moddwmapi.NewProc("DwmUnregisterThumbnail")
+ procDwmUpdateThumbnailProperties = moddwmapi.NewProc("DwmUpdateThumbnailProperties")
+)
+
+func DwmDefWindowProc(hWnd HWND, msg uint, wParam, lParam uintptr) (bool, uint) {
+ var result uint
+ ret, _, _ := procDwmDefWindowProc.Call(
+ uintptr(hWnd),
+ uintptr(msg),
+ wParam,
+ lParam,
+ uintptr(unsafe.Pointer(&result)))
+ return ret != 0, result
+}
+
+func DwmEnableBlurBehindWindow(hWnd HWND, pBlurBehind *DWM_BLURBEHIND) HRESULT {
+ ret, _, _ := procDwmEnableBlurBehindWindow.Call(
+ uintptr(hWnd),
+ uintptr(unsafe.Pointer(pBlurBehind)))
+ return HRESULT(ret)
+}
+
+func DwmEnableMMCSS(fEnableMMCSS bool) HRESULT {
+ ret, _, _ := procDwmEnableMMCSS.Call(
+ uintptr(BoolToBOOL(fEnableMMCSS)))
+ return HRESULT(ret)
+}
+
+func DwmExtendFrameIntoClientArea(hWnd HWND, pMarInset *MARGINS) HRESULT {
+ ret, _, _ := procDwmExtendFrameIntoClientArea.Call(
+ uintptr(hWnd),
+ uintptr(unsafe.Pointer(pMarInset)))
+ return HRESULT(ret)
+}
+
+func DwmFlush() HRESULT {
+ ret, _, _ := procDwmFlush.Call()
+ return HRESULT(ret)
+}
+
+func DwmGetColorizationColor(pcrColorization *uint32, pfOpaqueBlend *BOOL) HRESULT {
+ ret, _, _ := procDwmGetColorizationColor.Call(
+ uintptr(unsafe.Pointer(pcrColorization)),
+ uintptr(unsafe.Pointer(pfOpaqueBlend)))
+ return HRESULT(ret)
+}
+
+func DwmGetCompositionTimingInfo(hWnd HWND, pTimingInfo *DWM_TIMING_INFO) HRESULT {
+ ret, _, _ := procDwmGetCompositionTimingInfo.Call(
+ uintptr(hWnd),
+ uintptr(unsafe.Pointer(pTimingInfo)))
+ return HRESULT(ret)
+}
+
+func DwmGetTransportAttributes(pfIsRemoting *BOOL, pfIsConnected *BOOL, pDwGeneration *uint32) HRESULT {
+ ret, _, _ := procDwmGetTransportAttributes.Call(
+ uintptr(unsafe.Pointer(pfIsRemoting)),
+ uintptr(unsafe.Pointer(pfIsConnected)),
+ uintptr(unsafe.Pointer(pDwGeneration)))
+ return HRESULT(ret)
+}
+
+// TODO: verify handling of variable arguments
+func DwmGetWindowAttribute(hWnd HWND, dwAttribute uint32) (pAttribute interface{}, result HRESULT) {
+ var pvAttribute, pvAttrSize uintptr
+ switch dwAttribute {
+ case DWMWA_NCRENDERING_ENABLED:
+ v := new(BOOL)
+ pAttribute = v
+ pvAttribute = uintptr(unsafe.Pointer(v))
+ pvAttrSize = unsafe.Sizeof(*v)
+ case DWMWA_CAPTION_BUTTON_BOUNDS, DWMWA_EXTENDED_FRAME_BOUNDS:
+ v := new(RECT)
+ pAttribute = v
+ pvAttribute = uintptr(unsafe.Pointer(v))
+ pvAttrSize = unsafe.Sizeof(*v)
+ case DWMWA_CLOAKED:
+ panic(fmt.Sprintf("DwmGetWindowAttribute(%d) is not currently supported.", dwAttribute))
+ default:
+ panic(fmt.Sprintf("DwmGetWindowAttribute(%d) is not valid.", dwAttribute))
+ }
+
+ ret, _, _ := procDwmGetWindowAttribute.Call(
+ uintptr(hWnd),
+ uintptr(dwAttribute),
+ pvAttribute,
+ pvAttrSize)
+ result = HRESULT(ret)
+ return
+}
+
+func DwmInvalidateIconicBitmaps(hWnd HWND) HRESULT {
+ ret, _, _ := procDwmInvalidateIconicBitmaps.Call(
+ uintptr(hWnd))
+ return HRESULT(ret)
+}
+
+func DwmIsCompositionEnabled(pfEnabled *BOOL) HRESULT {
+ ret, _, _ := procDwmIsCompositionEnabled.Call(
+ uintptr(unsafe.Pointer(pfEnabled)))
+ return HRESULT(ret)
+}
+
+func DwmModifyPreviousDxFrameDuration(hWnd HWND, cRefreshes int, fRelative bool) HRESULT {
+ ret, _, _ := procDwmModifyPreviousDxFrameDuration.Call(
+ uintptr(hWnd),
+ uintptr(cRefreshes),
+ uintptr(BoolToBOOL(fRelative)))
+ return HRESULT(ret)
+}
+
+func DwmQueryThumbnailSourceSize(hThumbnail HTHUMBNAIL, pSize *SIZE) HRESULT {
+ ret, _, _ := procDwmQueryThumbnailSourceSize.Call(
+ uintptr(hThumbnail),
+ uintptr(unsafe.Pointer(pSize)))
+ return HRESULT(ret)
+}
+
+func DwmRegisterThumbnail(hWndDestination HWND, hWndSource HWND, phThumbnailId *HTHUMBNAIL) HRESULT {
+ ret, _, _ := procDwmRegisterThumbnail.Call(
+ uintptr(hWndDestination),
+ uintptr(hWndSource),
+ uintptr(unsafe.Pointer(phThumbnailId)))
+ return HRESULT(ret)
+}
+
+func DwmRenderGesture(gt GESTURE_TYPE, cContacts uint, pdwPointerID *uint32, pPoints *POINT) {
+ procDwmRenderGesture.Call(
+ uintptr(gt),
+ uintptr(cContacts),
+ uintptr(unsafe.Pointer(pdwPointerID)),
+ uintptr(unsafe.Pointer(pPoints)))
+ return
+}
+
+func DwmSetDxFrameDuration(hWnd HWND, cRefreshes int) HRESULT {
+ ret, _, _ := procDwmSetDxFrameDuration.Call(
+ uintptr(hWnd),
+ uintptr(cRefreshes))
+ return HRESULT(ret)
+}
+
+func DwmSetIconicLivePreviewBitmap(hWnd HWND, hbmp HBITMAP, pptClient *POINT, dwSITFlags uint32) HRESULT {
+ ret, _, _ := procDwmSetIconicLivePreviewBitmap.Call(
+ uintptr(hWnd),
+ uintptr(hbmp),
+ uintptr(unsafe.Pointer(pptClient)),
+ uintptr(dwSITFlags))
+ return HRESULT(ret)
+}
+
+func DwmSetIconicThumbnail(hWnd HWND, hbmp HBITMAP, dwSITFlags uint32) HRESULT {
+ ret, _, _ := procDwmSetIconicThumbnail.Call(
+ uintptr(hWnd),
+ uintptr(hbmp),
+ uintptr(dwSITFlags))
+ return HRESULT(ret)
+}
+
+func DwmSetPresentParameters(hWnd HWND, pPresentParams *DWM_PRESENT_PARAMETERS) HRESULT {
+ ret, _, _ := procDwmSetPresentParameters.Call(
+ uintptr(hWnd),
+ uintptr(unsafe.Pointer(pPresentParams)))
+ return HRESULT(ret)
+}
+
+func DwmSetWindowAttribute(hWnd HWND, dwAttribute uint32, pvAttribute LPCVOID, cbAttribute uint32) HRESULT {
+ ret, _, _ := procDwmSetWindowAttribute.Call(
+ uintptr(hWnd),
+ uintptr(dwAttribute),
+ uintptr(pvAttribute),
+ uintptr(cbAttribute))
+ return HRESULT(ret)
+}
+
+func DwmShowContact(dwPointerID uint32, eShowContact DWM_SHOWCONTACT) {
+ procDwmShowContact.Call(
+ uintptr(dwPointerID),
+ uintptr(eShowContact))
+ return
+}
+
+func DwmTetherContact(dwPointerID uint32, fEnable bool, ptTether POINT) {
+ procDwmTetherContact.Call(
+ uintptr(dwPointerID),
+ uintptr(BoolToBOOL(fEnable)),
+ uintptr(unsafe.Pointer(&ptTether)))
+ return
+}
+
+func DwmTransitionOwnedWindow(hWnd HWND, target DWMTRANSITION_OWNEDWINDOW_TARGET) {
+ procDwmTransitionOwnedWindow.Call(
+ uintptr(hWnd),
+ uintptr(target))
+ return
+}
+
+func DwmUnregisterThumbnail(hThumbnailId HTHUMBNAIL) HRESULT {
+ ret, _, _ := procDwmUnregisterThumbnail.Call(
+ uintptr(hThumbnailId))
+ return HRESULT(ret)
+}
+
+func DwmUpdateThumbnailProperties(hThumbnailId HTHUMBNAIL, ptnProperties *DWM_THUMBNAIL_PROPERTIES) HRESULT {
+ ret, _, _ := procDwmUpdateThumbnailProperties.Call(
+ uintptr(hThumbnailId),
+ uintptr(unsafe.Pointer(ptnProperties)))
+ return HRESULT(ret)
+}
diff --git a/vendor/github.com/shirou/w32/gdi32.go b/vendor/github.com/shirou/w32/gdi32.go
new file mode 100644
index 0000000..34f032c
--- /dev/null
+++ b/vendor/github.com/shirou/w32/gdi32.go
@@ -0,0 +1,511 @@
+// Copyright 2010-2012 The W32 Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build windows
+
+package w32
+
+import (
+ "syscall"
+ "unsafe"
+)
+
+var (
+ modgdi32 = syscall.NewLazyDLL("gdi32.dll")
+
+ procGetDeviceCaps = modgdi32.NewProc("GetDeviceCaps")
+ procDeleteObject = modgdi32.NewProc("DeleteObject")
+ procCreateFontIndirect = modgdi32.NewProc("CreateFontIndirectW")
+ procAbortDoc = modgdi32.NewProc("AbortDoc")
+ procBitBlt = modgdi32.NewProc("BitBlt")
+ procCloseEnhMetaFile = modgdi32.NewProc("CloseEnhMetaFile")
+ procCopyEnhMetaFile = modgdi32.NewProc("CopyEnhMetaFileW")
+ procCreateBrushIndirect = modgdi32.NewProc("CreateBrushIndirect")
+ procCreateCompatibleDC = modgdi32.NewProc("CreateCompatibleDC")
+ procCreateDC = modgdi32.NewProc("CreateDCW")
+ procCreateDIBSection = modgdi32.NewProc("CreateDIBSection")
+ procCreateEnhMetaFile = modgdi32.NewProc("CreateEnhMetaFileW")
+ procCreateIC = modgdi32.NewProc("CreateICW")
+ procDeleteDC = modgdi32.NewProc("DeleteDC")
+ procDeleteEnhMetaFile = modgdi32.NewProc("DeleteEnhMetaFile")
+ procEllipse = modgdi32.NewProc("Ellipse")
+ procEndDoc = modgdi32.NewProc("EndDoc")
+ procEndPage = modgdi32.NewProc("EndPage")
+ procExtCreatePen = modgdi32.NewProc("ExtCreatePen")
+ procGetEnhMetaFile = modgdi32.NewProc("GetEnhMetaFileW")
+ procGetEnhMetaFileHeader = modgdi32.NewProc("GetEnhMetaFileHeader")
+ procGetObject = modgdi32.NewProc("GetObjectW")
+ procGetStockObject = modgdi32.NewProc("GetStockObject")
+ procGetTextExtentExPoint = modgdi32.NewProc("GetTextExtentExPointW")
+ procGetTextExtentPoint32 = modgdi32.NewProc("GetTextExtentPoint32W")
+ procGetTextMetrics = modgdi32.NewProc("GetTextMetricsW")
+ procLineTo = modgdi32.NewProc("LineTo")
+ procMoveToEx = modgdi32.NewProc("MoveToEx")
+ procPlayEnhMetaFile = modgdi32.NewProc("PlayEnhMetaFile")
+ procRectangle = modgdi32.NewProc("Rectangle")
+ procResetDC = modgdi32.NewProc("ResetDCW")
+ procSelectObject = modgdi32.NewProc("SelectObject")
+ procSetBkMode = modgdi32.NewProc("SetBkMode")
+ procSetBrushOrgEx = modgdi32.NewProc("SetBrushOrgEx")
+ procSetStretchBltMode = modgdi32.NewProc("SetStretchBltMode")
+ procSetTextColor = modgdi32.NewProc("SetTextColor")
+ procSetBkColor = modgdi32.NewProc("SetBkColor")
+ procStartDoc = modgdi32.NewProc("StartDocW")
+ procStartPage = modgdi32.NewProc("StartPage")
+ procStretchBlt = modgdi32.NewProc("StretchBlt")
+ procSetDIBitsToDevice = modgdi32.NewProc("SetDIBitsToDevice")
+ procChoosePixelFormat = modgdi32.NewProc("ChoosePixelFormat")
+ procDescribePixelFormat = modgdi32.NewProc("DescribePixelFormat")
+ procGetEnhMetaFilePixelFormat = modgdi32.NewProc("GetEnhMetaFilePixelFormat")
+ procGetPixelFormat = modgdi32.NewProc("GetPixelFormat")
+ procSetPixelFormat = modgdi32.NewProc("SetPixelFormat")
+ procSwapBuffers = modgdi32.NewProc("SwapBuffers")
+)
+
+func GetDeviceCaps(hdc HDC, index int) int {
+ ret, _, _ := procGetDeviceCaps.Call(
+ uintptr(hdc),
+ uintptr(index))
+
+ return int(ret)
+}
+
+func DeleteObject(hObject HGDIOBJ) bool {
+ ret, _, _ := procDeleteObject.Call(
+ uintptr(hObject))
+
+ return ret != 0
+}
+
+func CreateFontIndirect(logFont *LOGFONT) HFONT {
+ ret, _, _ := procCreateFontIndirect.Call(
+ uintptr(unsafe.Pointer(logFont)))
+
+ return HFONT(ret)
+}
+
+func AbortDoc(hdc HDC) int {
+ ret, _, _ := procAbortDoc.Call(
+ uintptr(hdc))
+
+ return int(ret)
+}
+
+func BitBlt(hdcDest HDC, nXDest, nYDest, nWidth, nHeight int, hdcSrc HDC, nXSrc, nYSrc int, dwRop uint) {
+ ret, _, _ := procBitBlt.Call(
+ uintptr(hdcDest),
+ uintptr(nXDest),
+ uintptr(nYDest),
+ uintptr(nWidth),
+ uintptr(nHeight),
+ uintptr(hdcSrc),
+ uintptr(nXSrc),
+ uintptr(nYSrc),
+ uintptr(dwRop))
+
+ if ret == 0 {
+ panic("BitBlt failed")
+ }
+}
+
+func CloseEnhMetaFile(hdc HDC) HENHMETAFILE {
+ ret, _, _ := procCloseEnhMetaFile.Call(
+ uintptr(hdc))
+
+ return HENHMETAFILE(ret)
+}
+
+func CopyEnhMetaFile(hemfSrc HENHMETAFILE, lpszFile *uint16) HENHMETAFILE {
+ ret, _, _ := procCopyEnhMetaFile.Call(
+ uintptr(hemfSrc),
+ uintptr(unsafe.Pointer(lpszFile)))
+
+ return HENHMETAFILE(ret)
+}
+
+func CreateBrushIndirect(lplb *LOGBRUSH) HBRUSH {
+ ret, _, _ := procCreateBrushIndirect.Call(
+ uintptr(unsafe.Pointer(lplb)))
+
+ return HBRUSH(ret)
+}
+
+func CreateCompatibleDC(hdc HDC) HDC {
+ ret, _, _ := procCreateCompatibleDC.Call(
+ uintptr(hdc))
+
+ if ret == 0 {
+ panic("Create compatible DC failed")
+ }
+
+ return HDC(ret)
+}
+
+func CreateDC(lpszDriver, lpszDevice, lpszOutput *uint16, lpInitData *DEVMODE) HDC {
+ ret, _, _ := procCreateDC.Call(
+ uintptr(unsafe.Pointer(lpszDriver)),
+ uintptr(unsafe.Pointer(lpszDevice)),
+ uintptr(unsafe.Pointer(lpszOutput)),
+ uintptr(unsafe.Pointer(lpInitData)))
+
+ return HDC(ret)
+}
+
+func CreateDIBSection(hdc HDC, pbmi *BITMAPINFO, iUsage uint, ppvBits *unsafe.Pointer, hSection HANDLE, dwOffset uint) HBITMAP {
+ ret, _, _ := procCreateDIBSection.Call(
+ uintptr(hdc),
+ uintptr(unsafe.Pointer(pbmi)),
+ uintptr(iUsage),
+ uintptr(unsafe.Pointer(ppvBits)),
+ uintptr(hSection),
+ uintptr(dwOffset))
+
+ return HBITMAP(ret)
+}
+
+func CreateEnhMetaFile(hdcRef HDC, lpFilename *uint16, lpRect *RECT, lpDescription *uint16) HDC {
+ ret, _, _ := procCreateEnhMetaFile.Call(
+ uintptr(hdcRef),
+ uintptr(unsafe.Pointer(lpFilename)),
+ uintptr(unsafe.Pointer(lpRect)),
+ uintptr(unsafe.Pointer(lpDescription)))
+
+ return HDC(ret)
+}
+
+func CreateIC(lpszDriver, lpszDevice, lpszOutput *uint16, lpdvmInit *DEVMODE) HDC {
+ ret, _, _ := procCreateIC.Call(
+ uintptr(unsafe.Pointer(lpszDriver)),
+ uintptr(unsafe.Pointer(lpszDevice)),
+ uintptr(unsafe.Pointer(lpszOutput)),
+ uintptr(unsafe.Pointer(lpdvmInit)))
+
+ return HDC(ret)
+}
+
+func DeleteDC(hdc HDC) bool {
+ ret, _, _ := procDeleteDC.Call(
+ uintptr(hdc))
+
+ return ret != 0
+}
+
+func DeleteEnhMetaFile(hemf HENHMETAFILE) bool {
+ ret, _, _ := procDeleteEnhMetaFile.Call(
+ uintptr(hemf))
+
+ return ret != 0
+}
+
+func Ellipse(hdc HDC, nLeftRect, nTopRect, nRightRect, nBottomRect int) bool {
+ ret, _, _ := procEllipse.Call(
+ uintptr(hdc),
+ uintptr(nLeftRect),
+ uintptr(nTopRect),
+ uintptr(nRightRect),
+ uintptr(nBottomRect))
+
+ return ret != 0
+}
+
+func EndDoc(hdc HDC) int {
+ ret, _, _ := procEndDoc.Call(
+ uintptr(hdc))
+
+ return int(ret)
+}
+
+func EndPage(hdc HDC) int {
+ ret, _, _ := procEndPage.Call(
+ uintptr(hdc))
+
+ return int(ret)
+}
+
+func ExtCreatePen(dwPenStyle, dwWidth uint, lplb *LOGBRUSH, dwStyleCount uint, lpStyle *uint) HPEN {
+ ret, _, _ := procExtCreatePen.Call(
+ uintptr(dwPenStyle),
+ uintptr(dwWidth),
+ uintptr(unsafe.Pointer(lplb)),
+ uintptr(dwStyleCount),
+ uintptr(unsafe.Pointer(lpStyle)))
+
+ return HPEN(ret)
+}
+
+func GetEnhMetaFile(lpszMetaFile *uint16) HENHMETAFILE {
+ ret, _, _ := procGetEnhMetaFile.Call(
+ uintptr(unsafe.Pointer(lpszMetaFile)))
+
+ return HENHMETAFILE(ret)
+}
+
+func GetEnhMetaFileHeader(hemf HENHMETAFILE, cbBuffer uint, lpemh *ENHMETAHEADER) uint {
+ ret, _, _ := procGetEnhMetaFileHeader.Call(
+ uintptr(hemf),
+ uintptr(cbBuffer),
+ uintptr(unsafe.Pointer(lpemh)))
+
+ return uint(ret)
+}
+
+func GetObject(hgdiobj HGDIOBJ, cbBuffer uintptr, lpvObject unsafe.Pointer) int {
+ ret, _, _ := procGetObject.Call(
+ uintptr(hgdiobj),
+ uintptr(cbBuffer),
+ uintptr(lpvObject))
+
+ return int(ret)
+}
+
+func GetStockObject(fnObject int) HGDIOBJ {
+ ret, _, _ := procGetDeviceCaps.Call(
+ uintptr(fnObject))
+
+ return HGDIOBJ(ret)
+}
+
+func GetTextExtentExPoint(hdc HDC, lpszStr *uint16, cchString, nMaxExtent int, lpnFit, alpDx *int, lpSize *SIZE) bool {
+ ret, _, _ := procGetTextExtentExPoint.Call(
+ uintptr(hdc),
+ uintptr(unsafe.Pointer(lpszStr)),
+ uintptr(cchString),
+ uintptr(nMaxExtent),
+ uintptr(unsafe.Pointer(lpnFit)),
+ uintptr(unsafe.Pointer(alpDx)),
+ uintptr(unsafe.Pointer(lpSize)))
+
+ return ret != 0
+}
+
+func GetTextExtentPoint32(hdc HDC, lpString *uint16, c int, lpSize *SIZE) bool {
+ ret, _, _ := procGetTextExtentPoint32.Call(
+ uintptr(hdc),
+ uintptr(unsafe.Pointer(lpString)),
+ uintptr(c),
+ uintptr(unsafe.Pointer(lpSize)))
+
+ return ret != 0
+}
+
+func GetTextMetrics(hdc HDC, lptm *TEXTMETRIC) bool {
+ ret, _, _ := procGetTextMetrics.Call(
+ uintptr(hdc),
+ uintptr(unsafe.Pointer(lptm)))
+
+ return ret != 0
+}
+
+func LineTo(hdc HDC, nXEnd, nYEnd int) bool {
+ ret, _, _ := procLineTo.Call(
+ uintptr(hdc),
+ uintptr(nXEnd),
+ uintptr(nYEnd))
+
+ return ret != 0
+}
+
+func MoveToEx(hdc HDC, x, y int, lpPoint *POINT) bool {
+ ret, _, _ := procMoveToEx.Call(
+ uintptr(hdc),
+ uintptr(x),
+ uintptr(y),
+ uintptr(unsafe.Pointer(lpPoint)))
+
+ return ret != 0
+}
+
+func PlayEnhMetaFile(hdc HDC, hemf HENHMETAFILE, lpRect *RECT) bool {
+ ret, _, _ := procPlayEnhMetaFile.Call(
+ uintptr(hdc),
+ uintptr(hemf),
+ uintptr(unsafe.Pointer(lpRect)))
+
+ return ret != 0
+}
+
+func Rectangle(hdc HDC, nLeftRect, nTopRect, nRightRect, nBottomRect int) bool {
+ ret, _, _ := procRectangle.Call(
+ uintptr(hdc),
+ uintptr(nLeftRect),
+ uintptr(nTopRect),
+ uintptr(nRightRect),
+ uintptr(nBottomRect))
+
+ return ret != 0
+}
+
+func ResetDC(hdc HDC, lpInitData *DEVMODE) HDC {
+ ret, _, _ := procResetDC.Call(
+ uintptr(hdc),
+ uintptr(unsafe.Pointer(lpInitData)))
+
+ return HDC(ret)
+}
+
+func SelectObject(hdc HDC, hgdiobj HGDIOBJ) HGDIOBJ {
+ ret, _, _ := procSelectObject.Call(
+ uintptr(hdc),
+ uintptr(hgdiobj))
+
+ if ret == 0 {
+ panic("SelectObject failed")
+ }
+
+ return HGDIOBJ(ret)
+}
+
+func SetBkMode(hdc HDC, iBkMode int) int {
+ ret, _, _ := procSetBkMode.Call(
+ uintptr(hdc),
+ uintptr(iBkMode))
+
+ if ret == 0 {
+ panic("SetBkMode failed")
+ }
+
+ return int(ret)
+}
+
+func SetBrushOrgEx(hdc HDC, nXOrg, nYOrg int, lppt *POINT) bool {
+ ret, _, _ := procSetBrushOrgEx.Call(
+ uintptr(hdc),
+ uintptr(nXOrg),
+ uintptr(nYOrg),
+ uintptr(unsafe.Pointer(lppt)))
+
+ return ret != 0
+}
+
+func SetStretchBltMode(hdc HDC, iStretchMode int) int {
+ ret, _, _ := procSetStretchBltMode.Call(
+ uintptr(hdc),
+ uintptr(iStretchMode))
+
+ return int(ret)
+}
+
+func SetTextColor(hdc HDC, crColor COLORREF) COLORREF {
+ ret, _, _ := procSetTextColor.Call(
+ uintptr(hdc),
+ uintptr(crColor))
+
+ if ret == CLR_INVALID {
+ panic("SetTextColor failed")
+ }
+
+ return COLORREF(ret)
+}
+
+func SetBkColor(hdc HDC, crColor COLORREF) COLORREF {
+ ret, _, _ := procSetBkColor.Call(
+ uintptr(hdc),
+ uintptr(crColor))
+
+ if ret == CLR_INVALID {
+ panic("SetBkColor failed")
+ }
+
+ return COLORREF(ret)
+}
+
+func StartDoc(hdc HDC, lpdi *DOCINFO) int {
+ ret, _, _ := procStartDoc.Call(
+ uintptr(hdc),
+ uintptr(unsafe.Pointer(lpdi)))
+
+ return int(ret)
+}
+
+func StartPage(hdc HDC) int {
+ ret, _, _ := procStartPage.Call(
+ uintptr(hdc))
+
+ return int(ret)
+}
+
+func StretchBlt(hdcDest HDC, nXOriginDest, nYOriginDest, nWidthDest, nHeightDest int, hdcSrc HDC, nXOriginSrc, nYOriginSrc, nWidthSrc, nHeightSrc int, dwRop uint) {
+ ret, _, _ := procStretchBlt.Call(
+ uintptr(hdcDest),
+ uintptr(nXOriginDest),
+ uintptr(nYOriginDest),
+ uintptr(nWidthDest),
+ uintptr(nHeightDest),
+ uintptr(hdcSrc),
+ uintptr(nXOriginSrc),
+ uintptr(nYOriginSrc),
+ uintptr(nWidthSrc),
+ uintptr(nHeightSrc),
+ uintptr(dwRop))
+
+ if ret == 0 {
+ panic("StretchBlt failed")
+ }
+}
+
+func SetDIBitsToDevice(hdc HDC, xDest, yDest, dwWidth, dwHeight, xSrc, ySrc int, uStartScan, cScanLines uint, lpvBits []byte, lpbmi *BITMAPINFO, fuColorUse uint) int {
+ ret, _, _ := procSetDIBitsToDevice.Call(
+ uintptr(hdc),
+ uintptr(xDest),
+ uintptr(yDest),
+ uintptr(dwWidth),
+ uintptr(dwHeight),
+ uintptr(xSrc),
+ uintptr(ySrc),
+ uintptr(uStartScan),
+ uintptr(cScanLines),
+ uintptr(unsafe.Pointer(&lpvBits[0])),
+ uintptr(unsafe.Pointer(lpbmi)),
+ uintptr(fuColorUse))
+
+ return int(ret)
+}
+
+func ChoosePixelFormat(hdc HDC, pfd *PIXELFORMATDESCRIPTOR) int {
+ ret, _, _ := procChoosePixelFormat.Call(
+ uintptr(hdc),
+ uintptr(unsafe.Pointer(pfd)),
+ )
+ return int(ret)
+}
+
+func DescribePixelFormat(hdc HDC, iPixelFormat int, nBytes uint, pfd *PIXELFORMATDESCRIPTOR) int {
+ ret, _, _ := procDescribePixelFormat.Call(
+ uintptr(hdc),
+ uintptr(iPixelFormat),
+ uintptr(nBytes),
+ uintptr(unsafe.Pointer(pfd)),
+ )
+ return int(ret)
+}
+
+func GetEnhMetaFilePixelFormat(hemf HENHMETAFILE, cbBuffer uint32, pfd *PIXELFORMATDESCRIPTOR) uint {
+ ret, _, _ := procGetEnhMetaFilePixelFormat.Call(
+ uintptr(hemf),
+ uintptr(cbBuffer),
+ uintptr(unsafe.Pointer(pfd)),
+ )
+ return uint(ret)
+}
+
+func GetPixelFormat(hdc HDC) int {
+ ret, _, _ := procGetPixelFormat.Call(
+ uintptr(hdc),
+ )
+ return int(ret)
+}
+
+func SetPixelFormat(hdc HDC, iPixelFormat int, pfd *PIXELFORMATDESCRIPTOR) bool {
+ ret, _, _ := procSetPixelFormat.Call(
+ uintptr(hdc),
+ uintptr(iPixelFormat),
+ uintptr(unsafe.Pointer(pfd)),
+ )
+ return ret == TRUE
+}
+
+func SwapBuffers(hdc HDC) bool {
+ ret, _, _ := procSwapBuffers.Call(uintptr(hdc))
+ return ret == TRUE
+}
diff --git a/vendor/github.com/shirou/w32/gdiplus.go b/vendor/github.com/shirou/w32/gdiplus.go
new file mode 100644
index 0000000..443334b
--- /dev/null
+++ b/vendor/github.com/shirou/w32/gdiplus.go
@@ -0,0 +1,177 @@
+// Copyright 2010-2012 The W32 Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build windows
+
+package w32
+
+import (
+ "errors"
+ "fmt"
+ "syscall"
+ "unsafe"
+)
+
+const (
+ Ok = 0
+ GenericError = 1
+ InvalidParameter = 2
+ OutOfMemory = 3
+ ObjectBusy = 4
+ InsufficientBuffer = 5
+ NotImplemented = 6
+ Win32Error = 7
+ WrongState = 8
+ Aborted = 9
+ FileNotFound = 10
+ ValueOverflow = 11
+ AccessDenied = 12
+ UnknownImageFormat = 13
+ FontFamilyNotFound = 14
+ FontStyleNotFound = 15
+ NotTrueTypeFont = 16
+ UnsupportedGdiplusVersion = 17
+ GdiplusNotInitialized = 18
+ PropertyNotFound = 19
+ PropertyNotSupported = 20
+ ProfileNotFound = 21
+)
+
+func GetGpStatus(s int32) string {
+ switch s {
+ case Ok:
+ return "Ok"
+ case GenericError:
+ return "GenericError"
+ case InvalidParameter:
+ return "InvalidParameter"
+ case OutOfMemory:
+ return "OutOfMemory"
+ case ObjectBusy:
+ return "ObjectBusy"
+ case InsufficientBuffer:
+ return "InsufficientBuffer"
+ case NotImplemented:
+ return "NotImplemented"
+ case Win32Error:
+ return "Win32Error"
+ case WrongState:
+ return "WrongState"
+ case Aborted:
+ return "Aborted"
+ case FileNotFound:
+ return "FileNotFound"
+ case ValueOverflow:
+ return "ValueOverflow"
+ case AccessDenied:
+ return "AccessDenied"
+ case UnknownImageFormat:
+ return "UnknownImageFormat"
+ case FontFamilyNotFound:
+ return "FontFamilyNotFound"
+ case FontStyleNotFound:
+ return "FontStyleNotFound"
+ case NotTrueTypeFont:
+ return "NotTrueTypeFont"
+ case UnsupportedGdiplusVersion:
+ return "UnsupportedGdiplusVersion"
+ case GdiplusNotInitialized:
+ return "GdiplusNotInitialized"
+ case PropertyNotFound:
+ return "PropertyNotFound"
+ case PropertyNotSupported:
+ return "PropertyNotSupported"
+ case ProfileNotFound:
+ return "ProfileNotFound"
+ }
+ return "Unknown Status Value"
+}
+
+var (
+ token uintptr
+
+ modgdiplus = syscall.NewLazyDLL("gdiplus.dll")
+
+ procGdipCreateBitmapFromFile = modgdiplus.NewProc("GdipCreateBitmapFromFile")
+ procGdipCreateBitmapFromHBITMAP = modgdiplus.NewProc("GdipCreateBitmapFromHBITMAP")
+ procGdipCreateHBITMAPFromBitmap = modgdiplus.NewProc("GdipCreateHBITMAPFromBitmap")
+ procGdipCreateBitmapFromResource = modgdiplus.NewProc("GdipCreateBitmapFromResource")
+ procGdipCreateBitmapFromStream = modgdiplus.NewProc("GdipCreateBitmapFromStream")
+ procGdipDisposeImage = modgdiplus.NewProc("GdipDisposeImage")
+ procGdiplusShutdown = modgdiplus.NewProc("GdiplusShutdown")
+ procGdiplusStartup = modgdiplus.NewProc("GdiplusStartup")
+)
+
+func GdipCreateBitmapFromFile(filename string) (*uintptr, error) {
+ var bitmap *uintptr
+ ret, _, _ := procGdipCreateBitmapFromFile.Call(
+ uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(filename))),
+ uintptr(unsafe.Pointer(&bitmap)))
+
+ if ret != Ok {
+ return nil, errors.New(fmt.Sprintf("GdipCreateBitmapFromFile failed with status '%s' for file '%s'", GetGpStatus(int32(ret)), filename))
+ }
+
+ return bitmap, nil
+}
+
+func GdipCreateBitmapFromResource(instance HINSTANCE, resId *uint16) (*uintptr, error) {
+ var bitmap *uintptr
+ ret, _, _ := procGdipCreateBitmapFromResource.Call(
+ uintptr(instance),
+ uintptr(unsafe.Pointer(resId)),
+ uintptr(unsafe.Pointer(&bitmap)))
+
+ if ret != Ok {
+ return nil, errors.New(fmt.Sprintf("GdiCreateBitmapFromResource failed with status '%s'", GetGpStatus(int32(ret))))
+ }
+
+ return bitmap, nil
+}
+
+func GdipCreateBitmapFromStream(stream *IStream) (*uintptr, error) {
+ var bitmap *uintptr
+ ret, _, _ := procGdipCreateBitmapFromStream.Call(
+ uintptr(unsafe.Pointer(stream)),
+ uintptr(unsafe.Pointer(&bitmap)))
+
+ if ret != Ok {
+ return nil, errors.New(fmt.Sprintf("GdipCreateBitmapFromStream failed with status '%s'", GetGpStatus(int32(ret))))
+ }
+
+ return bitmap, nil
+}
+
+func GdipCreateHBITMAPFromBitmap(bitmap *uintptr, background uint32) (HBITMAP, error) {
+ var hbitmap HBITMAP
+ ret, _, _ := procGdipCreateHBITMAPFromBitmap.Call(
+ uintptr(unsafe.Pointer(bitmap)),
+ uintptr(unsafe.Pointer(&hbitmap)),
+ uintptr(background))
+
+ if ret != Ok {
+ return 0, errors.New(fmt.Sprintf("GdipCreateHBITMAPFromBitmap failed with status '%s'", GetGpStatus(int32(ret))))
+ }
+
+ return hbitmap, nil
+}
+
+func GdipDisposeImage(image *uintptr) {
+ procGdipDisposeImage.Call(uintptr(unsafe.Pointer(image)))
+}
+
+func GdiplusShutdown() {
+ procGdiplusShutdown.Call(token)
+}
+
+func GdiplusStartup(input *GdiplusStartupInput, output *GdiplusStartupOutput) {
+ ret, _, _ := procGdiplusStartup.Call(
+ uintptr(unsafe.Pointer(&token)),
+ uintptr(unsafe.Pointer(input)),
+ uintptr(unsafe.Pointer(output)))
+
+ if ret != Ok {
+ panic("GdiplusStartup failed with status " + GetGpStatus(int32(ret)))
+ }
+}
diff --git a/vendor/github.com/shirou/w32/idispatch.go b/vendor/github.com/shirou/w32/idispatch.go
new file mode 100644
index 0000000..d6c2504
--- /dev/null
+++ b/vendor/github.com/shirou/w32/idispatch.go
@@ -0,0 +1,45 @@
+// Copyright 2010-2012 The W32 Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build windows
+
+package w32
+
+import (
+ "unsafe"
+)
+
+type pIDispatchVtbl struct {
+ pQueryInterface uintptr
+ pAddRef uintptr
+ pRelease uintptr
+ pGetTypeInfoCount uintptr
+ pGetTypeInfo uintptr
+ pGetIDsOfNames uintptr
+ pInvoke uintptr
+}
+
+type IDispatch struct {
+ lpVtbl *pIDispatchVtbl
+}
+
+func (this *IDispatch) QueryInterface(id *GUID) *IDispatch {
+ return ComQueryInterface((*IUnknown)(unsafe.Pointer(this)), id)
+}
+
+func (this *IDispatch) AddRef() int32 {
+ return ComAddRef((*IUnknown)(unsafe.Pointer(this)))
+}
+
+func (this *IDispatch) Release() int32 {
+ return ComRelease((*IUnknown)(unsafe.Pointer(this)))
+}
+
+func (this *IDispatch) GetIDsOfName(names []string) []int32 {
+ return ComGetIDsOfName(this, names)
+}
+
+func (this *IDispatch) Invoke(dispid int32, dispatch int16, params ...interface{}) *VARIANT {
+ return ComInvoke(this, dispid, dispatch, params...)
+}
diff --git a/vendor/github.com/shirou/w32/istream.go b/vendor/github.com/shirou/w32/istream.go
new file mode 100644
index 0000000..0bb2822
--- /dev/null
+++ b/vendor/github.com/shirou/w32/istream.go
@@ -0,0 +1,33 @@
+// Copyright 2010-2012 The W32 Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build windows
+
+package w32
+
+import (
+ "unsafe"
+)
+
+type pIStreamVtbl struct {
+ pQueryInterface uintptr
+ pAddRef uintptr
+ pRelease uintptr
+}
+
+type IStream struct {
+ lpVtbl *pIStreamVtbl
+}
+
+func (this *IStream) QueryInterface(id *GUID) *IDispatch {
+ return ComQueryInterface((*IUnknown)(unsafe.Pointer(this)), id)
+}
+
+func (this *IStream) AddRef() int32 {
+ return ComAddRef((*IUnknown)(unsafe.Pointer(this)))
+}
+
+func (this *IStream) Release() int32 {
+ return ComRelease((*IUnknown)(unsafe.Pointer(this)))
+}
diff --git a/vendor/github.com/shirou/w32/iunknown.go b/vendor/github.com/shirou/w32/iunknown.go
new file mode 100644
index 0000000..847fba7
--- /dev/null
+++ b/vendor/github.com/shirou/w32/iunknown.go
@@ -0,0 +1,29 @@
+// Copyright 2010-2012 The W32 Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build windows
+
+package w32
+
+type pIUnknownVtbl struct {
+ pQueryInterface uintptr
+ pAddRef uintptr
+ pRelease uintptr
+}
+
+type IUnknown struct {
+ lpVtbl *pIUnknownVtbl
+}
+
+func (this *IUnknown) QueryInterface(id *GUID) *IDispatch {
+ return ComQueryInterface(this, id)
+}
+
+func (this *IUnknown) AddRef() int32 {
+ return ComAddRef(this)
+}
+
+func (this *IUnknown) Release() int32 {
+ return ComRelease(this)
+}
diff --git a/vendor/github.com/shirou/w32/kernel32.go b/vendor/github.com/shirou/w32/kernel32.go
new file mode 100644
index 0000000..5d5b4d8
--- /dev/null
+++ b/vendor/github.com/shirou/w32/kernel32.go
@@ -0,0 +1,316 @@
+// Copyright 2010-2012 The W32 Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build windows
+
+package w32
+
+import (
+ "syscall"
+ "unsafe"
+)
+
+var (
+ modkernel32 = syscall.NewLazyDLL("kernel32.dll")
+
+ procGetModuleHandle = modkernel32.NewProc("GetModuleHandleW")
+ procMulDiv = modkernel32.NewProc("MulDiv")
+ procGetConsoleWindow = modkernel32.NewProc("GetConsoleWindow")
+ procGetCurrentThread = modkernel32.NewProc("GetCurrentThread")
+ procGetLogicalDrives = modkernel32.NewProc("GetLogicalDrives")
+ procGetUserDefaultLCID = modkernel32.NewProc("GetUserDefaultLCID")
+ procLstrlen = modkernel32.NewProc("lstrlenW")
+ procLstrcpy = modkernel32.NewProc("lstrcpyW")
+ procGlobalAlloc = modkernel32.NewProc("GlobalAlloc")
+ procGlobalFree = modkernel32.NewProc("GlobalFree")
+ procGlobalLock = modkernel32.NewProc("GlobalLock")
+ procGlobalUnlock = modkernel32.NewProc("GlobalUnlock")
+ procMoveMemory = modkernel32.NewProc("RtlMoveMemory")
+ procFindResource = modkernel32.NewProc("FindResourceW")
+ procSizeofResource = modkernel32.NewProc("SizeofResource")
+ procLockResource = modkernel32.NewProc("LockResource")
+ procLoadResource = modkernel32.NewProc("LoadResource")
+ procGetLastError = modkernel32.NewProc("GetLastError")
+ procOpenProcess = modkernel32.NewProc("OpenProcess")
+ procTerminateProcess = modkernel32.NewProc("TerminateProcess")
+ procCloseHandle = modkernel32.NewProc("CloseHandle")
+ procCreateToolhelp32Snapshot = modkernel32.NewProc("CreateToolhelp32Snapshot")
+ procModule32First = modkernel32.NewProc("Module32FirstW")
+ procModule32Next = modkernel32.NewProc("Module32NextW")
+ procProcess32First = modkernel32.NewProc("Process32FirstW")
+ procProcess32Next = modkernel32.NewProc("Process32NextW")
+ procGetSystemTimes = modkernel32.NewProc("GetSystemTimes")
+ procGetConsoleScreenBufferInfo = modkernel32.NewProc("GetConsoleScreenBufferInfo")
+ procSetConsoleTextAttribute = modkernel32.NewProc("SetConsoleTextAttribute")
+ procGetDiskFreeSpaceEx = modkernel32.NewProc("GetDiskFreeSpaceExW")
+ procGetProcessTimes = modkernel32.NewProc("GetProcessTimes")
+)
+
+func GetModuleHandle(modulename string) HINSTANCE {
+ var mn uintptr
+ if modulename == "" {
+ mn = 0
+ } else {
+ mn = uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(modulename)))
+ }
+ ret, _, _ := procGetModuleHandle.Call(mn)
+ return HINSTANCE(ret)
+}
+
+func MulDiv(number, numerator, denominator int) int {
+ ret, _, _ := procMulDiv.Call(
+ uintptr(number),
+ uintptr(numerator),
+ uintptr(denominator))
+
+ return int(ret)
+}
+
+func GetConsoleWindow() HWND {
+ ret, _, _ := procGetConsoleWindow.Call()
+
+ return HWND(ret)
+}
+
+func GetCurrentThread() HANDLE {
+ ret, _, _ := procGetCurrentThread.Call()
+
+ return HANDLE(ret)
+}
+
+func GetLogicalDrives() uint32 {
+ ret, _, _ := procGetLogicalDrives.Call()
+
+ return uint32(ret)
+}
+
+func GetUserDefaultLCID() uint32 {
+ ret, _, _ := procGetUserDefaultLCID.Call()
+
+ return uint32(ret)
+}
+
+func Lstrlen(lpString *uint16) int {
+ ret, _, _ := procLstrlen.Call(uintptr(unsafe.Pointer(lpString)))
+
+ return int(ret)
+}
+
+func Lstrcpy(buf []uint16, lpString *uint16) {
+ procLstrcpy.Call(
+ uintptr(unsafe.Pointer(&buf[0])),
+ uintptr(unsafe.Pointer(lpString)))
+}
+
+func GlobalAlloc(uFlags uint, dwBytes uint32) HGLOBAL {
+ ret, _, _ := procGlobalAlloc.Call(
+ uintptr(uFlags),
+ uintptr(dwBytes))
+
+ if ret == 0 {
+ panic("GlobalAlloc failed")
+ }
+
+ return HGLOBAL(ret)
+}
+
+func GlobalFree(hMem HGLOBAL) {
+ ret, _, _ := procGlobalFree.Call(uintptr(hMem))
+
+ if ret != 0 {
+ panic("GlobalFree failed")
+ }
+}
+
+func GlobalLock(hMem HGLOBAL) unsafe.Pointer {
+ ret, _, _ := procGlobalLock.Call(uintptr(hMem))
+
+ if ret == 0 {
+ panic("GlobalLock failed")
+ }
+
+ return unsafe.Pointer(ret)
+}
+
+func GlobalUnlock(hMem HGLOBAL) bool {
+ ret, _, _ := procGlobalUnlock.Call(uintptr(hMem))
+
+ return ret != 0
+}
+
+func MoveMemory(destination, source unsafe.Pointer, length uint32) {
+ procMoveMemory.Call(
+ uintptr(unsafe.Pointer(destination)),
+ uintptr(source),
+ uintptr(length))
+}
+
+func FindResource(hModule HMODULE, lpName, lpType *uint16) (HRSRC, error) {
+ ret, _, _ := procFindResource.Call(
+ uintptr(hModule),
+ uintptr(unsafe.Pointer(lpName)),
+ uintptr(unsafe.Pointer(lpType)))
+
+ if ret == 0 {
+ return 0, syscall.GetLastError()
+ }
+
+ return HRSRC(ret), nil
+}
+
+func SizeofResource(hModule HMODULE, hResInfo HRSRC) uint32 {
+ ret, _, _ := procSizeofResource.Call(
+ uintptr(hModule),
+ uintptr(hResInfo))
+
+ if ret == 0 {
+ panic("SizeofResource failed")
+ }
+
+ return uint32(ret)
+}
+
+func LockResource(hResData HGLOBAL) unsafe.Pointer {
+ ret, _, _ := procLockResource.Call(uintptr(hResData))
+
+ if ret == 0 {
+ panic("LockResource failed")
+ }
+
+ return unsafe.Pointer(ret)
+}
+
+func LoadResource(hModule HMODULE, hResInfo HRSRC) HGLOBAL {
+ ret, _, _ := procLoadResource.Call(
+ uintptr(hModule),
+ uintptr(hResInfo))
+
+ if ret == 0 {
+ panic("LoadResource failed")
+ }
+
+ return HGLOBAL(ret)
+}
+
+func GetLastError() uint32 {
+ ret, _, _ := procGetLastError.Call()
+ return uint32(ret)
+}
+
+func OpenProcess(desiredAccess uint32, inheritHandle bool, processId uint32) HANDLE {
+ inherit := 0
+ if inheritHandle {
+ inherit = 1
+ }
+
+ ret, _, _ := procOpenProcess.Call(
+ uintptr(desiredAccess),
+ uintptr(inherit),
+ uintptr(processId))
+ return HANDLE(ret)
+}
+
+func TerminateProcess(hProcess HANDLE, uExitCode uint) bool {
+ ret, _, _ := procTerminateProcess.Call(
+ uintptr(hProcess),
+ uintptr(uExitCode))
+ return ret != 0
+}
+
+func CloseHandle(object HANDLE) bool {
+ ret, _, _ := procCloseHandle.Call(
+ uintptr(object))
+ return ret != 0
+}
+
+func CreateToolhelp32Snapshot(flags, processId uint32) HANDLE {
+ ret, _, _ := procCreateToolhelp32Snapshot.Call(
+ uintptr(flags),
+ uintptr(processId))
+
+ if ret <= 0 {
+ return HANDLE(0)
+ }
+
+ return HANDLE(ret)
+}
+
+func Module32First(snapshot HANDLE, me *MODULEENTRY32) bool {
+ ret, _, _ := procModule32First.Call(
+ uintptr(snapshot),
+ uintptr(unsafe.Pointer(me)))
+
+ return ret != 0
+}
+
+func Module32Next(snapshot HANDLE, me *MODULEENTRY32) bool {
+ ret, _, _ := procModule32Next.Call(
+ uintptr(snapshot),
+ uintptr(unsafe.Pointer(me)))
+
+ return ret != 0
+}
+func Process32First(snapshot HANDLE, pe *PROCESSENTRY32) bool {
+ ret, _, _ := procProcess32First.Call(
+ uintptr(snapshot),
+ uintptr(unsafe.Pointer(pe)))
+
+ return ret != 0
+}
+
+func Process32Next(snapshot HANDLE, pe *PROCESSENTRY32) bool {
+ ret, _, _ := procProcess32Next.Call(
+ uintptr(snapshot),
+ uintptr(unsafe.Pointer(pe)))
+
+ return ret != 0
+}
+func GetSystemTimes(lpIdleTime, lpKernelTime, lpUserTime *FILETIME) bool {
+ ret, _, _ := procGetSystemTimes.Call(
+ uintptr(unsafe.Pointer(lpIdleTime)),
+ uintptr(unsafe.Pointer(lpKernelTime)),
+ uintptr(unsafe.Pointer(lpUserTime)))
+
+ return ret != 0
+}
+
+func GetProcessTimes(hProcess HANDLE, lpCreationTime, lpExitTime, lpKernelTime, lpUserTime *FILETIME) bool {
+ ret, _, _ := procGetProcessTimes.Call(
+ uintptr(hProcess),
+ uintptr(unsafe.Pointer(lpCreationTime)),
+ uintptr(unsafe.Pointer(lpExitTime)),
+ uintptr(unsafe.Pointer(lpKernelTime)),
+ uintptr(unsafe.Pointer(lpUserTime)))
+
+ return ret != 0
+}
+
+func GetConsoleScreenBufferInfo(hConsoleOutput HANDLE) *CONSOLE_SCREEN_BUFFER_INFO {
+ var csbi CONSOLE_SCREEN_BUFFER_INFO
+ ret, _, _ := procGetConsoleScreenBufferInfo.Call(
+ uintptr(hConsoleOutput),
+ uintptr(unsafe.Pointer(&csbi)))
+ if ret == 0 {
+ return nil
+ }
+ return &csbi
+}
+
+func SetConsoleTextAttribute(hConsoleOutput HANDLE, wAttributes uint16) bool {
+ ret, _, _ := procSetConsoleTextAttribute.Call(
+ uintptr(hConsoleOutput),
+ uintptr(wAttributes))
+ return ret != 0
+}
+
+func GetDiskFreeSpaceEx(dirName string) (r bool,
+ freeBytesAvailable, totalNumberOfBytes, totalNumberOfFreeBytes uint64) {
+ ret, _, _ := procGetDiskFreeSpaceEx.Call(
+ uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(dirName))),
+ uintptr(unsafe.Pointer(&freeBytesAvailable)),
+ uintptr(unsafe.Pointer(&totalNumberOfBytes)),
+ uintptr(unsafe.Pointer(&totalNumberOfFreeBytes)))
+ return ret != 0,
+ freeBytesAvailable, totalNumberOfBytes, totalNumberOfFreeBytes
+}
diff --git a/vendor/github.com/shirou/w32/ole32.go b/vendor/github.com/shirou/w32/ole32.go
new file mode 100644
index 0000000..4858984
--- /dev/null
+++ b/vendor/github.com/shirou/w32/ole32.go
@@ -0,0 +1,65 @@
+// Copyright 2010-2012 The W32 Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build windows
+
+package w32
+
+import (
+ "syscall"
+ "unsafe"
+)
+
+var (
+ modole32 = syscall.NewLazyDLL("ole32.dll")
+
+ procCoInitializeEx = modole32.NewProc("CoInitializeEx")
+ procCoInitialize = modole32.NewProc("CoInitialize")
+ procCoUninitialize = modole32.NewProc("CoUninitialize")
+ procCreateStreamOnHGlobal = modole32.NewProc("CreateStreamOnHGlobal")
+)
+
+func CoInitializeEx(coInit uintptr) HRESULT {
+ ret, _, _ := procCoInitializeEx.Call(
+ 0,
+ coInit)
+
+ switch uint32(ret) {
+ case E_INVALIDARG:
+ panic("CoInitializeEx failed with E_INVALIDARG")
+ case E_OUTOFMEMORY:
+ panic("CoInitializeEx failed with E_OUTOFMEMORY")
+ case E_UNEXPECTED:
+ panic("CoInitializeEx failed with E_UNEXPECTED")
+ }
+
+ return HRESULT(ret)
+}
+
+func CoInitialize() {
+ procCoInitialize.Call(0)
+}
+
+func CoUninitialize() {
+ procCoUninitialize.Call()
+}
+
+func CreateStreamOnHGlobal(hGlobal HGLOBAL, fDeleteOnRelease bool) *IStream {
+ stream := new(IStream)
+ ret, _, _ := procCreateStreamOnHGlobal.Call(
+ uintptr(hGlobal),
+ uintptr(BoolToBOOL(fDeleteOnRelease)),
+ uintptr(unsafe.Pointer(&stream)))
+
+ switch uint32(ret) {
+ case E_INVALIDARG:
+ panic("CreateStreamOnHGlobal failed with E_INVALIDARG")
+ case E_OUTOFMEMORY:
+ panic("CreateStreamOnHGlobal failed with E_OUTOFMEMORY")
+ case E_UNEXPECTED:
+ panic("CreateStreamOnHGlobal failed with E_UNEXPECTED")
+ }
+
+ return stream
+}
diff --git a/vendor/github.com/shirou/w32/oleaut32.go b/vendor/github.com/shirou/w32/oleaut32.go
new file mode 100644
index 0000000..cdfcb00
--- /dev/null
+++ b/vendor/github.com/shirou/w32/oleaut32.go
@@ -0,0 +1,50 @@
+// Copyright 2010-2012 The W32 Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build windows
+
+package w32
+
+import (
+ "syscall"
+ "unsafe"
+)
+
+var (
+ modoleaut32 = syscall.NewLazyDLL("oleaut32")
+
+ procVariantInit = modoleaut32.NewProc("VariantInit")
+ procSysAllocString = modoleaut32.NewProc("SysAllocString")
+ procSysFreeString = modoleaut32.NewProc("SysFreeString")
+ procSysStringLen = modoleaut32.NewProc("SysStringLen")
+ procCreateDispTypeInfo = modoleaut32.NewProc("CreateDispTypeInfo")
+ procCreateStdDispatch = modoleaut32.NewProc("CreateStdDispatch")
+)
+
+func VariantInit(v *VARIANT) {
+ hr, _, _ := procVariantInit.Call(uintptr(unsafe.Pointer(v)))
+ if hr != 0 {
+ panic("Invoke VariantInit error.")
+ }
+ return
+}
+
+func SysAllocString(v string) (ss *int16) {
+ pss, _, _ := procSysAllocString.Call(uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(v))))
+ ss = (*int16)(unsafe.Pointer(pss))
+ return
+}
+
+func SysFreeString(v *int16) {
+ hr, _, _ := procSysFreeString.Call(uintptr(unsafe.Pointer(v)))
+ if hr != 0 {
+ panic("Invoke SysFreeString error.")
+ }
+ return
+}
+
+func SysStringLen(v *int16) uint {
+ l, _, _ := procSysStringLen.Call(uintptr(unsafe.Pointer(v)))
+ return uint(l)
+}
diff --git a/vendor/github.com/shirou/w32/opengl32.go b/vendor/github.com/shirou/w32/opengl32.go
new file mode 100644
index 0000000..4f35f19
--- /dev/null
+++ b/vendor/github.com/shirou/w32/opengl32.go
@@ -0,0 +1,74 @@
+// Copyright 2010-2012 The W32 Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build windows
+
+package w32
+
+import (
+ "syscall"
+ "unsafe"
+)
+
+var (
+ modopengl32 = syscall.NewLazyDLL("opengl32.dll")
+
+ procwglCreateContext = modopengl32.NewProc("wglCreateContext")
+ procwglCreateLayerContext = modopengl32.NewProc("wglCreateLayerContext")
+ procwglDeleteContext = modopengl32.NewProc("wglDeleteContext")
+ procwglGetProcAddress = modopengl32.NewProc("wglGetProcAddress")
+ procwglMakeCurrent = modopengl32.NewProc("wglMakeCurrent")
+ procwglShareLists = modopengl32.NewProc("wglShareLists")
+)
+
+func WglCreateContext(hdc HDC) HGLRC {
+ ret, _, _ := procwglCreateContext.Call(
+ uintptr(hdc),
+ )
+
+ return HGLRC(ret)
+}
+
+func WglCreateLayerContext(hdc HDC, iLayerPlane int) HGLRC {
+ ret, _, _ := procwglCreateLayerContext.Call(
+ uintptr(hdc),
+ uintptr(iLayerPlane),
+ )
+
+ return HGLRC(ret)
+}
+
+func WglDeleteContext(hglrc HGLRC) bool {
+ ret, _, _ := procwglDeleteContext.Call(
+ uintptr(hglrc),
+ )
+
+ return ret == TRUE
+}
+
+func WglGetProcAddress(szProc string) uintptr {
+ ret, _, _ := procwglGetProcAddress.Call(
+ uintptr(unsafe.Pointer(syscall.StringBytePtr(szProc))),
+ )
+
+ return ret
+}
+
+func WglMakeCurrent(hdc HDC, hglrc HGLRC) bool {
+ ret, _, _ := procwglMakeCurrent.Call(
+ uintptr(hdc),
+ uintptr(hglrc),
+ )
+
+ return ret == TRUE
+}
+
+func WglShareLists(hglrc1, hglrc2 HGLRC) bool {
+ ret, _, _ := procwglShareLists.Call(
+ uintptr(hglrc1),
+ uintptr(hglrc2),
+ )
+
+ return ret == TRUE
+}
diff --git a/vendor/github.com/shirou/w32/psapi.go b/vendor/github.com/shirou/w32/psapi.go
new file mode 100644
index 0000000..ab7858c
--- /dev/null
+++ b/vendor/github.com/shirou/w32/psapi.go
@@ -0,0 +1,27 @@
+// Copyright 2010-2012 The W32 Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build windows
+
+package w32
+
+import (
+ "syscall"
+ "unsafe"
+)
+
+var (
+ modpsapi = syscall.NewLazyDLL("psapi.dll")
+
+ procEnumProcesses = modpsapi.NewProc("EnumProcesses")
+)
+
+func EnumProcesses(processIds []uint32, cb uint32, bytesReturned *uint32) bool {
+ ret, _, _ := procEnumProcesses.Call(
+ uintptr(unsafe.Pointer(&processIds[0])),
+ uintptr(cb),
+ uintptr(unsafe.Pointer(bytesReturned)))
+
+ return ret != 0
+}
diff --git a/vendor/github.com/shirou/w32/shell32.go b/vendor/github.com/shirou/w32/shell32.go
new file mode 100644
index 0000000..0f5ce8c
--- /dev/null
+++ b/vendor/github.com/shirou/w32/shell32.go
@@ -0,0 +1,155 @@
+// Copyright 2010-2012 The W32 Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build windows
+
+package w32
+
+import (
+ "errors"
+ "fmt"
+ "syscall"
+ "unsafe"
+)
+
+var (
+ modshell32 = syscall.NewLazyDLL("shell32.dll")
+
+ procSHBrowseForFolder = modshell32.NewProc("SHBrowseForFolderW")
+ procSHGetPathFromIDList = modshell32.NewProc("SHGetPathFromIDListW")
+ procDragAcceptFiles = modshell32.NewProc("DragAcceptFiles")
+ procDragQueryFile = modshell32.NewProc("DragQueryFileW")
+ procDragQueryPoint = modshell32.NewProc("DragQueryPoint")
+ procDragFinish = modshell32.NewProc("DragFinish")
+ procShellExecute = modshell32.NewProc("ShellExecuteW")
+ procExtractIcon = modshell32.NewProc("ExtractIconW")
+)
+
+func SHBrowseForFolder(bi *BROWSEINFO) uintptr {
+ ret, _, _ := procSHBrowseForFolder.Call(uintptr(unsafe.Pointer(bi)))
+
+ return ret
+}
+
+func SHGetPathFromIDList(idl uintptr) string {
+ buf := make([]uint16, 1024)
+ procSHGetPathFromIDList.Call(
+ idl,
+ uintptr(unsafe.Pointer(&buf[0])))
+
+ return syscall.UTF16ToString(buf)
+}
+
+func DragAcceptFiles(hwnd HWND, accept bool) {
+ procDragAcceptFiles.Call(
+ uintptr(hwnd),
+ uintptr(BoolToBOOL(accept)))
+}
+
+func DragQueryFile(hDrop HDROP, iFile uint) (fileName string, fileCount uint) {
+ ret, _, _ := procDragQueryFile.Call(
+ uintptr(hDrop),
+ uintptr(iFile),
+ 0,
+ 0)
+
+ fileCount = uint(ret)
+
+ if iFile != 0xFFFFFFFF {
+ buf := make([]uint16, fileCount+1)
+
+ ret, _, _ := procDragQueryFile.Call(
+ uintptr(hDrop),
+ uintptr(iFile),
+ uintptr(unsafe.Pointer(&buf[0])),
+ uintptr(fileCount+1))
+
+ if ret == 0 {
+ panic("Invoke DragQueryFile error.")
+ }
+
+ fileName = syscall.UTF16ToString(buf)
+ }
+
+ return
+}
+
+func DragQueryPoint(hDrop HDROP) (x, y int, isClientArea bool) {
+ var pt POINT
+ ret, _, _ := procDragQueryPoint.Call(
+ uintptr(hDrop),
+ uintptr(unsafe.Pointer(&pt)))
+
+ return int(pt.X), int(pt.Y), (ret == 1)
+}
+
+func DragFinish(hDrop HDROP) {
+ procDragFinish.Call(uintptr(hDrop))
+}
+
+func ShellExecute(hwnd HWND, lpOperation, lpFile, lpParameters, lpDirectory string, nShowCmd int) error {
+ var op, param, directory uintptr
+ if len(lpOperation) != 0 {
+ op = uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(lpOperation)))
+ }
+ if len(lpParameters) != 0 {
+ param = uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(lpParameters)))
+ }
+ if len(lpDirectory) != 0 {
+ directory = uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(lpDirectory)))
+ }
+
+ ret, _, _ := procShellExecute.Call(
+ uintptr(hwnd),
+ op,
+ uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(lpFile))),
+ param,
+ directory,
+ uintptr(nShowCmd))
+
+ errorMsg := ""
+ if ret != 0 && ret <= 32 {
+ switch int(ret) {
+ case ERROR_FILE_NOT_FOUND:
+ errorMsg = "The specified file was not found."
+ case ERROR_PATH_NOT_FOUND:
+ errorMsg = "The specified path was not found."
+ case ERROR_BAD_FORMAT:
+ errorMsg = "The .exe file is invalid (non-Win32 .exe or error in .exe image)."
+ case SE_ERR_ACCESSDENIED:
+ errorMsg = "The operating system denied access to the specified file."
+ case SE_ERR_ASSOCINCOMPLETE:
+ errorMsg = "The file name association is incomplete or invalid."
+ case SE_ERR_DDEBUSY:
+ errorMsg = "The DDE transaction could not be completed because other DDE transactions were being processed."
+ case SE_ERR_DDEFAIL:
+ errorMsg = "The DDE transaction failed."
+ case SE_ERR_DDETIMEOUT:
+ errorMsg = "The DDE transaction could not be completed because the request timed out."
+ case SE_ERR_DLLNOTFOUND:
+ errorMsg = "The specified DLL was not found."
+ case SE_ERR_NOASSOC:
+ errorMsg = "There is no application associated with the given file name extension. This error will also be returned if you attempt to print a file that is not printable."
+ case SE_ERR_OOM:
+ errorMsg = "There was not enough memory to complete the operation."
+ case SE_ERR_SHARE:
+ errorMsg = "A sharing violation occurred."
+ default:
+ errorMsg = fmt.Sprintf("Unknown error occurred with error code %v", ret)
+ }
+ } else {
+ return nil
+ }
+
+ return errors.New(errorMsg)
+}
+
+func ExtractIcon(lpszExeFileName string, nIconIndex int) HICON {
+ ret, _, _ := procExtractIcon.Call(
+ 0,
+ uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(lpszExeFileName))),
+ uintptr(nIconIndex))
+
+ return HICON(ret)
+}
diff --git a/vendor/github.com/shirou/w32/typedef.go b/vendor/github.com/shirou/w32/typedef.go
new file mode 100644
index 0000000..65f5111
--- /dev/null
+++ b/vendor/github.com/shirou/w32/typedef.go
@@ -0,0 +1,901 @@
+// Copyright 2010-2012 The W32 Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package w32
+
+import (
+ "unsafe"
+)
+
+// From MSDN: Windows Data Types
+// http://msdn.microsoft.com/en-us/library/s3f49ktz.aspx
+// http://msdn.microsoft.com/en-us/library/windows/desktop/aa383751.aspx
+// ATOM WORD
+// BOOL int32
+// BOOLEAN byte
+// BYTE byte
+// CCHAR int8
+// CHAR int8
+// COLORREF DWORD
+// DWORD uint32
+// DWORDLONG ULONGLONG
+// DWORD_PTR ULONG_PTR
+// DWORD32 uint32
+// DWORD64 uint64
+// FLOAT float32
+// HACCEL HANDLE
+// HALF_PTR struct{} // ???
+// HANDLE PVOID
+// HBITMAP HANDLE
+// HBRUSH HANDLE
+// HCOLORSPACE HANDLE
+// HCONV HANDLE
+// HCONVLIST HANDLE
+// HCURSOR HANDLE
+// HDC HANDLE
+// HDDEDATA HANDLE
+// HDESK HANDLE
+// HDROP HANDLE
+// HDWP HANDLE
+// HENHMETAFILE HANDLE
+// HFILE HANDLE
+// HFONT HANDLE
+// HGDIOBJ HANDLE
+// HGLOBAL HANDLE
+// HHOOK HANDLE
+// HICON HANDLE
+// HINSTANCE HANDLE
+// HKEY HANDLE
+// HKL HANDLE
+// HLOCAL HANDLE
+// HMENU HANDLE
+// HMETAFILE HANDLE
+// HMODULE HANDLE
+// HPALETTE HANDLE
+// HPEN HANDLE
+// HRESULT int32
+// HRGN HANDLE
+// HSZ HANDLE
+// HWINSTA HANDLE
+// HWND HANDLE
+// INT int32
+// INT_PTR uintptr
+// INT8 int8
+// INT16 int16
+// INT32 int32
+// INT64 int64
+// LANGID WORD
+// LCID DWORD
+// LCTYPE DWORD
+// LGRPID DWORD
+// LONG int32
+// LONGLONG int64
+// LONG_PTR uintptr
+// LONG32 int32
+// LONG64 int64
+// LPARAM LONG_PTR
+// LPBOOL *BOOL
+// LPBYTE *BYTE
+// LPCOLORREF *COLORREF
+// LPCSTR *int8
+// LPCTSTR LPCWSTR
+// LPCVOID unsafe.Pointer
+// LPCWSTR *WCHAR
+// LPDWORD *DWORD
+// LPHANDLE *HANDLE
+// LPINT *INT
+// LPLONG *LONG
+// LPSTR *CHAR
+// LPTSTR LPWSTR
+// LPVOID unsafe.Pointer
+// LPWORD *WORD
+// LPWSTR *WCHAR
+// LRESULT LONG_PTR
+// PBOOL *BOOL
+// PBOOLEAN *BOOLEAN
+// PBYTE *BYTE
+// PCHAR *CHAR
+// PCSTR *CHAR
+// PCTSTR PCWSTR
+// PCWSTR *WCHAR
+// PDWORD *DWORD
+// PDWORDLONG *DWORDLONG
+// PDWORD_PTR *DWORD_PTR
+// PDWORD32 *DWORD32
+// PDWORD64 *DWORD64
+// PFLOAT *FLOAT
+// PHALF_PTR *HALF_PTR
+// PHANDLE *HANDLE
+// PHKEY *HKEY
+// PINT_PTR *INT_PTR
+// PINT8 *INT8
+// PINT16 *INT16
+// PINT32 *INT32
+// PINT64 *INT64
+// PLCID *LCID
+// PLONG *LONG
+// PLONGLONG *LONGLONG
+// PLONG_PTR *LONG_PTR
+// PLONG32 *LONG32
+// PLONG64 *LONG64
+// POINTER_32 struct{} // ???
+// POINTER_64 struct{} // ???
+// POINTER_SIGNED uintptr
+// POINTER_UNSIGNED uintptr
+// PSHORT *SHORT
+// PSIZE_T *SIZE_T
+// PSSIZE_T *SSIZE_T
+// PSTR *CHAR
+// PTBYTE *TBYTE
+// PTCHAR *TCHAR
+// PTSTR PWSTR
+// PUCHAR *UCHAR
+// PUHALF_PTR *UHALF_PTR
+// PUINT *UINT
+// PUINT_PTR *UINT_PTR
+// PUINT8 *UINT8
+// PUINT16 *UINT16
+// PUINT32 *UINT32
+// PUINT64 *UINT64
+// PULONG *ULONG
+// PULONGLONG *ULONGLONG
+// PULONG_PTR *ULONG_PTR
+// PULONG32 *ULONG32
+// PULONG64 *ULONG64
+// PUSHORT *USHORT
+// PVOID unsafe.Pointer
+// PWCHAR *WCHAR
+// PWORD *WORD
+// PWSTR *WCHAR
+// QWORD uint64
+// SC_HANDLE HANDLE
+// SC_LOCK LPVOID
+// SERVICE_STATUS_HANDLE HANDLE
+// SHORT int16
+// SIZE_T ULONG_PTR
+// SSIZE_T LONG_PTR
+// TBYTE WCHAR
+// TCHAR WCHAR
+// UCHAR uint8
+// UHALF_PTR struct{} // ???
+// UINT uint32
+// UINT_PTR uintptr
+// UINT8 uint8
+// UINT16 uint16
+// UINT32 uint32
+// UINT64 uint64
+// ULONG uint32
+// ULONGLONG uint64
+// ULONG_PTR uintptr
+// ULONG32 uint32
+// ULONG64 uint64
+// USHORT uint16
+// USN LONGLONG
+// WCHAR uint16
+// WORD uint16
+// WPARAM UINT_PTR
+type (
+ ATOM uint16
+ BOOL int32
+ COLORREF uint32
+ DWM_FRAME_COUNT uint64
+ HACCEL HANDLE
+ HANDLE uintptr
+ HBITMAP HANDLE
+ HBRUSH HANDLE
+ HCURSOR HANDLE
+ HDC HANDLE
+ HDROP HANDLE
+ HDWP HANDLE
+ HENHMETAFILE HANDLE
+ HFONT HANDLE
+ HGDIOBJ HANDLE
+ HGLOBAL HANDLE
+ HGLRC HANDLE
+ HICON HANDLE
+ HIMAGELIST HANDLE
+ HINSTANCE HANDLE
+ HKEY HANDLE
+ HKL HANDLE
+ HMENU HANDLE
+ HMODULE HANDLE
+ HMONITOR HANDLE
+ HPEN HANDLE
+ HRESULT int32
+ HRGN HANDLE
+ HRSRC HANDLE
+ HTHUMBNAIL HANDLE
+ HWND HANDLE
+ LPCVOID unsafe.Pointer
+ PVOID unsafe.Pointer
+ QPC_TIME uint64
+)
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/dd162805.aspx
+type POINT struct {
+ X, Y int32
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/dd162897.aspx
+type RECT struct {
+ Left, Top, Right, Bottom int32
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/ms633577.aspx
+type WNDCLASSEX struct {
+ Size uint32
+ Style uint32
+ WndProc uintptr
+ ClsExtra int32
+ WndExtra int32
+ Instance HINSTANCE
+ Icon HICON
+ Cursor HCURSOR
+ Background HBRUSH
+ MenuName *uint16
+ ClassName *uint16
+ IconSm HICON
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/ms644958.aspx
+type MSG struct {
+ Hwnd HWND
+ Message uint32
+ WParam uintptr
+ LParam uintptr
+ Time uint32
+ Pt POINT
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/dd145037.aspx
+type LOGFONT struct {
+ Height int32
+ Width int32
+ Escapement int32
+ Orientation int32
+ Weight int32
+ Italic byte
+ Underline byte
+ StrikeOut byte
+ CharSet byte
+ OutPrecision byte
+ ClipPrecision byte
+ Quality byte
+ PitchAndFamily byte
+ FaceName [LF_FACESIZE]uint16
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/ms646839.aspx
+type OPENFILENAME struct {
+ StructSize uint32
+ Owner HWND
+ Instance HINSTANCE
+ Filter *uint16
+ CustomFilter *uint16
+ MaxCustomFilter uint32
+ FilterIndex uint32
+ File *uint16
+ MaxFile uint32
+ FileTitle *uint16
+ MaxFileTitle uint32
+ InitialDir *uint16
+ Title *uint16
+ Flags uint32
+ FileOffset uint16
+ FileExtension uint16
+ DefExt *uint16
+ CustData uintptr
+ FnHook uintptr
+ TemplateName *uint16
+ PvReserved unsafe.Pointer
+ DwReserved uint32
+ FlagsEx uint32
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/bb773205.aspx
+type BROWSEINFO struct {
+ Owner HWND
+ Root *uint16
+ DisplayName *uint16
+ Title *uint16
+ Flags uint32
+ CallbackFunc uintptr
+ LParam uintptr
+ Image int32
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/aa373931.aspx
+type GUID struct {
+ Data1 uint32
+ Data2 uint16
+ Data3 uint16
+ Data4 [8]byte
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/ms221627.aspx
+type VARIANT struct {
+ VT uint16 // 2
+ WReserved1 uint16 // 4
+ WReserved2 uint16 // 6
+ WReserved3 uint16 // 8
+ Val int64 // 16
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/ms221416.aspx
+type DISPPARAMS struct {
+ Rgvarg uintptr
+ RgdispidNamedArgs uintptr
+ CArgs uint32
+ CNamedArgs uint32
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/ms221133.aspx
+type EXCEPINFO struct {
+ WCode uint16
+ WReserved uint16
+ BstrSource *uint16
+ BstrDescription *uint16
+ BstrHelpFile *uint16
+ DwHelpContext uint32
+ PvReserved uintptr
+ PfnDeferredFillIn uintptr
+ Scode int32
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/dd145035.aspx
+type LOGBRUSH struct {
+ LbStyle uint32
+ LbColor COLORREF
+ LbHatch uintptr
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/dd183565.aspx
+type DEVMODE struct {
+ DmDeviceName [CCHDEVICENAME]uint16
+ DmSpecVersion uint16
+ DmDriverVersion uint16
+ DmSize uint16
+ DmDriverExtra uint16
+ DmFields uint32
+ DmOrientation int16
+ DmPaperSize int16
+ DmPaperLength int16
+ DmPaperWidth int16
+ DmScale int16
+ DmCopies int16
+ DmDefaultSource int16
+ DmPrintQuality int16
+ DmColor int16
+ DmDuplex int16
+ DmYResolution int16
+ DmTTOption int16
+ DmCollate int16
+ DmFormName [CCHFORMNAME]uint16
+ DmLogPixels uint16
+ DmBitsPerPel uint32
+ DmPelsWidth uint32
+ DmPelsHeight uint32
+ DmDisplayFlags uint32
+ DmDisplayFrequency uint32
+ DmICMMethod uint32
+ DmICMIntent uint32
+ DmMediaType uint32
+ DmDitherType uint32
+ DmReserved1 uint32
+ DmReserved2 uint32
+ DmPanningWidth uint32
+ DmPanningHeight uint32
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/dd183376.aspx
+type BITMAPINFOHEADER struct {
+ BiSize uint32
+ BiWidth int32
+ BiHeight int32
+ BiPlanes uint16
+ BiBitCount uint16
+ BiCompression uint32
+ BiSizeImage uint32
+ BiXPelsPerMeter int32
+ BiYPelsPerMeter int32
+ BiClrUsed uint32
+ BiClrImportant uint32
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/dd162938.aspx
+type RGBQUAD struct {
+ RgbBlue byte
+ RgbGreen byte
+ RgbRed byte
+ RgbReserved byte
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/dd183375.aspx
+type BITMAPINFO struct {
+ BmiHeader BITMAPINFOHEADER
+ BmiColors *RGBQUAD
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/dd183371.aspx
+type BITMAP struct {
+ BmType int32
+ BmWidth int32
+ BmHeight int32
+ BmWidthBytes int32
+ BmPlanes uint16
+ BmBitsPixel uint16
+ BmBits unsafe.Pointer
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/dd183567.aspx
+type DIBSECTION struct {
+ DsBm BITMAP
+ DsBmih BITMAPINFOHEADER
+ DsBitfields [3]uint32
+ DshSection HANDLE
+ DsOffset uint32
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/dd162607.aspx
+type ENHMETAHEADER struct {
+ IType uint32
+ NSize uint32
+ RclBounds RECT
+ RclFrame RECT
+ DSignature uint32
+ NVersion uint32
+ NBytes uint32
+ NRecords uint32
+ NHandles uint16
+ SReserved uint16
+ NDescription uint32
+ OffDescription uint32
+ NPalEntries uint32
+ SzlDevice SIZE
+ SzlMillimeters SIZE
+ CbPixelFormat uint32
+ OffPixelFormat uint32
+ BOpenGL uint32
+ SzlMicrometers SIZE
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/dd145106.aspx
+type SIZE struct {
+ CX, CY int32
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/dd145132.aspx
+type TEXTMETRIC struct {
+ TmHeight int32
+ TmAscent int32
+ TmDescent int32
+ TmInternalLeading int32
+ TmExternalLeading int32
+ TmAveCharWidth int32
+ TmMaxCharWidth int32
+ TmWeight int32
+ TmOverhang int32
+ TmDigitizedAspectX int32
+ TmDigitizedAspectY int32
+ TmFirstChar uint16
+ TmLastChar uint16
+ TmDefaultChar uint16
+ TmBreakChar uint16
+ TmItalic byte
+ TmUnderlined byte
+ TmStruckOut byte
+ TmPitchAndFamily byte
+ TmCharSet byte
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/dd183574.aspx
+type DOCINFO struct {
+ CbSize int32
+ LpszDocName *uint16
+ LpszOutput *uint16
+ LpszDatatype *uint16
+ FwType uint32
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/bb775514.aspx
+type NMHDR struct {
+ HwndFrom HWND
+ IdFrom uintptr
+ Code uint32
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/bb774743.aspx
+type LVCOLUMN struct {
+ Mask uint32
+ Fmt int32
+ Cx int32
+ PszText *uint16
+ CchTextMax int32
+ ISubItem int32
+ IImage int32
+ IOrder int32
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/bb774760.aspx
+type LVITEM struct {
+ Mask uint32
+ IItem int32
+ ISubItem int32
+ State uint32
+ StateMask uint32
+ PszText *uint16
+ CchTextMax int32
+ IImage int32
+ LParam uintptr
+ IIndent int32
+ IGroupId int32
+ CColumns uint32
+ PuColumns uint32
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/bb774754.aspx
+type LVHITTESTINFO struct {
+ Pt POINT
+ Flags uint32
+ IItem int32
+ ISubItem int32
+ IGroup int32
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/bb774771.aspx
+type NMITEMACTIVATE struct {
+ Hdr NMHDR
+ IItem int32
+ ISubItem int32
+ UNewState uint32
+ UOldState uint32
+ UChanged uint32
+ PtAction POINT
+ LParam uintptr
+ UKeyFlags uint32
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/bb774773.aspx
+type NMLISTVIEW struct {
+ Hdr NMHDR
+ IItem int32
+ ISubItem int32
+ UNewState uint32
+ UOldState uint32
+ UChanged uint32
+ PtAction POINT
+ LParam uintptr
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/bb774780.aspx
+type NMLVDISPINFO struct {
+ Hdr NMHDR
+ Item LVITEM
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/bb775507.aspx
+type INITCOMMONCONTROLSEX struct {
+ DwSize uint32
+ DwICC uint32
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/bb760256.aspx
+type TOOLINFO struct {
+ CbSize uint32
+ UFlags uint32
+ Hwnd HWND
+ UId uintptr
+ Rect RECT
+ Hinst HINSTANCE
+ LpszText *uint16
+ LParam uintptr
+ LpReserved unsafe.Pointer
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/ms645604.aspx
+type TRACKMOUSEEVENT struct {
+ CbSize uint32
+ DwFlags uint32
+ HwndTrack HWND
+ DwHoverTime uint32
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/ms534067.aspx
+type GdiplusStartupInput struct {
+ GdiplusVersion uint32
+ DebugEventCallback uintptr
+ SuppressBackgroundThread BOOL
+ SuppressExternalCodecs BOOL
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/ms534068.aspx
+type GdiplusStartupOutput struct {
+ NotificationHook uintptr
+ NotificationUnhook uintptr
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/dd162768.aspx
+type PAINTSTRUCT struct {
+ Hdc HDC
+ FErase BOOL
+ RcPaint RECT
+ FRestore BOOL
+ FIncUpdate BOOL
+ RgbReserved [32]byte
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/aa363646.aspx
+type EVENTLOGRECORD struct {
+ Length uint32
+ Reserved uint32
+ RecordNumber uint32
+ TimeGenerated uint32
+ TimeWritten uint32
+ EventID uint32
+ EventType uint16
+ NumStrings uint16
+ EventCategory uint16
+ ReservedFlags uint16
+ ClosingRecordNumber uint32
+ StringOffset uint32
+ UserSidLength uint32
+ UserSidOffset uint32
+ DataLength uint32
+ DataOffset uint32
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/ms685996.aspx
+type SERVICE_STATUS struct {
+ DwServiceType uint32
+ DwCurrentState uint32
+ DwControlsAccepted uint32
+ DwWin32ExitCode uint32
+ DwServiceSpecificExitCode uint32
+ DwCheckPoint uint32
+ DwWaitHint uint32
+}
+type PROCESSENTRY32 struct {
+ DwSize uint32
+ CntUsage uint32
+ Th32ProcessID uint32
+ Th32DefaultHeapID uintptr
+ Th32ModuleID uint32
+ CntThreads uint32
+ Th32ParentProcessID uint32
+ PcPriClassBase int32
+ DwFlags uint32
+ SzExeFile [MAX_PATH]uint16
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/ms684225.aspx
+type MODULEENTRY32 struct {
+ Size uint32
+ ModuleID uint32
+ ProcessID uint32
+ GlblcntUsage uint32
+ ProccntUsage uint32
+ ModBaseAddr *uint8
+ ModBaseSize uint32
+ HModule HMODULE
+ SzModule [MAX_MODULE_NAME32 + 1]uint16
+ SzExePath [MAX_PATH]uint16
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/ms724284.aspx
+type FILETIME struct {
+ DwLowDateTime uint32
+ DwHighDateTime uint32
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/ms682119.aspx
+type COORD struct {
+ X, Y int16
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/ms686311.aspx
+type SMALL_RECT struct {
+ Left, Top, Right, Bottom int16
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/ms682093.aspx
+type CONSOLE_SCREEN_BUFFER_INFO struct {
+ DwSize COORD
+ DwCursorPosition COORD
+ WAttributes uint16
+ SrWindow SMALL_RECT
+ DwMaximumWindowSize COORD
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/bb773244.aspx
+type MARGINS struct {
+ CxLeftWidth, CxRightWidth, CyTopHeight, CyBottomHeight int32
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/aa969500.aspx
+type DWM_BLURBEHIND struct {
+ DwFlags uint32
+ fEnable BOOL
+ hRgnBlur HRGN
+ fTransitionOnMaximized BOOL
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/aa969501.aspx
+type DWM_PRESENT_PARAMETERS struct {
+ cbSize uint32
+ fQueue BOOL
+ cRefreshStart DWM_FRAME_COUNT
+ cBuffer uint32
+ fUseSourceRate BOOL
+ rateSource UNSIGNED_RATIO
+ cRefreshesPerFrame uint32
+ eSampling DWM_SOURCE_FRAME_SAMPLING
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/aa969502.aspx
+type DWM_THUMBNAIL_PROPERTIES struct {
+ dwFlags uint32
+ rcDestination RECT
+ rcSource RECT
+ opacity byte
+ fVisible BOOL
+ fSourceClientAreaOnly BOOL
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/aa969503.aspx
+type DWM_TIMING_INFO struct {
+ cbSize uint32
+ rateRefresh UNSIGNED_RATIO
+ qpcRefreshPeriod QPC_TIME
+ rateCompose UNSIGNED_RATIO
+ qpcVBlank QPC_TIME
+ cRefresh DWM_FRAME_COUNT
+ cDXRefresh uint32
+ qpcCompose QPC_TIME
+ cFrame DWM_FRAME_COUNT
+ cDXPresent uint32
+ cRefreshFrame DWM_FRAME_COUNT
+ cFrameSubmitted DWM_FRAME_COUNT
+ cDXPresentSubmitted uint32
+ cFrameConfirmed DWM_FRAME_COUNT
+ cDXPresentConfirmed uint32
+ cRefreshConfirmed DWM_FRAME_COUNT
+ cDXRefreshConfirmed uint32
+ cFramesLate DWM_FRAME_COUNT
+ cFramesOutstanding uint32
+ cFrameDisplayed DWM_FRAME_COUNT
+ qpcFrameDisplayed QPC_TIME
+ cRefreshFrameDisplayed DWM_FRAME_COUNT
+ cFrameComplete DWM_FRAME_COUNT
+ qpcFrameComplete QPC_TIME
+ cFramePending DWM_FRAME_COUNT
+ qpcFramePending QPC_TIME
+ cFramesDisplayed DWM_FRAME_COUNT
+ cFramesComplete DWM_FRAME_COUNT
+ cFramesPending DWM_FRAME_COUNT
+ cFramesAvailable DWM_FRAME_COUNT
+ cFramesDropped DWM_FRAME_COUNT
+ cFramesMissed DWM_FRAME_COUNT
+ cRefreshNextDisplayed DWM_FRAME_COUNT
+ cRefreshNextPresented DWM_FRAME_COUNT
+ cRefreshesDisplayed DWM_FRAME_COUNT
+ cRefreshesPresented DWM_FRAME_COUNT
+ cRefreshStarted DWM_FRAME_COUNT
+ cPixelsReceived uint64
+ cPixelsDrawn uint64
+ cBuffersEmpty DWM_FRAME_COUNT
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/dd389402.aspx
+type MilMatrix3x2D struct {
+ S_11, S_12, S_21, S_22 float64
+ DX, DY float64
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/aa969505.aspx
+type UNSIGNED_RATIO struct {
+ uiNumerator uint32
+ uiDenominator uint32
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/ms632603.aspx
+type CREATESTRUCT struct {
+ CreateParams uintptr
+ Instance HINSTANCE
+ Menu HMENU
+ Parent HWND
+ Cy, Cx int32
+ Y, X int32
+ Style int32
+ Name *uint16
+ Class *uint16
+ dwExStyle uint32
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/dd145065.aspx
+type MONITORINFO struct {
+ CbSize uint32
+ RcMonitor RECT
+ RcWork RECT
+ DwFlags uint32
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/dd145066.aspx
+type MONITORINFOEX struct {
+ MONITORINFO
+ SzDevice [CCHDEVICENAME]uint16
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/dd368826.aspx
+type PIXELFORMATDESCRIPTOR struct {
+ Size uint16
+ Version uint16
+ DwFlags uint32
+ IPixelType byte
+ ColorBits byte
+ RedBits, RedShift byte
+ GreenBits, GreenShift byte
+ BlueBits, BlueShift byte
+ AlphaBits, AlphaShift byte
+ AccumBits byte
+ AccumRedBits byte
+ AccumGreenBits byte
+ AccumBlueBits byte
+ AccumAlphaBits byte
+ DepthBits, StencilBits byte
+ AuxBuffers byte
+ ILayerType byte
+ Reserved byte
+ DwLayerMask uint32
+ DwVisibleMask uint32
+ DwDamageMask uint32
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/ms646270(v=vs.85).aspx
+type INPUT struct {
+ Type uint32
+ Mi MOUSEINPUT
+ Ki KEYBDINPUT
+ Hi HARDWAREINPUT
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/ms646273(v=vs.85).aspx
+type MOUSEINPUT struct {
+ Dx int32
+ Dy int32
+ MouseData uint32
+ DwFlags uint32
+ Time uint32
+ DwExtraInfo uintptr
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/ms646271(v=vs.85).aspx
+type KEYBDINPUT struct {
+ WVk uint16
+ WScan uint16
+ DwFlags uint32
+ Time uint32
+ DwExtraInfo uintptr
+}
+
+// http://msdn.microsoft.com/en-us/library/windows/desktop/ms646269(v=vs.85).aspx
+type HARDWAREINPUT struct {
+ UMsg uint32
+ WParamL uint16
+ WParamH uint16
+}
+
+type KbdInput struct {
+ typ uint32
+ ki KEYBDINPUT
+}
+
+type MouseInput struct {
+ typ uint32
+ mi MOUSEINPUT
+}
+
+type HardwareInput struct {
+ typ uint32
+ hi HARDWAREINPUT
+}
diff --git a/vendor/github.com/shirou/w32/user32.go b/vendor/github.com/shirou/w32/user32.go
new file mode 100644
index 0000000..6aa7cd7
--- /dev/null
+++ b/vendor/github.com/shirou/w32/user32.go
@@ -0,0 +1,950 @@
+// Copyright 2010-2012 The W32 Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build windows
+
+package w32
+
+import (
+ "fmt"
+ "syscall"
+ "unsafe"
+)
+
+var (
+ moduser32 = syscall.NewLazyDLL("user32.dll")
+
+ procRegisterClassEx = moduser32.NewProc("RegisterClassExW")
+ procLoadIcon = moduser32.NewProc("LoadIconW")
+ procLoadCursor = moduser32.NewProc("LoadCursorW")
+ procShowWindow = moduser32.NewProc("ShowWindow")
+ procUpdateWindow = moduser32.NewProc("UpdateWindow")
+ procCreateWindowEx = moduser32.NewProc("CreateWindowExW")
+ procAdjustWindowRect = moduser32.NewProc("AdjustWindowRect")
+ procAdjustWindowRectEx = moduser32.NewProc("AdjustWindowRectEx")
+ procDestroyWindow = moduser32.NewProc("DestroyWindow")
+ procDefWindowProc = moduser32.NewProc("DefWindowProcW")
+ procDefDlgProc = moduser32.NewProc("DefDlgProcW")
+ procPostQuitMessage = moduser32.NewProc("PostQuitMessage")
+ procGetMessage = moduser32.NewProc("GetMessageW")
+ procTranslateMessage = moduser32.NewProc("TranslateMessage")
+ procDispatchMessage = moduser32.NewProc("DispatchMessageW")
+ procSendMessage = moduser32.NewProc("SendMessageW")
+ procPostMessage = moduser32.NewProc("PostMessageW")
+ procWaitMessage = moduser32.NewProc("WaitMessage")
+ procSetWindowText = moduser32.NewProc("SetWindowTextW")
+ procGetWindowTextLength = moduser32.NewProc("GetWindowTextLengthW")
+ procGetWindowText = moduser32.NewProc("GetWindowTextW")
+ procGetWindowRect = moduser32.NewProc("GetWindowRect")
+ procMoveWindow = moduser32.NewProc("MoveWindow")
+ procScreenToClient = moduser32.NewProc("ScreenToClient")
+ procCallWindowProc = moduser32.NewProc("CallWindowProcW")
+ procSetWindowLong = moduser32.NewProc("SetWindowLongW")
+ procSetWindowLongPtr = moduser32.NewProc("SetWindowLongW")
+ procGetWindowLong = moduser32.NewProc("GetWindowLongW")
+ procGetWindowLongPtr = moduser32.NewProc("GetWindowLongW")
+ procEnableWindow = moduser32.NewProc("EnableWindow")
+ procIsWindowEnabled = moduser32.NewProc("IsWindowEnabled")
+ procIsWindowVisible = moduser32.NewProc("IsWindowVisible")
+ procSetFocus = moduser32.NewProc("SetFocus")
+ procInvalidateRect = moduser32.NewProc("InvalidateRect")
+ procGetClientRect = moduser32.NewProc("GetClientRect")
+ procGetDC = moduser32.NewProc("GetDC")
+ procReleaseDC = moduser32.NewProc("ReleaseDC")
+ procSetCapture = moduser32.NewProc("SetCapture")
+ procReleaseCapture = moduser32.NewProc("ReleaseCapture")
+ procGetWindowThreadProcessId = moduser32.NewProc("GetWindowThreadProcessId")
+ procMessageBox = moduser32.NewProc("MessageBoxW")
+ procGetSystemMetrics = moduser32.NewProc("GetSystemMetrics")
+ procCopyRect = moduser32.NewProc("CopyRect")
+ procEqualRect = moduser32.NewProc("EqualRect")
+ procInflateRect = moduser32.NewProc("InflateRect")
+ procIntersectRect = moduser32.NewProc("IntersectRect")
+ procIsRectEmpty = moduser32.NewProc("IsRectEmpty")
+ procOffsetRect = moduser32.NewProc("OffsetRect")
+ procPtInRect = moduser32.NewProc("PtInRect")
+ procSetRect = moduser32.NewProc("SetRect")
+ procSetRectEmpty = moduser32.NewProc("SetRectEmpty")
+ procSubtractRect = moduser32.NewProc("SubtractRect")
+ procUnionRect = moduser32.NewProc("UnionRect")
+ procCreateDialogParam = moduser32.NewProc("CreateDialogParamW")
+ procDialogBoxParam = moduser32.NewProc("DialogBoxParamW")
+ procGetDlgItem = moduser32.NewProc("GetDlgItem")
+ procDrawIcon = moduser32.NewProc("DrawIcon")
+ procClientToScreen = moduser32.NewProc("ClientToScreen")
+ procIsDialogMessage = moduser32.NewProc("IsDialogMessageW")
+ procIsWindow = moduser32.NewProc("IsWindow")
+ procEndDialog = moduser32.NewProc("EndDialog")
+ procPeekMessage = moduser32.NewProc("PeekMessageW")
+ procTranslateAccelerator = moduser32.NewProc("TranslateAcceleratorW")
+ procSetWindowPos = moduser32.NewProc("SetWindowPos")
+ procFillRect = moduser32.NewProc("FillRect")
+ procDrawText = moduser32.NewProc("DrawTextW")
+ procAddClipboardFormatListener = moduser32.NewProc("AddClipboardFormatListener")
+ procRemoveClipboardFormatListener = moduser32.NewProc("RemoveClipboardFormatListener")
+ procOpenClipboard = moduser32.NewProc("OpenClipboard")
+ procCloseClipboard = moduser32.NewProc("CloseClipboard")
+ procEnumClipboardFormats = moduser32.NewProc("EnumClipboardFormats")
+ procGetClipboardData = moduser32.NewProc("GetClipboardData")
+ procSetClipboardData = moduser32.NewProc("SetClipboardData")
+ procEmptyClipboard = moduser32.NewProc("EmptyClipboard")
+ procGetClipboardFormatName = moduser32.NewProc("GetClipboardFormatNameW")
+ procIsClipboardFormatAvailable = moduser32.NewProc("IsClipboardFormatAvailable")
+ procBeginPaint = moduser32.NewProc("BeginPaint")
+ procEndPaint = moduser32.NewProc("EndPaint")
+ procGetKeyboardState = moduser32.NewProc("GetKeyboardState")
+ procMapVirtualKey = moduser32.NewProc("MapVirtualKeyExW")
+ procGetAsyncKeyState = moduser32.NewProc("GetAsyncKeyState")
+ procToAscii = moduser32.NewProc("ToAscii")
+ procSwapMouseButton = moduser32.NewProc("SwapMouseButton")
+ procGetCursorPos = moduser32.NewProc("GetCursorPos")
+ procSetCursorPos = moduser32.NewProc("SetCursorPos")
+ procSetCursor = moduser32.NewProc("SetCursor")
+ procCreateIcon = moduser32.NewProc("CreateIcon")
+ procDestroyIcon = moduser32.NewProc("DestroyIcon")
+ procMonitorFromPoint = moduser32.NewProc("MonitorFromPoint")
+ procMonitorFromRect = moduser32.NewProc("MonitorFromRect")
+ procMonitorFromWindow = moduser32.NewProc("MonitorFromWindow")
+ procGetMonitorInfo = moduser32.NewProc("GetMonitorInfoW")
+ procEnumDisplayMonitors = moduser32.NewProc("EnumDisplayMonitors")
+ procEnumDisplaySettingsEx = moduser32.NewProc("EnumDisplaySettingsExW")
+ procChangeDisplaySettingsEx = moduser32.NewProc("ChangeDisplaySettingsExW")
+ procSendInput = moduser32.NewProc("SendInput")
+)
+
+func RegisterClassEx(wndClassEx *WNDCLASSEX) ATOM {
+ ret, _, _ := procRegisterClassEx.Call(uintptr(unsafe.Pointer(wndClassEx)))
+ return ATOM(ret)
+}
+
+func LoadIcon(instance HINSTANCE, iconName *uint16) HICON {
+ ret, _, _ := procLoadIcon.Call(
+ uintptr(instance),
+ uintptr(unsafe.Pointer(iconName)))
+
+ return HICON(ret)
+
+}
+
+func LoadCursor(instance HINSTANCE, cursorName *uint16) HCURSOR {
+ ret, _, _ := procLoadCursor.Call(
+ uintptr(instance),
+ uintptr(unsafe.Pointer(cursorName)))
+
+ return HCURSOR(ret)
+
+}
+
+func ShowWindow(hwnd HWND, cmdshow int) bool {
+ ret, _, _ := procShowWindow.Call(
+ uintptr(hwnd),
+ uintptr(cmdshow))
+
+ return ret != 0
+
+}
+
+func UpdateWindow(hwnd HWND) bool {
+ ret, _, _ := procUpdateWindow.Call(
+ uintptr(hwnd))
+ return ret != 0
+}
+
+func CreateWindowEx(exStyle uint, className, windowName *uint16,
+ style uint, x, y, width, height int, parent HWND, menu HMENU,
+ instance HINSTANCE, param unsafe.Pointer) HWND {
+ ret, _, _ := procCreateWindowEx.Call(
+ uintptr(exStyle),
+ uintptr(unsafe.Pointer(className)),
+ uintptr(unsafe.Pointer(windowName)),
+ uintptr(style),
+ uintptr(x),
+ uintptr(y),
+ uintptr(width),
+ uintptr(height),
+ uintptr(parent),
+ uintptr(menu),
+ uintptr(instance),
+ uintptr(param))
+
+ return HWND(ret)
+}
+
+func AdjustWindowRectEx(rect *RECT, style uint, menu bool, exStyle uint) bool {
+ ret, _, _ := procAdjustWindowRectEx.Call(
+ uintptr(unsafe.Pointer(rect)),
+ uintptr(style),
+ uintptr(BoolToBOOL(menu)),
+ uintptr(exStyle))
+
+ return ret != 0
+}
+
+func AdjustWindowRect(rect *RECT, style uint, menu bool) bool {
+ ret, _, _ := procAdjustWindowRect.Call(
+ uintptr(unsafe.Pointer(rect)),
+ uintptr(style),
+ uintptr(BoolToBOOL(menu)))
+
+ return ret != 0
+}
+
+func DestroyWindow(hwnd HWND) bool {
+ ret, _, _ := procDestroyWindow.Call(
+ uintptr(hwnd))
+
+ return ret != 0
+}
+
+func DefWindowProc(hwnd HWND, msg uint32, wParam, lParam uintptr) uintptr {
+ ret, _, _ := procDefWindowProc.Call(
+ uintptr(hwnd),
+ uintptr(msg),
+ wParam,
+ lParam)
+
+ return ret
+}
+
+func DefDlgProc(hwnd HWND, msg uint32, wParam, lParam uintptr) uintptr {
+ ret, _, _ := procDefDlgProc.Call(
+ uintptr(hwnd),
+ uintptr(msg),
+ wParam,
+ lParam)
+
+ return ret
+}
+
+func PostQuitMessage(exitCode int) {
+ procPostQuitMessage.Call(
+ uintptr(exitCode))
+}
+
+func GetMessage(msg *MSG, hwnd HWND, msgFilterMin, msgFilterMax uint32) int {
+ ret, _, _ := procGetMessage.Call(
+ uintptr(unsafe.Pointer(msg)),
+ uintptr(hwnd),
+ uintptr(msgFilterMin),
+ uintptr(msgFilterMax))
+
+ return int(ret)
+}
+
+func TranslateMessage(msg *MSG) bool {
+ ret, _, _ := procTranslateMessage.Call(
+ uintptr(unsafe.Pointer(msg)))
+
+ return ret != 0
+
+}
+
+func DispatchMessage(msg *MSG) uintptr {
+ ret, _, _ := procDispatchMessage.Call(
+ uintptr(unsafe.Pointer(msg)))
+
+ return ret
+
+}
+
+func SendMessage(hwnd HWND, msg uint32, wParam, lParam uintptr) uintptr {
+ ret, _, _ := procSendMessage.Call(
+ uintptr(hwnd),
+ uintptr(msg),
+ wParam,
+ lParam)
+
+ return ret
+}
+
+func PostMessage(hwnd HWND, msg uint32, wParam, lParam uintptr) bool {
+ ret, _, _ := procPostMessage.Call(
+ uintptr(hwnd),
+ uintptr(msg),
+ wParam,
+ lParam)
+
+ return ret != 0
+}
+
+func WaitMessage() bool {
+ ret, _, _ := procWaitMessage.Call()
+ return ret != 0
+}
+
+func SetWindowText(hwnd HWND, text string) {
+ procSetWindowText.Call(
+ uintptr(hwnd),
+ uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(text))))
+}
+
+func GetWindowTextLength(hwnd HWND) int {
+ ret, _, _ := procGetWindowTextLength.Call(
+ uintptr(hwnd))
+
+ return int(ret)
+}
+
+func GetWindowText(hwnd HWND) string {
+ textLen := GetWindowTextLength(hwnd) + 1
+
+ buf := make([]uint16, textLen)
+ procGetWindowText.Call(
+ uintptr(hwnd),
+ uintptr(unsafe.Pointer(&buf[0])),
+ uintptr(textLen))
+
+ return syscall.UTF16ToString(buf)
+}
+
+func GetWindowRect(hwnd HWND) *RECT {
+ var rect RECT
+ procGetWindowRect.Call(
+ uintptr(hwnd),
+ uintptr(unsafe.Pointer(&rect)))
+
+ return &rect
+}
+
+func MoveWindow(hwnd HWND, x, y, width, height int, repaint bool) bool {
+ ret, _, _ := procMoveWindow.Call(
+ uintptr(hwnd),
+ uintptr(x),
+ uintptr(y),
+ uintptr(width),
+ uintptr(height),
+ uintptr(BoolToBOOL(repaint)))
+
+ return ret != 0
+
+}
+
+func ScreenToClient(hwnd HWND, x, y int) (X, Y int, ok bool) {
+ pt := POINT{X: int32(x), Y: int32(y)}
+ ret, _, _ := procScreenToClient.Call(
+ uintptr(hwnd),
+ uintptr(unsafe.Pointer(&pt)))
+
+ return int(pt.X), int(pt.Y), ret != 0
+}
+
+func CallWindowProc(preWndProc uintptr, hwnd HWND, msg uint32, wParam, lParam uintptr) uintptr {
+ ret, _, _ := procCallWindowProc.Call(
+ preWndProc,
+ uintptr(hwnd),
+ uintptr(msg),
+ wParam,
+ lParam)
+
+ return ret
+}
+
+func SetWindowLong(hwnd HWND, index int, value uint32) uint32 {
+ ret, _, _ := procSetWindowLong.Call(
+ uintptr(hwnd),
+ uintptr(index),
+ uintptr(value))
+
+ return uint32(ret)
+}
+
+func SetWindowLongPtr(hwnd HWND, index int, value uintptr) uintptr {
+ ret, _, _ := procSetWindowLongPtr.Call(
+ uintptr(hwnd),
+ uintptr(index),
+ value)
+
+ return ret
+}
+
+func GetWindowLong(hwnd HWND, index int) int32 {
+ ret, _, _ := procGetWindowLong.Call(
+ uintptr(hwnd),
+ uintptr(index))
+
+ return int32(ret)
+}
+
+func GetWindowLongPtr(hwnd HWND, index int) uintptr {
+ ret, _, _ := procGetWindowLongPtr.Call(
+ uintptr(hwnd),
+ uintptr(index))
+
+ return ret
+}
+
+func EnableWindow(hwnd HWND, b bool) bool {
+ ret, _, _ := procEnableWindow.Call(
+ uintptr(hwnd),
+ uintptr(BoolToBOOL(b)))
+ return ret != 0
+}
+
+func IsWindowEnabled(hwnd HWND) bool {
+ ret, _, _ := procIsWindowEnabled.Call(
+ uintptr(hwnd))
+
+ return ret != 0
+}
+
+func IsWindowVisible(hwnd HWND) bool {
+ ret, _, _ := procIsWindowVisible.Call(
+ uintptr(hwnd))
+
+ return ret != 0
+}
+
+func SetFocus(hwnd HWND) HWND {
+ ret, _, _ := procSetFocus.Call(
+ uintptr(hwnd))
+
+ return HWND(ret)
+}
+
+func InvalidateRect(hwnd HWND, rect *RECT, erase bool) bool {
+ ret, _, _ := procInvalidateRect.Call(
+ uintptr(hwnd),
+ uintptr(unsafe.Pointer(rect)),
+ uintptr(BoolToBOOL(erase)))
+
+ return ret != 0
+}
+
+func GetClientRect(hwnd HWND) *RECT {
+ var rect RECT
+ ret, _, _ := procGetClientRect.Call(
+ uintptr(hwnd),
+ uintptr(unsafe.Pointer(&rect)))
+
+ if ret == 0 {
+ panic(fmt.Sprintf("GetClientRect(%d) failed", hwnd))
+ }
+
+ return &rect
+}
+
+func GetDC(hwnd HWND) HDC {
+ ret, _, _ := procGetDC.Call(
+ uintptr(hwnd))
+
+ return HDC(ret)
+}
+
+func ReleaseDC(hwnd HWND, hDC HDC) bool {
+ ret, _, _ := procReleaseDC.Call(
+ uintptr(hwnd),
+ uintptr(hDC))
+
+ return ret != 0
+}
+
+func SetCapture(hwnd HWND) HWND {
+ ret, _, _ := procSetCapture.Call(
+ uintptr(hwnd))
+
+ return HWND(ret)
+}
+
+func ReleaseCapture() bool {
+ ret, _, _ := procReleaseCapture.Call()
+
+ return ret != 0
+}
+
+func GetWindowThreadProcessId(hwnd HWND) (HANDLE, int) {
+ var processId int
+ ret, _, _ := procGetWindowThreadProcessId.Call(
+ uintptr(hwnd),
+ uintptr(unsafe.Pointer(&processId)))
+
+ return HANDLE(ret), processId
+}
+
+func MessageBox(hwnd HWND, title, caption string, flags uint) int {
+ ret, _, _ := procMessageBox.Call(
+ uintptr(hwnd),
+ uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(title))),
+ uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(caption))),
+ uintptr(flags))
+
+ return int(ret)
+}
+
+func GetSystemMetrics(index int) int {
+ ret, _, _ := procGetSystemMetrics.Call(
+ uintptr(index))
+
+ return int(ret)
+}
+
+func CopyRect(dst, src *RECT) bool {
+ ret, _, _ := procCopyRect.Call(
+ uintptr(unsafe.Pointer(dst)),
+ uintptr(unsafe.Pointer(src)))
+
+ return ret != 0
+}
+
+func EqualRect(rect1, rect2 *RECT) bool {
+ ret, _, _ := procEqualRect.Call(
+ uintptr(unsafe.Pointer(rect1)),
+ uintptr(unsafe.Pointer(rect2)))
+
+ return ret != 0
+}
+
+func InflateRect(rect *RECT, dx, dy int) bool {
+ ret, _, _ := procInflateRect.Call(
+ uintptr(unsafe.Pointer(rect)),
+ uintptr(dx),
+ uintptr(dy))
+
+ return ret != 0
+}
+
+func IntersectRect(dst, src1, src2 *RECT) bool {
+ ret, _, _ := procIntersectRect.Call(
+ uintptr(unsafe.Pointer(dst)),
+ uintptr(unsafe.Pointer(src1)),
+ uintptr(unsafe.Pointer(src2)))
+
+ return ret != 0
+}
+
+func IsRectEmpty(rect *RECT) bool {
+ ret, _, _ := procIsRectEmpty.Call(
+ uintptr(unsafe.Pointer(rect)))
+
+ return ret != 0
+}
+
+func OffsetRect(rect *RECT, dx, dy int) bool {
+ ret, _, _ := procOffsetRect.Call(
+ uintptr(unsafe.Pointer(rect)),
+ uintptr(dx),
+ uintptr(dy))
+
+ return ret != 0
+}
+
+func PtInRect(rect *RECT, x, y int) bool {
+ pt := POINT{X: int32(x), Y: int32(y)}
+ ret, _, _ := procPtInRect.Call(
+ uintptr(unsafe.Pointer(rect)),
+ uintptr(unsafe.Pointer(&pt)))
+
+ return ret != 0
+}
+
+func SetRect(rect *RECT, left, top, right, bottom int) bool {
+ ret, _, _ := procSetRect.Call(
+ uintptr(unsafe.Pointer(rect)),
+ uintptr(left),
+ uintptr(top),
+ uintptr(right),
+ uintptr(bottom))
+
+ return ret != 0
+}
+
+func SetRectEmpty(rect *RECT) bool {
+ ret, _, _ := procSetRectEmpty.Call(
+ uintptr(unsafe.Pointer(rect)))
+
+ return ret != 0
+}
+
+func SubtractRect(dst, src1, src2 *RECT) bool {
+ ret, _, _ := procSubtractRect.Call(
+ uintptr(unsafe.Pointer(dst)),
+ uintptr(unsafe.Pointer(src1)),
+ uintptr(unsafe.Pointer(src2)))
+
+ return ret != 0
+}
+
+func UnionRect(dst, src1, src2 *RECT) bool {
+ ret, _, _ := procUnionRect.Call(
+ uintptr(unsafe.Pointer(dst)),
+ uintptr(unsafe.Pointer(src1)),
+ uintptr(unsafe.Pointer(src2)))
+
+ return ret != 0
+}
+
+func CreateDialog(hInstance HINSTANCE, lpTemplate *uint16, hWndParent HWND, lpDialogProc uintptr) HWND {
+ ret, _, _ := procCreateDialogParam.Call(
+ uintptr(hInstance),
+ uintptr(unsafe.Pointer(lpTemplate)),
+ uintptr(hWndParent),
+ lpDialogProc,
+ 0)
+
+ return HWND(ret)
+}
+
+func DialogBox(hInstance HINSTANCE, lpTemplateName *uint16, hWndParent HWND, lpDialogProc uintptr) int {
+ ret, _, _ := procDialogBoxParam.Call(
+ uintptr(hInstance),
+ uintptr(unsafe.Pointer(lpTemplateName)),
+ uintptr(hWndParent),
+ lpDialogProc,
+ 0)
+
+ return int(ret)
+}
+
+func GetDlgItem(hDlg HWND, nIDDlgItem int) HWND {
+ ret, _, _ := procGetDlgItem.Call(
+ uintptr(unsafe.Pointer(hDlg)),
+ uintptr(nIDDlgItem))
+
+ return HWND(ret)
+}
+
+func DrawIcon(hDC HDC, x, y int, hIcon HICON) bool {
+ ret, _, _ := procDrawIcon.Call(
+ uintptr(unsafe.Pointer(hDC)),
+ uintptr(x),
+ uintptr(y),
+ uintptr(unsafe.Pointer(hIcon)))
+
+ return ret != 0
+}
+
+func ClientToScreen(hwnd HWND, x, y int) (int, int) {
+ pt := POINT{X: int32(x), Y: int32(y)}
+
+ procClientToScreen.Call(
+ uintptr(hwnd),
+ uintptr(unsafe.Pointer(&pt)))
+
+ return int(pt.X), int(pt.Y)
+}
+
+func IsDialogMessage(hwnd HWND, msg *MSG) bool {
+ ret, _, _ := procIsDialogMessage.Call(
+ uintptr(hwnd),
+ uintptr(unsafe.Pointer(msg)))
+
+ return ret != 0
+}
+
+func IsWindow(hwnd HWND) bool {
+ ret, _, _ := procIsWindow.Call(
+ uintptr(hwnd))
+
+ return ret != 0
+}
+
+func EndDialog(hwnd HWND, nResult uintptr) bool {
+ ret, _, _ := procEndDialog.Call(
+ uintptr(hwnd),
+ nResult)
+
+ return ret != 0
+}
+
+func PeekMessage(lpMsg *MSG, hwnd HWND, wMsgFilterMin, wMsgFilterMax, wRemoveMsg uint32) bool {
+ ret, _, _ := procPeekMessage.Call(
+ uintptr(unsafe.Pointer(lpMsg)),
+ uintptr(hwnd),
+ uintptr(wMsgFilterMin),
+ uintptr(wMsgFilterMax),
+ uintptr(wRemoveMsg))
+
+ return ret != 0
+}
+
+func TranslateAccelerator(hwnd HWND, hAccTable HACCEL, lpMsg *MSG) bool {
+ ret, _, _ := procTranslateMessage.Call(
+ uintptr(hwnd),
+ uintptr(hAccTable),
+ uintptr(unsafe.Pointer(lpMsg)))
+
+ return ret != 0
+}
+
+func SetWindowPos(hwnd, hWndInsertAfter HWND, x, y, cx, cy int, uFlags uint) bool {
+ ret, _, _ := procSetWindowPos.Call(
+ uintptr(hwnd),
+ uintptr(hWndInsertAfter),
+ uintptr(x),
+ uintptr(y),
+ uintptr(cx),
+ uintptr(cy),
+ uintptr(uFlags))
+
+ return ret != 0
+}
+
+func FillRect(hDC HDC, lprc *RECT, hbr HBRUSH) bool {
+ ret, _, _ := procFillRect.Call(
+ uintptr(hDC),
+ uintptr(unsafe.Pointer(lprc)),
+ uintptr(hbr))
+
+ return ret != 0
+}
+
+func DrawText(hDC HDC, text string, uCount int, lpRect *RECT, uFormat uint) int {
+ ret, _, _ := procDrawText.Call(
+ uintptr(hDC),
+ uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(text))),
+ uintptr(uCount),
+ uintptr(unsafe.Pointer(lpRect)),
+ uintptr(uFormat))
+
+ return int(ret)
+}
+
+func AddClipboardFormatListener(hwnd HWND) bool {
+ ret, _, _ := procAddClipboardFormatListener.Call(
+ uintptr(hwnd))
+ return ret != 0
+}
+
+func RemoveClipboardFormatListener(hwnd HWND) bool {
+ ret, _, _ := procRemoveClipboardFormatListener.Call(
+ uintptr(hwnd))
+ return ret != 0
+}
+
+func OpenClipboard(hWndNewOwner HWND) bool {
+ ret, _, _ := procOpenClipboard.Call(
+ uintptr(hWndNewOwner))
+ return ret != 0
+}
+
+func CloseClipboard() bool {
+ ret, _, _ := procCloseClipboard.Call()
+ return ret != 0
+}
+
+func EnumClipboardFormats(format uint) uint {
+ ret, _, _ := procEnumClipboardFormats.Call(
+ uintptr(format))
+ return uint(ret)
+}
+
+func GetClipboardData(uFormat uint) HANDLE {
+ ret, _, _ := procGetClipboardData.Call(
+ uintptr(uFormat))
+ return HANDLE(ret)
+}
+
+func SetClipboardData(uFormat uint, hMem HANDLE) HANDLE {
+ ret, _, _ := procSetClipboardData.Call(
+ uintptr(uFormat),
+ uintptr(hMem))
+ return HANDLE(ret)
+}
+
+func EmptyClipboard() bool {
+ ret, _, _ := procEmptyClipboard.Call()
+ return ret != 0
+}
+
+func GetClipboardFormatName(format uint) (string, bool) {
+ cchMaxCount := 255
+ buf := make([]uint16, cchMaxCount)
+ ret, _, _ := procGetClipboardFormatName.Call(
+ uintptr(format),
+ uintptr(unsafe.Pointer(&buf[0])),
+ uintptr(cchMaxCount))
+
+ if ret > 0 {
+ return syscall.UTF16ToString(buf), true
+ }
+
+ return "Requested format does not exist or is predefined", false
+}
+
+func IsClipboardFormatAvailable(format uint) bool {
+ ret, _, _ := procIsClipboardFormatAvailable.Call(uintptr(format))
+ return ret != 0
+}
+
+func BeginPaint(hwnd HWND, paint *PAINTSTRUCT) HDC {
+ ret, _, _ := procBeginPaint.Call(
+ uintptr(hwnd),
+ uintptr(unsafe.Pointer(paint)))
+ return HDC(ret)
+}
+
+func EndPaint(hwnd HWND, paint *PAINTSTRUCT) {
+ procBeginPaint.Call(
+ uintptr(hwnd),
+ uintptr(unsafe.Pointer(paint)))
+}
+
+func GetKeyboardState(lpKeyState *[]byte) bool {
+ ret, _, _ := procGetKeyboardState.Call(
+ uintptr(unsafe.Pointer(&(*lpKeyState)[0])))
+ return ret != 0
+}
+
+func MapVirtualKeyEx(uCode, uMapType uint, dwhkl HKL) uint {
+ ret, _, _ := procMapVirtualKey.Call(
+ uintptr(uCode),
+ uintptr(uMapType),
+ uintptr(dwhkl))
+ return uint(ret)
+}
+
+func GetAsyncKeyState(vKey int) uint16 {
+ ret, _, _ := procGetAsyncKeyState.Call(uintptr(vKey))
+ return uint16(ret)
+}
+
+func ToAscii(uVirtKey, uScanCode uint, lpKeyState *byte, lpChar *uint16, uFlags uint) int {
+ ret, _, _ := procToAscii.Call(
+ uintptr(uVirtKey),
+ uintptr(uScanCode),
+ uintptr(unsafe.Pointer(lpKeyState)),
+ uintptr(unsafe.Pointer(lpChar)),
+ uintptr(uFlags))
+ return int(ret)
+}
+
+func SwapMouseButton(fSwap bool) bool {
+ ret, _, _ := procSwapMouseButton.Call(
+ uintptr(BoolToBOOL(fSwap)))
+ return ret != 0
+}
+
+func GetCursorPos() (x, y int, ok bool) {
+ pt := POINT{}
+ ret, _, _ := procGetCursorPos.Call(uintptr(unsafe.Pointer(&pt)))
+ return int(pt.X), int(pt.Y), ret != 0
+}
+
+func SetCursorPos(x, y int) bool {
+ ret, _, _ := procSetCursorPos.Call(
+ uintptr(x),
+ uintptr(y),
+ )
+ return ret != 0
+}
+
+func SetCursor(cursor HCURSOR) HCURSOR {
+ ret, _, _ := procSetCursor.Call(
+ uintptr(cursor),
+ )
+ return HCURSOR(ret)
+}
+
+func CreateIcon(instance HINSTANCE, nWidth, nHeight int, cPlanes, cBitsPerPixel byte, ANDbits, XORbits *byte) HICON {
+ ret, _, _ := procCreateIcon.Call(
+ uintptr(instance),
+ uintptr(nWidth),
+ uintptr(nHeight),
+ uintptr(cPlanes),
+ uintptr(cBitsPerPixel),
+ uintptr(unsafe.Pointer(ANDbits)),
+ uintptr(unsafe.Pointer(XORbits)),
+ )
+ return HICON(ret)
+}
+
+func DestroyIcon(icon HICON) bool {
+ ret, _, _ := procDestroyIcon.Call(
+ uintptr(icon),
+ )
+ return ret != 0
+}
+
+func MonitorFromPoint(x, y int, dwFlags uint32) HMONITOR {
+ ret, _, _ := procMonitorFromPoint.Call(
+ uintptr(x),
+ uintptr(y),
+ uintptr(dwFlags),
+ )
+ return HMONITOR(ret)
+}
+
+func MonitorFromRect(rc *RECT, dwFlags uint32) HMONITOR {
+ ret, _, _ := procMonitorFromRect.Call(
+ uintptr(unsafe.Pointer(rc)),
+ uintptr(dwFlags),
+ )
+ return HMONITOR(ret)
+}
+
+func MonitorFromWindow(hwnd HWND, dwFlags uint32) HMONITOR {
+ ret, _, _ := procMonitorFromWindow.Call(
+ uintptr(hwnd),
+ uintptr(dwFlags),
+ )
+ return HMONITOR(ret)
+}
+
+func GetMonitorInfo(hMonitor HMONITOR, lmpi *MONITORINFO) bool {
+ ret, _, _ := procGetMonitorInfo.Call(
+ uintptr(hMonitor),
+ uintptr(unsafe.Pointer(lmpi)),
+ )
+ return ret != 0
+}
+
+func EnumDisplayMonitors(hdc HDC, clip *RECT, fnEnum, dwData uintptr) bool {
+ ret, _, _ := procEnumDisplayMonitors.Call(
+ uintptr(hdc),
+ uintptr(unsafe.Pointer(clip)),
+ fnEnum,
+ dwData,
+ )
+ return ret != 0
+}
+
+func EnumDisplaySettingsEx(szDeviceName *uint16, iModeNum uint32, devMode *DEVMODE, dwFlags uint32) bool {
+ ret, _, _ := procEnumDisplaySettingsEx.Call(
+ uintptr(unsafe.Pointer(szDeviceName)),
+ uintptr(iModeNum),
+ uintptr(unsafe.Pointer(devMode)),
+ uintptr(dwFlags),
+ )
+ return ret != 0
+}
+
+func ChangeDisplaySettingsEx(szDeviceName *uint16, devMode *DEVMODE, hwnd HWND, dwFlags uint32, lParam uintptr) int32 {
+ ret, _, _ := procChangeDisplaySettingsEx.Call(
+ uintptr(unsafe.Pointer(szDeviceName)),
+ uintptr(unsafe.Pointer(devMode)),
+ uintptr(hwnd),
+ uintptr(dwFlags),
+ lParam,
+ )
+ return int32(ret)
+}
+
+/* remove to build without cgo
+func SendInput(inputs []INPUT) uint32 {
+ var validInputs []C.INPUT
+
+ for _, oneInput := range inputs {
+ input := C.INPUT{_type: C.DWORD(oneInput.Type)}
+
+ switch oneInput.Type {
+ case INPUT_MOUSE:
+ (*MouseInput)(unsafe.Pointer(&input)).mi = oneInput.Mi
+ case INPUT_KEYBOARD:
+ (*KbdInput)(unsafe.Pointer(&input)).ki = oneInput.Ki
+ case INPUT_HARDWARE:
+ (*HardwareInput)(unsafe.Pointer(&input)).hi = oneInput.Hi
+ default:
+ panic("unkown type")
+ }
+
+ validInputs = append(validInputs, input)
+ }
+
+ ret, _, _ := procSendInput.Call(
+ uintptr(len(validInputs)),
+ uintptr(unsafe.Pointer(&validInputs[0])),
+ uintptr(unsafe.Sizeof(C.INPUT{})),
+ )
+ return uint32(ret)
+}
+*/
diff --git a/vendor/github.com/shirou/w32/utils.go b/vendor/github.com/shirou/w32/utils.go
new file mode 100644
index 0000000..69aa31a
--- /dev/null
+++ b/vendor/github.com/shirou/w32/utils.go
@@ -0,0 +1,203 @@
+// Copyright 2010-2012 The W32 Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build windows
+
+package w32
+
+import (
+ "syscall"
+ "unicode/utf16"
+ "unsafe"
+)
+
+func MakeIntResource(id uint16) *uint16 {
+ return (*uint16)(unsafe.Pointer(uintptr(id)))
+}
+
+func LOWORD(dw uint32) uint16 {
+ return uint16(dw)
+}
+
+func HIWORD(dw uint32) uint16 {
+ return uint16(dw >> 16 & 0xffff)
+}
+
+func BoolToBOOL(value bool) BOOL {
+ if value {
+ return 1
+ }
+
+ return 0
+}
+
+func UTF16PtrToString(cstr *uint16) string {
+ if cstr != nil {
+ us := make([]uint16, 0, 256)
+ for p := uintptr(unsafe.Pointer(cstr)); ; p += 2 {
+ u := *(*uint16)(unsafe.Pointer(p))
+ if u == 0 {
+ return string(utf16.Decode(us))
+ }
+ us = append(us, u)
+ }
+ }
+
+ return ""
+}
+
+func ComAddRef(unknown *IUnknown) int32 {
+ ret, _, _ := syscall.Syscall(unknown.lpVtbl.pAddRef, 1,
+ uintptr(unsafe.Pointer(unknown)),
+ 0,
+ 0)
+ return int32(ret)
+}
+
+func ComRelease(unknown *IUnknown) int32 {
+ ret, _, _ := syscall.Syscall(unknown.lpVtbl.pRelease, 1,
+ uintptr(unsafe.Pointer(unknown)),
+ 0,
+ 0)
+ return int32(ret)
+}
+
+func ComQueryInterface(unknown *IUnknown, id *GUID) *IDispatch {
+ var disp *IDispatch
+ hr, _, _ := syscall.Syscall(unknown.lpVtbl.pQueryInterface, 3,
+ uintptr(unsafe.Pointer(unknown)),
+ uintptr(unsafe.Pointer(id)),
+ uintptr(unsafe.Pointer(&disp)))
+ if hr != 0 {
+ panic("Invoke QieryInterface error.")
+ }
+ return disp
+}
+
+func ComGetIDsOfName(disp *IDispatch, names []string) []int32 {
+ wnames := make([]*uint16, len(names))
+ dispid := make([]int32, len(names))
+ for i := 0; i < len(names); i++ {
+ wnames[i] = syscall.StringToUTF16Ptr(names[i])
+ }
+ hr, _, _ := syscall.Syscall6(disp.lpVtbl.pGetIDsOfNames, 6,
+ uintptr(unsafe.Pointer(disp)),
+ uintptr(unsafe.Pointer(IID_NULL)),
+ uintptr(unsafe.Pointer(&wnames[0])),
+ uintptr(len(names)),
+ uintptr(GetUserDefaultLCID()),
+ uintptr(unsafe.Pointer(&dispid[0])))
+ if hr != 0 {
+ panic("Invoke GetIDsOfName error.")
+ }
+ return dispid
+}
+
+func ComInvoke(disp *IDispatch, dispid int32, dispatch int16, params ...interface{}) (result *VARIANT) {
+ var dispparams DISPPARAMS
+
+ if dispatch&DISPATCH_PROPERTYPUT != 0 {
+ dispnames := [1]int32{DISPID_PROPERTYPUT}
+ dispparams.RgdispidNamedArgs = uintptr(unsafe.Pointer(&dispnames[0]))
+ dispparams.CNamedArgs = 1
+ }
+ var vargs []VARIANT
+ if len(params) > 0 {
+ vargs = make([]VARIANT, len(params))
+ for i, v := range params {
+ //n := len(params)-i-1
+ n := len(params) - i - 1
+ VariantInit(&vargs[n])
+ switch v.(type) {
+ case bool:
+ if v.(bool) {
+ vargs[n] = VARIANT{VT_BOOL, 0, 0, 0, 0xffff}
+ } else {
+ vargs[n] = VARIANT{VT_BOOL, 0, 0, 0, 0}
+ }
+ case *bool:
+ vargs[n] = VARIANT{VT_BOOL | VT_BYREF, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(*bool))))}
+ case byte:
+ vargs[n] = VARIANT{VT_I1, 0, 0, 0, int64(v.(byte))}
+ case *byte:
+ vargs[n] = VARIANT{VT_I1 | VT_BYREF, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(*byte))))}
+ case int16:
+ vargs[n] = VARIANT{VT_I2, 0, 0, 0, int64(v.(int16))}
+ case *int16:
+ vargs[n] = VARIANT{VT_I2 | VT_BYREF, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(*int16))))}
+ case uint16:
+ vargs[n] = VARIANT{VT_UI2, 0, 0, 0, int64(v.(int16))}
+ case *uint16:
+ vargs[n] = VARIANT{VT_UI2 | VT_BYREF, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(*uint16))))}
+ case int, int32:
+ vargs[n] = VARIANT{VT_UI4, 0, 0, 0, int64(v.(int))}
+ case *int, *int32:
+ vargs[n] = VARIANT{VT_I4 | VT_BYREF, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(*int))))}
+ case uint, uint32:
+ vargs[n] = VARIANT{VT_UI4, 0, 0, 0, int64(v.(uint))}
+ case *uint, *uint32:
+ vargs[n] = VARIANT{VT_UI4 | VT_BYREF, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(*uint))))}
+ case int64:
+ vargs[n] = VARIANT{VT_I8, 0, 0, 0, v.(int64)}
+ case *int64:
+ vargs[n] = VARIANT{VT_I8 | VT_BYREF, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(*int64))))}
+ case uint64:
+ vargs[n] = VARIANT{VT_UI8, 0, 0, 0, int64(v.(uint64))}
+ case *uint64:
+ vargs[n] = VARIANT{VT_UI8 | VT_BYREF, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(*uint64))))}
+ case float32:
+ vargs[n] = VARIANT{VT_R4, 0, 0, 0, int64(v.(float32))}
+ case *float32:
+ vargs[n] = VARIANT{VT_R4 | VT_BYREF, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(*float32))))}
+ case float64:
+ vargs[n] = VARIANT{VT_R8, 0, 0, 0, int64(v.(float64))}
+ case *float64:
+ vargs[n] = VARIANT{VT_R8 | VT_BYREF, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(*float64))))}
+ case string:
+ vargs[n] = VARIANT{VT_BSTR, 0, 0, 0, int64(uintptr(unsafe.Pointer(SysAllocString(v.(string)))))}
+ case *string:
+ vargs[n] = VARIANT{VT_BSTR | VT_BYREF, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(*string))))}
+ case *IDispatch:
+ vargs[n] = VARIANT{VT_DISPATCH, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(*IDispatch))))}
+ case **IDispatch:
+ vargs[n] = VARIANT{VT_DISPATCH | VT_BYREF, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(**IDispatch))))}
+ case nil:
+ vargs[n] = VARIANT{VT_NULL, 0, 0, 0, 0}
+ case *VARIANT:
+ vargs[n] = VARIANT{VT_VARIANT | VT_BYREF, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(*VARIANT))))}
+ default:
+ panic("unknown type")
+ }
+ }
+ dispparams.Rgvarg = uintptr(unsafe.Pointer(&vargs[0]))
+ dispparams.CArgs = uint32(len(params))
+ }
+
+ var ret VARIANT
+ var excepInfo EXCEPINFO
+ VariantInit(&ret)
+ hr, _, _ := syscall.Syscall9(disp.lpVtbl.pInvoke, 8,
+ uintptr(unsafe.Pointer(disp)),
+ uintptr(dispid),
+ uintptr(unsafe.Pointer(IID_NULL)),
+ uintptr(GetUserDefaultLCID()),
+ uintptr(dispatch),
+ uintptr(unsafe.Pointer(&dispparams)),
+ uintptr(unsafe.Pointer(&ret)),
+ uintptr(unsafe.Pointer(&excepInfo)),
+ 0)
+ if hr != 0 {
+ if excepInfo.BstrDescription != nil {
+ bs := UTF16PtrToString(excepInfo.BstrDescription)
+ panic(bs)
+ }
+ }
+ for _, varg := range vargs {
+ if varg.VT == VT_BSTR && varg.Val != 0 {
+ SysFreeString(((*int16)(unsafe.Pointer(uintptr(varg.Val)))))
+ }
+ }
+ result = &ret
+ return
+}
diff --git a/vendor/github.com/shirou/w32/vars.go b/vendor/github.com/shirou/w32/vars.go
new file mode 100644
index 0000000..2dab2e3
--- /dev/null
+++ b/vendor/github.com/shirou/w32/vars.go
@@ -0,0 +1,13 @@
+// Copyright 2010-2012 The W32 Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package w32
+
+var (
+ IID_NULL = &GUID{0x00000000, 0x0000, 0x0000, [8]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}
+ IID_IUnknown = &GUID{0x00000000, 0x0000, 0x0000, [8]byte{0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46}}
+ IID_IDispatch = &GUID{0x00020400, 0x0000, 0x0000, [8]byte{0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46}}
+ IID_IConnectionPointContainer = &GUID{0xB196B284, 0xBAB4, 0x101A, [8]byte{0xB6, 0x9C, 0x00, 0xAA, 0x00, 0x34, 0x1D, 0x07}}
+ IID_IConnectionPoint = &GUID{0xB196B286, 0xBAB4, 0x101A, [8]byte{0xB6, 0x9C, 0x00, 0xAA, 0x00, 0x34, 0x1D, 0x07}}
+)
diff --git a/vendor/github.com/signalfx/sapm-proto/LICENSE b/vendor/github.com/signalfx/sapm-proto/LICENSE
new file mode 100644
index 0000000..261eeb9
--- /dev/null
+++ b/vendor/github.com/signalfx/sapm-proto/LICENSE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/vendor/github.com/signalfx/sapm-proto/client/client.go b/vendor/github.com/signalfx/sapm-proto/client/client.go
new file mode 100644
index 0000000..29ab5c8
--- /dev/null
+++ b/vendor/github.com/signalfx/sapm-proto/client/client.go
@@ -0,0 +1,176 @@
+// Copyright 2019 Splunk, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package client
+
+import (
+ "context"
+ "fmt"
+ "net"
+ "net/http"
+ "sync"
+ "time"
+
+ jaegerpb "github.com/jaegertracing/jaeger/model"
+ "go.opencensus.io/stats/view"
+)
+
+const (
+ idleConnTimeout = 30 * time.Second
+ tlsHandshakeTimeout = 10 * time.Second
+ dialerTimeout = 30 * time.Second
+ dialerKeepAlive = 30 * time.Second
+
+ // default values
+ defaultNumWorkers uint = 8
+ defaultMaxRetries uint = 8
+ defaultMaxIdleCons = 100
+ defaultHTTPTimeout = 10 * time.Second
+)
+
+type sendRequest struct {
+ message []byte
+ spans int64
+ batches int64
+}
+
+// Client implements an HTTP sender for the SAPM protocol
+type Client struct {
+ numWorkers uint
+ maxIdleCons uint
+ endpoint string
+ accessToken string
+ httpClient *http.Client
+ disableCompression bool
+ closeCh chan struct{}
+
+ workers chan *worker
+}
+
+// New creates a new SAPM Client
+func New(opts ...Option) (*Client, error) {
+ views := metricViews()
+ if err := view.Register(views...); err != nil {
+ return nil, err
+ }
+
+ c := &Client{
+ numWorkers: defaultNumWorkers,
+ maxIdleCons: defaultMaxIdleCons,
+ }
+
+ for _, opt := range opts {
+ err := opt(c)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ if c.endpoint == "" {
+ return nil, fmt.Errorf(
+ "endpoint cannot be empty. WithEndpoint option must be called with a valid endpoint value",
+ )
+ }
+
+ if c.httpClient == nil {
+ c.httpClient = &http.Client{
+ Timeout: defaultHTTPTimeout,
+ Transport: &http.Transport{
+ Proxy: http.ProxyFromEnvironment,
+ DialContext: (&net.Dialer{
+ Timeout: dialerTimeout,
+ KeepAlive: dialerKeepAlive,
+ }).DialContext,
+ MaxIdleConns: int(c.maxIdleCons),
+ MaxIdleConnsPerHost: int(c.maxIdleCons),
+ IdleConnTimeout: idleConnTimeout,
+ TLSHandshakeTimeout: tlsHandshakeTimeout,
+ },
+ }
+ }
+
+ c.closeCh = make(chan struct{})
+ c.workers = make(chan *worker, c.numWorkers)
+ for i := uint(0); i < c.numWorkers; i++ {
+ w := newWorker(c.httpClient, c.endpoint, c.accessToken, c.disableCompression)
+ c.workers <- w
+ }
+
+ return c, nil
+}
+
+// Export takes a Jaeger batches and uses one of the available workers to export it synchronously.
+// It returns an error in case a request cannot be processed. It's up to the caller to retry.
+func (sa *Client) Export(ctx context.Context, batches []*jaegerpb.Batch) error {
+ w := <-sa.workers
+ sendErr := w.export(ctx, batches)
+ sa.workers <- w
+ if sendErr != nil {
+ if sendErr.RetryDelaySeconds > 0 {
+ go sa.pauseForDuration(time.Duration(sendErr.RetryDelaySeconds) * time.Second)
+ }
+ return sendErr
+ }
+ return nil
+}
+
+// Stop waits for all inflight requests to finish and then drains the worker pool so no more work can be done.
+// It returns once all workers are drained from the pool. Note that the client can accept new requests while
+// Stop() waits for other requests to finish.
+func (sa *Client) Stop() {
+ wg := sync.WaitGroup{}
+ wg.Add(int(sa.numWorkers))
+ close(sa.closeCh)
+ for i := uint(0); i < sa.numWorkers; i++ {
+ go func() {
+ <-sa.workers
+ wg.Done()
+ }()
+ }
+ wg.Wait()
+}
+
+// pauseForDuration takes workers all workers from the pool and holds on to them until either the duration passes or
+// the client is stopped.
+func (sa *Client) pauseForDuration(d time.Duration) {
+ if d <= 0 {
+ return
+ }
+
+ done := make(chan struct{})
+ workers := make([]*worker, 0, sa.numWorkers)
+ ticker := time.NewTicker(d)
+
+ // steal all workers from pool and hold them until time passes
+ go func() {
+ loop:
+ for {
+ select {
+ case w := <-sa.workers:
+ workers = append(workers, w)
+ case <-ticker.C:
+ break loop
+ case <-sa.closeCh:
+ break loop
+ }
+ }
+ close(done)
+ }()
+
+ <-done
+ // return held workers back to the pool
+ for _, w := range workers {
+ sa.workers <- w
+ }
+}
diff --git a/vendor/github.com/signalfx/sapm-proto/client/errors.go b/vendor/github.com/signalfx/sapm-proto/client/errors.go
new file mode 100644
index 0000000..60ce4b1
--- /dev/null
+++ b/vendor/github.com/signalfx/sapm-proto/client/errors.go
@@ -0,0 +1,27 @@
+// Copyright 2019 Splunk, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package client
+
+// ErrSend is returned by the HTTP sender when it fails to complete a request for any reason.
+type ErrSend struct {
+ Err error
+ StatusCode int
+ Permanent bool
+ RetryDelaySeconds int
+}
+
+func (e *ErrSend) Error() string {
+ return e.Err.Error()
+}
diff --git a/vendor/github.com/signalfx/sapm-proto/client/metrics.go b/vendor/github.com/signalfx/sapm-proto/client/metrics.go
new file mode 100644
index 0000000..083ebd5
--- /dev/null
+++ b/vendor/github.com/signalfx/sapm-proto/client/metrics.go
@@ -0,0 +1,67 @@
+// Copyright 2019 Splunk, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package client
+
+import (
+ "context"
+
+ "go.opencensus.io/stats"
+ "go.opencensus.io/stats/view"
+)
+
+var mFailedEncodings = stats.Int64("sapm/encodings_failed", "Number of times encoding/compressing a request failed", stats.UnitDimensionless)
+var mRequestsCompleted = stats.Int64("sapm/requests_completed", "Number of HTTP requests made successfully", stats.UnitDimensionless)
+var mRequestsFailed = stats.Int64("sapm/requests_failed", "Number of failed HTTP requests", stats.UnitDimensionless)
+var mBatchesDropped = stats.Int64("sapm/batches_dropped", "Number of batches dropped", stats.UnitDimensionless)
+var mSpansDropped = stats.Int64("sapm/spans_dropped", "Number of spans dropped", stats.UnitDimensionless)
+var mBatchesExported = stats.Int64("sapm/batches_exported", "Number of batches successfully exporter", stats.UnitDimensionless)
+var mSpansExported = stats.Int64("sapm/spans_exported", "Number of spans successfully exporter", stats.UnitDimensionless)
+
+func newMetricsView(m stats.Measure) *view.View {
+ return &view.View{
+ Name: m.Name(),
+ Measure: m,
+ Description: m.Description(),
+ Aggregation: view.Sum(),
+ }
+}
+
+func metricViews() []*view.View {
+ return []*view.View{
+ newMetricsView(mFailedEncodings),
+ newMetricsView(mRequestsCompleted),
+ newMetricsView(mRequestsFailed),
+ newMetricsView(mBatchesDropped),
+ newMetricsView(mBatchesExported),
+ newMetricsView(mSpansDropped),
+ newMetricsView(mSpansExported),
+ }
+}
+
+func recordEncodingFailure(ctx context.Context, sr *sendRequest) {
+ stats.Record(ctx, mFailedEncodings.M(1))
+}
+
+func recordSendFailure(ctx context.Context, sr *sendRequest) {
+ stats.Record(ctx, mRequestsFailed.M(1))
+}
+
+func recordDrops(ctx context.Context, sr *sendRequest) {
+ stats.Record(ctx, mBatchesDropped.M(sr.batches), mSpansDropped.M(sr.spans))
+}
+
+func recordSuccess(ctx context.Context, sr *sendRequest) {
+ stats.Record(ctx, mBatchesExported.M(sr.batches), mSpansExported.M(sr.spans))
+}
diff --git a/vendor/github.com/signalfx/sapm-proto/client/mock_http_client.go b/vendor/github.com/signalfx/sapm-proto/client/mock_http_client.go
new file mode 100644
index 0000000..481c6e5
--- /dev/null
+++ b/vendor/github.com/signalfx/sapm-proto/client/mock_http_client.go
@@ -0,0 +1,92 @@
+// Copyright 2019 Splunk, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package client
+
+import (
+ "io/ioutil"
+ "net/http"
+ "strings"
+ "sync"
+ "time"
+)
+
+type request struct {
+ r *http.Request
+ receivedAt time.Time
+}
+
+type mockTransport struct {
+ sync.Mutex
+ delay time.Duration
+ statusCode int
+ headers map[string]string
+ err error
+ received []*request
+}
+
+func (m *mockTransport) RoundTrip(r *http.Request) (*http.Response, error) {
+ if m.delay > 0 {
+ time.Sleep(m.delay)
+ }
+ m.record(r)
+ if m.err != nil {
+ return nil, m.err
+ }
+
+ resp := &http.Response{
+ StatusCode: m.statusCode,
+ Body: ioutil.NopCloser(strings.NewReader("")),
+ }
+ resp.Header = http.Header{}
+ for k, v := range m.headers {
+ resp.Header.Add(k, v)
+ }
+ return resp, nil
+}
+
+func (m *mockTransport) reset(code int) {
+ m.Lock()
+ m.delay = time.Duration(0)
+ m.statusCode = code
+ m.received = []*request{}
+ m.Unlock()
+}
+
+func (m *mockTransport) record(r *http.Request) {
+ m.Lock()
+ m.received = append(m.received, &request{r, time.Now()})
+ m.Unlock()
+}
+
+func (m *mockTransport) requests() []*request {
+ m.Lock()
+ r := make([]*request, len(m.received))
+ copy(r, m.received)
+ defer m.Unlock()
+ return r
+}
+
+func newMockHTTPClient(m *mockTransport) *http.Client {
+ if m.statusCode == 0 {
+ m.statusCode = 200
+ }
+ if m.received == nil {
+ m.received = []*request{}
+ }
+ if m.headers == nil {
+ m.headers = map[string]string{}
+ }
+ return &http.Client{Transport: m}
+}
diff --git a/vendor/github.com/signalfx/sapm-proto/client/oc_status_code.go b/vendor/github.com/signalfx/sapm-proto/client/oc_status_code.go
new file mode 100644
index 0000000..c5165bc
--- /dev/null
+++ b/vendor/github.com/signalfx/sapm-proto/client/oc_status_code.go
@@ -0,0 +1,78 @@
+// Copyright 2019 Splunk, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package client
+
+// This code is taken from OpenTelemetry project in order to avoid adding the whole project as a dependency.
+
+// https://github.com/googleapis/googleapis/blob/bee79fbe03254a35db125dc6d2f1e9b752b390fe/google/rpc/code.proto#L33-L186
+const (
+ OCOK = 0
+ OCCancelled = 1
+ OCUnknown = 2
+ OCInvalidArgument = 3
+ OCDeadlineExceeded = 4
+ OCNotFound = 5
+ OCAlreadyExists = 6
+ OCPermissionDenied = 7
+ OCResourceExhausted = 8
+ OCFailedPrecondition = 9
+ OCAborted = 10
+ OCOutOfRange = 11
+ OCUnimplemented = 12
+ OCInternal = 13
+ OCUnavailable = 14
+ OCDataLoss = 15
+ OCUnauthenticated = 16
+)
+
+const (
+ defaultRateLimitingBackoffSeconds = 8
+ headerAccessToken = "X-SF-Token"
+ headerRetryAfter = "Retry-After"
+ headerContentEncoding = "Content-Encoding"
+ headerContentType = "Content-Type"
+ headerValueGZIP = "gzip"
+ headerValueXProtobuf = "application/x-protobuf"
+ maxHTTPBodyReadBytes = 256 << 10
+)
+
+var httpToOCCodeMap = map[int32]int32{
+ 401: OCUnauthenticated,
+ 403: OCPermissionDenied,
+ 404: OCNotFound,
+ 429: OCResourceExhausted,
+ 499: OCCancelled,
+ 501: OCUnimplemented,
+ 503: OCUnavailable,
+ 504: OCDeadlineExceeded,
+}
+
+// OCStatusCodeFromHTTP takes an HTTP status code and return the appropriate OpenTelemetry status code
+// See: https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/data-http.md
+func OCStatusCodeFromHTTP(code int32) int32 {
+ if code >= 100 && code < 400 {
+ return OCOK
+ }
+ if rvCode, ok := httpToOCCodeMap[code]; ok {
+ return rvCode
+ }
+ if code >= 400 && code < 500 {
+ return OCInvalidArgument
+ }
+ if code >= 500 && code < 600 {
+ return OCInternal
+ }
+ return OCUnknown
+}
diff --git a/vendor/github.com/signalfx/sapm-proto/client/options.go b/vendor/github.com/signalfx/sapm-proto/client/options.go
new file mode 100644
index 0000000..cb035c4
--- /dev/null
+++ b/vendor/github.com/signalfx/sapm-proto/client/options.go
@@ -0,0 +1,69 @@
+// Copyright 2019 Splunk, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package client
+
+import "net/http"
+
+// Option takes a reference to a Client and sets relevant config fields on it.
+type Option func(*Client) error
+
+// WithEndpoint takes an HTTP endpoint as a string in the format scheme://address:port/path and configures the
+// client to export all requests to this endpoint.
+func WithEndpoint(endpoint string) Option {
+ return func(a *Client) error {
+ a.endpoint = endpoint
+ return nil
+ }
+}
+
+// WithWorkers configures the client to use N number of workers.
+func WithWorkers(n uint) Option {
+ return func(a *Client) error {
+ a.numWorkers = n
+ return nil
+ }
+}
+
+// WithMaxConnections allows to specify the max number of open HTTP connections the client should keep at any time.
+func WithMaxConnections(n uint) Option {
+ return func(a *Client) error {
+ a.maxIdleCons = n
+ return nil
+ }
+}
+
+// WithHTTPClient allows to pass a custom HTTP Client instance to SAPM Client
+func WithHTTPClient(c *http.Client) Option {
+ return func(a *Client) error {
+ a.httpClient = c
+ return nil
+ }
+}
+
+// WithAccessToken allows to pass an authentication token to the client. The auth token is set to X-SF-TOKEN HTTP header.
+func WithAccessToken(t string) Option {
+ return func(a *Client) error {
+ a.accessToken = t
+ return nil
+ }
+}
+
+// WithDisabledCompression configures the client to not apply GZip compression on the outgoing requests.
+func WithDisabledCompression() Option {
+ return func(a *Client) error {
+ a.disableCompression = true
+ return nil
+ }
+}
diff --git a/vendor/github.com/signalfx/sapm-proto/client/worker.go b/vendor/github.com/signalfx/sapm-proto/client/worker.go
new file mode 100644
index 0000000..3e1a491
--- /dev/null
+++ b/vendor/github.com/signalfx/sapm-proto/client/worker.go
@@ -0,0 +1,228 @@
+// Copyright 2019 Splunk, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package client
+
+import (
+ "bytes"
+ "compress/gzip"
+ "context"
+ "errors"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "net/http"
+ "strconv"
+
+ "github.com/golang/protobuf/proto"
+ jaegerpb "github.com/jaegertracing/jaeger/model"
+ "go.opencensus.io/trace"
+
+ sapmpb "github.com/signalfx/sapm-proto/gen"
+)
+
+// worker is not safe to be called from multiple goroutines. Each caller must use locks to avoid races
+// and data corruption. In case a caller needs to export multiple requests at the same time, it should
+// use one worker per request.
+type worker struct {
+ client *http.Client
+ accessToken string
+ endpoint string
+ gzipWriter *gzip.Writer
+ disableCompression bool
+}
+
+func newWorker(client *http.Client, endpoint string, accessToken string, disableCompression bool) *worker {
+ w := &worker{
+ client: client,
+ accessToken: accessToken,
+ endpoint: endpoint,
+ disableCompression: disableCompression,
+ gzipWriter: gzip.NewWriter(nil),
+ }
+ return w
+}
+
+func (w *worker) export(ctx context.Context, batches []*jaegerpb.Batch) *ErrSend {
+ ctx, span := trace.StartSpan(ctx, "export")
+ defer span.End()
+
+ var spansCount int
+ for _, batch := range batches {
+ spansCount += len(batch.Spans)
+ }
+
+ span.AddAttributes(trace.Int64Attribute("spans", int64(spansCount)))
+ span.AddAttributes(trace.Int64Attribute("batches", int64(len(batches))))
+ if spansCount == 0 {
+ return nil
+ }
+
+ sr, err := w.prepare(ctx, batches, spansCount)
+ if err != nil {
+ recordEncodingFailure(ctx, sr)
+ span.SetStatus(trace.Status{
+ Code: trace.StatusCodeInvalidArgument,
+ })
+ return &ErrSend{Err: err}
+ }
+
+ serr := w.send(ctx, sr)
+ if serr == nil {
+ recordSuccess(ctx, sr)
+ return nil
+ }
+ recordSendFailure(ctx, sr)
+ span.SetStatus(trace.Status{
+ Code: OCStatusCodeFromHTTP(int32(serr.StatusCode)),
+ })
+
+ if serr.Permanent {
+ recordDrops(ctx, sr)
+ }
+ return serr
+}
+
+func (w *worker) send(ctx context.Context, r *sendRequest) *ErrSend {
+ _, span := trace.StartSpan(ctx, "export")
+ defer span.End()
+
+ req, err := http.NewRequest("POST", w.endpoint, bytes.NewBuffer(r.message))
+ if err != nil {
+ span.SetStatus(trace.Status{
+ Code: trace.StatusCodeInvalidArgument,
+ Message: err.Error(),
+ })
+ return &ErrSend{Err: err, Permanent: true}
+ }
+ req.Header.Add(headerContentType, headerValueXProtobuf)
+
+ if !w.disableCompression {
+ req.Header.Add(headerContentEncoding, headerValueGZIP)
+ }
+
+ if w.accessToken != "" {
+ req.Header.Add(headerAccessToken, w.accessToken)
+ }
+
+ resp, err := w.client.Do(req)
+ if err != nil {
+ span.SetStatus(trace.Status{
+ Code: trace.StatusCodeInternal,
+ Message: err.Error(),
+ })
+ return &ErrSend{Err: err}
+ }
+ io.CopyN(ioutil.Discard, resp.Body, maxHTTPBodyReadBytes)
+ defer resp.Body.Close()
+
+ if resp.StatusCode >= 200 && resp.StatusCode <= 299 {
+ return nil
+ }
+
+ // Drop the batch if server thinks it is malformed in some way or client is not authorized
+ if resp.StatusCode == http.StatusBadRequest || resp.StatusCode == http.StatusUnauthorized {
+ msg := fmt.Sprintf("server responded with: %d", resp.StatusCode)
+ span.SetStatus(trace.Status{
+ Code: OCStatusCodeFromHTTP(int32(resp.StatusCode)),
+ Message: msg,
+ })
+ return &ErrSend{
+ Err: fmt.Errorf("dropping request: %s", msg),
+ StatusCode: http.StatusBadRequest,
+ Permanent: true,
+ }
+ }
+
+ // Check if server is overwhelmed and requested to pause sending for a while.
+ // Pause from sending more data till the specified number of seconds in the Retry-After header.
+ // Fallback to defaultRateLimitingBackoffSeconds if the header is not present
+ if resp.StatusCode == http.StatusTooManyRequests {
+ retryAfter := defaultRateLimitingBackoffSeconds
+ if val := resp.Header.Get(headerRetryAfter); val != "" {
+ if seconds, err := strconv.Atoi(val); err == nil {
+ retryAfter = seconds
+ }
+ }
+ span.SetStatus(trace.Status{Code: trace.StatusCodeResourceExhausted})
+ return &ErrSend{
+ Err: errors.New("server responded with 429"),
+ StatusCode: resp.StatusCode,
+ RetryDelaySeconds: retryAfter,
+ }
+ }
+
+ // TODO: handle 301, 307, 308
+ // redirects are not handled right now but should be to confirm with the spec.
+
+ span.SetStatus(trace.Status{Code: OCStatusCodeFromHTTP(int32(resp.StatusCode))})
+ return &ErrSend{
+ Err: fmt.Errorf("error exporting spans. server responded with status %d", resp.StatusCode),
+ StatusCode: resp.StatusCode,
+ }
+}
+
+// prepare takes a jaeger batches, converts them to a SAPM PostSpansRequest, compresses it and returns a request ready
+// to be sent.
+func (w *worker) prepare(ctx context.Context, batches []*jaegerpb.Batch, spansCount int) (*sendRequest, error) {
+ _, span := trace.StartSpan(ctx, "export")
+ defer span.End()
+
+ psr := &sapmpb.PostSpansRequest{
+ Batches: batches,
+ }
+
+ encoded, err := proto.Marshal(psr)
+ if err != nil {
+ span.SetStatus(trace.Status{
+ Code: trace.StatusCodeInvalidArgument,
+ Message: "failed to marshal request",
+ })
+ return nil, err
+ }
+
+ if w.disableCompression {
+ return &sendRequest{
+ message: encoded,
+ batches: int64(len(batches)),
+ spans: int64(spansCount),
+ }, nil
+ }
+
+ buf := bytes.NewBuffer([]byte{})
+ w.gzipWriter.Reset(buf)
+
+ _, err = w.gzipWriter.Write(encoded)
+ if err != nil {
+ span.SetStatus(trace.Status{
+ Code: trace.StatusCodeInvalidArgument,
+ Message: "failed to gzip request",
+ })
+ return nil, err
+ }
+
+ if err := w.gzipWriter.Close(); err != nil {
+ span.SetStatus(trace.Status{
+ Code: trace.StatusCodeInvalidArgument,
+ Message: "failed to gzip request",
+ })
+ return nil, err
+ }
+ sr := &sendRequest{
+ message: buf.Bytes(),
+ batches: int64(len(batches)),
+ spans: int64(spansCount),
+ }
+ return sr, nil
+}
diff --git a/vendor/github.com/signalfx/sapm-proto/gen/sapm.pb.go b/vendor/github.com/signalfx/sapm-proto/gen/sapm.pb.go
new file mode 100644
index 0000000..bf4436f
--- /dev/null
+++ b/vendor/github.com/signalfx/sapm-proto/gen/sapm.pb.go
@@ -0,0 +1,420 @@
+// Code generated by protoc-gen-gogo. DO NOT EDIT.
+// source: sapm.proto
+
+/*
+ Package splunk_sapm is a generated protocol buffer package.
+
+ It is generated from these files:
+ sapm.proto
+
+ It has these top-level messages:
+ PostSpansRequest
+ PostSpansResponse
+*/
+package splunk_sapm
+
+import proto "github.com/golang/protobuf/proto"
+import fmt "fmt"
+import math "math"
+import jaeger_api_v2 "github.com/jaegertracing/jaeger/model"
+
+import io "io"
+
+// Reference imports to suppress errors if they are not otherwise used.
+var _ = proto.Marshal
+var _ = fmt.Errorf
+var _ = math.Inf
+
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the proto package it is being compiled against.
+// A compilation error at this line likely means your copy of the
+// proto package needs to be updated.
+const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
+
+type PostSpansRequest struct {
+ Batches []*jaeger_api_v2.Batch `protobuf:"bytes,1,rep,name=batches" json:"batches,omitempty"`
+}
+
+func (m *PostSpansRequest) Reset() { *m = PostSpansRequest{} }
+func (m *PostSpansRequest) String() string { return proto.CompactTextString(m) }
+func (*PostSpansRequest) ProtoMessage() {}
+func (*PostSpansRequest) Descriptor() ([]byte, []int) { return fileDescriptorSapm, []int{0} }
+
+func (m *PostSpansRequest) GetBatches() []*jaeger_api_v2.Batch {
+ if m != nil {
+ return m.Batches
+ }
+ return nil
+}
+
+type PostSpansResponse struct {
+}
+
+func (m *PostSpansResponse) Reset() { *m = PostSpansResponse{} }
+func (m *PostSpansResponse) String() string { return proto.CompactTextString(m) }
+func (*PostSpansResponse) ProtoMessage() {}
+func (*PostSpansResponse) Descriptor() ([]byte, []int) { return fileDescriptorSapm, []int{1} }
+
+func init() {
+ proto.RegisterType((*PostSpansRequest)(nil), "splunk.sapm.PostSpansRequest")
+ proto.RegisterType((*PostSpansResponse)(nil), "splunk.sapm.PostSpansResponse")
+}
+func (m *PostSpansRequest) Marshal() (dAtA []byte, err error) {
+ size := m.Size()
+ dAtA = make([]byte, size)
+ n, err := m.MarshalTo(dAtA)
+ if err != nil {
+ return nil, err
+ }
+ return dAtA[:n], nil
+}
+
+func (m *PostSpansRequest) MarshalTo(dAtA []byte) (int, error) {
+ var i int
+ _ = i
+ var l int
+ _ = l
+ if len(m.Batches) > 0 {
+ for _, msg := range m.Batches {
+ dAtA[i] = 0xa
+ i++
+ i = encodeVarintSapm(dAtA, i, uint64(msg.Size()))
+ n, err := msg.MarshalTo(dAtA[i:])
+ if err != nil {
+ return 0, err
+ }
+ i += n
+ }
+ }
+ return i, nil
+}
+
+func (m *PostSpansResponse) Marshal() (dAtA []byte, err error) {
+ size := m.Size()
+ dAtA = make([]byte, size)
+ n, err := m.MarshalTo(dAtA)
+ if err != nil {
+ return nil, err
+ }
+ return dAtA[:n], nil
+}
+
+func (m *PostSpansResponse) MarshalTo(dAtA []byte) (int, error) {
+ var i int
+ _ = i
+ var l int
+ _ = l
+ return i, nil
+}
+
+func encodeFixed64Sapm(dAtA []byte, offset int, v uint64) int {
+ dAtA[offset] = uint8(v)
+ dAtA[offset+1] = uint8(v >> 8)
+ dAtA[offset+2] = uint8(v >> 16)
+ dAtA[offset+3] = uint8(v >> 24)
+ dAtA[offset+4] = uint8(v >> 32)
+ dAtA[offset+5] = uint8(v >> 40)
+ dAtA[offset+6] = uint8(v >> 48)
+ dAtA[offset+7] = uint8(v >> 56)
+ return offset + 8
+}
+func encodeFixed32Sapm(dAtA []byte, offset int, v uint32) int {
+ dAtA[offset] = uint8(v)
+ dAtA[offset+1] = uint8(v >> 8)
+ dAtA[offset+2] = uint8(v >> 16)
+ dAtA[offset+3] = uint8(v >> 24)
+ return offset + 4
+}
+func encodeVarintSapm(dAtA []byte, offset int, v uint64) int {
+ for v >= 1<<7 {
+ dAtA[offset] = uint8(v&0x7f | 0x80)
+ v >>= 7
+ offset++
+ }
+ dAtA[offset] = uint8(v)
+ return offset + 1
+}
+func (m *PostSpansRequest) Size() (n int) {
+ var l int
+ _ = l
+ if len(m.Batches) > 0 {
+ for _, e := range m.Batches {
+ l = e.Size()
+ n += 1 + l + sovSapm(uint64(l))
+ }
+ }
+ return n
+}
+
+func (m *PostSpansResponse) Size() (n int) {
+ var l int
+ _ = l
+ return n
+}
+
+func sovSapm(x uint64) (n int) {
+ for {
+ n++
+ x >>= 7
+ if x == 0 {
+ break
+ }
+ }
+ return n
+}
+func sozSapm(x uint64) (n int) {
+ return sovSapm(uint64((x << 1) ^ uint64((int64(x) >> 63))))
+}
+func (m *PostSpansRequest) Unmarshal(dAtA []byte) error {
+ l := len(dAtA)
+ iNdEx := 0
+ for iNdEx < l {
+ preIndex := iNdEx
+ var wire uint64
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowSapm
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ wire |= (uint64(b) & 0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ fieldNum := int32(wire >> 3)
+ wireType := int(wire & 0x7)
+ if wireType == 4 {
+ return fmt.Errorf("proto: PostSpansRequest: wiretype end group for non-group")
+ }
+ if fieldNum <= 0 {
+ return fmt.Errorf("proto: PostSpansRequest: illegal tag %d (wire type %d)", fieldNum, wire)
+ }
+ switch fieldNum {
+ case 1:
+ if wireType != 2 {
+ return fmt.Errorf("proto: wrong wireType = %d for field Batches", wireType)
+ }
+ var msglen int
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowSapm
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ msglen |= (int(b) & 0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ if msglen < 0 {
+ return ErrInvalidLengthSapm
+ }
+ postIndex := iNdEx + msglen
+ if postIndex > l {
+ return io.ErrUnexpectedEOF
+ }
+ m.Batches = append(m.Batches, &jaeger_api_v2.Batch{})
+ if err := m.Batches[len(m.Batches)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
+ return err
+ }
+ iNdEx = postIndex
+ default:
+ iNdEx = preIndex
+ skippy, err := skipSapm(dAtA[iNdEx:])
+ if err != nil {
+ return err
+ }
+ if skippy < 0 {
+ return ErrInvalidLengthSapm
+ }
+ if (iNdEx + skippy) > l {
+ return io.ErrUnexpectedEOF
+ }
+ iNdEx += skippy
+ }
+ }
+
+ if iNdEx > l {
+ return io.ErrUnexpectedEOF
+ }
+ return nil
+}
+func (m *PostSpansResponse) Unmarshal(dAtA []byte) error {
+ l := len(dAtA)
+ iNdEx := 0
+ for iNdEx < l {
+ preIndex := iNdEx
+ var wire uint64
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowSapm
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ wire |= (uint64(b) & 0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ fieldNum := int32(wire >> 3)
+ wireType := int(wire & 0x7)
+ if wireType == 4 {
+ return fmt.Errorf("proto: PostSpansResponse: wiretype end group for non-group")
+ }
+ if fieldNum <= 0 {
+ return fmt.Errorf("proto: PostSpansResponse: illegal tag %d (wire type %d)", fieldNum, wire)
+ }
+ switch fieldNum {
+ default:
+ iNdEx = preIndex
+ skippy, err := skipSapm(dAtA[iNdEx:])
+ if err != nil {
+ return err
+ }
+ if skippy < 0 {
+ return ErrInvalidLengthSapm
+ }
+ if (iNdEx + skippy) > l {
+ return io.ErrUnexpectedEOF
+ }
+ iNdEx += skippy
+ }
+ }
+
+ if iNdEx > l {
+ return io.ErrUnexpectedEOF
+ }
+ return nil
+}
+func skipSapm(dAtA []byte) (n int, err error) {
+ l := len(dAtA)
+ iNdEx := 0
+ for iNdEx < l {
+ var wire uint64
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return 0, ErrIntOverflowSapm
+ }
+ if iNdEx >= l {
+ return 0, io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ wire |= (uint64(b) & 0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ wireType := int(wire & 0x7)
+ switch wireType {
+ case 0:
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return 0, ErrIntOverflowSapm
+ }
+ if iNdEx >= l {
+ return 0, io.ErrUnexpectedEOF
+ }
+ iNdEx++
+ if dAtA[iNdEx-1] < 0x80 {
+ break
+ }
+ }
+ return iNdEx, nil
+ case 1:
+ iNdEx += 8
+ return iNdEx, nil
+ case 2:
+ var length int
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return 0, ErrIntOverflowSapm
+ }
+ if iNdEx >= l {
+ return 0, io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ length |= (int(b) & 0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ iNdEx += length
+ if length < 0 {
+ return 0, ErrInvalidLengthSapm
+ }
+ return iNdEx, nil
+ case 3:
+ for {
+ var innerWire uint64
+ var start int = iNdEx
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return 0, ErrIntOverflowSapm
+ }
+ if iNdEx >= l {
+ return 0, io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ innerWire |= (uint64(b) & 0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ innerWireType := int(innerWire & 0x7)
+ if innerWireType == 4 {
+ break
+ }
+ next, err := skipSapm(dAtA[start:])
+ if err != nil {
+ return 0, err
+ }
+ iNdEx = start + next
+ }
+ return iNdEx, nil
+ case 4:
+ return iNdEx, nil
+ case 5:
+ iNdEx += 4
+ return iNdEx, nil
+ default:
+ return 0, fmt.Errorf("proto: illegal wireType %d", wireType)
+ }
+ }
+ panic("unreachable")
+}
+
+var (
+ ErrInvalidLengthSapm = fmt.Errorf("proto: negative length found during unmarshaling")
+ ErrIntOverflowSapm = fmt.Errorf("proto: integer overflow")
+)
+
+func init() { proto.RegisterFile("sapm.proto", fileDescriptorSapm) }
+
+var fileDescriptorSapm = []byte{
+ // 177 bytes of a gzipped FileDescriptorProto
+ 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x2a, 0x4e, 0x2c, 0xc8,
+ 0xd5, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0xe2, 0x2e, 0x2e, 0xc8, 0x29, 0xcd, 0xcb, 0xd6, 0x03,
+ 0x09, 0x49, 0x19, 0xa6, 0x67, 0x96, 0x64, 0x94, 0x26, 0xe9, 0x25, 0xe7, 0xe7, 0xea, 0x67, 0x25,
+ 0xa6, 0xa6, 0xa7, 0x16, 0x95, 0x14, 0x25, 0x26, 0x67, 0xe6, 0xa5, 0x43, 0x79, 0xfa, 0xb9, 0xf9,
+ 0x29, 0xa9, 0x39, 0x10, 0x12, 0xa2, 0x5f, 0xc9, 0x89, 0x4b, 0x20, 0x20, 0xbf, 0xb8, 0x24, 0xb8,
+ 0x20, 0x31, 0xaf, 0x38, 0x28, 0xb5, 0xb0, 0x34, 0xb5, 0xb8, 0x44, 0x48, 0x8f, 0x8b, 0x3d, 0x29,
+ 0xb1, 0x24, 0x39, 0x23, 0xb5, 0x58, 0x82, 0x51, 0x81, 0x59, 0x83, 0xdb, 0x48, 0x44, 0x0f, 0xa2,
+ 0x5f, 0x2f, 0xb1, 0x20, 0x33, 0xbe, 0xcc, 0x48, 0xcf, 0x09, 0x24, 0x1b, 0x04, 0x53, 0xa4, 0x24,
+ 0xcc, 0x25, 0x88, 0x64, 0x46, 0x71, 0x41, 0x7e, 0x5e, 0x71, 0xaa, 0x93, 0xc0, 0x89, 0x47, 0x72,
+ 0x8c, 0x17, 0x1e, 0xc9, 0x31, 0x3e, 0x78, 0x24, 0xc7, 0x38, 0xe3, 0xb1, 0x1c, 0x43, 0x12, 0x1b,
+ 0xd8, 0x46, 0x63, 0x40, 0x00, 0x00, 0x00, 0xff, 0xff, 0x35, 0x77, 0x35, 0x95, 0xbf, 0x00, 0x00,
+ 0x00,
+}
diff --git a/vendor/github.com/signalfx/sapm-proto/sapmprotocol/constants.go b/vendor/github.com/signalfx/sapm-proto/sapmprotocol/constants.go
new file mode 100644
index 0000000..1990006
--- /dev/null
+++ b/vendor/github.com/signalfx/sapm-proto/sapmprotocol/constants.go
@@ -0,0 +1,31 @@
+// Copyright 2019 Splunk, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package sapmprotocol
+
+const (
+ // TraceEndpointV2 is the endpoint used for SAPM v2 traces. The SAPM protocol started with v2. There is no v1.
+ TraceEndpointV2 = "/v2/trace"
+ // ContentTypeHeaderName is the http header name used for Content-Type
+ ContentTypeHeaderName = "Content-Type"
+ // ContentTypeHeaderValue is the value used for protobuf Content-Type http headers
+ ContentTypeHeaderValue = "application/x-protobuf"
+
+ // AcceptEncodingHeaderName is the http header name used for Accept-Encoding
+ AcceptEncodingHeaderName = "Accept-Encoding"
+ // ContentEncodingHeaderName is the http header name used for Content-Encoding
+ ContentEncodingHeaderName = "Content-Encoding"
+ // GZipEncodingHeaderValue is the value used for gzipped encoding http headers
+ GZipEncodingHeaderValue = "gzip"
+)
diff --git a/vendor/github.com/signalfx/sapm-proto/sapmprotocol/parser.go b/vendor/github.com/signalfx/sapm-proto/sapmprotocol/parser.go
new file mode 100644
index 0000000..906a1a8
--- /dev/null
+++ b/vendor/github.com/signalfx/sapm-proto/sapmprotocol/parser.go
@@ -0,0 +1,96 @@
+// Copyright 2019 Splunk, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package sapmprotocol
+
+import (
+ "bytes"
+ "compress/gzip"
+ "errors"
+ "io"
+ "net/http"
+ "sync"
+
+ "github.com/golang/protobuf/proto"
+
+ splunksapm "github.com/signalfx/sapm-proto/gen"
+)
+
+type poolObj struct {
+ gr *gzip.Reader
+ jeff *bytes.Buffer
+ tmp []byte
+}
+
+var (
+ // ErrBadContentType indicates an incompatible content type was received
+ ErrBadContentType = errors.New("bad content type")
+
+ pool = &sync.Pool{
+ New: func() interface{} {
+ // create a new gzip reader with a bytes reader and array of bytes containing only the gzip header
+ gr, _ := gzip.NewReader(bytes.NewReader([]byte{31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 0, 0, 0, 255, 255, 1, 0, 0, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0}))
+ jeff := &bytes.Buffer{}
+ tmp := make([]byte, 32*1024)
+ return &poolObj{
+ gr: gr,
+ jeff: jeff,
+ tmp: tmp,
+ }
+ },
+ }
+)
+
+// ParseTraceV2Request processes an http request request into SAPM
+func ParseTraceV2Request(req *http.Request) (*splunksapm.PostSpansRequest, error) {
+ // content type MUST be application/x-protobuf
+ if req.Header.Get(ContentTypeHeaderName) != ContentTypeHeaderValue {
+ return nil, ErrBadContentType
+ }
+
+ var err error
+ var reader io.Reader
+
+ obj := pool.Get().(*poolObj)
+ defer pool.Put(obj)
+ obj.jeff.Reset()
+
+ // content encoding SHOULD be gzip
+ if req.Header.Get(ContentEncodingHeaderName) == GZipEncodingHeaderValue {
+ // get the gzip reader
+ // reset the reader with the request body
+ err = obj.gr.Reset(req.Body)
+ if err != nil {
+ return nil, err
+ }
+ reader = obj.gr
+ } else {
+ reader = req.Body
+ }
+
+ _, err = io.CopyBuffer(obj.jeff, reader, obj.tmp)
+ if err != nil {
+ return nil, err
+ }
+
+ var sapm = &splunksapm.PostSpansRequest{}
+
+ // unmarshal request body
+ err = proto.Unmarshal(obj.jeff.Bytes(), sapm)
+ if err != nil {
+ return nil, err
+ }
+
+ return sapm, err
+}
diff --git a/vendor/github.com/stretchr/testify/LICENSE b/vendor/github.com/stretchr/testify/LICENSE
new file mode 100644
index 0000000..f38ec59
--- /dev/null
+++ b/vendor/github.com/stretchr/testify/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2012-2018 Mat Ryer and Tyler Bunnell
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/vendor/github.com/stretchr/testify/assert/assertion_format.go b/vendor/github.com/stretchr/testify/assert/assertion_format.go
new file mode 100644
index 0000000..e0364e9
--- /dev/null
+++ b/vendor/github.com/stretchr/testify/assert/assertion_format.go
@@ -0,0 +1,566 @@
+/*
+* CODE GENERATED AUTOMATICALLY WITH github.com/stretchr/testify/_codegen
+* THIS FILE MUST NOT BE EDITED BY HAND
+ */
+
+package assert
+
+import (
+ http "net/http"
+ url "net/url"
+ time "time"
+)
+
+// Conditionf uses a Comparison to assert a complex condition.
+func Conditionf(t TestingT, comp Comparison, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ return Condition(t, comp, append([]interface{}{msg}, args...)...)
+}
+
+// Containsf asserts that the specified string, list(array, slice...) or map contains the
+// specified substring or element.
+//
+// assert.Containsf(t, "Hello World", "World", "error message %s", "formatted")
+// assert.Containsf(t, ["Hello", "World"], "World", "error message %s", "formatted")
+// assert.Containsf(t, {"Hello": "World"}, "Hello", "error message %s", "formatted")
+func Containsf(t TestingT, s interface{}, contains interface{}, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ return Contains(t, s, contains, append([]interface{}{msg}, args...)...)
+}
+
+// DirExistsf checks whether a directory exists in the given path. It also fails if the path is a file rather a directory or there is an error checking whether it exists.
+func DirExistsf(t TestingT, path string, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ return DirExists(t, path, append([]interface{}{msg}, args...)...)
+}
+
+// ElementsMatchf asserts that the specified listA(array, slice...) is equal to specified
+// listB(array, slice...) ignoring the order of the elements. If there are duplicate elements,
+// the number of appearances of each of them in both lists should match.
+//
+// assert.ElementsMatchf(t, [1, 3, 2, 3], [1, 3, 3, 2], "error message %s", "formatted")
+func ElementsMatchf(t TestingT, listA interface{}, listB interface{}, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ return ElementsMatch(t, listA, listB, append([]interface{}{msg}, args...)...)
+}
+
+// Emptyf asserts that the specified object is empty. I.e. nil, "", false, 0 or either
+// a slice or a channel with len == 0.
+//
+// assert.Emptyf(t, obj, "error message %s", "formatted")
+func Emptyf(t TestingT, object interface{}, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ return Empty(t, object, append([]interface{}{msg}, args...)...)
+}
+
+// Equalf asserts that two objects are equal.
+//
+// assert.Equalf(t, 123, 123, "error message %s", "formatted")
+//
+// Pointer variable equality is determined based on the equality of the
+// referenced values (as opposed to the memory addresses). Function equality
+// cannot be determined and will always fail.
+func Equalf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ return Equal(t, expected, actual, append([]interface{}{msg}, args...)...)
+}
+
+// EqualErrorf asserts that a function returned an error (i.e. not `nil`)
+// and that it is equal to the provided error.
+//
+// actualObj, err := SomeFunction()
+// assert.EqualErrorf(t, err, expectedErrorString, "error message %s", "formatted")
+func EqualErrorf(t TestingT, theError error, errString string, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ return EqualError(t, theError, errString, append([]interface{}{msg}, args...)...)
+}
+
+// EqualValuesf asserts that two objects are equal or convertable to the same types
+// and equal.
+//
+// assert.EqualValuesf(t, uint32(123, "error message %s", "formatted"), int32(123))
+func EqualValuesf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ return EqualValues(t, expected, actual, append([]interface{}{msg}, args...)...)
+}
+
+// Errorf asserts that a function returned an error (i.e. not `nil`).
+//
+// actualObj, err := SomeFunction()
+// if assert.Errorf(t, err, "error message %s", "formatted") {
+// assert.Equal(t, expectedErrorf, err)
+// }
+func Errorf(t TestingT, err error, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ return Error(t, err, append([]interface{}{msg}, args...)...)
+}
+
+// Eventuallyf asserts that given condition will be met in waitFor time,
+// periodically checking target function each tick.
+//
+// assert.Eventuallyf(t, func() bool { return true; }, time.Second, 10*time.Millisecond, "error message %s", "formatted")
+func Eventuallyf(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ return Eventually(t, condition, waitFor, tick, append([]interface{}{msg}, args...)...)
+}
+
+// Exactlyf asserts that two objects are equal in value and type.
+//
+// assert.Exactlyf(t, int32(123, "error message %s", "formatted"), int64(123))
+func Exactlyf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ return Exactly(t, expected, actual, append([]interface{}{msg}, args...)...)
+}
+
+// Failf reports a failure through
+func Failf(t TestingT, failureMessage string, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ return Fail(t, failureMessage, append([]interface{}{msg}, args...)...)
+}
+
+// FailNowf fails test
+func FailNowf(t TestingT, failureMessage string, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ return FailNow(t, failureMessage, append([]interface{}{msg}, args...)...)
+}
+
+// Falsef asserts that the specified value is false.
+//
+// assert.Falsef(t, myBool, "error message %s", "formatted")
+func Falsef(t TestingT, value bool, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ return False(t, value, append([]interface{}{msg}, args...)...)
+}
+
+// FileExistsf checks whether a file exists in the given path. It also fails if the path points to a directory or there is an error when trying to check the file.
+func FileExistsf(t TestingT, path string, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ return FileExists(t, path, append([]interface{}{msg}, args...)...)
+}
+
+// Greaterf asserts that the first element is greater than the second
+//
+// assert.Greaterf(t, 2, 1, "error message %s", "formatted")
+// assert.Greaterf(t, float64(2, "error message %s", "formatted"), float64(1))
+// assert.Greaterf(t, "b", "a", "error message %s", "formatted")
+func Greaterf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ return Greater(t, e1, e2, append([]interface{}{msg}, args...)...)
+}
+
+// GreaterOrEqualf asserts that the first element is greater than or equal to the second
+//
+// assert.GreaterOrEqualf(t, 2, 1, "error message %s", "formatted")
+// assert.GreaterOrEqualf(t, 2, 2, "error message %s", "formatted")
+// assert.GreaterOrEqualf(t, "b", "a", "error message %s", "formatted")
+// assert.GreaterOrEqualf(t, "b", "b", "error message %s", "formatted")
+func GreaterOrEqualf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ return GreaterOrEqual(t, e1, e2, append([]interface{}{msg}, args...)...)
+}
+
+// HTTPBodyContainsf asserts that a specified handler returns a
+// body that contains a string.
+//
+// assert.HTTPBodyContainsf(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func HTTPBodyContainsf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ return HTTPBodyContains(t, handler, method, url, values, str, append([]interface{}{msg}, args...)...)
+}
+
+// HTTPBodyNotContainsf asserts that a specified handler returns a
+// body that does not contain a string.
+//
+// assert.HTTPBodyNotContainsf(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func HTTPBodyNotContainsf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ return HTTPBodyNotContains(t, handler, method, url, values, str, append([]interface{}{msg}, args...)...)
+}
+
+// HTTPErrorf asserts that a specified handler returns an error status code.
+//
+// assert.HTTPErrorf(t, myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}}
+//
+// Returns whether the assertion was successful (true, "error message %s", "formatted") or not (false).
+func HTTPErrorf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ return HTTPError(t, handler, method, url, values, append([]interface{}{msg}, args...)...)
+}
+
+// HTTPRedirectf asserts that a specified handler returns a redirect status code.
+//
+// assert.HTTPRedirectf(t, myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}}
+//
+// Returns whether the assertion was successful (true, "error message %s", "formatted") or not (false).
+func HTTPRedirectf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ return HTTPRedirect(t, handler, method, url, values, append([]interface{}{msg}, args...)...)
+}
+
+// HTTPSuccessf asserts that a specified handler returns a success status code.
+//
+// assert.HTTPSuccessf(t, myHandler, "POST", "http://www.google.com", nil, "error message %s", "formatted")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func HTTPSuccessf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ return HTTPSuccess(t, handler, method, url, values, append([]interface{}{msg}, args...)...)
+}
+
+// Implementsf asserts that an object is implemented by the specified interface.
+//
+// assert.Implementsf(t, (*MyInterface, "error message %s", "formatted")(nil), new(MyObject))
+func Implementsf(t TestingT, interfaceObject interface{}, object interface{}, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ return Implements(t, interfaceObject, object, append([]interface{}{msg}, args...)...)
+}
+
+// InDeltaf asserts that the two numerals are within delta of each other.
+//
+// assert.InDeltaf(t, math.Pi, (22 / 7.0, "error message %s", "formatted"), 0.01)
+func InDeltaf(t TestingT, expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ return InDelta(t, expected, actual, delta, append([]interface{}{msg}, args...)...)
+}
+
+// InDeltaMapValuesf is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys.
+func InDeltaMapValuesf(t TestingT, expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ return InDeltaMapValues(t, expected, actual, delta, append([]interface{}{msg}, args...)...)
+}
+
+// InDeltaSlicef is the same as InDelta, except it compares two slices.
+func InDeltaSlicef(t TestingT, expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ return InDeltaSlice(t, expected, actual, delta, append([]interface{}{msg}, args...)...)
+}
+
+// InEpsilonf asserts that expected and actual have a relative error less than epsilon
+func InEpsilonf(t TestingT, expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ return InEpsilon(t, expected, actual, epsilon, append([]interface{}{msg}, args...)...)
+}
+
+// InEpsilonSlicef is the same as InEpsilon, except it compares each value from two slices.
+func InEpsilonSlicef(t TestingT, expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ return InEpsilonSlice(t, expected, actual, epsilon, append([]interface{}{msg}, args...)...)
+}
+
+// IsTypef asserts that the specified objects are of the same type.
+func IsTypef(t TestingT, expectedType interface{}, object interface{}, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ return IsType(t, expectedType, object, append([]interface{}{msg}, args...)...)
+}
+
+// JSONEqf asserts that two JSON strings are equivalent.
+//
+// assert.JSONEqf(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`, "error message %s", "formatted")
+func JSONEqf(t TestingT, expected string, actual string, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ return JSONEq(t, expected, actual, append([]interface{}{msg}, args...)...)
+}
+
+// YAMLEqf asserts that two YAML strings are equivalent.
+func YAMLEqf(t TestingT, expected string, actual string, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ return YAMLEq(t, expected, actual, append([]interface{}{msg}, args...)...)
+}
+
+// Lenf asserts that the specified object has specific length.
+// Lenf also fails if the object has a type that len() not accept.
+//
+// assert.Lenf(t, mySlice, 3, "error message %s", "formatted")
+func Lenf(t TestingT, object interface{}, length int, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ return Len(t, object, length, append([]interface{}{msg}, args...)...)
+}
+
+// Lessf asserts that the first element is less than the second
+//
+// assert.Lessf(t, 1, 2, "error message %s", "formatted")
+// assert.Lessf(t, float64(1, "error message %s", "formatted"), float64(2))
+// assert.Lessf(t, "a", "b", "error message %s", "formatted")
+func Lessf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ return Less(t, e1, e2, append([]interface{}{msg}, args...)...)
+}
+
+// LessOrEqualf asserts that the first element is less than or equal to the second
+//
+// assert.LessOrEqualf(t, 1, 2, "error message %s", "formatted")
+// assert.LessOrEqualf(t, 2, 2, "error message %s", "formatted")
+// assert.LessOrEqualf(t, "a", "b", "error message %s", "formatted")
+// assert.LessOrEqualf(t, "b", "b", "error message %s", "formatted")
+func LessOrEqualf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ return LessOrEqual(t, e1, e2, append([]interface{}{msg}, args...)...)
+}
+
+// Nilf asserts that the specified object is nil.
+//
+// assert.Nilf(t, err, "error message %s", "formatted")
+func Nilf(t TestingT, object interface{}, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ return Nil(t, object, append([]interface{}{msg}, args...)...)
+}
+
+// NoErrorf asserts that a function returned no error (i.e. `nil`).
+//
+// actualObj, err := SomeFunction()
+// if assert.NoErrorf(t, err, "error message %s", "formatted") {
+// assert.Equal(t, expectedObj, actualObj)
+// }
+func NoErrorf(t TestingT, err error, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ return NoError(t, err, append([]interface{}{msg}, args...)...)
+}
+
+// NotContainsf asserts that the specified string, list(array, slice...) or map does NOT contain the
+// specified substring or element.
+//
+// assert.NotContainsf(t, "Hello World", "Earth", "error message %s", "formatted")
+// assert.NotContainsf(t, ["Hello", "World"], "Earth", "error message %s", "formatted")
+// assert.NotContainsf(t, {"Hello": "World"}, "Earth", "error message %s", "formatted")
+func NotContainsf(t TestingT, s interface{}, contains interface{}, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ return NotContains(t, s, contains, append([]interface{}{msg}, args...)...)
+}
+
+// NotEmptyf asserts that the specified object is NOT empty. I.e. not nil, "", false, 0 or either
+// a slice or a channel with len == 0.
+//
+// if assert.NotEmptyf(t, obj, "error message %s", "formatted") {
+// assert.Equal(t, "two", obj[1])
+// }
+func NotEmptyf(t TestingT, object interface{}, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ return NotEmpty(t, object, append([]interface{}{msg}, args...)...)
+}
+
+// NotEqualf asserts that the specified values are NOT equal.
+//
+// assert.NotEqualf(t, obj1, obj2, "error message %s", "formatted")
+//
+// Pointer variable equality is determined based on the equality of the
+// referenced values (as opposed to the memory addresses).
+func NotEqualf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ return NotEqual(t, expected, actual, append([]interface{}{msg}, args...)...)
+}
+
+// NotNilf asserts that the specified object is not nil.
+//
+// assert.NotNilf(t, err, "error message %s", "formatted")
+func NotNilf(t TestingT, object interface{}, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ return NotNil(t, object, append([]interface{}{msg}, args...)...)
+}
+
+// NotPanicsf asserts that the code inside the specified PanicTestFunc does NOT panic.
+//
+// assert.NotPanicsf(t, func(){ RemainCalm() }, "error message %s", "formatted")
+func NotPanicsf(t TestingT, f PanicTestFunc, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ return NotPanics(t, f, append([]interface{}{msg}, args...)...)
+}
+
+// NotRegexpf asserts that a specified regexp does not match a string.
+//
+// assert.NotRegexpf(t, regexp.MustCompile("starts", "error message %s", "formatted"), "it's starting")
+// assert.NotRegexpf(t, "^start", "it's not starting", "error message %s", "formatted")
+func NotRegexpf(t TestingT, rx interface{}, str interface{}, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ return NotRegexp(t, rx, str, append([]interface{}{msg}, args...)...)
+}
+
+// NotSubsetf asserts that the specified list(array, slice...) contains not all
+// elements given in the specified subset(array, slice...).
+//
+// assert.NotSubsetf(t, [1, 3, 4], [1, 2], "But [1, 3, 4] does not contain [1, 2]", "error message %s", "formatted")
+func NotSubsetf(t TestingT, list interface{}, subset interface{}, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ return NotSubset(t, list, subset, append([]interface{}{msg}, args...)...)
+}
+
+// NotZerof asserts that i is not the zero value for its type.
+func NotZerof(t TestingT, i interface{}, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ return NotZero(t, i, append([]interface{}{msg}, args...)...)
+}
+
+// Panicsf asserts that the code inside the specified PanicTestFunc panics.
+//
+// assert.Panicsf(t, func(){ GoCrazy() }, "error message %s", "formatted")
+func Panicsf(t TestingT, f PanicTestFunc, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ return Panics(t, f, append([]interface{}{msg}, args...)...)
+}
+
+// PanicsWithValuef asserts that the code inside the specified PanicTestFunc panics, and that
+// the recovered panic value equals the expected panic value.
+//
+// assert.PanicsWithValuef(t, "crazy error", func(){ GoCrazy() }, "error message %s", "formatted")
+func PanicsWithValuef(t TestingT, expected interface{}, f PanicTestFunc, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ return PanicsWithValue(t, expected, f, append([]interface{}{msg}, args...)...)
+}
+
+// Regexpf asserts that a specified regexp matches a string.
+//
+// assert.Regexpf(t, regexp.MustCompile("start", "error message %s", "formatted"), "it's starting")
+// assert.Regexpf(t, "start...$", "it's not starting", "error message %s", "formatted")
+func Regexpf(t TestingT, rx interface{}, str interface{}, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ return Regexp(t, rx, str, append([]interface{}{msg}, args...)...)
+}
+
+// Samef asserts that two pointers reference the same object.
+//
+// assert.Samef(t, ptr1, ptr2, "error message %s", "formatted")
+//
+// Both arguments must be pointer variables. Pointer variable sameness is
+// determined based on the equality of both type and value.
+func Samef(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ return Same(t, expected, actual, append([]interface{}{msg}, args...)...)
+}
+
+// Subsetf asserts that the specified list(array, slice...) contains all
+// elements given in the specified subset(array, slice...).
+//
+// assert.Subsetf(t, [1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]", "error message %s", "formatted")
+func Subsetf(t TestingT, list interface{}, subset interface{}, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ return Subset(t, list, subset, append([]interface{}{msg}, args...)...)
+}
+
+// Truef asserts that the specified value is true.
+//
+// assert.Truef(t, myBool, "error message %s", "formatted")
+func Truef(t TestingT, value bool, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ return True(t, value, append([]interface{}{msg}, args...)...)
+}
+
+// WithinDurationf asserts that the two times are within duration delta of each other.
+//
+// assert.WithinDurationf(t, time.Now(), time.Now(), 10*time.Second, "error message %s", "formatted")
+func WithinDurationf(t TestingT, expected time.Time, actual time.Time, delta time.Duration, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ return WithinDuration(t, expected, actual, delta, append([]interface{}{msg}, args...)...)
+}
+
+// Zerof asserts that i is the zero value for its type.
+func Zerof(t TestingT, i interface{}, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ return Zero(t, i, append([]interface{}{msg}, args...)...)
+}
diff --git a/vendor/github.com/stretchr/testify/assert/assertion_format.go.tmpl b/vendor/github.com/stretchr/testify/assert/assertion_format.go.tmpl
new file mode 100644
index 0000000..d2bb0b8
--- /dev/null
+++ b/vendor/github.com/stretchr/testify/assert/assertion_format.go.tmpl
@@ -0,0 +1,5 @@
+{{.CommentFormat}}
+func {{.DocInfo.Name}}f(t TestingT, {{.ParamsFormat}}) bool {
+ if h, ok := t.(tHelper); ok { h.Helper() }
+ return {{.DocInfo.Name}}(t, {{.ForwardedParamsFormat}})
+}
diff --git a/vendor/github.com/stretchr/testify/assert/assertion_forward.go b/vendor/github.com/stretchr/testify/assert/assertion_forward.go
new file mode 100644
index 0000000..2683040
--- /dev/null
+++ b/vendor/github.com/stretchr/testify/assert/assertion_forward.go
@@ -0,0 +1,1120 @@
+/*
+* CODE GENERATED AUTOMATICALLY WITH github.com/stretchr/testify/_codegen
+* THIS FILE MUST NOT BE EDITED BY HAND
+ */
+
+package assert
+
+import (
+ http "net/http"
+ url "net/url"
+ time "time"
+)
+
+// Condition uses a Comparison to assert a complex condition.
+func (a *Assertions) Condition(comp Comparison, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return Condition(a.t, comp, msgAndArgs...)
+}
+
+// Conditionf uses a Comparison to assert a complex condition.
+func (a *Assertions) Conditionf(comp Comparison, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return Conditionf(a.t, comp, msg, args...)
+}
+
+// Contains asserts that the specified string, list(array, slice...) or map contains the
+// specified substring or element.
+//
+// a.Contains("Hello World", "World")
+// a.Contains(["Hello", "World"], "World")
+// a.Contains({"Hello": "World"}, "Hello")
+func (a *Assertions) Contains(s interface{}, contains interface{}, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return Contains(a.t, s, contains, msgAndArgs...)
+}
+
+// Containsf asserts that the specified string, list(array, slice...) or map contains the
+// specified substring or element.
+//
+// a.Containsf("Hello World", "World", "error message %s", "formatted")
+// a.Containsf(["Hello", "World"], "World", "error message %s", "formatted")
+// a.Containsf({"Hello": "World"}, "Hello", "error message %s", "formatted")
+func (a *Assertions) Containsf(s interface{}, contains interface{}, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return Containsf(a.t, s, contains, msg, args...)
+}
+
+// DirExists checks whether a directory exists in the given path. It also fails if the path is a file rather a directory or there is an error checking whether it exists.
+func (a *Assertions) DirExists(path string, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return DirExists(a.t, path, msgAndArgs...)
+}
+
+// DirExistsf checks whether a directory exists in the given path. It also fails if the path is a file rather a directory or there is an error checking whether it exists.
+func (a *Assertions) DirExistsf(path string, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return DirExistsf(a.t, path, msg, args...)
+}
+
+// ElementsMatch asserts that the specified listA(array, slice...) is equal to specified
+// listB(array, slice...) ignoring the order of the elements. If there are duplicate elements,
+// the number of appearances of each of them in both lists should match.
+//
+// a.ElementsMatch([1, 3, 2, 3], [1, 3, 3, 2])
+func (a *Assertions) ElementsMatch(listA interface{}, listB interface{}, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return ElementsMatch(a.t, listA, listB, msgAndArgs...)
+}
+
+// ElementsMatchf asserts that the specified listA(array, slice...) is equal to specified
+// listB(array, slice...) ignoring the order of the elements. If there are duplicate elements,
+// the number of appearances of each of them in both lists should match.
+//
+// a.ElementsMatchf([1, 3, 2, 3], [1, 3, 3, 2], "error message %s", "formatted")
+func (a *Assertions) ElementsMatchf(listA interface{}, listB interface{}, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return ElementsMatchf(a.t, listA, listB, msg, args...)
+}
+
+// Empty asserts that the specified object is empty. I.e. nil, "", false, 0 or either
+// a slice or a channel with len == 0.
+//
+// a.Empty(obj)
+func (a *Assertions) Empty(object interface{}, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return Empty(a.t, object, msgAndArgs...)
+}
+
+// Emptyf asserts that the specified object is empty. I.e. nil, "", false, 0 or either
+// a slice or a channel with len == 0.
+//
+// a.Emptyf(obj, "error message %s", "formatted")
+func (a *Assertions) Emptyf(object interface{}, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return Emptyf(a.t, object, msg, args...)
+}
+
+// Equal asserts that two objects are equal.
+//
+// a.Equal(123, 123)
+//
+// Pointer variable equality is determined based on the equality of the
+// referenced values (as opposed to the memory addresses). Function equality
+// cannot be determined and will always fail.
+func (a *Assertions) Equal(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return Equal(a.t, expected, actual, msgAndArgs...)
+}
+
+// EqualError asserts that a function returned an error (i.e. not `nil`)
+// and that it is equal to the provided error.
+//
+// actualObj, err := SomeFunction()
+// a.EqualError(err, expectedErrorString)
+func (a *Assertions) EqualError(theError error, errString string, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return EqualError(a.t, theError, errString, msgAndArgs...)
+}
+
+// EqualErrorf asserts that a function returned an error (i.e. not `nil`)
+// and that it is equal to the provided error.
+//
+// actualObj, err := SomeFunction()
+// a.EqualErrorf(err, expectedErrorString, "error message %s", "formatted")
+func (a *Assertions) EqualErrorf(theError error, errString string, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return EqualErrorf(a.t, theError, errString, msg, args...)
+}
+
+// EqualValues asserts that two objects are equal or convertable to the same types
+// and equal.
+//
+// a.EqualValues(uint32(123), int32(123))
+func (a *Assertions) EqualValues(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return EqualValues(a.t, expected, actual, msgAndArgs...)
+}
+
+// EqualValuesf asserts that two objects are equal or convertable to the same types
+// and equal.
+//
+// a.EqualValuesf(uint32(123, "error message %s", "formatted"), int32(123))
+func (a *Assertions) EqualValuesf(expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return EqualValuesf(a.t, expected, actual, msg, args...)
+}
+
+// Equalf asserts that two objects are equal.
+//
+// a.Equalf(123, 123, "error message %s", "formatted")
+//
+// Pointer variable equality is determined based on the equality of the
+// referenced values (as opposed to the memory addresses). Function equality
+// cannot be determined and will always fail.
+func (a *Assertions) Equalf(expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return Equalf(a.t, expected, actual, msg, args...)
+}
+
+// Error asserts that a function returned an error (i.e. not `nil`).
+//
+// actualObj, err := SomeFunction()
+// if a.Error(err) {
+// assert.Equal(t, expectedError, err)
+// }
+func (a *Assertions) Error(err error, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return Error(a.t, err, msgAndArgs...)
+}
+
+// Errorf asserts that a function returned an error (i.e. not `nil`).
+//
+// actualObj, err := SomeFunction()
+// if a.Errorf(err, "error message %s", "formatted") {
+// assert.Equal(t, expectedErrorf, err)
+// }
+func (a *Assertions) Errorf(err error, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return Errorf(a.t, err, msg, args...)
+}
+
+// Eventually asserts that given condition will be met in waitFor time,
+// periodically checking target function each tick.
+//
+// a.Eventually(func() bool { return true; }, time.Second, 10*time.Millisecond)
+func (a *Assertions) Eventually(condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return Eventually(a.t, condition, waitFor, tick, msgAndArgs...)
+}
+
+// Eventuallyf asserts that given condition will be met in waitFor time,
+// periodically checking target function each tick.
+//
+// a.Eventuallyf(func() bool { return true; }, time.Second, 10*time.Millisecond, "error message %s", "formatted")
+func (a *Assertions) Eventuallyf(condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return Eventuallyf(a.t, condition, waitFor, tick, msg, args...)
+}
+
+// Exactly asserts that two objects are equal in value and type.
+//
+// a.Exactly(int32(123), int64(123))
+func (a *Assertions) Exactly(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return Exactly(a.t, expected, actual, msgAndArgs...)
+}
+
+// Exactlyf asserts that two objects are equal in value and type.
+//
+// a.Exactlyf(int32(123, "error message %s", "formatted"), int64(123))
+func (a *Assertions) Exactlyf(expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return Exactlyf(a.t, expected, actual, msg, args...)
+}
+
+// Fail reports a failure through
+func (a *Assertions) Fail(failureMessage string, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return Fail(a.t, failureMessage, msgAndArgs...)
+}
+
+// FailNow fails test
+func (a *Assertions) FailNow(failureMessage string, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return FailNow(a.t, failureMessage, msgAndArgs...)
+}
+
+// FailNowf fails test
+func (a *Assertions) FailNowf(failureMessage string, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return FailNowf(a.t, failureMessage, msg, args...)
+}
+
+// Failf reports a failure through
+func (a *Assertions) Failf(failureMessage string, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return Failf(a.t, failureMessage, msg, args...)
+}
+
+// False asserts that the specified value is false.
+//
+// a.False(myBool)
+func (a *Assertions) False(value bool, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return False(a.t, value, msgAndArgs...)
+}
+
+// Falsef asserts that the specified value is false.
+//
+// a.Falsef(myBool, "error message %s", "formatted")
+func (a *Assertions) Falsef(value bool, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return Falsef(a.t, value, msg, args...)
+}
+
+// FileExists checks whether a file exists in the given path. It also fails if the path points to a directory or there is an error when trying to check the file.
+func (a *Assertions) FileExists(path string, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return FileExists(a.t, path, msgAndArgs...)
+}
+
+// FileExistsf checks whether a file exists in the given path. It also fails if the path points to a directory or there is an error when trying to check the file.
+func (a *Assertions) FileExistsf(path string, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return FileExistsf(a.t, path, msg, args...)
+}
+
+// Greater asserts that the first element is greater than the second
+//
+// a.Greater(2, 1)
+// a.Greater(float64(2), float64(1))
+// a.Greater("b", "a")
+func (a *Assertions) Greater(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return Greater(a.t, e1, e2, msgAndArgs...)
+}
+
+// GreaterOrEqual asserts that the first element is greater than or equal to the second
+//
+// a.GreaterOrEqual(2, 1)
+// a.GreaterOrEqual(2, 2)
+// a.GreaterOrEqual("b", "a")
+// a.GreaterOrEqual("b", "b")
+func (a *Assertions) GreaterOrEqual(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return GreaterOrEqual(a.t, e1, e2, msgAndArgs...)
+}
+
+// GreaterOrEqualf asserts that the first element is greater than or equal to the second
+//
+// a.GreaterOrEqualf(2, 1, "error message %s", "formatted")
+// a.GreaterOrEqualf(2, 2, "error message %s", "formatted")
+// a.GreaterOrEqualf("b", "a", "error message %s", "formatted")
+// a.GreaterOrEqualf("b", "b", "error message %s", "formatted")
+func (a *Assertions) GreaterOrEqualf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return GreaterOrEqualf(a.t, e1, e2, msg, args...)
+}
+
+// Greaterf asserts that the first element is greater than the second
+//
+// a.Greaterf(2, 1, "error message %s", "formatted")
+// a.Greaterf(float64(2, "error message %s", "formatted"), float64(1))
+// a.Greaterf("b", "a", "error message %s", "formatted")
+func (a *Assertions) Greaterf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return Greaterf(a.t, e1, e2, msg, args...)
+}
+
+// HTTPBodyContains asserts that a specified handler returns a
+// body that contains a string.
+//
+// a.HTTPBodyContains(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) HTTPBodyContains(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return HTTPBodyContains(a.t, handler, method, url, values, str, msgAndArgs...)
+}
+
+// HTTPBodyContainsf asserts that a specified handler returns a
+// body that contains a string.
+//
+// a.HTTPBodyContainsf(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) HTTPBodyContainsf(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return HTTPBodyContainsf(a.t, handler, method, url, values, str, msg, args...)
+}
+
+// HTTPBodyNotContains asserts that a specified handler returns a
+// body that does not contain a string.
+//
+// a.HTTPBodyNotContains(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) HTTPBodyNotContains(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return HTTPBodyNotContains(a.t, handler, method, url, values, str, msgAndArgs...)
+}
+
+// HTTPBodyNotContainsf asserts that a specified handler returns a
+// body that does not contain a string.
+//
+// a.HTTPBodyNotContainsf(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) HTTPBodyNotContainsf(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return HTTPBodyNotContainsf(a.t, handler, method, url, values, str, msg, args...)
+}
+
+// HTTPError asserts that a specified handler returns an error status code.
+//
+// a.HTTPError(myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}}
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) HTTPError(handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return HTTPError(a.t, handler, method, url, values, msgAndArgs...)
+}
+
+// HTTPErrorf asserts that a specified handler returns an error status code.
+//
+// a.HTTPErrorf(myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}}
+//
+// Returns whether the assertion was successful (true, "error message %s", "formatted") or not (false).
+func (a *Assertions) HTTPErrorf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return HTTPErrorf(a.t, handler, method, url, values, msg, args...)
+}
+
+// HTTPRedirect asserts that a specified handler returns a redirect status code.
+//
+// a.HTTPRedirect(myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}}
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) HTTPRedirect(handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return HTTPRedirect(a.t, handler, method, url, values, msgAndArgs...)
+}
+
+// HTTPRedirectf asserts that a specified handler returns a redirect status code.
+//
+// a.HTTPRedirectf(myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}}
+//
+// Returns whether the assertion was successful (true, "error message %s", "formatted") or not (false).
+func (a *Assertions) HTTPRedirectf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return HTTPRedirectf(a.t, handler, method, url, values, msg, args...)
+}
+
+// HTTPSuccess asserts that a specified handler returns a success status code.
+//
+// a.HTTPSuccess(myHandler, "POST", "http://www.google.com", nil)
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) HTTPSuccess(handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return HTTPSuccess(a.t, handler, method, url, values, msgAndArgs...)
+}
+
+// HTTPSuccessf asserts that a specified handler returns a success status code.
+//
+// a.HTTPSuccessf(myHandler, "POST", "http://www.google.com", nil, "error message %s", "formatted")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) HTTPSuccessf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return HTTPSuccessf(a.t, handler, method, url, values, msg, args...)
+}
+
+// Implements asserts that an object is implemented by the specified interface.
+//
+// a.Implements((*MyInterface)(nil), new(MyObject))
+func (a *Assertions) Implements(interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return Implements(a.t, interfaceObject, object, msgAndArgs...)
+}
+
+// Implementsf asserts that an object is implemented by the specified interface.
+//
+// a.Implementsf((*MyInterface, "error message %s", "formatted")(nil), new(MyObject))
+func (a *Assertions) Implementsf(interfaceObject interface{}, object interface{}, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return Implementsf(a.t, interfaceObject, object, msg, args...)
+}
+
+// InDelta asserts that the two numerals are within delta of each other.
+//
+// a.InDelta(math.Pi, (22 / 7.0), 0.01)
+func (a *Assertions) InDelta(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return InDelta(a.t, expected, actual, delta, msgAndArgs...)
+}
+
+// InDeltaMapValues is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys.
+func (a *Assertions) InDeltaMapValues(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return InDeltaMapValues(a.t, expected, actual, delta, msgAndArgs...)
+}
+
+// InDeltaMapValuesf is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys.
+func (a *Assertions) InDeltaMapValuesf(expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return InDeltaMapValuesf(a.t, expected, actual, delta, msg, args...)
+}
+
+// InDeltaSlice is the same as InDelta, except it compares two slices.
+func (a *Assertions) InDeltaSlice(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return InDeltaSlice(a.t, expected, actual, delta, msgAndArgs...)
+}
+
+// InDeltaSlicef is the same as InDelta, except it compares two slices.
+func (a *Assertions) InDeltaSlicef(expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return InDeltaSlicef(a.t, expected, actual, delta, msg, args...)
+}
+
+// InDeltaf asserts that the two numerals are within delta of each other.
+//
+// a.InDeltaf(math.Pi, (22 / 7.0, "error message %s", "formatted"), 0.01)
+func (a *Assertions) InDeltaf(expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return InDeltaf(a.t, expected, actual, delta, msg, args...)
+}
+
+// InEpsilon asserts that expected and actual have a relative error less than epsilon
+func (a *Assertions) InEpsilon(expected interface{}, actual interface{}, epsilon float64, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return InEpsilon(a.t, expected, actual, epsilon, msgAndArgs...)
+}
+
+// InEpsilonSlice is the same as InEpsilon, except it compares each value from two slices.
+func (a *Assertions) InEpsilonSlice(expected interface{}, actual interface{}, epsilon float64, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return InEpsilonSlice(a.t, expected, actual, epsilon, msgAndArgs...)
+}
+
+// InEpsilonSlicef is the same as InEpsilon, except it compares each value from two slices.
+func (a *Assertions) InEpsilonSlicef(expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return InEpsilonSlicef(a.t, expected, actual, epsilon, msg, args...)
+}
+
+// InEpsilonf asserts that expected and actual have a relative error less than epsilon
+func (a *Assertions) InEpsilonf(expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return InEpsilonf(a.t, expected, actual, epsilon, msg, args...)
+}
+
+// IsType asserts that the specified objects are of the same type.
+func (a *Assertions) IsType(expectedType interface{}, object interface{}, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return IsType(a.t, expectedType, object, msgAndArgs...)
+}
+
+// IsTypef asserts that the specified objects are of the same type.
+func (a *Assertions) IsTypef(expectedType interface{}, object interface{}, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return IsTypef(a.t, expectedType, object, msg, args...)
+}
+
+// JSONEq asserts that two JSON strings are equivalent.
+//
+// a.JSONEq(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`)
+func (a *Assertions) JSONEq(expected string, actual string, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return JSONEq(a.t, expected, actual, msgAndArgs...)
+}
+
+// JSONEqf asserts that two JSON strings are equivalent.
+//
+// a.JSONEqf(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`, "error message %s", "formatted")
+func (a *Assertions) JSONEqf(expected string, actual string, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return JSONEqf(a.t, expected, actual, msg, args...)
+}
+
+// YAMLEq asserts that two YAML strings are equivalent.
+func (a *Assertions) YAMLEq(expected string, actual string, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return YAMLEq(a.t, expected, actual, msgAndArgs...)
+}
+
+// YAMLEqf asserts that two YAML strings are equivalent.
+func (a *Assertions) YAMLEqf(expected string, actual string, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return YAMLEqf(a.t, expected, actual, msg, args...)
+}
+
+// Len asserts that the specified object has specific length.
+// Len also fails if the object has a type that len() not accept.
+//
+// a.Len(mySlice, 3)
+func (a *Assertions) Len(object interface{}, length int, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return Len(a.t, object, length, msgAndArgs...)
+}
+
+// Lenf asserts that the specified object has specific length.
+// Lenf also fails if the object has a type that len() not accept.
+//
+// a.Lenf(mySlice, 3, "error message %s", "formatted")
+func (a *Assertions) Lenf(object interface{}, length int, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return Lenf(a.t, object, length, msg, args...)
+}
+
+// Less asserts that the first element is less than the second
+//
+// a.Less(1, 2)
+// a.Less(float64(1), float64(2))
+// a.Less("a", "b")
+func (a *Assertions) Less(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return Less(a.t, e1, e2, msgAndArgs...)
+}
+
+// LessOrEqual asserts that the first element is less than or equal to the second
+//
+// a.LessOrEqual(1, 2)
+// a.LessOrEqual(2, 2)
+// a.LessOrEqual("a", "b")
+// a.LessOrEqual("b", "b")
+func (a *Assertions) LessOrEqual(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return LessOrEqual(a.t, e1, e2, msgAndArgs...)
+}
+
+// LessOrEqualf asserts that the first element is less than or equal to the second
+//
+// a.LessOrEqualf(1, 2, "error message %s", "formatted")
+// a.LessOrEqualf(2, 2, "error message %s", "formatted")
+// a.LessOrEqualf("a", "b", "error message %s", "formatted")
+// a.LessOrEqualf("b", "b", "error message %s", "formatted")
+func (a *Assertions) LessOrEqualf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return LessOrEqualf(a.t, e1, e2, msg, args...)
+}
+
+// Lessf asserts that the first element is less than the second
+//
+// a.Lessf(1, 2, "error message %s", "formatted")
+// a.Lessf(float64(1, "error message %s", "formatted"), float64(2))
+// a.Lessf("a", "b", "error message %s", "formatted")
+func (a *Assertions) Lessf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return Lessf(a.t, e1, e2, msg, args...)
+}
+
+// Nil asserts that the specified object is nil.
+//
+// a.Nil(err)
+func (a *Assertions) Nil(object interface{}, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return Nil(a.t, object, msgAndArgs...)
+}
+
+// Nilf asserts that the specified object is nil.
+//
+// a.Nilf(err, "error message %s", "formatted")
+func (a *Assertions) Nilf(object interface{}, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return Nilf(a.t, object, msg, args...)
+}
+
+// NoError asserts that a function returned no error (i.e. `nil`).
+//
+// actualObj, err := SomeFunction()
+// if a.NoError(err) {
+// assert.Equal(t, expectedObj, actualObj)
+// }
+func (a *Assertions) NoError(err error, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return NoError(a.t, err, msgAndArgs...)
+}
+
+// NoErrorf asserts that a function returned no error (i.e. `nil`).
+//
+// actualObj, err := SomeFunction()
+// if a.NoErrorf(err, "error message %s", "formatted") {
+// assert.Equal(t, expectedObj, actualObj)
+// }
+func (a *Assertions) NoErrorf(err error, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return NoErrorf(a.t, err, msg, args...)
+}
+
+// NotContains asserts that the specified string, list(array, slice...) or map does NOT contain the
+// specified substring or element.
+//
+// a.NotContains("Hello World", "Earth")
+// a.NotContains(["Hello", "World"], "Earth")
+// a.NotContains({"Hello": "World"}, "Earth")
+func (a *Assertions) NotContains(s interface{}, contains interface{}, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return NotContains(a.t, s, contains, msgAndArgs...)
+}
+
+// NotContainsf asserts that the specified string, list(array, slice...) or map does NOT contain the
+// specified substring or element.
+//
+// a.NotContainsf("Hello World", "Earth", "error message %s", "formatted")
+// a.NotContainsf(["Hello", "World"], "Earth", "error message %s", "formatted")
+// a.NotContainsf({"Hello": "World"}, "Earth", "error message %s", "formatted")
+func (a *Assertions) NotContainsf(s interface{}, contains interface{}, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return NotContainsf(a.t, s, contains, msg, args...)
+}
+
+// NotEmpty asserts that the specified object is NOT empty. I.e. not nil, "", false, 0 or either
+// a slice or a channel with len == 0.
+//
+// if a.NotEmpty(obj) {
+// assert.Equal(t, "two", obj[1])
+// }
+func (a *Assertions) NotEmpty(object interface{}, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return NotEmpty(a.t, object, msgAndArgs...)
+}
+
+// NotEmptyf asserts that the specified object is NOT empty. I.e. not nil, "", false, 0 or either
+// a slice or a channel with len == 0.
+//
+// if a.NotEmptyf(obj, "error message %s", "formatted") {
+// assert.Equal(t, "two", obj[1])
+// }
+func (a *Assertions) NotEmptyf(object interface{}, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return NotEmptyf(a.t, object, msg, args...)
+}
+
+// NotEqual asserts that the specified values are NOT equal.
+//
+// a.NotEqual(obj1, obj2)
+//
+// Pointer variable equality is determined based on the equality of the
+// referenced values (as opposed to the memory addresses).
+func (a *Assertions) NotEqual(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return NotEqual(a.t, expected, actual, msgAndArgs...)
+}
+
+// NotEqualf asserts that the specified values are NOT equal.
+//
+// a.NotEqualf(obj1, obj2, "error message %s", "formatted")
+//
+// Pointer variable equality is determined based on the equality of the
+// referenced values (as opposed to the memory addresses).
+func (a *Assertions) NotEqualf(expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return NotEqualf(a.t, expected, actual, msg, args...)
+}
+
+// NotNil asserts that the specified object is not nil.
+//
+// a.NotNil(err)
+func (a *Assertions) NotNil(object interface{}, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return NotNil(a.t, object, msgAndArgs...)
+}
+
+// NotNilf asserts that the specified object is not nil.
+//
+// a.NotNilf(err, "error message %s", "formatted")
+func (a *Assertions) NotNilf(object interface{}, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return NotNilf(a.t, object, msg, args...)
+}
+
+// NotPanics asserts that the code inside the specified PanicTestFunc does NOT panic.
+//
+// a.NotPanics(func(){ RemainCalm() })
+func (a *Assertions) NotPanics(f PanicTestFunc, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return NotPanics(a.t, f, msgAndArgs...)
+}
+
+// NotPanicsf asserts that the code inside the specified PanicTestFunc does NOT panic.
+//
+// a.NotPanicsf(func(){ RemainCalm() }, "error message %s", "formatted")
+func (a *Assertions) NotPanicsf(f PanicTestFunc, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return NotPanicsf(a.t, f, msg, args...)
+}
+
+// NotRegexp asserts that a specified regexp does not match a string.
+//
+// a.NotRegexp(regexp.MustCompile("starts"), "it's starting")
+// a.NotRegexp("^start", "it's not starting")
+func (a *Assertions) NotRegexp(rx interface{}, str interface{}, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return NotRegexp(a.t, rx, str, msgAndArgs...)
+}
+
+// NotRegexpf asserts that a specified regexp does not match a string.
+//
+// a.NotRegexpf(regexp.MustCompile("starts", "error message %s", "formatted"), "it's starting")
+// a.NotRegexpf("^start", "it's not starting", "error message %s", "formatted")
+func (a *Assertions) NotRegexpf(rx interface{}, str interface{}, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return NotRegexpf(a.t, rx, str, msg, args...)
+}
+
+// NotSubset asserts that the specified list(array, slice...) contains not all
+// elements given in the specified subset(array, slice...).
+//
+// a.NotSubset([1, 3, 4], [1, 2], "But [1, 3, 4] does not contain [1, 2]")
+func (a *Assertions) NotSubset(list interface{}, subset interface{}, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return NotSubset(a.t, list, subset, msgAndArgs...)
+}
+
+// NotSubsetf asserts that the specified list(array, slice...) contains not all
+// elements given in the specified subset(array, slice...).
+//
+// a.NotSubsetf([1, 3, 4], [1, 2], "But [1, 3, 4] does not contain [1, 2]", "error message %s", "formatted")
+func (a *Assertions) NotSubsetf(list interface{}, subset interface{}, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return NotSubsetf(a.t, list, subset, msg, args...)
+}
+
+// NotZero asserts that i is not the zero value for its type.
+func (a *Assertions) NotZero(i interface{}, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return NotZero(a.t, i, msgAndArgs...)
+}
+
+// NotZerof asserts that i is not the zero value for its type.
+func (a *Assertions) NotZerof(i interface{}, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return NotZerof(a.t, i, msg, args...)
+}
+
+// Panics asserts that the code inside the specified PanicTestFunc panics.
+//
+// a.Panics(func(){ GoCrazy() })
+func (a *Assertions) Panics(f PanicTestFunc, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return Panics(a.t, f, msgAndArgs...)
+}
+
+// PanicsWithValue asserts that the code inside the specified PanicTestFunc panics, and that
+// the recovered panic value equals the expected panic value.
+//
+// a.PanicsWithValue("crazy error", func(){ GoCrazy() })
+func (a *Assertions) PanicsWithValue(expected interface{}, f PanicTestFunc, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return PanicsWithValue(a.t, expected, f, msgAndArgs...)
+}
+
+// PanicsWithValuef asserts that the code inside the specified PanicTestFunc panics, and that
+// the recovered panic value equals the expected panic value.
+//
+// a.PanicsWithValuef("crazy error", func(){ GoCrazy() }, "error message %s", "formatted")
+func (a *Assertions) PanicsWithValuef(expected interface{}, f PanicTestFunc, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return PanicsWithValuef(a.t, expected, f, msg, args...)
+}
+
+// Panicsf asserts that the code inside the specified PanicTestFunc panics.
+//
+// a.Panicsf(func(){ GoCrazy() }, "error message %s", "formatted")
+func (a *Assertions) Panicsf(f PanicTestFunc, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return Panicsf(a.t, f, msg, args...)
+}
+
+// Regexp asserts that a specified regexp matches a string.
+//
+// a.Regexp(regexp.MustCompile("start"), "it's starting")
+// a.Regexp("start...$", "it's not starting")
+func (a *Assertions) Regexp(rx interface{}, str interface{}, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return Regexp(a.t, rx, str, msgAndArgs...)
+}
+
+// Regexpf asserts that a specified regexp matches a string.
+//
+// a.Regexpf(regexp.MustCompile("start", "error message %s", "formatted"), "it's starting")
+// a.Regexpf("start...$", "it's not starting", "error message %s", "formatted")
+func (a *Assertions) Regexpf(rx interface{}, str interface{}, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return Regexpf(a.t, rx, str, msg, args...)
+}
+
+// Same asserts that two pointers reference the same object.
+//
+// a.Same(ptr1, ptr2)
+//
+// Both arguments must be pointer variables. Pointer variable sameness is
+// determined based on the equality of both type and value.
+func (a *Assertions) Same(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return Same(a.t, expected, actual, msgAndArgs...)
+}
+
+// Samef asserts that two pointers reference the same object.
+//
+// a.Samef(ptr1, ptr2, "error message %s", "formatted")
+//
+// Both arguments must be pointer variables. Pointer variable sameness is
+// determined based on the equality of both type and value.
+func (a *Assertions) Samef(expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return Samef(a.t, expected, actual, msg, args...)
+}
+
+// Subset asserts that the specified list(array, slice...) contains all
+// elements given in the specified subset(array, slice...).
+//
+// a.Subset([1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]")
+func (a *Assertions) Subset(list interface{}, subset interface{}, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return Subset(a.t, list, subset, msgAndArgs...)
+}
+
+// Subsetf asserts that the specified list(array, slice...) contains all
+// elements given in the specified subset(array, slice...).
+//
+// a.Subsetf([1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]", "error message %s", "formatted")
+func (a *Assertions) Subsetf(list interface{}, subset interface{}, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return Subsetf(a.t, list, subset, msg, args...)
+}
+
+// True asserts that the specified value is true.
+//
+// a.True(myBool)
+func (a *Assertions) True(value bool, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return True(a.t, value, msgAndArgs...)
+}
+
+// Truef asserts that the specified value is true.
+//
+// a.Truef(myBool, "error message %s", "formatted")
+func (a *Assertions) Truef(value bool, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return Truef(a.t, value, msg, args...)
+}
+
+// WithinDuration asserts that the two times are within duration delta of each other.
+//
+// a.WithinDuration(time.Now(), time.Now(), 10*time.Second)
+func (a *Assertions) WithinDuration(expected time.Time, actual time.Time, delta time.Duration, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return WithinDuration(a.t, expected, actual, delta, msgAndArgs...)
+}
+
+// WithinDurationf asserts that the two times are within duration delta of each other.
+//
+// a.WithinDurationf(time.Now(), time.Now(), 10*time.Second, "error message %s", "formatted")
+func (a *Assertions) WithinDurationf(expected time.Time, actual time.Time, delta time.Duration, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return WithinDurationf(a.t, expected, actual, delta, msg, args...)
+}
+
+// Zero asserts that i is the zero value for its type.
+func (a *Assertions) Zero(i interface{}, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return Zero(a.t, i, msgAndArgs...)
+}
+
+// Zerof asserts that i is the zero value for its type.
+func (a *Assertions) Zerof(i interface{}, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
+ return Zerof(a.t, i, msg, args...)
+}
diff --git a/vendor/github.com/stretchr/testify/assert/assertion_forward.go.tmpl b/vendor/github.com/stretchr/testify/assert/assertion_forward.go.tmpl
new file mode 100644
index 0000000..188bb9e
--- /dev/null
+++ b/vendor/github.com/stretchr/testify/assert/assertion_forward.go.tmpl
@@ -0,0 +1,5 @@
+{{.CommentWithoutT "a"}}
+func (a *Assertions) {{.DocInfo.Name}}({{.Params}}) bool {
+ if h, ok := a.t.(tHelper); ok { h.Helper() }
+ return {{.DocInfo.Name}}(a.t, {{.ForwardedParams}})
+}
diff --git a/vendor/github.com/stretchr/testify/assert/assertion_order.go b/vendor/github.com/stretchr/testify/assert/assertion_order.go
new file mode 100644
index 0000000..15a486c
--- /dev/null
+++ b/vendor/github.com/stretchr/testify/assert/assertion_order.go
@@ -0,0 +1,309 @@
+package assert
+
+import (
+ "fmt"
+ "reflect"
+)
+
+func compare(obj1, obj2 interface{}, kind reflect.Kind) (int, bool) {
+ switch kind {
+ case reflect.Int:
+ {
+ intobj1 := obj1.(int)
+ intobj2 := obj2.(int)
+ if intobj1 > intobj2 {
+ return -1, true
+ }
+ if intobj1 == intobj2 {
+ return 0, true
+ }
+ if intobj1 < intobj2 {
+ return 1, true
+ }
+ }
+ case reflect.Int8:
+ {
+ int8obj1 := obj1.(int8)
+ int8obj2 := obj2.(int8)
+ if int8obj1 > int8obj2 {
+ return -1, true
+ }
+ if int8obj1 == int8obj2 {
+ return 0, true
+ }
+ if int8obj1 < int8obj2 {
+ return 1, true
+ }
+ }
+ case reflect.Int16:
+ {
+ int16obj1 := obj1.(int16)
+ int16obj2 := obj2.(int16)
+ if int16obj1 > int16obj2 {
+ return -1, true
+ }
+ if int16obj1 == int16obj2 {
+ return 0, true
+ }
+ if int16obj1 < int16obj2 {
+ return 1, true
+ }
+ }
+ case reflect.Int32:
+ {
+ int32obj1 := obj1.(int32)
+ int32obj2 := obj2.(int32)
+ if int32obj1 > int32obj2 {
+ return -1, true
+ }
+ if int32obj1 == int32obj2 {
+ return 0, true
+ }
+ if int32obj1 < int32obj2 {
+ return 1, true
+ }
+ }
+ case reflect.Int64:
+ {
+ int64obj1 := obj1.(int64)
+ int64obj2 := obj2.(int64)
+ if int64obj1 > int64obj2 {
+ return -1, true
+ }
+ if int64obj1 == int64obj2 {
+ return 0, true
+ }
+ if int64obj1 < int64obj2 {
+ return 1, true
+ }
+ }
+ case reflect.Uint:
+ {
+ uintobj1 := obj1.(uint)
+ uintobj2 := obj2.(uint)
+ if uintobj1 > uintobj2 {
+ return -1, true
+ }
+ if uintobj1 == uintobj2 {
+ return 0, true
+ }
+ if uintobj1 < uintobj2 {
+ return 1, true
+ }
+ }
+ case reflect.Uint8:
+ {
+ uint8obj1 := obj1.(uint8)
+ uint8obj2 := obj2.(uint8)
+ if uint8obj1 > uint8obj2 {
+ return -1, true
+ }
+ if uint8obj1 == uint8obj2 {
+ return 0, true
+ }
+ if uint8obj1 < uint8obj2 {
+ return 1, true
+ }
+ }
+ case reflect.Uint16:
+ {
+ uint16obj1 := obj1.(uint16)
+ uint16obj2 := obj2.(uint16)
+ if uint16obj1 > uint16obj2 {
+ return -1, true
+ }
+ if uint16obj1 == uint16obj2 {
+ return 0, true
+ }
+ if uint16obj1 < uint16obj2 {
+ return 1, true
+ }
+ }
+ case reflect.Uint32:
+ {
+ uint32obj1 := obj1.(uint32)
+ uint32obj2 := obj2.(uint32)
+ if uint32obj1 > uint32obj2 {
+ return -1, true
+ }
+ if uint32obj1 == uint32obj2 {
+ return 0, true
+ }
+ if uint32obj1 < uint32obj2 {
+ return 1, true
+ }
+ }
+ case reflect.Uint64:
+ {
+ uint64obj1 := obj1.(uint64)
+ uint64obj2 := obj2.(uint64)
+ if uint64obj1 > uint64obj2 {
+ return -1, true
+ }
+ if uint64obj1 == uint64obj2 {
+ return 0, true
+ }
+ if uint64obj1 < uint64obj2 {
+ return 1, true
+ }
+ }
+ case reflect.Float32:
+ {
+ float32obj1 := obj1.(float32)
+ float32obj2 := obj2.(float32)
+ if float32obj1 > float32obj2 {
+ return -1, true
+ }
+ if float32obj1 == float32obj2 {
+ return 0, true
+ }
+ if float32obj1 < float32obj2 {
+ return 1, true
+ }
+ }
+ case reflect.Float64:
+ {
+ float64obj1 := obj1.(float64)
+ float64obj2 := obj2.(float64)
+ if float64obj1 > float64obj2 {
+ return -1, true
+ }
+ if float64obj1 == float64obj2 {
+ return 0, true
+ }
+ if float64obj1 < float64obj2 {
+ return 1, true
+ }
+ }
+ case reflect.String:
+ {
+ stringobj1 := obj1.(string)
+ stringobj2 := obj2.(string)
+ if stringobj1 > stringobj2 {
+ return -1, true
+ }
+ if stringobj1 == stringobj2 {
+ return 0, true
+ }
+ if stringobj1 < stringobj2 {
+ return 1, true
+ }
+ }
+ }
+
+ return 0, false
+}
+
+// Greater asserts that the first element is greater than the second
+//
+// assert.Greater(t, 2, 1)
+// assert.Greater(t, float64(2), float64(1))
+// assert.Greater(t, "b", "a")
+func Greater(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+
+ e1Kind := reflect.ValueOf(e1).Kind()
+ e2Kind := reflect.ValueOf(e2).Kind()
+ if e1Kind != e2Kind {
+ return Fail(t, "Elements should be the same type", msgAndArgs...)
+ }
+
+ res, isComparable := compare(e1, e2, e1Kind)
+ if !isComparable {
+ return Fail(t, fmt.Sprintf("Can not compare type \"%s\"", reflect.TypeOf(e1)), msgAndArgs...)
+ }
+
+ if res != -1 {
+ return Fail(t, fmt.Sprintf("\"%v\" is not greater than \"%v\"", e1, e2), msgAndArgs...)
+ }
+
+ return true
+}
+
+// GreaterOrEqual asserts that the first element is greater than or equal to the second
+//
+// assert.GreaterOrEqual(t, 2, 1)
+// assert.GreaterOrEqual(t, 2, 2)
+// assert.GreaterOrEqual(t, "b", "a")
+// assert.GreaterOrEqual(t, "b", "b")
+func GreaterOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+
+ e1Kind := reflect.ValueOf(e1).Kind()
+ e2Kind := reflect.ValueOf(e2).Kind()
+ if e1Kind != e2Kind {
+ return Fail(t, "Elements should be the same type", msgAndArgs...)
+ }
+
+ res, isComparable := compare(e1, e2, e1Kind)
+ if !isComparable {
+ return Fail(t, fmt.Sprintf("Can not compare type \"%s\"", reflect.TypeOf(e1)), msgAndArgs...)
+ }
+
+ if res != -1 && res != 0 {
+ return Fail(t, fmt.Sprintf("\"%v\" is not greater than or equal to \"%v\"", e1, e2), msgAndArgs...)
+ }
+
+ return true
+}
+
+// Less asserts that the first element is less than the second
+//
+// assert.Less(t, 1, 2)
+// assert.Less(t, float64(1), float64(2))
+// assert.Less(t, "a", "b")
+func Less(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+
+ e1Kind := reflect.ValueOf(e1).Kind()
+ e2Kind := reflect.ValueOf(e2).Kind()
+ if e1Kind != e2Kind {
+ return Fail(t, "Elements should be the same type", msgAndArgs...)
+ }
+
+ res, isComparable := compare(e1, e2, e1Kind)
+ if !isComparable {
+ return Fail(t, fmt.Sprintf("Can not compare type \"%s\"", reflect.TypeOf(e1)), msgAndArgs...)
+ }
+
+ if res != 1 {
+ return Fail(t, fmt.Sprintf("\"%v\" is not less than \"%v\"", e1, e2), msgAndArgs...)
+ }
+
+ return true
+}
+
+// LessOrEqual asserts that the first element is less than or equal to the second
+//
+// assert.LessOrEqual(t, 1, 2)
+// assert.LessOrEqual(t, 2, 2)
+// assert.LessOrEqual(t, "a", "b")
+// assert.LessOrEqual(t, "b", "b")
+func LessOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+
+ e1Kind := reflect.ValueOf(e1).Kind()
+ e2Kind := reflect.ValueOf(e2).Kind()
+ if e1Kind != e2Kind {
+ return Fail(t, "Elements should be the same type", msgAndArgs...)
+ }
+
+ res, isComparable := compare(e1, e2, e1Kind)
+ if !isComparable {
+ return Fail(t, fmt.Sprintf("Can not compare type \"%s\"", reflect.TypeOf(e1)), msgAndArgs...)
+ }
+
+ if res != 1 && res != 0 {
+ return Fail(t, fmt.Sprintf("\"%v\" is not less than or equal to \"%v\"", e1, e2), msgAndArgs...)
+ }
+
+ return true
+}
diff --git a/vendor/github.com/stretchr/testify/assert/assertions.go b/vendor/github.com/stretchr/testify/assert/assertions.go
new file mode 100644
index 0000000..044da8b
--- /dev/null
+++ b/vendor/github.com/stretchr/testify/assert/assertions.go
@@ -0,0 +1,1498 @@
+package assert
+
+import (
+ "bufio"
+ "bytes"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "math"
+ "os"
+ "reflect"
+ "regexp"
+ "runtime"
+ "strings"
+ "time"
+ "unicode"
+ "unicode/utf8"
+
+ "github.com/davecgh/go-spew/spew"
+ "github.com/pmezard/go-difflib/difflib"
+ yaml "gopkg.in/yaml.v2"
+)
+
+//go:generate go run ../_codegen/main.go -output-package=assert -template=assertion_format.go.tmpl
+
+// TestingT is an interface wrapper around *testing.T
+type TestingT interface {
+ Errorf(format string, args ...interface{})
+}
+
+// ComparisonAssertionFunc is a common function prototype when comparing two values. Can be useful
+// for table driven tests.
+type ComparisonAssertionFunc func(TestingT, interface{}, interface{}, ...interface{}) bool
+
+// ValueAssertionFunc is a common function prototype when validating a single value. Can be useful
+// for table driven tests.
+type ValueAssertionFunc func(TestingT, interface{}, ...interface{}) bool
+
+// BoolAssertionFunc is a common function prototype when validating a bool value. Can be useful
+// for table driven tests.
+type BoolAssertionFunc func(TestingT, bool, ...interface{}) bool
+
+// ErrorAssertionFunc is a common function prototype when validating an error value. Can be useful
+// for table driven tests.
+type ErrorAssertionFunc func(TestingT, error, ...interface{}) bool
+
+// Comparison a custom function that returns true on success and false on failure
+type Comparison func() (success bool)
+
+/*
+ Helper functions
+*/
+
+// ObjectsAreEqual determines if two objects are considered equal.
+//
+// This function does no assertion of any kind.
+func ObjectsAreEqual(expected, actual interface{}) bool {
+ if expected == nil || actual == nil {
+ return expected == actual
+ }
+
+ exp, ok := expected.([]byte)
+ if !ok {
+ return reflect.DeepEqual(expected, actual)
+ }
+
+ act, ok := actual.([]byte)
+ if !ok {
+ return false
+ }
+ if exp == nil || act == nil {
+ return exp == nil && act == nil
+ }
+ return bytes.Equal(exp, act)
+}
+
+// ObjectsAreEqualValues gets whether two objects are equal, or if their
+// values are equal.
+func ObjectsAreEqualValues(expected, actual interface{}) bool {
+ if ObjectsAreEqual(expected, actual) {
+ return true
+ }
+
+ actualType := reflect.TypeOf(actual)
+ if actualType == nil {
+ return false
+ }
+ expectedValue := reflect.ValueOf(expected)
+ if expectedValue.IsValid() && expectedValue.Type().ConvertibleTo(actualType) {
+ // Attempt comparison after type conversion
+ return reflect.DeepEqual(expectedValue.Convert(actualType).Interface(), actual)
+ }
+
+ return false
+}
+
+/* CallerInfo is necessary because the assert functions use the testing object
+internally, causing it to print the file:line of the assert method, rather than where
+the problem actually occurred in calling code.*/
+
+// CallerInfo returns an array of strings containing the file and line number
+// of each stack frame leading from the current test to the assert call that
+// failed.
+func CallerInfo() []string {
+
+ pc := uintptr(0)
+ file := ""
+ line := 0
+ ok := false
+ name := ""
+
+ callers := []string{}
+ for i := 0; ; i++ {
+ pc, file, line, ok = runtime.Caller(i)
+ if !ok {
+ // The breaks below failed to terminate the loop, and we ran off the
+ // end of the call stack.
+ break
+ }
+
+ // This is a huge edge case, but it will panic if this is the case, see #180
+ if file == "" {
+ break
+ }
+
+ f := runtime.FuncForPC(pc)
+ if f == nil {
+ break
+ }
+ name = f.Name()
+
+ // testing.tRunner is the standard library function that calls
+ // tests. Subtests are called directly by tRunner, without going through
+ // the Test/Benchmark/Example function that contains the t.Run calls, so
+ // with subtests we should break when we hit tRunner, without adding it
+ // to the list of callers.
+ if name == "testing.tRunner" {
+ break
+ }
+
+ parts := strings.Split(file, "/")
+ file = parts[len(parts)-1]
+ if len(parts) > 1 {
+ dir := parts[len(parts)-2]
+ if (dir != "assert" && dir != "mock" && dir != "require") || file == "mock_test.go" {
+ callers = append(callers, fmt.Sprintf("%s:%d", file, line))
+ }
+ }
+
+ // Drop the package
+ segments := strings.Split(name, ".")
+ name = segments[len(segments)-1]
+ if isTest(name, "Test") ||
+ isTest(name, "Benchmark") ||
+ isTest(name, "Example") {
+ break
+ }
+ }
+
+ return callers
+}
+
+// Stolen from the `go test` tool.
+// isTest tells whether name looks like a test (or benchmark, according to prefix).
+// It is a Test (say) if there is a character after Test that is not a lower-case letter.
+// We don't want TesticularCancer.
+func isTest(name, prefix string) bool {
+ if !strings.HasPrefix(name, prefix) {
+ return false
+ }
+ if len(name) == len(prefix) { // "Test" is ok
+ return true
+ }
+ rune, _ := utf8.DecodeRuneInString(name[len(prefix):])
+ return !unicode.IsLower(rune)
+}
+
+func messageFromMsgAndArgs(msgAndArgs ...interface{}) string {
+ if len(msgAndArgs) == 0 || msgAndArgs == nil {
+ return ""
+ }
+ if len(msgAndArgs) == 1 {
+ msg := msgAndArgs[0]
+ if msgAsStr, ok := msg.(string); ok {
+ return msgAsStr
+ }
+ return fmt.Sprintf("%+v", msg)
+ }
+ if len(msgAndArgs) > 1 {
+ return fmt.Sprintf(msgAndArgs[0].(string), msgAndArgs[1:]...)
+ }
+ return ""
+}
+
+// Aligns the provided message so that all lines after the first line start at the same location as the first line.
+// Assumes that the first line starts at the correct location (after carriage return, tab, label, spacer and tab).
+// The longestLabelLen parameter specifies the length of the longest label in the output (required becaues this is the
+// basis on which the alignment occurs).
+func indentMessageLines(message string, longestLabelLen int) string {
+ outBuf := new(bytes.Buffer)
+
+ for i, scanner := 0, bufio.NewScanner(strings.NewReader(message)); scanner.Scan(); i++ {
+ // no need to align first line because it starts at the correct location (after the label)
+ if i != 0 {
+ // append alignLen+1 spaces to align with "{{longestLabel}}:" before adding tab
+ outBuf.WriteString("\n\t" + strings.Repeat(" ", longestLabelLen+1) + "\t")
+ }
+ outBuf.WriteString(scanner.Text())
+ }
+
+ return outBuf.String()
+}
+
+type failNower interface {
+ FailNow()
+}
+
+// FailNow fails test
+func FailNow(t TestingT, failureMessage string, msgAndArgs ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ Fail(t, failureMessage, msgAndArgs...)
+
+ // We cannot extend TestingT with FailNow() and
+ // maintain backwards compatibility, so we fallback
+ // to panicking when FailNow is not available in
+ // TestingT.
+ // See issue #263
+
+ if t, ok := t.(failNower); ok {
+ t.FailNow()
+ } else {
+ panic("test failed and t is missing `FailNow()`")
+ }
+ return false
+}
+
+// Fail reports a failure through
+func Fail(t TestingT, failureMessage string, msgAndArgs ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ content := []labeledContent{
+ {"Error Trace", strings.Join(CallerInfo(), "\n\t\t\t")},
+ {"Error", failureMessage},
+ }
+
+ // Add test name if the Go version supports it
+ if n, ok := t.(interface {
+ Name() string
+ }); ok {
+ content = append(content, labeledContent{"Test", n.Name()})
+ }
+
+ message := messageFromMsgAndArgs(msgAndArgs...)
+ if len(message) > 0 {
+ content = append(content, labeledContent{"Messages", message})
+ }
+
+ t.Errorf("\n%s", ""+labeledOutput(content...))
+
+ return false
+}
+
+type labeledContent struct {
+ label string
+ content string
+}
+
+// labeledOutput returns a string consisting of the provided labeledContent. Each labeled output is appended in the following manner:
+//
+// \t{{label}}:{{align_spaces}}\t{{content}}\n
+//
+// The initial carriage return is required to undo/erase any padding added by testing.T.Errorf. The "\t{{label}}:" is for the label.
+// If a label is shorter than the longest label provided, padding spaces are added to make all the labels match in length. Once this
+// alignment is achieved, "\t{{content}}\n" is added for the output.
+//
+// If the content of the labeledOutput contains line breaks, the subsequent lines are aligned so that they start at the same location as the first line.
+func labeledOutput(content ...labeledContent) string {
+ longestLabel := 0
+ for _, v := range content {
+ if len(v.label) > longestLabel {
+ longestLabel = len(v.label)
+ }
+ }
+ var output string
+ for _, v := range content {
+ output += "\t" + v.label + ":" + strings.Repeat(" ", longestLabel-len(v.label)) + "\t" + indentMessageLines(v.content, longestLabel) + "\n"
+ }
+ return output
+}
+
+// Implements asserts that an object is implemented by the specified interface.
+//
+// assert.Implements(t, (*MyInterface)(nil), new(MyObject))
+func Implements(t TestingT, interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ interfaceType := reflect.TypeOf(interfaceObject).Elem()
+
+ if object == nil {
+ return Fail(t, fmt.Sprintf("Cannot check if nil implements %v", interfaceType), msgAndArgs...)
+ }
+ if !reflect.TypeOf(object).Implements(interfaceType) {
+ return Fail(t, fmt.Sprintf("%T must implement %v", object, interfaceType), msgAndArgs...)
+ }
+
+ return true
+}
+
+// IsType asserts that the specified objects are of the same type.
+func IsType(t TestingT, expectedType interface{}, object interface{}, msgAndArgs ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+
+ if !ObjectsAreEqual(reflect.TypeOf(object), reflect.TypeOf(expectedType)) {
+ return Fail(t, fmt.Sprintf("Object expected to be of type %v, but was %v", reflect.TypeOf(expectedType), reflect.TypeOf(object)), msgAndArgs...)
+ }
+
+ return true
+}
+
+// Equal asserts that two objects are equal.
+//
+// assert.Equal(t, 123, 123)
+//
+// Pointer variable equality is determined based on the equality of the
+// referenced values (as opposed to the memory addresses). Function equality
+// cannot be determined and will always fail.
+func Equal(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if err := validateEqualArgs(expected, actual); err != nil {
+ return Fail(t, fmt.Sprintf("Invalid operation: %#v == %#v (%s)",
+ expected, actual, err), msgAndArgs...)
+ }
+
+ if !ObjectsAreEqual(expected, actual) {
+ diff := diff(expected, actual)
+ expected, actual = formatUnequalValues(expected, actual)
+ return Fail(t, fmt.Sprintf("Not equal: \n"+
+ "expected: %s\n"+
+ "actual : %s%s", expected, actual, diff), msgAndArgs...)
+ }
+
+ return true
+
+}
+
+// Same asserts that two pointers reference the same object.
+//
+// assert.Same(t, ptr1, ptr2)
+//
+// Both arguments must be pointer variables. Pointer variable sameness is
+// determined based on the equality of both type and value.
+func Same(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+
+ expectedPtr, actualPtr := reflect.ValueOf(expected), reflect.ValueOf(actual)
+ if expectedPtr.Kind() != reflect.Ptr || actualPtr.Kind() != reflect.Ptr {
+ return Fail(t, "Invalid operation: both arguments must be pointers", msgAndArgs...)
+ }
+
+ expectedType, actualType := reflect.TypeOf(expected), reflect.TypeOf(actual)
+ if expectedType != actualType {
+ return Fail(t, fmt.Sprintf("Pointer expected to be of type %v, but was %v",
+ expectedType, actualType), msgAndArgs...)
+ }
+
+ if expected != actual {
+ return Fail(t, fmt.Sprintf("Not same: \n"+
+ "expected: %p %#v\n"+
+ "actual : %p %#v", expected, expected, actual, actual), msgAndArgs...)
+ }
+
+ return true
+}
+
+// formatUnequalValues takes two values of arbitrary types and returns string
+// representations appropriate to be presented to the user.
+//
+// If the values are not of like type, the returned strings will be prefixed
+// with the type name, and the value will be enclosed in parenthesis similar
+// to a type conversion in the Go grammar.
+func formatUnequalValues(expected, actual interface{}) (e string, a string) {
+ if reflect.TypeOf(expected) != reflect.TypeOf(actual) {
+ return fmt.Sprintf("%T(%#v)", expected, expected),
+ fmt.Sprintf("%T(%#v)", actual, actual)
+ }
+
+ return fmt.Sprintf("%#v", expected),
+ fmt.Sprintf("%#v", actual)
+}
+
+// EqualValues asserts that two objects are equal or convertable to the same types
+// and equal.
+//
+// assert.EqualValues(t, uint32(123), int32(123))
+func EqualValues(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+
+ if !ObjectsAreEqualValues(expected, actual) {
+ diff := diff(expected, actual)
+ expected, actual = formatUnequalValues(expected, actual)
+ return Fail(t, fmt.Sprintf("Not equal: \n"+
+ "expected: %s\n"+
+ "actual : %s%s", expected, actual, diff), msgAndArgs...)
+ }
+
+ return true
+
+}
+
+// Exactly asserts that two objects are equal in value and type.
+//
+// assert.Exactly(t, int32(123), int64(123))
+func Exactly(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+
+ aType := reflect.TypeOf(expected)
+ bType := reflect.TypeOf(actual)
+
+ if aType != bType {
+ return Fail(t, fmt.Sprintf("Types expected to match exactly\n\t%v != %v", aType, bType), msgAndArgs...)
+ }
+
+ return Equal(t, expected, actual, msgAndArgs...)
+
+}
+
+// NotNil asserts that the specified object is not nil.
+//
+// assert.NotNil(t, err)
+func NotNil(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if !isNil(object) {
+ return true
+ }
+ return Fail(t, "Expected value not to be nil.", msgAndArgs...)
+}
+
+// containsKind checks if a specified kind in the slice of kinds.
+func containsKind(kinds []reflect.Kind, kind reflect.Kind) bool {
+ for i := 0; i < len(kinds); i++ {
+ if kind == kinds[i] {
+ return true
+ }
+ }
+
+ return false
+}
+
+// isNil checks if a specified object is nil or not, without Failing.
+func isNil(object interface{}) bool {
+ if object == nil {
+ return true
+ }
+
+ value := reflect.ValueOf(object)
+ kind := value.Kind()
+ isNilableKind := containsKind(
+ []reflect.Kind{
+ reflect.Chan, reflect.Func,
+ reflect.Interface, reflect.Map,
+ reflect.Ptr, reflect.Slice},
+ kind)
+
+ if isNilableKind && value.IsNil() {
+ return true
+ }
+
+ return false
+}
+
+// Nil asserts that the specified object is nil.
+//
+// assert.Nil(t, err)
+func Nil(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if isNil(object) {
+ return true
+ }
+ return Fail(t, fmt.Sprintf("Expected nil, but got: %#v", object), msgAndArgs...)
+}
+
+// isEmpty gets whether the specified object is considered empty or not.
+func isEmpty(object interface{}) bool {
+
+ // get nil case out of the way
+ if object == nil {
+ return true
+ }
+
+ objValue := reflect.ValueOf(object)
+
+ switch objValue.Kind() {
+ // collection types are empty when they have no element
+ case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice:
+ return objValue.Len() == 0
+ // pointers are empty if nil or if the value they point to is empty
+ case reflect.Ptr:
+ if objValue.IsNil() {
+ return true
+ }
+ deref := objValue.Elem().Interface()
+ return isEmpty(deref)
+ // for all other types, compare against the zero value
+ default:
+ zero := reflect.Zero(objValue.Type())
+ return reflect.DeepEqual(object, zero.Interface())
+ }
+}
+
+// Empty asserts that the specified object is empty. I.e. nil, "", false, 0 or either
+// a slice or a channel with len == 0.
+//
+// assert.Empty(t, obj)
+func Empty(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+
+ pass := isEmpty(object)
+ if !pass {
+ Fail(t, fmt.Sprintf("Should be empty, but was %v", object), msgAndArgs...)
+ }
+
+ return pass
+
+}
+
+// NotEmpty asserts that the specified object is NOT empty. I.e. not nil, "", false, 0 or either
+// a slice or a channel with len == 0.
+//
+// if assert.NotEmpty(t, obj) {
+// assert.Equal(t, "two", obj[1])
+// }
+func NotEmpty(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+
+ pass := !isEmpty(object)
+ if !pass {
+ Fail(t, fmt.Sprintf("Should NOT be empty, but was %v", object), msgAndArgs...)
+ }
+
+ return pass
+
+}
+
+// getLen try to get length of object.
+// return (false, 0) if impossible.
+func getLen(x interface{}) (ok bool, length int) {
+ v := reflect.ValueOf(x)
+ defer func() {
+ if e := recover(); e != nil {
+ ok = false
+ }
+ }()
+ return true, v.Len()
+}
+
+// Len asserts that the specified object has specific length.
+// Len also fails if the object has a type that len() not accept.
+//
+// assert.Len(t, mySlice, 3)
+func Len(t TestingT, object interface{}, length int, msgAndArgs ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ ok, l := getLen(object)
+ if !ok {
+ return Fail(t, fmt.Sprintf("\"%s\" could not be applied builtin len()", object), msgAndArgs...)
+ }
+
+ if l != length {
+ return Fail(t, fmt.Sprintf("\"%s\" should have %d item(s), but has %d", object, length, l), msgAndArgs...)
+ }
+ return true
+}
+
+// True asserts that the specified value is true.
+//
+// assert.True(t, myBool)
+func True(t TestingT, value bool, msgAndArgs ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if h, ok := t.(interface {
+ Helper()
+ }); ok {
+ h.Helper()
+ }
+
+ if value != true {
+ return Fail(t, "Should be true", msgAndArgs...)
+ }
+
+ return true
+
+}
+
+// False asserts that the specified value is false.
+//
+// assert.False(t, myBool)
+func False(t TestingT, value bool, msgAndArgs ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+
+ if value != false {
+ return Fail(t, "Should be false", msgAndArgs...)
+ }
+
+ return true
+
+}
+
+// NotEqual asserts that the specified values are NOT equal.
+//
+// assert.NotEqual(t, obj1, obj2)
+//
+// Pointer variable equality is determined based on the equality of the
+// referenced values (as opposed to the memory addresses).
+func NotEqual(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if err := validateEqualArgs(expected, actual); err != nil {
+ return Fail(t, fmt.Sprintf("Invalid operation: %#v != %#v (%s)",
+ expected, actual, err), msgAndArgs...)
+ }
+
+ if ObjectsAreEqual(expected, actual) {
+ return Fail(t, fmt.Sprintf("Should not be: %#v\n", actual), msgAndArgs...)
+ }
+
+ return true
+
+}
+
+// containsElement try loop over the list check if the list includes the element.
+// return (false, false) if impossible.
+// return (true, false) if element was not found.
+// return (true, true) if element was found.
+func includeElement(list interface{}, element interface{}) (ok, found bool) {
+
+ listValue := reflect.ValueOf(list)
+ listKind := reflect.TypeOf(list).Kind()
+ defer func() {
+ if e := recover(); e != nil {
+ ok = false
+ found = false
+ }
+ }()
+
+ if listKind == reflect.String {
+ elementValue := reflect.ValueOf(element)
+ return true, strings.Contains(listValue.String(), elementValue.String())
+ }
+
+ if listKind == reflect.Map {
+ mapKeys := listValue.MapKeys()
+ for i := 0; i < len(mapKeys); i++ {
+ if ObjectsAreEqual(mapKeys[i].Interface(), element) {
+ return true, true
+ }
+ }
+ return true, false
+ }
+
+ for i := 0; i < listValue.Len(); i++ {
+ if ObjectsAreEqual(listValue.Index(i).Interface(), element) {
+ return true, true
+ }
+ }
+ return true, false
+
+}
+
+// Contains asserts that the specified string, list(array, slice...) or map contains the
+// specified substring or element.
+//
+// assert.Contains(t, "Hello World", "World")
+// assert.Contains(t, ["Hello", "World"], "World")
+// assert.Contains(t, {"Hello": "World"}, "Hello")
+func Contains(t TestingT, s, contains interface{}, msgAndArgs ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+
+ ok, found := includeElement(s, contains)
+ if !ok {
+ return Fail(t, fmt.Sprintf("\"%s\" could not be applied builtin len()", s), msgAndArgs...)
+ }
+ if !found {
+ return Fail(t, fmt.Sprintf("\"%s\" does not contain \"%s\"", s, contains), msgAndArgs...)
+ }
+
+ return true
+
+}
+
+// NotContains asserts that the specified string, list(array, slice...) or map does NOT contain the
+// specified substring or element.
+//
+// assert.NotContains(t, "Hello World", "Earth")
+// assert.NotContains(t, ["Hello", "World"], "Earth")
+// assert.NotContains(t, {"Hello": "World"}, "Earth")
+func NotContains(t TestingT, s, contains interface{}, msgAndArgs ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+
+ ok, found := includeElement(s, contains)
+ if !ok {
+ return Fail(t, fmt.Sprintf("\"%s\" could not be applied builtin len()", s), msgAndArgs...)
+ }
+ if found {
+ return Fail(t, fmt.Sprintf("\"%s\" should not contain \"%s\"", s, contains), msgAndArgs...)
+ }
+
+ return true
+
+}
+
+// Subset asserts that the specified list(array, slice...) contains all
+// elements given in the specified subset(array, slice...).
+//
+// assert.Subset(t, [1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]")
+func Subset(t TestingT, list, subset interface{}, msgAndArgs ...interface{}) (ok bool) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if subset == nil {
+ return true // we consider nil to be equal to the nil set
+ }
+
+ subsetValue := reflect.ValueOf(subset)
+ defer func() {
+ if e := recover(); e != nil {
+ ok = false
+ }
+ }()
+
+ listKind := reflect.TypeOf(list).Kind()
+ subsetKind := reflect.TypeOf(subset).Kind()
+
+ if listKind != reflect.Array && listKind != reflect.Slice {
+ return Fail(t, fmt.Sprintf("%q has an unsupported type %s", list, listKind), msgAndArgs...)
+ }
+
+ if subsetKind != reflect.Array && subsetKind != reflect.Slice {
+ return Fail(t, fmt.Sprintf("%q has an unsupported type %s", subset, subsetKind), msgAndArgs...)
+ }
+
+ for i := 0; i < subsetValue.Len(); i++ {
+ element := subsetValue.Index(i).Interface()
+ ok, found := includeElement(list, element)
+ if !ok {
+ return Fail(t, fmt.Sprintf("\"%s\" could not be applied builtin len()", list), msgAndArgs...)
+ }
+ if !found {
+ return Fail(t, fmt.Sprintf("\"%s\" does not contain \"%s\"", list, element), msgAndArgs...)
+ }
+ }
+
+ return true
+}
+
+// NotSubset asserts that the specified list(array, slice...) contains not all
+// elements given in the specified subset(array, slice...).
+//
+// assert.NotSubset(t, [1, 3, 4], [1, 2], "But [1, 3, 4] does not contain [1, 2]")
+func NotSubset(t TestingT, list, subset interface{}, msgAndArgs ...interface{}) (ok bool) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if subset == nil {
+ return Fail(t, fmt.Sprintf("nil is the empty set which is a subset of every set"), msgAndArgs...)
+ }
+
+ subsetValue := reflect.ValueOf(subset)
+ defer func() {
+ if e := recover(); e != nil {
+ ok = false
+ }
+ }()
+
+ listKind := reflect.TypeOf(list).Kind()
+ subsetKind := reflect.TypeOf(subset).Kind()
+
+ if listKind != reflect.Array && listKind != reflect.Slice {
+ return Fail(t, fmt.Sprintf("%q has an unsupported type %s", list, listKind), msgAndArgs...)
+ }
+
+ if subsetKind != reflect.Array && subsetKind != reflect.Slice {
+ return Fail(t, fmt.Sprintf("%q has an unsupported type %s", subset, subsetKind), msgAndArgs...)
+ }
+
+ for i := 0; i < subsetValue.Len(); i++ {
+ element := subsetValue.Index(i).Interface()
+ ok, found := includeElement(list, element)
+ if !ok {
+ return Fail(t, fmt.Sprintf("\"%s\" could not be applied builtin len()", list), msgAndArgs...)
+ }
+ if !found {
+ return true
+ }
+ }
+
+ return Fail(t, fmt.Sprintf("%q is a subset of %q", subset, list), msgAndArgs...)
+}
+
+// ElementsMatch asserts that the specified listA(array, slice...) is equal to specified
+// listB(array, slice...) ignoring the order of the elements. If there are duplicate elements,
+// the number of appearances of each of them in both lists should match.
+//
+// assert.ElementsMatch(t, [1, 3, 2, 3], [1, 3, 3, 2])
+func ElementsMatch(t TestingT, listA, listB interface{}, msgAndArgs ...interface{}) (ok bool) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if isEmpty(listA) && isEmpty(listB) {
+ return true
+ }
+
+ aKind := reflect.TypeOf(listA).Kind()
+ bKind := reflect.TypeOf(listB).Kind()
+
+ if aKind != reflect.Array && aKind != reflect.Slice {
+ return Fail(t, fmt.Sprintf("%q has an unsupported type %s", listA, aKind), msgAndArgs...)
+ }
+
+ if bKind != reflect.Array && bKind != reflect.Slice {
+ return Fail(t, fmt.Sprintf("%q has an unsupported type %s", listB, bKind), msgAndArgs...)
+ }
+
+ aValue := reflect.ValueOf(listA)
+ bValue := reflect.ValueOf(listB)
+
+ aLen := aValue.Len()
+ bLen := bValue.Len()
+
+ if aLen != bLen {
+ return Fail(t, fmt.Sprintf("lengths don't match: %d != %d", aLen, bLen), msgAndArgs...)
+ }
+
+ // Mark indexes in bValue that we already used
+ visited := make([]bool, bLen)
+ for i := 0; i < aLen; i++ {
+ element := aValue.Index(i).Interface()
+ found := false
+ for j := 0; j < bLen; j++ {
+ if visited[j] {
+ continue
+ }
+ if ObjectsAreEqual(bValue.Index(j).Interface(), element) {
+ visited[j] = true
+ found = true
+ break
+ }
+ }
+ if !found {
+ return Fail(t, fmt.Sprintf("element %s appears more times in %s than in %s", element, aValue, bValue), msgAndArgs...)
+ }
+ }
+
+ return true
+}
+
+// Condition uses a Comparison to assert a complex condition.
+func Condition(t TestingT, comp Comparison, msgAndArgs ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ result := comp()
+ if !result {
+ Fail(t, "Condition failed!", msgAndArgs...)
+ }
+ return result
+}
+
+// PanicTestFunc defines a func that should be passed to the assert.Panics and assert.NotPanics
+// methods, and represents a simple func that takes no arguments, and returns nothing.
+type PanicTestFunc func()
+
+// didPanic returns true if the function passed to it panics. Otherwise, it returns false.
+func didPanic(f PanicTestFunc) (bool, interface{}) {
+
+ didPanic := false
+ var message interface{}
+ func() {
+
+ defer func() {
+ if message = recover(); message != nil {
+ didPanic = true
+ }
+ }()
+
+ // call the target function
+ f()
+
+ }()
+
+ return didPanic, message
+
+}
+
+// Panics asserts that the code inside the specified PanicTestFunc panics.
+//
+// assert.Panics(t, func(){ GoCrazy() })
+func Panics(t TestingT, f PanicTestFunc, msgAndArgs ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+
+ if funcDidPanic, panicValue := didPanic(f); !funcDidPanic {
+ return Fail(t, fmt.Sprintf("func %#v should panic\n\tPanic value:\t%#v", f, panicValue), msgAndArgs...)
+ }
+
+ return true
+}
+
+// PanicsWithValue asserts that the code inside the specified PanicTestFunc panics, and that
+// the recovered panic value equals the expected panic value.
+//
+// assert.PanicsWithValue(t, "crazy error", func(){ GoCrazy() })
+func PanicsWithValue(t TestingT, expected interface{}, f PanicTestFunc, msgAndArgs ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+
+ funcDidPanic, panicValue := didPanic(f)
+ if !funcDidPanic {
+ return Fail(t, fmt.Sprintf("func %#v should panic\n\tPanic value:\t%#v", f, panicValue), msgAndArgs...)
+ }
+ if panicValue != expected {
+ return Fail(t, fmt.Sprintf("func %#v should panic with value:\t%#v\n\tPanic value:\t%#v", f, expected, panicValue), msgAndArgs...)
+ }
+
+ return true
+}
+
+// NotPanics asserts that the code inside the specified PanicTestFunc does NOT panic.
+//
+// assert.NotPanics(t, func(){ RemainCalm() })
+func NotPanics(t TestingT, f PanicTestFunc, msgAndArgs ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+
+ if funcDidPanic, panicValue := didPanic(f); funcDidPanic {
+ return Fail(t, fmt.Sprintf("func %#v should not panic\n\tPanic value:\t%v", f, panicValue), msgAndArgs...)
+ }
+
+ return true
+}
+
+// WithinDuration asserts that the two times are within duration delta of each other.
+//
+// assert.WithinDuration(t, time.Now(), time.Now(), 10*time.Second)
+func WithinDuration(t TestingT, expected, actual time.Time, delta time.Duration, msgAndArgs ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+
+ dt := expected.Sub(actual)
+ if dt < -delta || dt > delta {
+ return Fail(t, fmt.Sprintf("Max difference between %v and %v allowed is %v, but difference was %v", expected, actual, delta, dt), msgAndArgs...)
+ }
+
+ return true
+}
+
+func toFloat(x interface{}) (float64, bool) {
+ var xf float64
+ xok := true
+
+ switch xn := x.(type) {
+ case uint8:
+ xf = float64(xn)
+ case uint16:
+ xf = float64(xn)
+ case uint32:
+ xf = float64(xn)
+ case uint64:
+ xf = float64(xn)
+ case int:
+ xf = float64(xn)
+ case int8:
+ xf = float64(xn)
+ case int16:
+ xf = float64(xn)
+ case int32:
+ xf = float64(xn)
+ case int64:
+ xf = float64(xn)
+ case float32:
+ xf = float64(xn)
+ case float64:
+ xf = float64(xn)
+ case time.Duration:
+ xf = float64(xn)
+ default:
+ xok = false
+ }
+
+ return xf, xok
+}
+
+// InDelta asserts that the two numerals are within delta of each other.
+//
+// assert.InDelta(t, math.Pi, (22 / 7.0), 0.01)
+func InDelta(t TestingT, expected, actual interface{}, delta float64, msgAndArgs ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+
+ af, aok := toFloat(expected)
+ bf, bok := toFloat(actual)
+
+ if !aok || !bok {
+ return Fail(t, fmt.Sprintf("Parameters must be numerical"), msgAndArgs...)
+ }
+
+ if math.IsNaN(af) {
+ return Fail(t, fmt.Sprintf("Expected must not be NaN"), msgAndArgs...)
+ }
+
+ if math.IsNaN(bf) {
+ return Fail(t, fmt.Sprintf("Expected %v with delta %v, but was NaN", expected, delta), msgAndArgs...)
+ }
+
+ dt := af - bf
+ if dt < -delta || dt > delta {
+ return Fail(t, fmt.Sprintf("Max difference between %v and %v allowed is %v, but difference was %v", expected, actual, delta, dt), msgAndArgs...)
+ }
+
+ return true
+}
+
+// InDeltaSlice is the same as InDelta, except it compares two slices.
+func InDeltaSlice(t TestingT, expected, actual interface{}, delta float64, msgAndArgs ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if expected == nil || actual == nil ||
+ reflect.TypeOf(actual).Kind() != reflect.Slice ||
+ reflect.TypeOf(expected).Kind() != reflect.Slice {
+ return Fail(t, fmt.Sprintf("Parameters must be slice"), msgAndArgs...)
+ }
+
+ actualSlice := reflect.ValueOf(actual)
+ expectedSlice := reflect.ValueOf(expected)
+
+ for i := 0; i < actualSlice.Len(); i++ {
+ result := InDelta(t, actualSlice.Index(i).Interface(), expectedSlice.Index(i).Interface(), delta, msgAndArgs...)
+ if !result {
+ return result
+ }
+ }
+
+ return true
+}
+
+// InDeltaMapValues is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys.
+func InDeltaMapValues(t TestingT, expected, actual interface{}, delta float64, msgAndArgs ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if expected == nil || actual == nil ||
+ reflect.TypeOf(actual).Kind() != reflect.Map ||
+ reflect.TypeOf(expected).Kind() != reflect.Map {
+ return Fail(t, "Arguments must be maps", msgAndArgs...)
+ }
+
+ expectedMap := reflect.ValueOf(expected)
+ actualMap := reflect.ValueOf(actual)
+
+ if expectedMap.Len() != actualMap.Len() {
+ return Fail(t, "Arguments must have the same number of keys", msgAndArgs...)
+ }
+
+ for _, k := range expectedMap.MapKeys() {
+ ev := expectedMap.MapIndex(k)
+ av := actualMap.MapIndex(k)
+
+ if !ev.IsValid() {
+ return Fail(t, fmt.Sprintf("missing key %q in expected map", k), msgAndArgs...)
+ }
+
+ if !av.IsValid() {
+ return Fail(t, fmt.Sprintf("missing key %q in actual map", k), msgAndArgs...)
+ }
+
+ if !InDelta(
+ t,
+ ev.Interface(),
+ av.Interface(),
+ delta,
+ msgAndArgs...,
+ ) {
+ return false
+ }
+ }
+
+ return true
+}
+
+func calcRelativeError(expected, actual interface{}) (float64, error) {
+ af, aok := toFloat(expected)
+ if !aok {
+ return 0, fmt.Errorf("expected value %q cannot be converted to float", expected)
+ }
+ if af == 0 {
+ return 0, fmt.Errorf("expected value must have a value other than zero to calculate the relative error")
+ }
+ bf, bok := toFloat(actual)
+ if !bok {
+ return 0, fmt.Errorf("actual value %q cannot be converted to float", actual)
+ }
+
+ return math.Abs(af-bf) / math.Abs(af), nil
+}
+
+// InEpsilon asserts that expected and actual have a relative error less than epsilon
+func InEpsilon(t TestingT, expected, actual interface{}, epsilon float64, msgAndArgs ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ actualEpsilon, err := calcRelativeError(expected, actual)
+ if err != nil {
+ return Fail(t, err.Error(), msgAndArgs...)
+ }
+ if actualEpsilon > epsilon {
+ return Fail(t, fmt.Sprintf("Relative error is too high: %#v (expected)\n"+
+ " < %#v (actual)", epsilon, actualEpsilon), msgAndArgs...)
+ }
+
+ return true
+}
+
+// InEpsilonSlice is the same as InEpsilon, except it compares each value from two slices.
+func InEpsilonSlice(t TestingT, expected, actual interface{}, epsilon float64, msgAndArgs ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if expected == nil || actual == nil ||
+ reflect.TypeOf(actual).Kind() != reflect.Slice ||
+ reflect.TypeOf(expected).Kind() != reflect.Slice {
+ return Fail(t, fmt.Sprintf("Parameters must be slice"), msgAndArgs...)
+ }
+
+ actualSlice := reflect.ValueOf(actual)
+ expectedSlice := reflect.ValueOf(expected)
+
+ for i := 0; i < actualSlice.Len(); i++ {
+ result := InEpsilon(t, actualSlice.Index(i).Interface(), expectedSlice.Index(i).Interface(), epsilon)
+ if !result {
+ return result
+ }
+ }
+
+ return true
+}
+
+/*
+ Errors
+*/
+
+// NoError asserts that a function returned no error (i.e. `nil`).
+//
+// actualObj, err := SomeFunction()
+// if assert.NoError(t, err) {
+// assert.Equal(t, expectedObj, actualObj)
+// }
+func NoError(t TestingT, err error, msgAndArgs ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if err != nil {
+ return Fail(t, fmt.Sprintf("Received unexpected error:\n%+v", err), msgAndArgs...)
+ }
+
+ return true
+}
+
+// Error asserts that a function returned an error (i.e. not `nil`).
+//
+// actualObj, err := SomeFunction()
+// if assert.Error(t, err) {
+// assert.Equal(t, expectedError, err)
+// }
+func Error(t TestingT, err error, msgAndArgs ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+
+ if err == nil {
+ return Fail(t, "An error is expected but got nil.", msgAndArgs...)
+ }
+
+ return true
+}
+
+// EqualError asserts that a function returned an error (i.e. not `nil`)
+// and that it is equal to the provided error.
+//
+// actualObj, err := SomeFunction()
+// assert.EqualError(t, err, expectedErrorString)
+func EqualError(t TestingT, theError error, errString string, msgAndArgs ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if !Error(t, theError, msgAndArgs...) {
+ return false
+ }
+ expected := errString
+ actual := theError.Error()
+ // don't need to use deep equals here, we know they are both strings
+ if expected != actual {
+ return Fail(t, fmt.Sprintf("Error message not equal:\n"+
+ "expected: %q\n"+
+ "actual : %q", expected, actual), msgAndArgs...)
+ }
+ return true
+}
+
+// matchRegexp return true if a specified regexp matches a string.
+func matchRegexp(rx interface{}, str interface{}) bool {
+
+ var r *regexp.Regexp
+ if rr, ok := rx.(*regexp.Regexp); ok {
+ r = rr
+ } else {
+ r = regexp.MustCompile(fmt.Sprint(rx))
+ }
+
+ return (r.FindStringIndex(fmt.Sprint(str)) != nil)
+
+}
+
+// Regexp asserts that a specified regexp matches a string.
+//
+// assert.Regexp(t, regexp.MustCompile("start"), "it's starting")
+// assert.Regexp(t, "start...$", "it's not starting")
+func Regexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+
+ match := matchRegexp(rx, str)
+
+ if !match {
+ Fail(t, fmt.Sprintf("Expect \"%v\" to match \"%v\"", str, rx), msgAndArgs...)
+ }
+
+ return match
+}
+
+// NotRegexp asserts that a specified regexp does not match a string.
+//
+// assert.NotRegexp(t, regexp.MustCompile("starts"), "it's starting")
+// assert.NotRegexp(t, "^start", "it's not starting")
+func NotRegexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ match := matchRegexp(rx, str)
+
+ if match {
+ Fail(t, fmt.Sprintf("Expect \"%v\" to NOT match \"%v\"", str, rx), msgAndArgs...)
+ }
+
+ return !match
+
+}
+
+// Zero asserts that i is the zero value for its type.
+func Zero(t TestingT, i interface{}, msgAndArgs ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if i != nil && !reflect.DeepEqual(i, reflect.Zero(reflect.TypeOf(i)).Interface()) {
+ return Fail(t, fmt.Sprintf("Should be zero, but was %v", i), msgAndArgs...)
+ }
+ return true
+}
+
+// NotZero asserts that i is not the zero value for its type.
+func NotZero(t TestingT, i interface{}, msgAndArgs ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if i == nil || reflect.DeepEqual(i, reflect.Zero(reflect.TypeOf(i)).Interface()) {
+ return Fail(t, fmt.Sprintf("Should not be zero, but was %v", i), msgAndArgs...)
+ }
+ return true
+}
+
+// FileExists checks whether a file exists in the given path. It also fails if the path points to a directory or there is an error when trying to check the file.
+func FileExists(t TestingT, path string, msgAndArgs ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ info, err := os.Lstat(path)
+ if err != nil {
+ if os.IsNotExist(err) {
+ return Fail(t, fmt.Sprintf("unable to find file %q", path), msgAndArgs...)
+ }
+ return Fail(t, fmt.Sprintf("error when running os.Lstat(%q): %s", path, err), msgAndArgs...)
+ }
+ if info.IsDir() {
+ return Fail(t, fmt.Sprintf("%q is a directory", path), msgAndArgs...)
+ }
+ return true
+}
+
+// DirExists checks whether a directory exists in the given path. It also fails if the path is a file rather a directory or there is an error checking whether it exists.
+func DirExists(t TestingT, path string, msgAndArgs ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ info, err := os.Lstat(path)
+ if err != nil {
+ if os.IsNotExist(err) {
+ return Fail(t, fmt.Sprintf("unable to find file %q", path), msgAndArgs...)
+ }
+ return Fail(t, fmt.Sprintf("error when running os.Lstat(%q): %s", path, err), msgAndArgs...)
+ }
+ if !info.IsDir() {
+ return Fail(t, fmt.Sprintf("%q is a file", path), msgAndArgs...)
+ }
+ return true
+}
+
+// JSONEq asserts that two JSON strings are equivalent.
+//
+// assert.JSONEq(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`)
+func JSONEq(t TestingT, expected string, actual string, msgAndArgs ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ var expectedJSONAsInterface, actualJSONAsInterface interface{}
+
+ if err := json.Unmarshal([]byte(expected), &expectedJSONAsInterface); err != nil {
+ return Fail(t, fmt.Sprintf("Expected value ('%s') is not valid json.\nJSON parsing error: '%s'", expected, err.Error()), msgAndArgs...)
+ }
+
+ if err := json.Unmarshal([]byte(actual), &actualJSONAsInterface); err != nil {
+ return Fail(t, fmt.Sprintf("Input ('%s') needs to be valid json.\nJSON parsing error: '%s'", actual, err.Error()), msgAndArgs...)
+ }
+
+ return Equal(t, expectedJSONAsInterface, actualJSONAsInterface, msgAndArgs...)
+}
+
+// YAMLEq asserts that two YAML strings are equivalent.
+func YAMLEq(t TestingT, expected string, actual string, msgAndArgs ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ var expectedYAMLAsInterface, actualYAMLAsInterface interface{}
+
+ if err := yaml.Unmarshal([]byte(expected), &expectedYAMLAsInterface); err != nil {
+ return Fail(t, fmt.Sprintf("Expected value ('%s') is not valid yaml.\nYAML parsing error: '%s'", expected, err.Error()), msgAndArgs...)
+ }
+
+ if err := yaml.Unmarshal([]byte(actual), &actualYAMLAsInterface); err != nil {
+ return Fail(t, fmt.Sprintf("Input ('%s') needs to be valid yaml.\nYAML error: '%s'", actual, err.Error()), msgAndArgs...)
+ }
+
+ return Equal(t, expectedYAMLAsInterface, actualYAMLAsInterface, msgAndArgs...)
+}
+
+func typeAndKind(v interface{}) (reflect.Type, reflect.Kind) {
+ t := reflect.TypeOf(v)
+ k := t.Kind()
+
+ if k == reflect.Ptr {
+ t = t.Elem()
+ k = t.Kind()
+ }
+ return t, k
+}
+
+// diff returns a diff of both values as long as both are of the same type and
+// are a struct, map, slice, array or string. Otherwise it returns an empty string.
+func diff(expected interface{}, actual interface{}) string {
+ if expected == nil || actual == nil {
+ return ""
+ }
+
+ et, ek := typeAndKind(expected)
+ at, _ := typeAndKind(actual)
+
+ if et != at {
+ return ""
+ }
+
+ if ek != reflect.Struct && ek != reflect.Map && ek != reflect.Slice && ek != reflect.Array && ek != reflect.String {
+ return ""
+ }
+
+ var e, a string
+ if et != reflect.TypeOf("") {
+ e = spewConfig.Sdump(expected)
+ a = spewConfig.Sdump(actual)
+ } else {
+ e = reflect.ValueOf(expected).String()
+ a = reflect.ValueOf(actual).String()
+ }
+
+ diff, _ := difflib.GetUnifiedDiffString(difflib.UnifiedDiff{
+ A: difflib.SplitLines(e),
+ B: difflib.SplitLines(a),
+ FromFile: "Expected",
+ FromDate: "",
+ ToFile: "Actual",
+ ToDate: "",
+ Context: 1,
+ })
+
+ return "\n\nDiff:\n" + diff
+}
+
+// validateEqualArgs checks whether provided arguments can be safely used in the
+// Equal/NotEqual functions.
+func validateEqualArgs(expected, actual interface{}) error {
+ if isFunction(expected) || isFunction(actual) {
+ return errors.New("cannot take func type as argument")
+ }
+ return nil
+}
+
+func isFunction(arg interface{}) bool {
+ if arg == nil {
+ return false
+ }
+ return reflect.TypeOf(arg).Kind() == reflect.Func
+}
+
+var spewConfig = spew.ConfigState{
+ Indent: " ",
+ DisablePointerAddresses: true,
+ DisableCapacities: true,
+ SortKeys: true,
+}
+
+type tHelper interface {
+ Helper()
+}
+
+// Eventually asserts that given condition will be met in waitFor time,
+// periodically checking target function each tick.
+//
+// assert.Eventually(t, func() bool { return true; }, time.Second, 10*time.Millisecond)
+func Eventually(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+
+ timer := time.NewTimer(waitFor)
+ ticker := time.NewTicker(tick)
+ checkPassed := make(chan bool)
+ defer timer.Stop()
+ defer ticker.Stop()
+ defer close(checkPassed)
+ for {
+ select {
+ case <-timer.C:
+ return Fail(t, "Condition never satisfied", msgAndArgs...)
+ case result := <-checkPassed:
+ if result {
+ return true
+ }
+ case <-ticker.C:
+ go func() {
+ checkPassed <- condition()
+ }()
+ }
+ }
+}
diff --git a/vendor/github.com/stretchr/testify/assert/doc.go b/vendor/github.com/stretchr/testify/assert/doc.go
new file mode 100644
index 0000000..c9dccc4
--- /dev/null
+++ b/vendor/github.com/stretchr/testify/assert/doc.go
@@ -0,0 +1,45 @@
+// Package assert provides a set of comprehensive testing tools for use with the normal Go testing system.
+//
+// Example Usage
+//
+// The following is a complete example using assert in a standard test function:
+// import (
+// "testing"
+// "github.com/stretchr/testify/assert"
+// )
+//
+// func TestSomething(t *testing.T) {
+//
+// var a string = "Hello"
+// var b string = "Hello"
+//
+// assert.Equal(t, a, b, "The two words should be the same.")
+//
+// }
+//
+// if you assert many times, use the format below:
+//
+// import (
+// "testing"
+// "github.com/stretchr/testify/assert"
+// )
+//
+// func TestSomething(t *testing.T) {
+// assert := assert.New(t)
+//
+// var a string = "Hello"
+// var b string = "Hello"
+//
+// assert.Equal(a, b, "The two words should be the same.")
+// }
+//
+// Assertions
+//
+// Assertions allow you to easily write test code, and are global funcs in the `assert` package.
+// All assertion functions take, as the first argument, the `*testing.T` object provided by the
+// testing framework. This allows the assertion funcs to write the failings and other details to
+// the correct place.
+//
+// Every assertion function also takes an optional string message as the final argument,
+// allowing custom error messages to be appended to the message the assertion method outputs.
+package assert
diff --git a/vendor/github.com/stretchr/testify/assert/errors.go b/vendor/github.com/stretchr/testify/assert/errors.go
new file mode 100644
index 0000000..ac9dc9d
--- /dev/null
+++ b/vendor/github.com/stretchr/testify/assert/errors.go
@@ -0,0 +1,10 @@
+package assert
+
+import (
+ "errors"
+)
+
+// AnError is an error instance useful for testing. If the code does not care
+// about error specifics, and only needs to return the error for example, this
+// error should be used to make the test code more readable.
+var AnError = errors.New("assert.AnError general error for testing")
diff --git a/vendor/github.com/stretchr/testify/assert/forward_assertions.go b/vendor/github.com/stretchr/testify/assert/forward_assertions.go
new file mode 100644
index 0000000..9ad5685
--- /dev/null
+++ b/vendor/github.com/stretchr/testify/assert/forward_assertions.go
@@ -0,0 +1,16 @@
+package assert
+
+// Assertions provides assertion methods around the
+// TestingT interface.
+type Assertions struct {
+ t TestingT
+}
+
+// New makes a new Assertions object for the specified TestingT.
+func New(t TestingT) *Assertions {
+ return &Assertions{
+ t: t,
+ }
+}
+
+//go:generate go run ../_codegen/main.go -output-package=assert -template=assertion_forward.go.tmpl -include-format-funcs
diff --git a/vendor/github.com/stretchr/testify/assert/http_assertions.go b/vendor/github.com/stretchr/testify/assert/http_assertions.go
new file mode 100644
index 0000000..df46fa7
--- /dev/null
+++ b/vendor/github.com/stretchr/testify/assert/http_assertions.go
@@ -0,0 +1,143 @@
+package assert
+
+import (
+ "fmt"
+ "net/http"
+ "net/http/httptest"
+ "net/url"
+ "strings"
+)
+
+// httpCode is a helper that returns HTTP code of the response. It returns -1 and
+// an error if building a new request fails.
+func httpCode(handler http.HandlerFunc, method, url string, values url.Values) (int, error) {
+ w := httptest.NewRecorder()
+ req, err := http.NewRequest(method, url, nil)
+ if err != nil {
+ return -1, err
+ }
+ req.URL.RawQuery = values.Encode()
+ handler(w, req)
+ return w.Code, nil
+}
+
+// HTTPSuccess asserts that a specified handler returns a success status code.
+//
+// assert.HTTPSuccess(t, myHandler, "POST", "http://www.google.com", nil)
+//
+// Returns whether the assertion was successful (true) or not (false).
+func HTTPSuccess(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, msgAndArgs ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ code, err := httpCode(handler, method, url, values)
+ if err != nil {
+ Fail(t, fmt.Sprintf("Failed to build test request, got error: %s", err))
+ return false
+ }
+
+ isSuccessCode := code >= http.StatusOK && code <= http.StatusPartialContent
+ if !isSuccessCode {
+ Fail(t, fmt.Sprintf("Expected HTTP success status code for %q but received %d", url+"?"+values.Encode(), code))
+ }
+
+ return isSuccessCode
+}
+
+// HTTPRedirect asserts that a specified handler returns a redirect status code.
+//
+// assert.HTTPRedirect(t, myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}}
+//
+// Returns whether the assertion was successful (true) or not (false).
+func HTTPRedirect(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, msgAndArgs ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ code, err := httpCode(handler, method, url, values)
+ if err != nil {
+ Fail(t, fmt.Sprintf("Failed to build test request, got error: %s", err))
+ return false
+ }
+
+ isRedirectCode := code >= http.StatusMultipleChoices && code <= http.StatusTemporaryRedirect
+ if !isRedirectCode {
+ Fail(t, fmt.Sprintf("Expected HTTP redirect status code for %q but received %d", url+"?"+values.Encode(), code))
+ }
+
+ return isRedirectCode
+}
+
+// HTTPError asserts that a specified handler returns an error status code.
+//
+// assert.HTTPError(t, myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}}
+//
+// Returns whether the assertion was successful (true) or not (false).
+func HTTPError(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, msgAndArgs ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ code, err := httpCode(handler, method, url, values)
+ if err != nil {
+ Fail(t, fmt.Sprintf("Failed to build test request, got error: %s", err))
+ return false
+ }
+
+ isErrorCode := code >= http.StatusBadRequest
+ if !isErrorCode {
+ Fail(t, fmt.Sprintf("Expected HTTP error status code for %q but received %d", url+"?"+values.Encode(), code))
+ }
+
+ return isErrorCode
+}
+
+// HTTPBody is a helper that returns HTTP body of the response. It returns
+// empty string if building a new request fails.
+func HTTPBody(handler http.HandlerFunc, method, url string, values url.Values) string {
+ w := httptest.NewRecorder()
+ req, err := http.NewRequest(method, url+"?"+values.Encode(), nil)
+ if err != nil {
+ return ""
+ }
+ handler(w, req)
+ return w.Body.String()
+}
+
+// HTTPBodyContains asserts that a specified handler returns a
+// body that contains a string.
+//
+// assert.HTTPBodyContains(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func HTTPBodyContains(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ body := HTTPBody(handler, method, url, values)
+
+ contains := strings.Contains(body, fmt.Sprint(str))
+ if !contains {
+ Fail(t, fmt.Sprintf("Expected response body for \"%s\" to contain \"%s\" but found \"%s\"", url+"?"+values.Encode(), str, body))
+ }
+
+ return contains
+}
+
+// HTTPBodyNotContains asserts that a specified handler returns a
+// body that does not contain a string.
+//
+// assert.HTTPBodyNotContains(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func HTTPBodyNotContains(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ body := HTTPBody(handler, method, url, values)
+
+ contains := strings.Contains(body, fmt.Sprint(str))
+ if contains {
+ Fail(t, fmt.Sprintf("Expected response body for \"%s\" to NOT contain \"%s\" but found \"%s\"", url+"?"+values.Encode(), str, body))
+ }
+
+ return !contains
+}
diff --git a/vendor/go.opencensus.io/.gitignore b/vendor/go.opencensus.io/.gitignore
new file mode 100644
index 0000000..74a6db4
--- /dev/null
+++ b/vendor/go.opencensus.io/.gitignore
@@ -0,0 +1,9 @@
+/.idea/
+
+# go.opencensus.io/exporter/aws
+/exporter/aws/
+
+# Exclude vendor, use dep ensure after checkout:
+/vendor/github.com/
+/vendor/golang.org/
+/vendor/google.golang.org/
diff --git a/vendor/go.opencensus.io/.travis.yml b/vendor/go.opencensus.io/.travis.yml
new file mode 100644
index 0000000..bd6b66e
--- /dev/null
+++ b/vendor/go.opencensus.io/.travis.yml
@@ -0,0 +1,17 @@
+language: go
+
+go_import_path: go.opencensus.io
+
+go:
+ - 1.11.x
+
+env:
+ global:
+ GO111MODULE=on
+
+before_script:
+ - make install-tools
+
+script:
+ - make travis-ci
+ - go run internal/check/version.go # TODO move this to makefile
diff --git a/vendor/go.opencensus.io/AUTHORS b/vendor/go.opencensus.io/AUTHORS
new file mode 100644
index 0000000..e491a9e
--- /dev/null
+++ b/vendor/go.opencensus.io/AUTHORS
@@ -0,0 +1 @@
+Google Inc.
diff --git a/vendor/go.opencensus.io/CONTRIBUTING.md b/vendor/go.opencensus.io/CONTRIBUTING.md
new file mode 100644
index 0000000..1ba3962
--- /dev/null
+++ b/vendor/go.opencensus.io/CONTRIBUTING.md
@@ -0,0 +1,63 @@
+# How to contribute
+
+We'd love to accept your patches and contributions to this project. There are
+just a few small guidelines you need to follow.
+
+## Contributor License Agreement
+
+Contributions to this project must be accompanied by a Contributor License
+Agreement. You (or your employer) retain the copyright to your contribution,
+this simply gives us permission to use and redistribute your contributions as
+part of the project. Head over to to see
+your current agreements on file or to sign a new one.
+
+You generally only need to submit a CLA once, so if you've already submitted one
+(even if it was for a different project), you probably don't need to do it
+again.
+
+## Code reviews
+
+All submissions, including submissions by project members, require review. We
+use GitHub pull requests for this purpose. Consult [GitHub Help] for more
+information on using pull requests.
+
+[GitHub Help]: https://help.github.com/articles/about-pull-requests/
+
+## Instructions
+
+Fork the repo, checkout the upstream repo to your GOPATH by:
+
+```
+$ go get -d go.opencensus.io
+```
+
+Add your fork as an origin:
+
+```
+cd $(go env GOPATH)/src/go.opencensus.io
+git remote add fork git@github.com:YOUR_GITHUB_USERNAME/opencensus-go.git
+```
+
+Run tests:
+
+```
+$ make install-tools # Only first time.
+$ make
+```
+
+Checkout a new branch, make modifications and push the branch to your fork:
+
+```
+$ git checkout -b feature
+# edit files
+$ git commit
+$ git push fork feature
+```
+
+Open a pull request against the main opencensus-go repo.
+
+## General Notes
+This project uses Appveyor and Travis for CI.
+
+The dependencies are managed with `go mod` if you work with the sources under your
+`$GOPATH` you need to set the environment variable `GO111MODULE=on`.
\ No newline at end of file
diff --git a/vendor/go.opencensus.io/LICENSE b/vendor/go.opencensus.io/LICENSE
new file mode 100644
index 0000000..7a4a3ea
--- /dev/null
+++ b/vendor/go.opencensus.io/LICENSE
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
\ No newline at end of file
diff --git a/vendor/go.opencensus.io/Makefile b/vendor/go.opencensus.io/Makefile
new file mode 100644
index 0000000..457866c
--- /dev/null
+++ b/vendor/go.opencensus.io/Makefile
@@ -0,0 +1,96 @@
+# TODO: Fix this on windows.
+ALL_SRC := $(shell find . -name '*.go' \
+ -not -path './vendor/*' \
+ -not -path '*/gen-go/*' \
+ -type f | sort)
+ALL_PKGS := $(shell go list $(sort $(dir $(ALL_SRC))))
+
+GOTEST_OPT?=-v -race -timeout 30s
+GOTEST_OPT_WITH_COVERAGE = $(GOTEST_OPT) -coverprofile=coverage.txt -covermode=atomic
+GOTEST=go test
+GOFMT=gofmt
+GOLINT=golint
+GOVET=go vet
+EMBEDMD=embedmd
+# TODO decide if we need to change these names.
+TRACE_ID_LINT_EXCEPTION="type name will be used as trace.TraceID by other packages"
+TRACE_OPTION_LINT_EXCEPTION="type name will be used as trace.TraceOptions by other packages"
+README_FILES := $(shell find . -name '*README.md' | sort | tr '\n' ' ')
+
+.DEFAULT_GOAL := fmt-lint-vet-embedmd-test
+
+.PHONY: fmt-lint-vet-embedmd-test
+fmt-lint-vet-embedmd-test: fmt lint vet embedmd test
+
+# TODO enable test-with-coverage in tavis
+.PHONY: travis-ci
+travis-ci: fmt lint vet embedmd test test-386
+
+all-pkgs:
+ @echo $(ALL_PKGS) | tr ' ' '\n' | sort
+
+all-srcs:
+ @echo $(ALL_SRC) | tr ' ' '\n' | sort
+
+.PHONY: test
+test:
+ $(GOTEST) $(GOTEST_OPT) $(ALL_PKGS)
+
+.PHONY: test-386
+test-386:
+ GOARCH=386 $(GOTEST) -v -timeout 30s $(ALL_PKGS)
+
+.PHONY: test-with-coverage
+test-with-coverage:
+ $(GOTEST) $(GOTEST_OPT_WITH_COVERAGE) $(ALL_PKGS)
+
+.PHONY: fmt
+fmt:
+ @FMTOUT=`$(GOFMT) -s -l $(ALL_SRC) 2>&1`; \
+ if [ "$$FMTOUT" ]; then \
+ echo "$(GOFMT) FAILED => gofmt the following files:\n"; \
+ echo "$$FMTOUT\n"; \
+ exit 1; \
+ else \
+ echo "Fmt finished successfully"; \
+ fi
+
+.PHONY: lint
+lint:
+ @LINTOUT=`$(GOLINT) $(ALL_PKGS) | grep -v $(TRACE_ID_LINT_EXCEPTION) | grep -v $(TRACE_OPTION_LINT_EXCEPTION) 2>&1`; \
+ if [ "$$LINTOUT" ]; then \
+ echo "$(GOLINT) FAILED => clean the following lint errors:\n"; \
+ echo "$$LINTOUT\n"; \
+ exit 1; \
+ else \
+ echo "Lint finished successfully"; \
+ fi
+
+.PHONY: vet
+vet:
+ # TODO: Understand why go vet downloads "github.com/google/go-cmp v0.2.0"
+ @VETOUT=`$(GOVET) ./... | grep -v "go: downloading" 2>&1`; \
+ if [ "$$VETOUT" ]; then \
+ echo "$(GOVET) FAILED => go vet the following files:\n"; \
+ echo "$$VETOUT\n"; \
+ exit 1; \
+ else \
+ echo "Vet finished successfully"; \
+ fi
+
+.PHONY: embedmd
+embedmd:
+ @EMBEDMDOUT=`$(EMBEDMD) -d $(README_FILES) 2>&1`; \
+ if [ "$$EMBEDMDOUT" ]; then \
+ echo "$(EMBEDMD) FAILED => embedmd the following files:\n"; \
+ echo "$$EMBEDMDOUT\n"; \
+ exit 1; \
+ else \
+ echo "Embedmd finished successfully"; \
+ fi
+
+.PHONY: install-tools
+install-tools:
+ go get -u golang.org/x/tools/cmd/cover
+ go get -u golang.org/x/lint/golint
+ go get -u github.com/rakyll/embedmd
diff --git a/vendor/go.opencensus.io/README.md b/vendor/go.opencensus.io/README.md
new file mode 100644
index 0000000..1d7e837
--- /dev/null
+++ b/vendor/go.opencensus.io/README.md
@@ -0,0 +1,267 @@
+# OpenCensus Libraries for Go
+
+[![Build Status][travis-image]][travis-url]
+[![Windows Build Status][appveyor-image]][appveyor-url]
+[![GoDoc][godoc-image]][godoc-url]
+[![Gitter chat][gitter-image]][gitter-url]
+
+OpenCensus Go is a Go implementation of OpenCensus, a toolkit for
+collecting application performance and behavior monitoring data.
+Currently it consists of three major components: tags, stats and tracing.
+
+#### OpenCensus and OpenTracing have merged to form OpenTelemetry, which serves as the next major version of OpenCensus and OpenTracing. OpenTelemetry will offer backwards compatibility with existing OpenCensus integrations, and we will continue to make security patches to existing OpenCensus libraries for two years. Read more about the merger [here](https://medium.com/opentracing/a-roadmap-to-convergence-b074e5815289).
+
+## Installation
+
+```
+$ go get -u go.opencensus.io
+```
+
+The API of this project is still evolving, see: [Deprecation Policy](#deprecation-policy).
+The use of vendoring or a dependency management tool is recommended.
+
+## Prerequisites
+
+OpenCensus Go libraries require Go 1.8 or later.
+
+## Getting Started
+
+The easiest way to get started using OpenCensus in your application is to use an existing
+integration with your RPC framework:
+
+* [net/http](https://godoc.org/go.opencensus.io/plugin/ochttp)
+* [gRPC](https://godoc.org/go.opencensus.io/plugin/ocgrpc)
+* [database/sql](https://godoc.org/github.com/opencensus-integrations/ocsql)
+* [Go kit](https://godoc.org/github.com/go-kit/kit/tracing/opencensus)
+* [Groupcache](https://godoc.org/github.com/orijtech/groupcache)
+* [Caddy webserver](https://godoc.org/github.com/orijtech/caddy)
+* [MongoDB](https://godoc.org/github.com/orijtech/mongo-go-driver)
+* [Redis gomodule/redigo](https://godoc.org/github.com/orijtech/redigo)
+* [Redis goredis/redis](https://godoc.org/github.com/orijtech/redis)
+* [Memcache](https://godoc.org/github.com/orijtech/gomemcache)
+
+If you're using a framework not listed here, you could either implement your own middleware for your
+framework or use [custom stats](#stats) and [spans](#spans) directly in your application.
+
+## Exporters
+
+OpenCensus can export instrumentation data to various backends.
+OpenCensus has exporter implementations for the following, users
+can implement their own exporters by implementing the exporter interfaces
+([stats](https://godoc.org/go.opencensus.io/stats/view#Exporter),
+[trace](https://godoc.org/go.opencensus.io/trace#Exporter)):
+
+* [Prometheus][exporter-prom] for stats
+* [OpenZipkin][exporter-zipkin] for traces
+* [Stackdriver][exporter-stackdriver] Monitoring for stats and Trace for traces
+* [Jaeger][exporter-jaeger] for traces
+* [AWS X-Ray][exporter-xray] for traces
+* [Datadog][exporter-datadog] for stats and traces
+* [Graphite][exporter-graphite] for stats
+* [Honeycomb][exporter-honeycomb] for traces
+* [New Relic][exporter-newrelic] for stats and traces
+
+## Overview
+
+![OpenCensus Overview](https://i.imgur.com/cf4ElHE.jpg)
+
+In a microservices environment, a user request may go through
+multiple services until there is a response. OpenCensus allows
+you to instrument your services and collect diagnostics data all
+through your services end-to-end.
+
+## Tags
+
+Tags represent propagated key-value pairs. They are propagated using `context.Context`
+in the same process or can be encoded to be transmitted on the wire. Usually, this will
+be handled by an integration plugin, e.g. `ocgrpc.ServerHandler` and `ocgrpc.ClientHandler`
+for gRPC.
+
+Package `tag` allows adding or modifying tags in the current context.
+
+[embedmd]:# (internal/readme/tags.go new)
+```go
+ctx, err := tag.New(ctx,
+ tag.Insert(osKey, "macOS-10.12.5"),
+ tag.Upsert(userIDKey, "cde36753ed"),
+)
+if err != nil {
+ log.Fatal(err)
+}
+```
+
+## Stats
+
+OpenCensus is a low-overhead framework even if instrumentation is always enabled.
+In order to be so, it is optimized to make recording of data points fast
+and separate from the data aggregation.
+
+OpenCensus stats collection happens in two stages:
+
+* Definition of measures and recording of data points
+* Definition of views and aggregation of the recorded data
+
+### Recording
+
+Measurements are data points associated with a measure.
+Recording implicitly tags the set of Measurements with the tags from the
+provided context:
+
+[embedmd]:# (internal/readme/stats.go record)
+```go
+stats.Record(ctx, videoSize.M(102478))
+```
+
+### Views
+
+Views are how Measures are aggregated. You can think of them as queries over the
+set of recorded data points (measurements).
+
+Views have two parts: the tags to group by and the aggregation type used.
+
+Currently three types of aggregations are supported:
+* CountAggregation is used to count the number of times a sample was recorded.
+* DistributionAggregation is used to provide a histogram of the values of the samples.
+* SumAggregation is used to sum up all sample values.
+
+[embedmd]:# (internal/readme/stats.go aggs)
+```go
+distAgg := view.Distribution(1<<32, 2<<32, 3<<32)
+countAgg := view.Count()
+sumAgg := view.Sum()
+```
+
+Here we create a view with the DistributionAggregation over our measure.
+
+[embedmd]:# (internal/readme/stats.go view)
+```go
+if err := view.Register(&view.View{
+ Name: "example.com/video_size_distribution",
+ Description: "distribution of processed video size over time",
+ Measure: videoSize,
+ Aggregation: view.Distribution(1<<32, 2<<32, 3<<32),
+}); err != nil {
+ log.Fatalf("Failed to register view: %v", err)
+}
+```
+
+Register begins collecting data for the view. Registered views' data will be
+exported via the registered exporters.
+
+## Traces
+
+A distributed trace tracks the progression of a single user request as
+it is handled by the services and processes that make up an application.
+Each step is called a span in the trace. Spans include metadata about the step,
+including especially the time spent in the step, called the span’s latency.
+
+Below you see a trace and several spans underneath it.
+
+![Traces and spans](https://i.imgur.com/7hZwRVj.png)
+
+### Spans
+
+Span is the unit step in a trace. Each span has a name, latency, status and
+additional metadata.
+
+Below we are starting a span for a cache read and ending it
+when we are done:
+
+[embedmd]:# (internal/readme/trace.go startend)
+```go
+ctx, span := trace.StartSpan(ctx, "cache.Get")
+defer span.End()
+
+// Do work to get from cache.
+```
+
+### Propagation
+
+Spans can have parents or can be root spans if they don't have any parents.
+The current span is propagated in-process and across the network to allow associating
+new child spans with the parent.
+
+In the same process, `context.Context` is used to propagate spans.
+`trace.StartSpan` creates a new span as a root if the current context
+doesn't contain a span. Or, it creates a child of the span that is
+already in current context. The returned context can be used to keep
+propagating the newly created span in the current context.
+
+[embedmd]:# (internal/readme/trace.go startend)
+```go
+ctx, span := trace.StartSpan(ctx, "cache.Get")
+defer span.End()
+
+// Do work to get from cache.
+```
+
+Across the network, OpenCensus provides different propagation
+methods for different protocols.
+
+* gRPC integrations use the OpenCensus' [binary propagation format](https://godoc.org/go.opencensus.io/trace/propagation).
+* HTTP integrations use Zipkin's [B3](https://github.com/openzipkin/b3-propagation)
+ by default but can be configured to use a custom propagation method by setting another
+ [propagation.HTTPFormat](https://godoc.org/go.opencensus.io/trace/propagation#HTTPFormat).
+
+## Execution Tracer
+
+With Go 1.11, OpenCensus Go will support integration with the Go execution tracer.
+See [Debugging Latency in Go](https://medium.com/observability/debugging-latency-in-go-1-11-9f97a7910d68)
+for an example of their mutual use.
+
+## Profiles
+
+OpenCensus tags can be applied as profiler labels
+for users who are on Go 1.9 and above.
+
+[embedmd]:# (internal/readme/tags.go profiler)
+```go
+ctx, err = tag.New(ctx,
+ tag.Insert(osKey, "macOS-10.12.5"),
+ tag.Insert(userIDKey, "fff0989878"),
+)
+if err != nil {
+ log.Fatal(err)
+}
+tag.Do(ctx, func(ctx context.Context) {
+ // Do work.
+ // When profiling is on, samples will be
+ // recorded with the key/values from the tag map.
+})
+```
+
+A screenshot of the CPU profile from the program above:
+
+![CPU profile](https://i.imgur.com/jBKjlkw.png)
+
+## Deprecation Policy
+
+Before version 1.0.0, the following deprecation policy will be observed:
+
+No backwards-incompatible changes will be made except for the removal of symbols that have
+been marked as *Deprecated* for at least one minor release (e.g. 0.9.0 to 0.10.0). A release
+removing the *Deprecated* functionality will be made no sooner than 28 days after the first
+release in which the functionality was marked *Deprecated*.
+
+[travis-image]: https://travis-ci.org/census-instrumentation/opencensus-go.svg?branch=master
+[travis-url]: https://travis-ci.org/census-instrumentation/opencensus-go
+[appveyor-image]: https://ci.appveyor.com/api/projects/status/vgtt29ps1783ig38?svg=true
+[appveyor-url]: https://ci.appveyor.com/project/opencensusgoteam/opencensus-go/branch/master
+[godoc-image]: https://godoc.org/go.opencensus.io?status.svg
+[godoc-url]: https://godoc.org/go.opencensus.io
+[gitter-image]: https://badges.gitter.im/census-instrumentation/lobby.svg
+[gitter-url]: https://gitter.im/census-instrumentation/lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge
+
+
+[new-ex]: https://godoc.org/go.opencensus.io/tag#example-NewMap
+[new-replace-ex]: https://godoc.org/go.opencensus.io/tag#example-NewMap--Replace
+
+[exporter-prom]: https://godoc.org/contrib.go.opencensus.io/exporter/prometheus
+[exporter-stackdriver]: https://godoc.org/contrib.go.opencensus.io/exporter/stackdriver
+[exporter-zipkin]: https://godoc.org/contrib.go.opencensus.io/exporter/zipkin
+[exporter-jaeger]: https://godoc.org/contrib.go.opencensus.io/exporter/jaeger
+[exporter-xray]: https://github.com/census-ecosystem/opencensus-go-exporter-aws
+[exporter-datadog]: https://github.com/DataDog/opencensus-go-exporter-datadog
+[exporter-graphite]: https://github.com/census-ecosystem/opencensus-go-exporter-graphite
+[exporter-honeycomb]: https://github.com/honeycombio/opencensus-exporter
+[exporter-newrelic]: https://github.com/newrelic/newrelic-opencensus-exporter-go
diff --git a/vendor/go.opencensus.io/appveyor.yml b/vendor/go.opencensus.io/appveyor.yml
new file mode 100644
index 0000000..d08f0ed
--- /dev/null
+++ b/vendor/go.opencensus.io/appveyor.yml
@@ -0,0 +1,24 @@
+version: "{build}"
+
+platform: x64
+
+clone_folder: c:\gopath\src\go.opencensus.io
+
+environment:
+ GOPATH: 'c:\gopath'
+ GO111MODULE: 'on'
+ CGO_ENABLED: '0' # See: https://github.com/appveyor/ci/issues/2613
+
+stack: go 1.11
+
+before_test:
+ - go version
+ - go env
+
+build: false
+deploy: false
+
+test_script:
+ - cd %APPVEYOR_BUILD_FOLDER%
+ - go build -v .\...
+ - go test -v .\... # No -race because cgo is disabled
diff --git a/vendor/go.opencensus.io/go.mod b/vendor/go.opencensus.io/go.mod
new file mode 100644
index 0000000..c867df5
--- /dev/null
+++ b/vendor/go.opencensus.io/go.mod
@@ -0,0 +1,15 @@
+module go.opencensus.io
+
+require (
+ github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6
+ github.com/golang/protobuf v1.3.1
+ github.com/google/go-cmp v0.3.0
+ github.com/stretchr/testify v1.4.0
+ golang.org/x/net v0.0.0-20190620200207-3b0461eec859
+ golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd // indirect
+ golang.org/x/text v0.3.2 // indirect
+ google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb // indirect
+ google.golang.org/grpc v1.20.1
+)
+
+go 1.13
diff --git a/vendor/go.opencensus.io/go.sum b/vendor/go.opencensus.io/go.sum
new file mode 100644
index 0000000..ed2a1d8
--- /dev/null
+++ b/vendor/go.opencensus.io/go.sum
@@ -0,0 +1,73 @@
+cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
+github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
+github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
+github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
+github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6 h1:ZgQEtGgCBiWRM39fZuwSd1LwSqqSW0hOdXCYYDX0R3I=
+github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
+github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg=
+github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY=
+github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
+github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
+golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
+golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3 h1:XQyxROzUlZH+WIQwySDgnISgOivlhjIEwaQaJEJrrN0=
+golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190311183353-d8887717615a h1:oWX7TPOiFAMXLq8o0ikBYfCJVlRHBcsciT5bXOrH628=
+golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI=
+golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
+golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f h1:wMNYb4v58l5UBM7MYRLPG6ZhfOqbKu7X5eyFl8ZhKvA=
+golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181108010431-42b317875d0f h1:Bl/8QSvNqXvPGPGXa2z5xUTmV7VDcZyvRZ+QQXkXTZQ=
+golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6 h1:bjcUS9ztw9kFmmIxJInhon/0Is3p+EHBKNgquIzo1OI=
+golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd h1:r7DufRZuZbWB7j439YfAzP8RPDa9unLkpwQKUYbIMPI=
+golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
+golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
+golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
+golang.org/x/tools v0.0.0-20190311212946-11955173bddd h1:/e+gpKk9r3dJobndpTytxS2gOy6m5uvpg+ISQoEcusQ=
+golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
+google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8 h1:Nw54tB0rB7hY/N0NQvRW8DG4Yk3Q6T9cu9RcFQDu1tc=
+google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
+google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb h1:i1Ppqkc3WQXikh8bXiwHqAN5Rv3/qDCcRk0/Otx73BY=
+google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/grpc v1.19.0 h1:cfg4PD8YEdSFnm7qLV4++93WcmhH2nIUhMjhdCvl3j8=
+google.golang.org/grpc v1.19.0 h1:cfg4PD8YEdSFnm7qLV4++93WcmhH2nIUhMjhdCvl3j8=
+google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
+google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
+google.golang.org/grpc v1.20.1 h1:Hz2g2wirWK7H0qIIhGIqRGTuMwTE8HEKFnDZZ7lm9NU=
+google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
+gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
diff --git a/vendor/go.opencensus.io/internal/internal.go b/vendor/go.opencensus.io/internal/internal.go
new file mode 100644
index 0000000..81dc718
--- /dev/null
+++ b/vendor/go.opencensus.io/internal/internal.go
@@ -0,0 +1,37 @@
+// Copyright 2017, OpenCensus Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package internal // import "go.opencensus.io/internal"
+
+import (
+ "fmt"
+ "time"
+
+ opencensus "go.opencensus.io"
+)
+
+// UserAgent is the user agent to be added to the outgoing
+// requests from the exporters.
+var UserAgent = fmt.Sprintf("opencensus-go/%s", opencensus.Version())
+
+// MonotonicEndTime returns the end time at present
+// but offset from start, monotonically.
+//
+// The monotonic clock is used in subtractions hence
+// the duration since start added back to start gives
+// end as a monotonic time.
+// See https://golang.org/pkg/time/#hdr-Monotonic_Clocks
+func MonotonicEndTime(start time.Time) time.Time {
+ return start.Add(time.Since(start))
+}
diff --git a/vendor/go.opencensus.io/internal/sanitize.go b/vendor/go.opencensus.io/internal/sanitize.go
new file mode 100644
index 0000000..de8ccf2
--- /dev/null
+++ b/vendor/go.opencensus.io/internal/sanitize.go
@@ -0,0 +1,50 @@
+// Copyright 2017, OpenCensus Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package internal
+
+import (
+ "strings"
+ "unicode"
+)
+
+const labelKeySizeLimit = 100
+
+// Sanitize returns a string that is trunacated to 100 characters if it's too
+// long, and replaces non-alphanumeric characters to underscores.
+func Sanitize(s string) string {
+ if len(s) == 0 {
+ return s
+ }
+ if len(s) > labelKeySizeLimit {
+ s = s[:labelKeySizeLimit]
+ }
+ s = strings.Map(sanitizeRune, s)
+ if unicode.IsDigit(rune(s[0])) {
+ s = "key_" + s
+ }
+ if s[0] == '_' {
+ s = "key" + s
+ }
+ return s
+}
+
+// converts anything that is not a letter or digit to an underscore
+func sanitizeRune(r rune) rune {
+ if unicode.IsLetter(r) || unicode.IsDigit(r) {
+ return r
+ }
+ // Everything else turns into an underscore
+ return '_'
+}
diff --git a/vendor/go.opencensus.io/internal/tagencoding/tagencoding.go b/vendor/go.opencensus.io/internal/tagencoding/tagencoding.go
new file mode 100644
index 0000000..41b2c3f
--- /dev/null
+++ b/vendor/go.opencensus.io/internal/tagencoding/tagencoding.go
@@ -0,0 +1,75 @@
+// Copyright 2017, OpenCensus Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Package tagencoding contains the tag encoding
+// used interally by the stats collector.
+package tagencoding // import "go.opencensus.io/internal/tagencoding"
+
+// Values represent the encoded buffer for the values.
+type Values struct {
+ Buffer []byte
+ WriteIndex int
+ ReadIndex int
+}
+
+func (vb *Values) growIfRequired(expected int) {
+ if len(vb.Buffer)-vb.WriteIndex < expected {
+ tmp := make([]byte, 2*(len(vb.Buffer)+1)+expected)
+ copy(tmp, vb.Buffer)
+ vb.Buffer = tmp
+ }
+}
+
+// WriteValue is the helper method to encode Values from map[Key][]byte.
+func (vb *Values) WriteValue(v []byte) {
+ length := len(v) & 0xff
+ vb.growIfRequired(1 + length)
+
+ // writing length of v
+ vb.Buffer[vb.WriteIndex] = byte(length)
+ vb.WriteIndex++
+
+ if length == 0 {
+ // No value was encoded for this key
+ return
+ }
+
+ // writing v
+ copy(vb.Buffer[vb.WriteIndex:], v[:length])
+ vb.WriteIndex += length
+}
+
+// ReadValue is the helper method to decode Values to a map[Key][]byte.
+func (vb *Values) ReadValue() []byte {
+ // read length of v
+ length := int(vb.Buffer[vb.ReadIndex])
+ vb.ReadIndex++
+ if length == 0 {
+ // No value was encoded for this key
+ return nil
+ }
+
+ // read value of v
+ v := make([]byte, length)
+ endIdx := vb.ReadIndex + length
+ copy(v, vb.Buffer[vb.ReadIndex:endIdx])
+ vb.ReadIndex = endIdx
+ return v
+}
+
+// Bytes returns a reference to already written bytes in the Buffer.
+func (vb *Values) Bytes() []byte {
+ return vb.Buffer[:vb.WriteIndex]
+}
diff --git a/vendor/go.opencensus.io/internal/traceinternals.go b/vendor/go.opencensus.io/internal/traceinternals.go
new file mode 100644
index 0000000..073af7b
--- /dev/null
+++ b/vendor/go.opencensus.io/internal/traceinternals.go
@@ -0,0 +1,53 @@
+// Copyright 2017, OpenCensus Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package internal
+
+import (
+ "time"
+)
+
+// Trace allows internal access to some trace functionality.
+// TODO(#412): remove this
+var Trace interface{}
+
+// LocalSpanStoreEnabled true if the local span store is enabled.
+var LocalSpanStoreEnabled bool
+
+// BucketConfiguration stores the number of samples to store for span buckets
+// for successful and failed spans for a particular span name.
+type BucketConfiguration struct {
+ Name string
+ MaxRequestsSucceeded int
+ MaxRequestsErrors int
+}
+
+// PerMethodSummary is a summary of the spans stored for a single span name.
+type PerMethodSummary struct {
+ Active int
+ LatencyBuckets []LatencyBucketSummary
+ ErrorBuckets []ErrorBucketSummary
+}
+
+// LatencyBucketSummary is a summary of a latency bucket.
+type LatencyBucketSummary struct {
+ MinLatency, MaxLatency time.Duration
+ Size int
+}
+
+// ErrorBucketSummary is a summary of an error bucket.
+type ErrorBucketSummary struct {
+ ErrorCode int32
+ Size int
+}
diff --git a/vendor/go.opencensus.io/metric/metricdata/doc.go b/vendor/go.opencensus.io/metric/metricdata/doc.go
new file mode 100644
index 0000000..52a7b3b
--- /dev/null
+++ b/vendor/go.opencensus.io/metric/metricdata/doc.go
@@ -0,0 +1,19 @@
+// Copyright 2018, OpenCensus Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Package metricdata contains the metrics data model.
+//
+// This is an EXPERIMENTAL package, and may change in arbitrary ways without
+// notice.
+package metricdata // import "go.opencensus.io/metric/metricdata"
diff --git a/vendor/go.opencensus.io/metric/metricdata/exemplar.go b/vendor/go.opencensus.io/metric/metricdata/exemplar.go
new file mode 100644
index 0000000..12695ce
--- /dev/null
+++ b/vendor/go.opencensus.io/metric/metricdata/exemplar.go
@@ -0,0 +1,38 @@
+// Copyright 2018, OpenCensus Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package metricdata
+
+import (
+ "time"
+)
+
+// Exemplars keys.
+const (
+ AttachmentKeySpanContext = "SpanContext"
+)
+
+// Exemplar is an example data point associated with each bucket of a
+// distribution type aggregation.
+//
+// Their purpose is to provide an example of the kind of thing
+// (request, RPC, trace span, etc.) that resulted in that measurement.
+type Exemplar struct {
+ Value float64 // the value that was recorded
+ Timestamp time.Time // the time the value was recorded
+ Attachments Attachments // attachments (if any)
+}
+
+// Attachments is a map of extra values associated with a recorded data point.
+type Attachments map[string]interface{}
diff --git a/vendor/go.opencensus.io/metric/metricdata/label.go b/vendor/go.opencensus.io/metric/metricdata/label.go
new file mode 100644
index 0000000..aadae41
--- /dev/null
+++ b/vendor/go.opencensus.io/metric/metricdata/label.go
@@ -0,0 +1,35 @@
+// Copyright 2018, OpenCensus Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package metricdata
+
+// LabelKey represents key of a label. It has optional
+// description attribute.
+type LabelKey struct {
+ Key string
+ Description string
+}
+
+// LabelValue represents the value of a label.
+// The zero value represents a missing label value, which may be treated
+// differently to an empty string value by some back ends.
+type LabelValue struct {
+ Value string // string value of the label
+ Present bool // flag that indicated whether a value is present or not
+}
+
+// NewLabelValue creates a new non-nil LabelValue that represents the given string.
+func NewLabelValue(val string) LabelValue {
+ return LabelValue{Value: val, Present: true}
+}
diff --git a/vendor/go.opencensus.io/metric/metricdata/metric.go b/vendor/go.opencensus.io/metric/metricdata/metric.go
new file mode 100644
index 0000000..8293712
--- /dev/null
+++ b/vendor/go.opencensus.io/metric/metricdata/metric.go
@@ -0,0 +1,46 @@
+// Copyright 2018, OpenCensus Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package metricdata
+
+import (
+ "time"
+
+ "go.opencensus.io/resource"
+)
+
+// Descriptor holds metadata about a metric.
+type Descriptor struct {
+ Name string // full name of the metric
+ Description string // human-readable description
+ Unit Unit // units for the measure
+ Type Type // type of measure
+ LabelKeys []LabelKey // label keys
+}
+
+// Metric represents a quantity measured against a resource with different
+// label value combinations.
+type Metric struct {
+ Descriptor Descriptor // metric descriptor
+ Resource *resource.Resource // resource against which this was measured
+ TimeSeries []*TimeSeries // one time series for each combination of label values
+}
+
+// TimeSeries is a sequence of points associated with a combination of label
+// values.
+type TimeSeries struct {
+ LabelValues []LabelValue // label values, same order as keys in the metric descriptor
+ Points []Point // points sequence
+ StartTime time.Time // time we started recording this time series
+}
diff --git a/vendor/go.opencensus.io/metric/metricdata/point.go b/vendor/go.opencensus.io/metric/metricdata/point.go
new file mode 100644
index 0000000..7fe057b
--- /dev/null
+++ b/vendor/go.opencensus.io/metric/metricdata/point.go
@@ -0,0 +1,193 @@
+// Copyright 2018, OpenCensus Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package metricdata
+
+import (
+ "time"
+)
+
+// Point is a single data point of a time series.
+type Point struct {
+ // Time is the point in time that this point represents in a time series.
+ Time time.Time
+ // Value is the value of this point. Prefer using ReadValue to switching on
+ // the value type, since new value types might be added.
+ Value interface{}
+}
+
+//go:generate stringer -type ValueType
+
+// NewFloat64Point creates a new Point holding a float64 value.
+func NewFloat64Point(t time.Time, val float64) Point {
+ return Point{
+ Value: val,
+ Time: t,
+ }
+}
+
+// NewInt64Point creates a new Point holding an int64 value.
+func NewInt64Point(t time.Time, val int64) Point {
+ return Point{
+ Value: val,
+ Time: t,
+ }
+}
+
+// NewDistributionPoint creates a new Point holding a Distribution value.
+func NewDistributionPoint(t time.Time, val *Distribution) Point {
+ return Point{
+ Value: val,
+ Time: t,
+ }
+}
+
+// NewSummaryPoint creates a new Point holding a Summary value.
+func NewSummaryPoint(t time.Time, val *Summary) Point {
+ return Point{
+ Value: val,
+ Time: t,
+ }
+}
+
+// ValueVisitor allows reading the value of a point.
+type ValueVisitor interface {
+ VisitFloat64Value(float64)
+ VisitInt64Value(int64)
+ VisitDistributionValue(*Distribution)
+ VisitSummaryValue(*Summary)
+}
+
+// ReadValue accepts a ValueVisitor and calls the appropriate method with the
+// value of this point.
+// Consumers of Point should use this in preference to switching on the type
+// of the value directly, since new value types may be added.
+func (p Point) ReadValue(vv ValueVisitor) {
+ switch v := p.Value.(type) {
+ case int64:
+ vv.VisitInt64Value(v)
+ case float64:
+ vv.VisitFloat64Value(v)
+ case *Distribution:
+ vv.VisitDistributionValue(v)
+ case *Summary:
+ vv.VisitSummaryValue(v)
+ default:
+ panic("unexpected value type")
+ }
+}
+
+// Distribution contains summary statistics for a population of values. It
+// optionally contains a histogram representing the distribution of those
+// values across a set of buckets.
+type Distribution struct {
+ // Count is the number of values in the population. Must be non-negative. This value
+ // must equal the sum of the values in bucket_counts if a histogram is
+ // provided.
+ Count int64
+ // Sum is the sum of the values in the population. If count is zero then this field
+ // must be zero.
+ Sum float64
+ // SumOfSquaredDeviation is the sum of squared deviations from the mean of the values in the
+ // population. For values x_i this is:
+ //
+ // Sum[i=1..n]((x_i - mean)^2)
+ //
+ // Knuth, "The Art of Computer Programming", Vol. 2, page 323, 3rd edition
+ // describes Welford's method for accumulating this sum in one pass.
+ //
+ // If count is zero then this field must be zero.
+ SumOfSquaredDeviation float64
+ // BucketOptions describes the bounds of the histogram buckets in this
+ // distribution.
+ //
+ // A Distribution may optionally contain a histogram of the values in the
+ // population.
+ //
+ // If nil, there is no associated histogram.
+ BucketOptions *BucketOptions
+ // Bucket If the distribution does not have a histogram, then omit this field.
+ // If there is a histogram, then the sum of the values in the Bucket counts
+ // must equal the value in the count field of the distribution.
+ Buckets []Bucket
+}
+
+// BucketOptions describes the bounds of the histogram buckets in this
+// distribution.
+type BucketOptions struct {
+ // Bounds specifies a set of bucket upper bounds.
+ // This defines len(bounds) + 1 (= N) buckets. The boundaries for bucket
+ // index i are:
+ //
+ // [0, Bounds[i]) for i == 0
+ // [Bounds[i-1], Bounds[i]) for 0 < i < N-1
+ // [Bounds[i-1], +infinity) for i == N-1
+ Bounds []float64
+}
+
+// Bucket represents a single bucket (value range) in a distribution.
+type Bucket struct {
+ // Count is the number of values in each bucket of the histogram, as described in
+ // bucket_bounds.
+ Count int64
+ // Exemplar associated with this bucket (if any).
+ Exemplar *Exemplar
+}
+
+// Summary is a representation of percentiles.
+type Summary struct {
+ // Count is the cumulative count (if available).
+ Count int64
+ // Sum is the cumulative sum of values (if available).
+ Sum float64
+ // HasCountAndSum is true if Count and Sum are available.
+ HasCountAndSum bool
+ // Snapshot represents percentiles calculated over an arbitrary time window.
+ // The values in this struct can be reset at arbitrary unknown times, with
+ // the requirement that all of them are reset at the same time.
+ Snapshot Snapshot
+}
+
+// Snapshot represents percentiles over an arbitrary time.
+// The values in this struct can be reset at arbitrary unknown times, with
+// the requirement that all of them are reset at the same time.
+type Snapshot struct {
+ // Count is the number of values in the snapshot. Optional since some systems don't
+ // expose this. Set to 0 if not available.
+ Count int64
+ // Sum is the sum of values in the snapshot. Optional since some systems don't
+ // expose this. If count is 0 then this field must be zero.
+ Sum float64
+ // Percentiles is a map from percentile (range (0-100.0]) to the value of
+ // the percentile.
+ Percentiles map[float64]float64
+}
+
+//go:generate stringer -type Type
+
+// Type is the overall type of metric, including its value type and whether it
+// represents a cumulative total (since the start time) or if it represents a
+// gauge value.
+type Type int
+
+// Metric types.
+const (
+ TypeGaugeInt64 Type = iota
+ TypeGaugeFloat64
+ TypeGaugeDistribution
+ TypeCumulativeInt64
+ TypeCumulativeFloat64
+ TypeCumulativeDistribution
+ TypeSummary
+)
diff --git a/vendor/go.opencensus.io/metric/metricdata/type_string.go b/vendor/go.opencensus.io/metric/metricdata/type_string.go
new file mode 100644
index 0000000..c3f8ec2
--- /dev/null
+++ b/vendor/go.opencensus.io/metric/metricdata/type_string.go
@@ -0,0 +1,16 @@
+// Code generated by "stringer -type Type"; DO NOT EDIT.
+
+package metricdata
+
+import "strconv"
+
+const _Type_name = "TypeGaugeInt64TypeGaugeFloat64TypeGaugeDistributionTypeCumulativeInt64TypeCumulativeFloat64TypeCumulativeDistributionTypeSummary"
+
+var _Type_index = [...]uint8{0, 14, 30, 51, 70, 91, 117, 128}
+
+func (i Type) String() string {
+ if i < 0 || i >= Type(len(_Type_index)-1) {
+ return "Type(" + strconv.FormatInt(int64(i), 10) + ")"
+ }
+ return _Type_name[_Type_index[i]:_Type_index[i+1]]
+}
diff --git a/vendor/go.opencensus.io/metric/metricdata/unit.go b/vendor/go.opencensus.io/metric/metricdata/unit.go
new file mode 100644
index 0000000..b483a13
--- /dev/null
+++ b/vendor/go.opencensus.io/metric/metricdata/unit.go
@@ -0,0 +1,27 @@
+// Copyright 2018, OpenCensus Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package metricdata
+
+// Unit is a string encoded according to the case-sensitive abbreviations from the
+// Unified Code for Units of Measure: http://unitsofmeasure.org/ucum.html
+type Unit string
+
+// Predefined units. To record against a unit not represented here, create your
+// own Unit type constant from a string.
+const (
+ UnitDimensionless Unit = "1"
+ UnitBytes Unit = "By"
+ UnitMilliseconds Unit = "ms"
+)
diff --git a/vendor/go.opencensus.io/metric/metricproducer/manager.go b/vendor/go.opencensus.io/metric/metricproducer/manager.go
new file mode 100644
index 0000000..ca1f390
--- /dev/null
+++ b/vendor/go.opencensus.io/metric/metricproducer/manager.go
@@ -0,0 +1,78 @@
+// Copyright 2019, OpenCensus Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package metricproducer
+
+import (
+ "sync"
+)
+
+// Manager maintains a list of active producers. Producers can register
+// with the manager to allow readers to read all metrics provided by them.
+// Readers can retrieve all producers registered with the manager,
+// read metrics from the producers and export them.
+type Manager struct {
+ mu sync.RWMutex
+ producers map[Producer]struct{}
+}
+
+var prodMgr *Manager
+var once sync.Once
+
+// GlobalManager is a single instance of producer manager
+// that is used by all producers and all readers.
+func GlobalManager() *Manager {
+ once.Do(func() {
+ prodMgr = &Manager{}
+ prodMgr.producers = make(map[Producer]struct{})
+ })
+ return prodMgr
+}
+
+// AddProducer adds the producer to the Manager if it is not already present.
+func (pm *Manager) AddProducer(producer Producer) {
+ if producer == nil {
+ return
+ }
+ pm.mu.Lock()
+ defer pm.mu.Unlock()
+ pm.producers[producer] = struct{}{}
+}
+
+// DeleteProducer deletes the producer from the Manager if it is present.
+func (pm *Manager) DeleteProducer(producer Producer) {
+ if producer == nil {
+ return
+ }
+ pm.mu.Lock()
+ defer pm.mu.Unlock()
+ delete(pm.producers, producer)
+}
+
+// GetAll returns a slice of all producer currently registered with
+// the Manager. For each call it generates a new slice. The slice
+// should not be cached as registration may change at any time. It is
+// typically called periodically by exporter to read metrics from
+// the producers.
+func (pm *Manager) GetAll() []Producer {
+ pm.mu.Lock()
+ defer pm.mu.Unlock()
+ producers := make([]Producer, len(pm.producers))
+ i := 0
+ for producer := range pm.producers {
+ producers[i] = producer
+ i++
+ }
+ return producers
+}
diff --git a/vendor/go.opencensus.io/metric/metricproducer/producer.go b/vendor/go.opencensus.io/metric/metricproducer/producer.go
new file mode 100644
index 0000000..6cee9ed
--- /dev/null
+++ b/vendor/go.opencensus.io/metric/metricproducer/producer.go
@@ -0,0 +1,28 @@
+// Copyright 2019, OpenCensus Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package metricproducer
+
+import (
+ "go.opencensus.io/metric/metricdata"
+)
+
+// Producer is a source of metrics.
+type Producer interface {
+ // Read should return the current values of all metrics supported by this
+ // metric provider.
+ // The returned metrics should be unique for each combination of name and
+ // resource.
+ Read() []*metricdata.Metric
+}
diff --git a/vendor/go.opencensus.io/opencensus.go b/vendor/go.opencensus.io/opencensus.go
new file mode 100644
index 0000000..e5e4b43
--- /dev/null
+++ b/vendor/go.opencensus.io/opencensus.go
@@ -0,0 +1,21 @@
+// Copyright 2017, OpenCensus Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Package opencensus contains Go support for OpenCensus.
+package opencensus // import "go.opencensus.io"
+
+// Version is the current release version of OpenCensus in use.
+func Version() string {
+ return "0.23.0"
+}
diff --git a/vendor/go.opencensus.io/resource/resource.go b/vendor/go.opencensus.io/resource/resource.go
new file mode 100644
index 0000000..b1764e1
--- /dev/null
+++ b/vendor/go.opencensus.io/resource/resource.go
@@ -0,0 +1,164 @@
+// Copyright 2018, OpenCensus Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Package resource provides functionality for resource, which capture
+// identifying information about the entities for which signals are exported.
+package resource
+
+import (
+ "context"
+ "fmt"
+ "os"
+ "regexp"
+ "sort"
+ "strconv"
+ "strings"
+)
+
+// Environment variables used by FromEnv to decode a resource.
+const (
+ EnvVarType = "OC_RESOURCE_TYPE"
+ EnvVarLabels = "OC_RESOURCE_LABELS"
+)
+
+// Resource describes an entity about which identifying information and metadata is exposed.
+// For example, a type "k8s.io/container" may hold labels describing the pod name and namespace.
+type Resource struct {
+ Type string
+ Labels map[string]string
+}
+
+// EncodeLabels encodes a labels map to a string as provided via the OC_RESOURCE_LABELS environment variable.
+func EncodeLabels(labels map[string]string) string {
+ sortedKeys := make([]string, 0, len(labels))
+ for k := range labels {
+ sortedKeys = append(sortedKeys, k)
+ }
+ sort.Strings(sortedKeys)
+
+ s := ""
+ for i, k := range sortedKeys {
+ if i > 0 {
+ s += ","
+ }
+ s += k + "=" + strconv.Quote(labels[k])
+ }
+ return s
+}
+
+var labelRegex = regexp.MustCompile(`^\s*([[:ascii:]]{1,256}?)=("[[:ascii:]]{0,256}?")\s*,`)
+
+// DecodeLabels decodes a serialized label map as used in the OC_RESOURCE_LABELS variable.
+// A list of labels of the form `="",="",...` is accepted.
+// Domain names and paths are accepted as label keys.
+// Most users will want to use FromEnv instead.
+func DecodeLabels(s string) (map[string]string, error) {
+ m := map[string]string{}
+ // Ensure a trailing comma, which allows us to keep the regex simpler
+ s = strings.TrimRight(strings.TrimSpace(s), ",") + ","
+
+ for len(s) > 0 {
+ match := labelRegex.FindStringSubmatch(s)
+ if len(match) == 0 {
+ return nil, fmt.Errorf("invalid label formatting, remainder: %s", s)
+ }
+ v := match[2]
+ if v == "" {
+ v = match[3]
+ } else {
+ var err error
+ if v, err = strconv.Unquote(v); err != nil {
+ return nil, fmt.Errorf("invalid label formatting, remainder: %s, err: %s", s, err)
+ }
+ }
+ m[match[1]] = v
+
+ s = s[len(match[0]):]
+ }
+ return m, nil
+}
+
+// FromEnv is a detector that loads resource information from the OC_RESOURCE_TYPE
+// and OC_RESOURCE_labelS environment variables.
+func FromEnv(context.Context) (*Resource, error) {
+ res := &Resource{
+ Type: strings.TrimSpace(os.Getenv(EnvVarType)),
+ }
+ labels := strings.TrimSpace(os.Getenv(EnvVarLabels))
+ if labels == "" {
+ return res, nil
+ }
+ var err error
+ if res.Labels, err = DecodeLabels(labels); err != nil {
+ return nil, err
+ }
+ return res, nil
+}
+
+var _ Detector = FromEnv
+
+// merge resource information from b into a. In case of a collision, a takes precedence.
+func merge(a, b *Resource) *Resource {
+ if a == nil {
+ return b
+ }
+ if b == nil {
+ return a
+ }
+ res := &Resource{
+ Type: a.Type,
+ Labels: map[string]string{},
+ }
+ if res.Type == "" {
+ res.Type = b.Type
+ }
+ for k, v := range b.Labels {
+ res.Labels[k] = v
+ }
+ // Labels from resource a overwrite labels from resource b.
+ for k, v := range a.Labels {
+ res.Labels[k] = v
+ }
+ return res
+}
+
+// Detector attempts to detect resource information.
+// If the detector cannot find resource information, the returned resource is nil but no
+// error is returned.
+// An error is only returned on unexpected failures.
+type Detector func(context.Context) (*Resource, error)
+
+// MultiDetector returns a Detector that calls all input detectors in order and
+// merges each result with the previous one. In case a type of label key is already set,
+// the first set value is takes precedence.
+// It returns on the first error that a sub-detector encounters.
+func MultiDetector(detectors ...Detector) Detector {
+ return func(ctx context.Context) (*Resource, error) {
+ return detectAll(ctx, detectors...)
+ }
+}
+
+// detectall calls all input detectors sequentially an merges each result with the previous one.
+// It returns on the first error that a sub-detector encounters.
+func detectAll(ctx context.Context, detectors ...Detector) (*Resource, error) {
+ var res *Resource
+ for _, d := range detectors {
+ r, err := d(ctx)
+ if err != nil {
+ return nil, err
+ }
+ res = merge(res, r)
+ }
+ return res, nil
+}
diff --git a/vendor/go.opencensus.io/stats/doc.go b/vendor/go.opencensus.io/stats/doc.go
new file mode 100644
index 0000000..00d473e
--- /dev/null
+++ b/vendor/go.opencensus.io/stats/doc.go
@@ -0,0 +1,69 @@
+// Copyright 2017, OpenCensus Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+/*
+Package stats contains support for OpenCensus stats recording.
+
+OpenCensus allows users to create typed measures, record measurements,
+aggregate the collected data, and export the aggregated data.
+
+Measures
+
+A measure represents a type of data point to be tracked and recorded.
+For example, latency, request Mb/s, and response Mb/s are measures
+to collect from a server.
+
+Measure constructors such as Int64 and Float64 automatically
+register the measure by the given name. Each registered measure needs
+to be unique by name. Measures also have a description and a unit.
+
+Libraries can define and export measures. Application authors can then
+create views and collect and break down measures by the tags they are
+interested in.
+
+Recording measurements
+
+Measurement is a data point to be collected for a measure. For example,
+for a latency (ms) measure, 100 is a measurement that represents a 100ms
+latency event. Measurements are created from measures with
+the current context. Tags from the current context are recorded with the
+measurements if they are any.
+
+Recorded measurements are dropped immediately if no views are registered for them.
+There is usually no need to conditionally enable and disable
+recording to reduce cost. Recording of measurements is cheap.
+
+Libraries can always record measurements, and applications can later decide
+on which measurements they want to collect by registering views. This allows
+libraries to turn on the instrumentation by default.
+
+Exemplars
+
+For a given recorded measurement, the associated exemplar is a diagnostic map
+that gives more information about the measurement.
+
+When aggregated using a Distribution aggregation, an exemplar is kept for each
+bucket in the Distribution. This allows you to easily find an example of a
+measurement that fell into each bucket.
+
+For example, if you also use the OpenCensus trace package and you
+record a measurement with a context that contains a sampled trace span,
+then the trace span will be added to the exemplar associated with the measurement.
+
+When exported to a supporting back end, you should be able to easily navigate
+to example traces that fell into each bucket in the Distribution.
+
+*/
+package stats // import "go.opencensus.io/stats"
diff --git a/vendor/go.opencensus.io/stats/internal/record.go b/vendor/go.opencensus.io/stats/internal/record.go
new file mode 100644
index 0000000..36935e6
--- /dev/null
+++ b/vendor/go.opencensus.io/stats/internal/record.go
@@ -0,0 +1,25 @@
+// Copyright 2018, OpenCensus Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package internal
+
+import (
+ "go.opencensus.io/tag"
+)
+
+// DefaultRecorder will be called for each Record call.
+var DefaultRecorder func(tags *tag.Map, measurement interface{}, attachments map[string]interface{})
+
+// SubscriptionReporter reports when a view subscribed with a measure.
+var SubscriptionReporter func(measure string)
diff --git a/vendor/go.opencensus.io/stats/measure.go b/vendor/go.opencensus.io/stats/measure.go
new file mode 100644
index 0000000..1ffd3ce
--- /dev/null
+++ b/vendor/go.opencensus.io/stats/measure.go
@@ -0,0 +1,109 @@
+// Copyright 2017, OpenCensus Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package stats
+
+import (
+ "sync"
+ "sync/atomic"
+)
+
+// Measure represents a single numeric value to be tracked and recorded.
+// For example, latency, request bytes, and response bytes could be measures
+// to collect from a server.
+//
+// Measures by themselves have no outside effects. In order to be exported,
+// the measure needs to be used in a View. If no Views are defined over a
+// measure, there is very little cost in recording it.
+type Measure interface {
+ // Name returns the name of this measure.
+ //
+ // Measure names are globally unique (among all libraries linked into your program).
+ // We recommend prefixing the measure name with a domain name relevant to your
+ // project or application.
+ //
+ // Measure names are never sent over the wire or exported to backends.
+ // They are only used to create Views.
+ Name() string
+
+ // Description returns the human-readable description of this measure.
+ Description() string
+
+ // Unit returns the units for the values this measure takes on.
+ //
+ // Units are encoded according to the case-sensitive abbreviations from the
+ // Unified Code for Units of Measure: http://unitsofmeasure.org/ucum.html
+ Unit() string
+}
+
+// measureDescriptor is the untyped descriptor associated with each measure.
+// Int64Measure and Float64Measure wrap measureDescriptor to provide typed
+// recording APIs.
+// Two Measures with the same name will have the same measureDescriptor.
+type measureDescriptor struct {
+ subs int32 // access atomically
+
+ name string
+ description string
+ unit string
+}
+
+func (m *measureDescriptor) subscribe() {
+ atomic.StoreInt32(&m.subs, 1)
+}
+
+func (m *measureDescriptor) subscribed() bool {
+ return atomic.LoadInt32(&m.subs) == 1
+}
+
+var (
+ mu sync.RWMutex
+ measures = make(map[string]*measureDescriptor)
+)
+
+func registerMeasureHandle(name, desc, unit string) *measureDescriptor {
+ mu.Lock()
+ defer mu.Unlock()
+
+ if stored, ok := measures[name]; ok {
+ return stored
+ }
+ m := &measureDescriptor{
+ name: name,
+ description: desc,
+ unit: unit,
+ }
+ measures[name] = m
+ return m
+}
+
+// Measurement is the numeric value measured when recording stats. Each measure
+// provides methods to create measurements of their kind. For example, Int64Measure
+// provides M to convert an int64 into a measurement.
+type Measurement struct {
+ v float64
+ m Measure
+ desc *measureDescriptor
+}
+
+// Value returns the value of the Measurement as a float64.
+func (m Measurement) Value() float64 {
+ return m.v
+}
+
+// Measure returns the Measure from which this Measurement was created.
+func (m Measurement) Measure() Measure {
+ return m.m
+}
diff --git a/vendor/go.opencensus.io/stats/measure_float64.go b/vendor/go.opencensus.io/stats/measure_float64.go
new file mode 100644
index 0000000..f02c1ed
--- /dev/null
+++ b/vendor/go.opencensus.io/stats/measure_float64.go
@@ -0,0 +1,55 @@
+// Copyright 2017, OpenCensus Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package stats
+
+// Float64Measure is a measure for float64 values.
+type Float64Measure struct {
+ desc *measureDescriptor
+}
+
+// M creates a new float64 measurement.
+// Use Record to record measurements.
+func (m *Float64Measure) M(v float64) Measurement {
+ return Measurement{
+ m: m,
+ desc: m.desc,
+ v: v,
+ }
+}
+
+// Float64 creates a new measure for float64 values.
+//
+// See the documentation for interface Measure for more guidance on the
+// parameters of this function.
+func Float64(name, description, unit string) *Float64Measure {
+ mi := registerMeasureHandle(name, description, unit)
+ return &Float64Measure{mi}
+}
+
+// Name returns the name of the measure.
+func (m *Float64Measure) Name() string {
+ return m.desc.name
+}
+
+// Description returns the description of the measure.
+func (m *Float64Measure) Description() string {
+ return m.desc.description
+}
+
+// Unit returns the unit of the measure.
+func (m *Float64Measure) Unit() string {
+ return m.desc.unit
+}
diff --git a/vendor/go.opencensus.io/stats/measure_int64.go b/vendor/go.opencensus.io/stats/measure_int64.go
new file mode 100644
index 0000000..d101d79
--- /dev/null
+++ b/vendor/go.opencensus.io/stats/measure_int64.go
@@ -0,0 +1,55 @@
+// Copyright 2017, OpenCensus Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package stats
+
+// Int64Measure is a measure for int64 values.
+type Int64Measure struct {
+ desc *measureDescriptor
+}
+
+// M creates a new int64 measurement.
+// Use Record to record measurements.
+func (m *Int64Measure) M(v int64) Measurement {
+ return Measurement{
+ m: m,
+ desc: m.desc,
+ v: float64(v),
+ }
+}
+
+// Int64 creates a new measure for int64 values.
+//
+// See the documentation for interface Measure for more guidance on the
+// parameters of this function.
+func Int64(name, description, unit string) *Int64Measure {
+ mi := registerMeasureHandle(name, description, unit)
+ return &Int64Measure{mi}
+}
+
+// Name returns the name of the measure.
+func (m *Int64Measure) Name() string {
+ return m.desc.name
+}
+
+// Description returns the description of the measure.
+func (m *Int64Measure) Description() string {
+ return m.desc.description
+}
+
+// Unit returns the unit of the measure.
+func (m *Int64Measure) Unit() string {
+ return m.desc.unit
+}
diff --git a/vendor/go.opencensus.io/stats/record.go b/vendor/go.opencensus.io/stats/record.go
new file mode 100644
index 0000000..ad46911
--- /dev/null
+++ b/vendor/go.opencensus.io/stats/record.go
@@ -0,0 +1,117 @@
+// Copyright 2018, OpenCensus Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package stats
+
+import (
+ "context"
+
+ "go.opencensus.io/metric/metricdata"
+ "go.opencensus.io/stats/internal"
+ "go.opencensus.io/tag"
+)
+
+func init() {
+ internal.SubscriptionReporter = func(measure string) {
+ mu.Lock()
+ measures[measure].subscribe()
+ mu.Unlock()
+ }
+}
+
+type recordOptions struct {
+ attachments metricdata.Attachments
+ mutators []tag.Mutator
+ measurements []Measurement
+}
+
+// WithAttachments applies provided exemplar attachments.
+func WithAttachments(attachments metricdata.Attachments) Options {
+ return func(ro *recordOptions) {
+ ro.attachments = attachments
+ }
+}
+
+// WithTags applies provided tag mutators.
+func WithTags(mutators ...tag.Mutator) Options {
+ return func(ro *recordOptions) {
+ ro.mutators = mutators
+ }
+}
+
+// WithMeasurements applies provided measurements.
+func WithMeasurements(measurements ...Measurement) Options {
+ return func(ro *recordOptions) {
+ ro.measurements = measurements
+ }
+}
+
+// Options apply changes to recordOptions.
+type Options func(*recordOptions)
+
+func createRecordOption(ros ...Options) *recordOptions {
+ o := &recordOptions{}
+ for _, ro := range ros {
+ ro(o)
+ }
+ return o
+}
+
+// Record records one or multiple measurements with the same context at once.
+// If there are any tags in the context, measurements will be tagged with them.
+func Record(ctx context.Context, ms ...Measurement) {
+ RecordWithOptions(ctx, WithMeasurements(ms...))
+}
+
+// RecordWithTags records one or multiple measurements at once.
+//
+// Measurements will be tagged with the tags in the context mutated by the mutators.
+// RecordWithTags is useful if you want to record with tag mutations but don't want
+// to propagate the mutations in the context.
+func RecordWithTags(ctx context.Context, mutators []tag.Mutator, ms ...Measurement) error {
+ return RecordWithOptions(ctx, WithTags(mutators...), WithMeasurements(ms...))
+}
+
+// RecordWithOptions records measurements from the given options (if any) against context
+// and tags and attachments in the options (if any).
+// If there are any tags in the context, measurements will be tagged with them.
+func RecordWithOptions(ctx context.Context, ros ...Options) error {
+ o := createRecordOption(ros...)
+ if len(o.measurements) == 0 {
+ return nil
+ }
+ recorder := internal.DefaultRecorder
+ if recorder == nil {
+ return nil
+ }
+ record := false
+ for _, m := range o.measurements {
+ if m.desc.subscribed() {
+ record = true
+ break
+ }
+ }
+ if !record {
+ return nil
+ }
+ if len(o.mutators) > 0 {
+ var err error
+ if ctx, err = tag.New(ctx, o.mutators...); err != nil {
+ return err
+ }
+ }
+ recorder(tag.FromContext(ctx), o.measurements, o.attachments)
+ return nil
+}
diff --git a/vendor/go.opencensus.io/stats/units.go b/vendor/go.opencensus.io/stats/units.go
new file mode 100644
index 0000000..7363996
--- /dev/null
+++ b/vendor/go.opencensus.io/stats/units.go
@@ -0,0 +1,26 @@
+// Copyright 2018, OpenCensus Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package stats
+
+// Units are encoded according to the case-sensitive abbreviations from the
+// Unified Code for Units of Measure: http://unitsofmeasure.org/ucum.html
+const (
+ UnitNone = "1" // Deprecated: Use UnitDimensionless.
+ UnitDimensionless = "1"
+ UnitBytes = "By"
+ UnitMilliseconds = "ms"
+ UnitSeconds = "s"
+)
diff --git a/vendor/go.opencensus.io/stats/view/aggregation.go b/vendor/go.opencensus.io/stats/view/aggregation.go
new file mode 100644
index 0000000..9d70937
--- /dev/null
+++ b/vendor/go.opencensus.io/stats/view/aggregation.go
@@ -0,0 +1,121 @@
+// Copyright 2017, OpenCensus Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package view
+
+// AggType represents the type of aggregation function used on a View.
+type AggType int
+
+// All available aggregation types.
+const (
+ AggTypeNone AggType = iota // no aggregation; reserved for future use.
+ AggTypeCount // the count aggregation, see Count.
+ AggTypeSum // the sum aggregation, see Sum.
+ AggTypeDistribution // the distribution aggregation, see Distribution.
+ AggTypeLastValue // the last value aggregation, see LastValue.
+)
+
+func (t AggType) String() string {
+ return aggTypeName[t]
+}
+
+var aggTypeName = map[AggType]string{
+ AggTypeNone: "None",
+ AggTypeCount: "Count",
+ AggTypeSum: "Sum",
+ AggTypeDistribution: "Distribution",
+ AggTypeLastValue: "LastValue",
+}
+
+// Aggregation represents a data aggregation method. Use one of the functions:
+// Count, Sum, or Distribution to construct an Aggregation.
+type Aggregation struct {
+ Type AggType // Type is the AggType of this Aggregation.
+ Buckets []float64 // Buckets are the bucket endpoints if this Aggregation represents a distribution, see Distribution.
+
+ newData func() AggregationData
+}
+
+var (
+ aggCount = &Aggregation{
+ Type: AggTypeCount,
+ newData: func() AggregationData {
+ return &CountData{}
+ },
+ }
+ aggSum = &Aggregation{
+ Type: AggTypeSum,
+ newData: func() AggregationData {
+ return &SumData{}
+ },
+ }
+)
+
+// Count indicates that data collected and aggregated
+// with this method will be turned into a count value.
+// For example, total number of accepted requests can be
+// aggregated by using Count.
+func Count() *Aggregation {
+ return aggCount
+}
+
+// Sum indicates that data collected and aggregated
+// with this method will be summed up.
+// For example, accumulated request bytes can be aggregated by using
+// Sum.
+func Sum() *Aggregation {
+ return aggSum
+}
+
+// Distribution indicates that the desired aggregation is
+// a histogram distribution.
+//
+// A distribution aggregation may contain a histogram of the values in the
+// population. The bucket boundaries for that histogram are described
+// by the bounds. This defines len(bounds)+1 buckets.
+//
+// If len(bounds) >= 2 then the boundaries for bucket index i are:
+//
+// [-infinity, bounds[i]) for i = 0
+// [bounds[i-1], bounds[i]) for 0 < i < length
+// [bounds[i-1], +infinity) for i = length
+//
+// If len(bounds) is 0 then there is no histogram associated with the
+// distribution. There will be a single bucket with boundaries
+// (-infinity, +infinity).
+//
+// If len(bounds) is 1 then there is no finite buckets, and that single
+// element is the common boundary of the overflow and underflow buckets.
+func Distribution(bounds ...float64) *Aggregation {
+ agg := &Aggregation{
+ Type: AggTypeDistribution,
+ Buckets: bounds,
+ }
+ agg.newData = func() AggregationData {
+ return newDistributionData(agg)
+ }
+ return agg
+}
+
+// LastValue only reports the last value recorded using this
+// aggregation. All other measurements will be dropped.
+func LastValue() *Aggregation {
+ return &Aggregation{
+ Type: AggTypeLastValue,
+ newData: func() AggregationData {
+ return &LastValueData{}
+ },
+ }
+}
diff --git a/vendor/go.opencensus.io/stats/view/aggregation_data.go b/vendor/go.opencensus.io/stats/view/aggregation_data.go
new file mode 100644
index 0000000..f331d45
--- /dev/null
+++ b/vendor/go.opencensus.io/stats/view/aggregation_data.go
@@ -0,0 +1,293 @@
+// Copyright 2017, OpenCensus Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package view
+
+import (
+ "math"
+ "time"
+
+ "go.opencensus.io/metric/metricdata"
+)
+
+// AggregationData represents an aggregated value from a collection.
+// They are reported on the view data during exporting.
+// Mosts users won't directly access aggregration data.
+type AggregationData interface {
+ isAggregationData() bool
+ addSample(v float64, attachments map[string]interface{}, t time.Time)
+ clone() AggregationData
+ equal(other AggregationData) bool
+ toPoint(t metricdata.Type, time time.Time) metricdata.Point
+}
+
+const epsilon = 1e-9
+
+// CountData is the aggregated data for the Count aggregation.
+// A count aggregation processes data and counts the recordings.
+//
+// Most users won't directly access count data.
+type CountData struct {
+ Value int64
+}
+
+func (a *CountData) isAggregationData() bool { return true }
+
+func (a *CountData) addSample(_ float64, _ map[string]interface{}, _ time.Time) {
+ a.Value = a.Value + 1
+}
+
+func (a *CountData) clone() AggregationData {
+ return &CountData{Value: a.Value}
+}
+
+func (a *CountData) equal(other AggregationData) bool {
+ a2, ok := other.(*CountData)
+ if !ok {
+ return false
+ }
+
+ return a.Value == a2.Value
+}
+
+func (a *CountData) toPoint(metricType metricdata.Type, t time.Time) metricdata.Point {
+ switch metricType {
+ case metricdata.TypeCumulativeInt64:
+ return metricdata.NewInt64Point(t, a.Value)
+ default:
+ panic("unsupported metricdata.Type")
+ }
+}
+
+// SumData is the aggregated data for the Sum aggregation.
+// A sum aggregation processes data and sums up the recordings.
+//
+// Most users won't directly access sum data.
+type SumData struct {
+ Value float64
+}
+
+func (a *SumData) isAggregationData() bool { return true }
+
+func (a *SumData) addSample(v float64, _ map[string]interface{}, _ time.Time) {
+ a.Value += v
+}
+
+func (a *SumData) clone() AggregationData {
+ return &SumData{Value: a.Value}
+}
+
+func (a *SumData) equal(other AggregationData) bool {
+ a2, ok := other.(*SumData)
+ if !ok {
+ return false
+ }
+ return math.Pow(a.Value-a2.Value, 2) < epsilon
+}
+
+func (a *SumData) toPoint(metricType metricdata.Type, t time.Time) metricdata.Point {
+ switch metricType {
+ case metricdata.TypeCumulativeInt64:
+ return metricdata.NewInt64Point(t, int64(a.Value))
+ case metricdata.TypeCumulativeFloat64:
+ return metricdata.NewFloat64Point(t, a.Value)
+ default:
+ panic("unsupported metricdata.Type")
+ }
+}
+
+// DistributionData is the aggregated data for the
+// Distribution aggregation.
+//
+// Most users won't directly access distribution data.
+//
+// For a distribution with N bounds, the associated DistributionData will have
+// N+1 buckets.
+type DistributionData struct {
+ Count int64 // number of data points aggregated
+ Min float64 // minimum value in the distribution
+ Max float64 // max value in the distribution
+ Mean float64 // mean of the distribution
+ SumOfSquaredDev float64 // sum of the squared deviation from the mean
+ CountPerBucket []int64 // number of occurrences per bucket
+ // ExemplarsPerBucket is slice the same length as CountPerBucket containing
+ // an exemplar for the associated bucket, or nil.
+ ExemplarsPerBucket []*metricdata.Exemplar
+ bounds []float64 // histogram distribution of the values
+}
+
+func newDistributionData(agg *Aggregation) *DistributionData {
+ bucketCount := len(agg.Buckets) + 1
+ return &DistributionData{
+ CountPerBucket: make([]int64, bucketCount),
+ ExemplarsPerBucket: make([]*metricdata.Exemplar, bucketCount),
+ bounds: agg.Buckets,
+ Min: math.MaxFloat64,
+ Max: math.SmallestNonzeroFloat64,
+ }
+}
+
+// Sum returns the sum of all samples collected.
+func (a *DistributionData) Sum() float64 { return a.Mean * float64(a.Count) }
+
+func (a *DistributionData) variance() float64 {
+ if a.Count <= 1 {
+ return 0
+ }
+ return a.SumOfSquaredDev / float64(a.Count-1)
+}
+
+func (a *DistributionData) isAggregationData() bool { return true }
+
+// TODO(songy23): support exemplar attachments.
+func (a *DistributionData) addSample(v float64, attachments map[string]interface{}, t time.Time) {
+ if v < a.Min {
+ a.Min = v
+ }
+ if v > a.Max {
+ a.Max = v
+ }
+ a.Count++
+ a.addToBucket(v, attachments, t)
+
+ if a.Count == 1 {
+ a.Mean = v
+ return
+ }
+
+ oldMean := a.Mean
+ a.Mean = a.Mean + (v-a.Mean)/float64(a.Count)
+ a.SumOfSquaredDev = a.SumOfSquaredDev + (v-oldMean)*(v-a.Mean)
+}
+
+func (a *DistributionData) addToBucket(v float64, attachments map[string]interface{}, t time.Time) {
+ var count *int64
+ var i int
+ var b float64
+ for i, b = range a.bounds {
+ if v < b {
+ count = &a.CountPerBucket[i]
+ break
+ }
+ }
+ if count == nil { // Last bucket.
+ i = len(a.bounds)
+ count = &a.CountPerBucket[i]
+ }
+ *count++
+ if exemplar := getExemplar(v, attachments, t); exemplar != nil {
+ a.ExemplarsPerBucket[i] = exemplar
+ }
+}
+
+func getExemplar(v float64, attachments map[string]interface{}, t time.Time) *metricdata.Exemplar {
+ if len(attachments) == 0 {
+ return nil
+ }
+ return &metricdata.Exemplar{
+ Value: v,
+ Timestamp: t,
+ Attachments: attachments,
+ }
+}
+
+func (a *DistributionData) clone() AggregationData {
+ c := *a
+ c.CountPerBucket = append([]int64(nil), a.CountPerBucket...)
+ c.ExemplarsPerBucket = append([]*metricdata.Exemplar(nil), a.ExemplarsPerBucket...)
+ return &c
+}
+
+func (a *DistributionData) equal(other AggregationData) bool {
+ a2, ok := other.(*DistributionData)
+ if !ok {
+ return false
+ }
+ if a2 == nil {
+ return false
+ }
+ if len(a.CountPerBucket) != len(a2.CountPerBucket) {
+ return false
+ }
+ for i := range a.CountPerBucket {
+ if a.CountPerBucket[i] != a2.CountPerBucket[i] {
+ return false
+ }
+ }
+ return a.Count == a2.Count && a.Min == a2.Min && a.Max == a2.Max && math.Pow(a.Mean-a2.Mean, 2) < epsilon && math.Pow(a.variance()-a2.variance(), 2) < epsilon
+}
+
+func (a *DistributionData) toPoint(metricType metricdata.Type, t time.Time) metricdata.Point {
+ switch metricType {
+ case metricdata.TypeCumulativeDistribution:
+ buckets := []metricdata.Bucket{}
+ for i := 0; i < len(a.CountPerBucket); i++ {
+ buckets = append(buckets, metricdata.Bucket{
+ Count: a.CountPerBucket[i],
+ Exemplar: a.ExemplarsPerBucket[i],
+ })
+ }
+ bucketOptions := &metricdata.BucketOptions{Bounds: a.bounds}
+
+ val := &metricdata.Distribution{
+ Count: a.Count,
+ Sum: a.Sum(),
+ SumOfSquaredDeviation: a.SumOfSquaredDev,
+ BucketOptions: bucketOptions,
+ Buckets: buckets,
+ }
+ return metricdata.NewDistributionPoint(t, val)
+
+ default:
+ // TODO: [rghetia] when we have a use case for TypeGaugeDistribution.
+ panic("unsupported metricdata.Type")
+ }
+}
+
+// LastValueData returns the last value recorded for LastValue aggregation.
+type LastValueData struct {
+ Value float64
+}
+
+func (l *LastValueData) isAggregationData() bool {
+ return true
+}
+
+func (l *LastValueData) addSample(v float64, _ map[string]interface{}, _ time.Time) {
+ l.Value = v
+}
+
+func (l *LastValueData) clone() AggregationData {
+ return &LastValueData{l.Value}
+}
+
+func (l *LastValueData) equal(other AggregationData) bool {
+ a2, ok := other.(*LastValueData)
+ if !ok {
+ return false
+ }
+ return l.Value == a2.Value
+}
+
+func (l *LastValueData) toPoint(metricType metricdata.Type, t time.Time) metricdata.Point {
+ switch metricType {
+ case metricdata.TypeGaugeInt64:
+ return metricdata.NewInt64Point(t, int64(l.Value))
+ case metricdata.TypeGaugeFloat64:
+ return metricdata.NewFloat64Point(t, l.Value)
+ default:
+ panic("unsupported metricdata.Type")
+ }
+}
diff --git a/vendor/go.opencensus.io/stats/view/collector.go b/vendor/go.opencensus.io/stats/view/collector.go
new file mode 100644
index 0000000..8a6a2c0
--- /dev/null
+++ b/vendor/go.opencensus.io/stats/view/collector.go
@@ -0,0 +1,86 @@
+// Copyright 2017, OpenCensus Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package view
+
+import (
+ "sort"
+ "time"
+
+ "go.opencensus.io/internal/tagencoding"
+ "go.opencensus.io/tag"
+)
+
+type collector struct {
+ // signatures holds the aggregations values for each unique tag signature
+ // (values for all keys) to its aggregator.
+ signatures map[string]AggregationData
+ // Aggregation is the description of the aggregation to perform for this
+ // view.
+ a *Aggregation
+}
+
+func (c *collector) addSample(s string, v float64, attachments map[string]interface{}, t time.Time) {
+ aggregator, ok := c.signatures[s]
+ if !ok {
+ aggregator = c.a.newData()
+ c.signatures[s] = aggregator
+ }
+ aggregator.addSample(v, attachments, t)
+}
+
+// collectRows returns a snapshot of the collected Row values.
+func (c *collector) collectedRows(keys []tag.Key) []*Row {
+ rows := make([]*Row, 0, len(c.signatures))
+ for sig, aggregator := range c.signatures {
+ tags := decodeTags([]byte(sig), keys)
+ row := &Row{Tags: tags, Data: aggregator.clone()}
+ rows = append(rows, row)
+ }
+ return rows
+}
+
+func (c *collector) clearRows() {
+ c.signatures = make(map[string]AggregationData)
+}
+
+// encodeWithKeys encodes the map by using values
+// only associated with the keys provided.
+func encodeWithKeys(m *tag.Map, keys []tag.Key) []byte {
+ vb := &tagencoding.Values{
+ Buffer: make([]byte, len(keys)),
+ }
+ for _, k := range keys {
+ v, _ := m.Value(k)
+ vb.WriteValue([]byte(v))
+ }
+ return vb.Bytes()
+}
+
+// decodeTags decodes tags from the buffer and
+// orders them by the keys.
+func decodeTags(buf []byte, keys []tag.Key) []tag.Tag {
+ vb := &tagencoding.Values{Buffer: buf}
+ var tags []tag.Tag
+ for _, k := range keys {
+ v := vb.ReadValue()
+ if v != nil {
+ tags = append(tags, tag.Tag{Key: k, Value: string(v)})
+ }
+ }
+ vb.ReadIndex = 0
+ sort.Slice(tags, func(i, j int) bool { return tags[i].Key.Name() < tags[j].Key.Name() })
+ return tags
+}
diff --git a/vendor/go.opencensus.io/stats/view/doc.go b/vendor/go.opencensus.io/stats/view/doc.go
new file mode 100644
index 0000000..7bbedfe
--- /dev/null
+++ b/vendor/go.opencensus.io/stats/view/doc.go
@@ -0,0 +1,47 @@
+// Copyright 2017, OpenCensus Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Package view contains support for collecting and exposing aggregates over stats.
+//
+// In order to collect measurements, views need to be defined and registered.
+// A view allows recorded measurements to be filtered and aggregated.
+//
+// All recorded measurements can be grouped by a list of tags.
+//
+// OpenCensus provides several aggregation methods: Count, Distribution and Sum.
+//
+// Count only counts the number of measurement points recorded.
+// Distribution provides statistical summary of the aggregated data by counting
+// how many recorded measurements fall into each bucket.
+// Sum adds up the measurement values.
+// LastValue just keeps track of the most recently recorded measurement value.
+// All aggregations are cumulative.
+//
+// Views can be registered and unregistered at any time during program execution.
+//
+// Libraries can define views but it is recommended that in most cases registering
+// views be left up to applications.
+//
+// Exporting
+//
+// Collected and aggregated data can be exported to a metric collection
+// backend by registering its exporter.
+//
+// Multiple exporters can be registered to upload the data to various
+// different back ends.
+package view // import "go.opencensus.io/stats/view"
+
+// TODO(acetechnologist): Add a link to the language independent OpenCensus
+// spec when it is available.
diff --git a/vendor/go.opencensus.io/stats/view/export.go b/vendor/go.opencensus.io/stats/view/export.go
new file mode 100644
index 0000000..7cb5971
--- /dev/null
+++ b/vendor/go.opencensus.io/stats/view/export.go
@@ -0,0 +1,58 @@
+// Copyright 2017, OpenCensus Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package view
+
+import "sync"
+
+var (
+ exportersMu sync.RWMutex // guards exporters
+ exporters = make(map[Exporter]struct{})
+)
+
+// Exporter exports the collected records as view data.
+//
+// The ExportView method should return quickly; if an
+// Exporter takes a significant amount of time to
+// process a Data, that work should be done on another goroutine.
+//
+// It is safe to assume that ExportView will not be called concurrently from
+// multiple goroutines.
+//
+// The Data should not be modified.
+type Exporter interface {
+ ExportView(viewData *Data)
+}
+
+// RegisterExporter registers an exporter.
+// Collected data will be reported via all the
+// registered exporters. Once you no longer
+// want data to be exported, invoke UnregisterExporter
+// with the previously registered exporter.
+//
+// Binaries can register exporters, libraries shouldn't register exporters.
+func RegisterExporter(e Exporter) {
+ exportersMu.Lock()
+ defer exportersMu.Unlock()
+
+ exporters[e] = struct{}{}
+}
+
+// UnregisterExporter unregisters an exporter.
+func UnregisterExporter(e Exporter) {
+ exportersMu.Lock()
+ defer exportersMu.Unlock()
+
+ delete(exporters, e)
+}
diff --git a/vendor/go.opencensus.io/stats/view/view.go b/vendor/go.opencensus.io/stats/view/view.go
new file mode 100644
index 0000000..293b54e
--- /dev/null
+++ b/vendor/go.opencensus.io/stats/view/view.go
@@ -0,0 +1,221 @@
+// Copyright 2017, OpenCensus Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package view
+
+import (
+ "bytes"
+ "errors"
+ "fmt"
+ "reflect"
+ "sort"
+ "sync/atomic"
+ "time"
+
+ "go.opencensus.io/metric/metricdata"
+ "go.opencensus.io/stats"
+ "go.opencensus.io/tag"
+)
+
+// View allows users to aggregate the recorded stats.Measurements.
+// Views need to be passed to the Register function before data will be
+// collected and sent to Exporters.
+type View struct {
+ Name string // Name of View. Must be unique. If unset, will default to the name of the Measure.
+ Description string // Description is a human-readable description for this view.
+
+ // TagKeys are the tag keys describing the grouping of this view.
+ // A single Row will be produced for each combination of associated tag values.
+ TagKeys []tag.Key
+
+ // Measure is a stats.Measure to aggregate in this view.
+ Measure stats.Measure
+
+ // Aggregation is the aggregation function to apply to the set of Measurements.
+ Aggregation *Aggregation
+}
+
+// WithName returns a copy of the View with a new name. This is useful for
+// renaming views to cope with limitations placed on metric names by various
+// backends.
+func (v *View) WithName(name string) *View {
+ vNew := *v
+ vNew.Name = name
+ return &vNew
+}
+
+// same compares two views and returns true if they represent the same aggregation.
+func (v *View) same(other *View) bool {
+ if v == other {
+ return true
+ }
+ if v == nil {
+ return false
+ }
+ return reflect.DeepEqual(v.Aggregation, other.Aggregation) &&
+ v.Measure.Name() == other.Measure.Name()
+}
+
+// ErrNegativeBucketBounds error returned if histogram contains negative bounds.
+//
+// Deprecated: this should not be public.
+var ErrNegativeBucketBounds = errors.New("negative bucket bounds not supported")
+
+// canonicalize canonicalizes v by setting explicit
+// defaults for Name and Description and sorting the TagKeys
+func (v *View) canonicalize() error {
+ if v.Measure == nil {
+ return fmt.Errorf("cannot register view %q: measure not set", v.Name)
+ }
+ if v.Aggregation == nil {
+ return fmt.Errorf("cannot register view %q: aggregation not set", v.Name)
+ }
+ if v.Name == "" {
+ v.Name = v.Measure.Name()
+ }
+ if v.Description == "" {
+ v.Description = v.Measure.Description()
+ }
+ if err := checkViewName(v.Name); err != nil {
+ return err
+ }
+ sort.Slice(v.TagKeys, func(i, j int) bool {
+ return v.TagKeys[i].Name() < v.TagKeys[j].Name()
+ })
+ sort.Float64s(v.Aggregation.Buckets)
+ for _, b := range v.Aggregation.Buckets {
+ if b < 0 {
+ return ErrNegativeBucketBounds
+ }
+ }
+ // drop 0 bucket silently.
+ v.Aggregation.Buckets = dropZeroBounds(v.Aggregation.Buckets...)
+
+ return nil
+}
+
+func dropZeroBounds(bounds ...float64) []float64 {
+ for i, bound := range bounds {
+ if bound > 0 {
+ return bounds[i:]
+ }
+ }
+ return []float64{}
+}
+
+// viewInternal is the internal representation of a View.
+type viewInternal struct {
+ view *View // view is the canonicalized View definition associated with this view.
+ subscribed uint32 // 1 if someone is subscribed and data need to be exported, use atomic to access
+ collector *collector
+ metricDescriptor *metricdata.Descriptor
+}
+
+func newViewInternal(v *View) (*viewInternal, error) {
+ return &viewInternal{
+ view: v,
+ collector: &collector{make(map[string]AggregationData), v.Aggregation},
+ metricDescriptor: viewToMetricDescriptor(v),
+ }, nil
+}
+
+func (v *viewInternal) subscribe() {
+ atomic.StoreUint32(&v.subscribed, 1)
+}
+
+func (v *viewInternal) unsubscribe() {
+ atomic.StoreUint32(&v.subscribed, 0)
+}
+
+// isSubscribed returns true if the view is exporting
+// data by subscription.
+func (v *viewInternal) isSubscribed() bool {
+ return atomic.LoadUint32(&v.subscribed) == 1
+}
+
+func (v *viewInternal) clearRows() {
+ v.collector.clearRows()
+}
+
+func (v *viewInternal) collectedRows() []*Row {
+ return v.collector.collectedRows(v.view.TagKeys)
+}
+
+func (v *viewInternal) addSample(m *tag.Map, val float64, attachments map[string]interface{}, t time.Time) {
+ if !v.isSubscribed() {
+ return
+ }
+ sig := string(encodeWithKeys(m, v.view.TagKeys))
+ v.collector.addSample(sig, val, attachments, t)
+}
+
+// A Data is a set of rows about usage of the single measure associated
+// with the given view. Each row is specific to a unique set of tags.
+type Data struct {
+ View *View
+ Start, End time.Time
+ Rows []*Row
+}
+
+// Row is the collected value for a specific set of key value pairs a.k.a tags.
+type Row struct {
+ Tags []tag.Tag
+ Data AggregationData
+}
+
+func (r *Row) String() string {
+ var buffer bytes.Buffer
+ buffer.WriteString("{ ")
+ buffer.WriteString("{ ")
+ for _, t := range r.Tags {
+ buffer.WriteString(fmt.Sprintf("{%v %v}", t.Key.Name(), t.Value))
+ }
+ buffer.WriteString(" }")
+ buffer.WriteString(fmt.Sprintf("%v", r.Data))
+ buffer.WriteString(" }")
+ return buffer.String()
+}
+
+// Equal returns true if both rows are equal. Tags are expected to be ordered
+// by the key name. Even if both rows have the same tags but the tags appear in
+// different orders it will return false.
+func (r *Row) Equal(other *Row) bool {
+ if r == other {
+ return true
+ }
+ return reflect.DeepEqual(r.Tags, other.Tags) && r.Data.equal(other.Data)
+}
+
+const maxNameLength = 255
+
+// Returns true if the given string contains only printable characters.
+func isPrintable(str string) bool {
+ for _, r := range str {
+ if !(r >= ' ' && r <= '~') {
+ return false
+ }
+ }
+ return true
+}
+
+func checkViewName(name string) error {
+ if len(name) > maxNameLength {
+ return fmt.Errorf("view name cannot be larger than %v", maxNameLength)
+ }
+ if !isPrintable(name) {
+ return fmt.Errorf("view name needs to be an ASCII string")
+ }
+ return nil
+}
diff --git a/vendor/go.opencensus.io/stats/view/view_to_metric.go b/vendor/go.opencensus.io/stats/view/view_to_metric.go
new file mode 100644
index 0000000..293c164
--- /dev/null
+++ b/vendor/go.opencensus.io/stats/view/view_to_metric.go
@@ -0,0 +1,149 @@
+// Copyright 2019, OpenCensus Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package view
+
+import (
+ "time"
+
+ "go.opencensus.io/metric/metricdata"
+ "go.opencensus.io/stats"
+)
+
+func getUnit(unit string) metricdata.Unit {
+ switch unit {
+ case "1":
+ return metricdata.UnitDimensionless
+ case "ms":
+ return metricdata.UnitMilliseconds
+ case "By":
+ return metricdata.UnitBytes
+ }
+ return metricdata.UnitDimensionless
+}
+
+func getType(v *View) metricdata.Type {
+ m := v.Measure
+ agg := v.Aggregation
+
+ switch agg.Type {
+ case AggTypeSum:
+ switch m.(type) {
+ case *stats.Int64Measure:
+ return metricdata.TypeCumulativeInt64
+ case *stats.Float64Measure:
+ return metricdata.TypeCumulativeFloat64
+ default:
+ panic("unexpected measure type")
+ }
+ case AggTypeDistribution:
+ return metricdata.TypeCumulativeDistribution
+ case AggTypeLastValue:
+ switch m.(type) {
+ case *stats.Int64Measure:
+ return metricdata.TypeGaugeInt64
+ case *stats.Float64Measure:
+ return metricdata.TypeGaugeFloat64
+ default:
+ panic("unexpected measure type")
+ }
+ case AggTypeCount:
+ switch m.(type) {
+ case *stats.Int64Measure:
+ return metricdata.TypeCumulativeInt64
+ case *stats.Float64Measure:
+ return metricdata.TypeCumulativeInt64
+ default:
+ panic("unexpected measure type")
+ }
+ default:
+ panic("unexpected aggregation type")
+ }
+}
+
+func getLabelKeys(v *View) []metricdata.LabelKey {
+ labelKeys := []metricdata.LabelKey{}
+ for _, k := range v.TagKeys {
+ labelKeys = append(labelKeys, metricdata.LabelKey{Key: k.Name()})
+ }
+ return labelKeys
+}
+
+func viewToMetricDescriptor(v *View) *metricdata.Descriptor {
+ return &metricdata.Descriptor{
+ Name: v.Name,
+ Description: v.Description,
+ Unit: convertUnit(v),
+ Type: getType(v),
+ LabelKeys: getLabelKeys(v),
+ }
+}
+
+func convertUnit(v *View) metricdata.Unit {
+ switch v.Aggregation.Type {
+ case AggTypeCount:
+ return metricdata.UnitDimensionless
+ default:
+ return getUnit(v.Measure.Unit())
+ }
+}
+
+func toLabelValues(row *Row, expectedKeys []metricdata.LabelKey) []metricdata.LabelValue {
+ labelValues := []metricdata.LabelValue{}
+ tagMap := make(map[string]string)
+ for _, tag := range row.Tags {
+ tagMap[tag.Key.Name()] = tag.Value
+ }
+
+ for _, key := range expectedKeys {
+ if val, ok := tagMap[key.Key]; ok {
+ labelValues = append(labelValues, metricdata.NewLabelValue(val))
+ } else {
+ labelValues = append(labelValues, metricdata.LabelValue{})
+ }
+ }
+ return labelValues
+}
+
+func rowToTimeseries(v *viewInternal, row *Row, now time.Time, startTime time.Time) *metricdata.TimeSeries {
+ return &metricdata.TimeSeries{
+ Points: []metricdata.Point{row.Data.toPoint(v.metricDescriptor.Type, now)},
+ LabelValues: toLabelValues(row, v.metricDescriptor.LabelKeys),
+ StartTime: startTime,
+ }
+}
+
+func viewToMetric(v *viewInternal, now time.Time, startTime time.Time) *metricdata.Metric {
+ if v.metricDescriptor.Type == metricdata.TypeGaugeInt64 ||
+ v.metricDescriptor.Type == metricdata.TypeGaugeFloat64 {
+ startTime = time.Time{}
+ }
+
+ rows := v.collectedRows()
+ if len(rows) == 0 {
+ return nil
+ }
+
+ ts := []*metricdata.TimeSeries{}
+ for _, row := range rows {
+ ts = append(ts, rowToTimeseries(v, row, now, startTime))
+ }
+
+ m := &metricdata.Metric{
+ Descriptor: *v.metricDescriptor,
+ TimeSeries: ts,
+ }
+ return m
+}
diff --git a/vendor/go.opencensus.io/stats/view/worker.go b/vendor/go.opencensus.io/stats/view/worker.go
new file mode 100644
index 0000000..2f3c018
--- /dev/null
+++ b/vendor/go.opencensus.io/stats/view/worker.go
@@ -0,0 +1,281 @@
+// Copyright 2017, OpenCensus Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package view
+
+import (
+ "fmt"
+ "sync"
+ "time"
+
+ "go.opencensus.io/metric/metricdata"
+ "go.opencensus.io/metric/metricproducer"
+ "go.opencensus.io/stats"
+ "go.opencensus.io/stats/internal"
+ "go.opencensus.io/tag"
+)
+
+func init() {
+ defaultWorker = newWorker()
+ go defaultWorker.start()
+ internal.DefaultRecorder = record
+}
+
+type measureRef struct {
+ measure string
+ views map[*viewInternal]struct{}
+}
+
+type worker struct {
+ measures map[string]*measureRef
+ views map[string]*viewInternal
+ startTimes map[*viewInternal]time.Time
+
+ timer *time.Ticker
+ c chan command
+ quit, done chan bool
+ mu sync.RWMutex
+}
+
+var defaultWorker *worker
+
+var defaultReportingDuration = 10 * time.Second
+
+// Find returns a registered view associated with this name.
+// If no registered view is found, nil is returned.
+func Find(name string) (v *View) {
+ req := &getViewByNameReq{
+ name: name,
+ c: make(chan *getViewByNameResp),
+ }
+ defaultWorker.c <- req
+ resp := <-req.c
+ return resp.v
+}
+
+// Register begins collecting data for the given views.
+// Once a view is registered, it reports data to the registered exporters.
+func Register(views ...*View) error {
+ req := ®isterViewReq{
+ views: views,
+ err: make(chan error),
+ }
+ defaultWorker.c <- req
+ return <-req.err
+}
+
+// Unregister the given views. Data will not longer be exported for these views
+// after Unregister returns.
+// It is not necessary to unregister from views you expect to collect for the
+// duration of your program execution.
+func Unregister(views ...*View) {
+ names := make([]string, len(views))
+ for i := range views {
+ names[i] = views[i].Name
+ }
+ req := &unregisterFromViewReq{
+ views: names,
+ done: make(chan struct{}),
+ }
+ defaultWorker.c <- req
+ <-req.done
+}
+
+// RetrieveData gets a snapshot of the data collected for the the view registered
+// with the given name. It is intended for testing only.
+func RetrieveData(viewName string) ([]*Row, error) {
+ req := &retrieveDataReq{
+ now: time.Now(),
+ v: viewName,
+ c: make(chan *retrieveDataResp),
+ }
+ defaultWorker.c <- req
+ resp := <-req.c
+ return resp.rows, resp.err
+}
+
+func record(tags *tag.Map, ms interface{}, attachments map[string]interface{}) {
+ req := &recordReq{
+ tm: tags,
+ ms: ms.([]stats.Measurement),
+ attachments: attachments,
+ t: time.Now(),
+ }
+ defaultWorker.c <- req
+}
+
+// SetReportingPeriod sets the interval between reporting aggregated views in
+// the program. If duration is less than or equal to zero, it enables the
+// default behavior.
+//
+// Note: each exporter makes different promises about what the lowest supported
+// duration is. For example, the Stackdriver exporter recommends a value no
+// lower than 1 minute. Consult each exporter per your needs.
+func SetReportingPeriod(d time.Duration) {
+ // TODO(acetechnologist): ensure that the duration d is more than a certain
+ // value. e.g. 1s
+ req := &setReportingPeriodReq{
+ d: d,
+ c: make(chan bool),
+ }
+ defaultWorker.c <- req
+ <-req.c // don't return until the timer is set to the new duration.
+}
+
+func newWorker() *worker {
+ return &worker{
+ measures: make(map[string]*measureRef),
+ views: make(map[string]*viewInternal),
+ startTimes: make(map[*viewInternal]time.Time),
+ timer: time.NewTicker(defaultReportingDuration),
+ c: make(chan command, 1024),
+ quit: make(chan bool),
+ done: make(chan bool),
+ }
+}
+
+func (w *worker) start() {
+ prodMgr := metricproducer.GlobalManager()
+ prodMgr.AddProducer(w)
+
+ for {
+ select {
+ case cmd := <-w.c:
+ cmd.handleCommand(w)
+ case <-w.timer.C:
+ w.reportUsage(time.Now())
+ case <-w.quit:
+ w.timer.Stop()
+ close(w.c)
+ w.done <- true
+ return
+ }
+ }
+}
+
+func (w *worker) stop() {
+ prodMgr := metricproducer.GlobalManager()
+ prodMgr.DeleteProducer(w)
+
+ w.quit <- true
+ <-w.done
+}
+
+func (w *worker) getMeasureRef(name string) *measureRef {
+ if mr, ok := w.measures[name]; ok {
+ return mr
+ }
+ mr := &measureRef{
+ measure: name,
+ views: make(map[*viewInternal]struct{}),
+ }
+ w.measures[name] = mr
+ return mr
+}
+
+func (w *worker) tryRegisterView(v *View) (*viewInternal, error) {
+ w.mu.Lock()
+ defer w.mu.Unlock()
+ vi, err := newViewInternal(v)
+ if err != nil {
+ return nil, err
+ }
+ if x, ok := w.views[vi.view.Name]; ok {
+ if !x.view.same(vi.view) {
+ return nil, fmt.Errorf("cannot register view %q; a different view with the same name is already registered", v.Name)
+ }
+
+ // the view is already registered so there is nothing to do and the
+ // command is considered successful.
+ return x, nil
+ }
+ w.views[vi.view.Name] = vi
+ ref := w.getMeasureRef(vi.view.Measure.Name())
+ ref.views[vi] = struct{}{}
+ return vi, nil
+}
+
+func (w *worker) unregisterView(viewName string) {
+ w.mu.Lock()
+ defer w.mu.Unlock()
+ delete(w.views, viewName)
+}
+
+func (w *worker) reportView(v *viewInternal, now time.Time) {
+ if !v.isSubscribed() {
+ return
+ }
+ rows := v.collectedRows()
+ _, ok := w.startTimes[v]
+ if !ok {
+ w.startTimes[v] = now
+ }
+ viewData := &Data{
+ View: v.view,
+ Start: w.startTimes[v],
+ End: time.Now(),
+ Rows: rows,
+ }
+ exportersMu.Lock()
+ for e := range exporters {
+ e.ExportView(viewData)
+ }
+ exportersMu.Unlock()
+}
+
+func (w *worker) reportUsage(now time.Time) {
+ w.mu.Lock()
+ defer w.mu.Unlock()
+ for _, v := range w.views {
+ w.reportView(v, now)
+ }
+}
+
+func (w *worker) toMetric(v *viewInternal, now time.Time) *metricdata.Metric {
+ if !v.isSubscribed() {
+ return nil
+ }
+
+ _, ok := w.startTimes[v]
+ if !ok {
+ w.startTimes[v] = now
+ }
+
+ var startTime time.Time
+ if v.metricDescriptor.Type == metricdata.TypeGaugeInt64 ||
+ v.metricDescriptor.Type == metricdata.TypeGaugeFloat64 {
+ startTime = time.Time{}
+ } else {
+ startTime = w.startTimes[v]
+ }
+
+ return viewToMetric(v, now, startTime)
+}
+
+// Read reads all view data and returns them as metrics.
+// It is typically invoked by metric reader to export stats in metric format.
+func (w *worker) Read() []*metricdata.Metric {
+ w.mu.Lock()
+ defer w.mu.Unlock()
+ now := time.Now()
+ metrics := make([]*metricdata.Metric, 0, len(w.views))
+ for _, v := range w.views {
+ metric := w.toMetric(v, now)
+ if metric != nil {
+ metrics = append(metrics, metric)
+ }
+ }
+ return metrics
+}
diff --git a/vendor/go.opencensus.io/stats/view/worker_commands.go b/vendor/go.opencensus.io/stats/view/worker_commands.go
new file mode 100644
index 0000000..0267e17
--- /dev/null
+++ b/vendor/go.opencensus.io/stats/view/worker_commands.go
@@ -0,0 +1,186 @@
+// Copyright 2017, OpenCensus Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package view
+
+import (
+ "errors"
+ "fmt"
+ "strings"
+ "time"
+
+ "go.opencensus.io/stats"
+ "go.opencensus.io/stats/internal"
+ "go.opencensus.io/tag"
+)
+
+type command interface {
+ handleCommand(w *worker)
+}
+
+// getViewByNameReq is the command to get a view given its name.
+type getViewByNameReq struct {
+ name string
+ c chan *getViewByNameResp
+}
+
+type getViewByNameResp struct {
+ v *View
+}
+
+func (cmd *getViewByNameReq) handleCommand(w *worker) {
+ v := w.views[cmd.name]
+ if v == nil {
+ cmd.c <- &getViewByNameResp{nil}
+ return
+ }
+ cmd.c <- &getViewByNameResp{v.view}
+}
+
+// registerViewReq is the command to register a view.
+type registerViewReq struct {
+ views []*View
+ err chan error
+}
+
+func (cmd *registerViewReq) handleCommand(w *worker) {
+ for _, v := range cmd.views {
+ if err := v.canonicalize(); err != nil {
+ cmd.err <- err
+ return
+ }
+ }
+ var errstr []string
+ for _, view := range cmd.views {
+ vi, err := w.tryRegisterView(view)
+ if err != nil {
+ errstr = append(errstr, fmt.Sprintf("%s: %v", view.Name, err))
+ continue
+ }
+ internal.SubscriptionReporter(view.Measure.Name())
+ vi.subscribe()
+ }
+ if len(errstr) > 0 {
+ cmd.err <- errors.New(strings.Join(errstr, "\n"))
+ } else {
+ cmd.err <- nil
+ }
+}
+
+// unregisterFromViewReq is the command to unregister to a view. Has no
+// impact on the data collection for client that are pulling data from the
+// library.
+type unregisterFromViewReq struct {
+ views []string
+ done chan struct{}
+}
+
+func (cmd *unregisterFromViewReq) handleCommand(w *worker) {
+ for _, name := range cmd.views {
+ vi, ok := w.views[name]
+ if !ok {
+ continue
+ }
+
+ // Report pending data for this view before removing it.
+ w.reportView(vi, time.Now())
+
+ vi.unsubscribe()
+ if !vi.isSubscribed() {
+ // this was the last subscription and view is not collecting anymore.
+ // The collected data can be cleared.
+ vi.clearRows()
+ }
+ w.unregisterView(name)
+ }
+ cmd.done <- struct{}{}
+}
+
+// retrieveDataReq is the command to retrieve data for a view.
+type retrieveDataReq struct {
+ now time.Time
+ v string
+ c chan *retrieveDataResp
+}
+
+type retrieveDataResp struct {
+ rows []*Row
+ err error
+}
+
+func (cmd *retrieveDataReq) handleCommand(w *worker) {
+ w.mu.Lock()
+ defer w.mu.Unlock()
+ vi, ok := w.views[cmd.v]
+ if !ok {
+ cmd.c <- &retrieveDataResp{
+ nil,
+ fmt.Errorf("cannot retrieve data; view %q is not registered", cmd.v),
+ }
+ return
+ }
+
+ if !vi.isSubscribed() {
+ cmd.c <- &retrieveDataResp{
+ nil,
+ fmt.Errorf("cannot retrieve data; view %q has no subscriptions or collection is not forcibly started", cmd.v),
+ }
+ return
+ }
+ cmd.c <- &retrieveDataResp{
+ vi.collectedRows(),
+ nil,
+ }
+}
+
+// recordReq is the command to record data related to multiple measures
+// at once.
+type recordReq struct {
+ tm *tag.Map
+ ms []stats.Measurement
+ attachments map[string]interface{}
+ t time.Time
+}
+
+func (cmd *recordReq) handleCommand(w *worker) {
+ w.mu.Lock()
+ defer w.mu.Unlock()
+ for _, m := range cmd.ms {
+ if (m == stats.Measurement{}) { // not registered
+ continue
+ }
+ ref := w.getMeasureRef(m.Measure().Name())
+ for v := range ref.views {
+ v.addSample(cmd.tm, m.Value(), cmd.attachments, time.Now())
+ }
+ }
+}
+
+// setReportingPeriodReq is the command to modify the duration between
+// reporting the collected data to the registered clients.
+type setReportingPeriodReq struct {
+ d time.Duration
+ c chan bool
+}
+
+func (cmd *setReportingPeriodReq) handleCommand(w *worker) {
+ w.timer.Stop()
+ if cmd.d <= 0 {
+ w.timer = time.NewTicker(defaultReportingDuration)
+ } else {
+ w.timer = time.NewTicker(cmd.d)
+ }
+ cmd.c <- true
+}
diff --git a/vendor/go.opencensus.io/tag/context.go b/vendor/go.opencensus.io/tag/context.go
new file mode 100644
index 0000000..b27d1b2
--- /dev/null
+++ b/vendor/go.opencensus.io/tag/context.go
@@ -0,0 +1,43 @@
+// Copyright 2017, OpenCensus Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package tag
+
+import (
+ "context"
+)
+
+// FromContext returns the tag map stored in the context.
+func FromContext(ctx context.Context) *Map {
+ // The returned tag map shouldn't be mutated.
+ ts := ctx.Value(mapCtxKey)
+ if ts == nil {
+ return nil
+ }
+ return ts.(*Map)
+}
+
+// NewContext creates a new context with the given tag map.
+// To propagate a tag map to downstream methods and downstream RPCs, add a tag map
+// to the current context. NewContext will return a copy of the current context,
+// and put the tag map into the returned one.
+// If there is already a tag map in the current context, it will be replaced with m.
+func NewContext(ctx context.Context, m *Map) context.Context {
+ return context.WithValue(ctx, mapCtxKey, m)
+}
+
+type ctxKey struct{}
+
+var mapCtxKey = ctxKey{}
diff --git a/vendor/go.opencensus.io/tag/doc.go b/vendor/go.opencensus.io/tag/doc.go
new file mode 100644
index 0000000..da16b74
--- /dev/null
+++ b/vendor/go.opencensus.io/tag/doc.go
@@ -0,0 +1,26 @@
+// Copyright 2017, OpenCensus Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+/*
+Package tag contains OpenCensus tags.
+
+Tags are key-value pairs. Tags provide additional cardinality to
+the OpenCensus instrumentation data.
+
+Tags can be propagated on the wire and in the same
+process via context.Context. Encode and Decode should be
+used to represent tags into their binary propagation form.
+*/
+package tag // import "go.opencensus.io/tag"
diff --git a/vendor/go.opencensus.io/tag/key.go b/vendor/go.opencensus.io/tag/key.go
new file mode 100644
index 0000000..71ec913
--- /dev/null
+++ b/vendor/go.opencensus.io/tag/key.go
@@ -0,0 +1,44 @@
+// Copyright 2017, OpenCensus Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package tag
+
+// Key represents a tag key.
+type Key struct {
+ name string
+}
+
+// NewKey creates or retrieves a string key identified by name.
+// Calling NewKey more than once with the same name returns the same key.
+func NewKey(name string) (Key, error) {
+ if !checkKeyName(name) {
+ return Key{}, errInvalidKeyName
+ }
+ return Key{name: name}, nil
+}
+
+// MustNewKey returns a key with the given name, and panics if name is an invalid key name.
+func MustNewKey(name string) Key {
+ k, err := NewKey(name)
+ if err != nil {
+ panic(err)
+ }
+ return k
+}
+
+// Name returns the name of the key.
+func (k Key) Name() string {
+ return k.name
+}
diff --git a/vendor/go.opencensus.io/tag/map.go b/vendor/go.opencensus.io/tag/map.go
new file mode 100644
index 0000000..0272ef8
--- /dev/null
+++ b/vendor/go.opencensus.io/tag/map.go
@@ -0,0 +1,229 @@
+// Copyright 2017, OpenCensus Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package tag
+
+import (
+ "bytes"
+ "context"
+ "fmt"
+ "sort"
+)
+
+// Tag is a key value pair that can be propagated on wire.
+type Tag struct {
+ Key Key
+ Value string
+}
+
+type tagContent struct {
+ value string
+ m metadatas
+}
+
+// Map is a map of tags. Use New to create a context containing
+// a new Map.
+type Map struct {
+ m map[Key]tagContent
+}
+
+// Value returns the value for the key if a value for the key exists.
+func (m *Map) Value(k Key) (string, bool) {
+ if m == nil {
+ return "", false
+ }
+ v, ok := m.m[k]
+ return v.value, ok
+}
+
+func (m *Map) String() string {
+ if m == nil {
+ return "nil"
+ }
+ keys := make([]Key, 0, len(m.m))
+ for k := range m.m {
+ keys = append(keys, k)
+ }
+ sort.Slice(keys, func(i, j int) bool { return keys[i].Name() < keys[j].Name() })
+
+ var buffer bytes.Buffer
+ buffer.WriteString("{ ")
+ for _, k := range keys {
+ buffer.WriteString(fmt.Sprintf("{%v %v}", k.name, m.m[k]))
+ }
+ buffer.WriteString(" }")
+ return buffer.String()
+}
+
+func (m *Map) insert(k Key, v string, md metadatas) {
+ if _, ok := m.m[k]; ok {
+ return
+ }
+ m.m[k] = tagContent{value: v, m: md}
+}
+
+func (m *Map) update(k Key, v string, md metadatas) {
+ if _, ok := m.m[k]; ok {
+ m.m[k] = tagContent{value: v, m: md}
+ }
+}
+
+func (m *Map) upsert(k Key, v string, md metadatas) {
+ m.m[k] = tagContent{value: v, m: md}
+}
+
+func (m *Map) delete(k Key) {
+ delete(m.m, k)
+}
+
+func newMap() *Map {
+ return &Map{m: make(map[Key]tagContent)}
+}
+
+// Mutator modifies a tag map.
+type Mutator interface {
+ Mutate(t *Map) (*Map, error)
+}
+
+// Insert returns a mutator that inserts a
+// value associated with k. If k already exists in the tag map,
+// mutator doesn't update the value.
+// Metadata applies metadata to the tag. It is optional.
+// Metadatas are applied in the order in which it is provided.
+// If more than one metadata updates the same attribute then
+// the update from the last metadata prevails.
+func Insert(k Key, v string, mds ...Metadata) Mutator {
+ return &mutator{
+ fn: func(m *Map) (*Map, error) {
+ if !checkValue(v) {
+ return nil, errInvalidValue
+ }
+ m.insert(k, v, createMetadatas(mds...))
+ return m, nil
+ },
+ }
+}
+
+// Update returns a mutator that updates the
+// value of the tag associated with k with v. If k doesn't
+// exists in the tag map, the mutator doesn't insert the value.
+// Metadata applies metadata to the tag. It is optional.
+// Metadatas are applied in the order in which it is provided.
+// If more than one metadata updates the same attribute then
+// the update from the last metadata prevails.
+func Update(k Key, v string, mds ...Metadata) Mutator {
+ return &mutator{
+ fn: func(m *Map) (*Map, error) {
+ if !checkValue(v) {
+ return nil, errInvalidValue
+ }
+ m.update(k, v, createMetadatas(mds...))
+ return m, nil
+ },
+ }
+}
+
+// Upsert returns a mutator that upserts the
+// value of the tag associated with k with v. It inserts the
+// value if k doesn't exist already. It mutates the value
+// if k already exists.
+// Metadata applies metadata to the tag. It is optional.
+// Metadatas are applied in the order in which it is provided.
+// If more than one metadata updates the same attribute then
+// the update from the last metadata prevails.
+func Upsert(k Key, v string, mds ...Metadata) Mutator {
+ return &mutator{
+ fn: func(m *Map) (*Map, error) {
+ if !checkValue(v) {
+ return nil, errInvalidValue
+ }
+ m.upsert(k, v, createMetadatas(mds...))
+ return m, nil
+ },
+ }
+}
+
+func createMetadatas(mds ...Metadata) metadatas {
+ var metas metadatas
+ if len(mds) > 0 {
+ for _, md := range mds {
+ if md != nil {
+ md(&metas)
+ }
+ }
+ } else {
+ WithTTL(TTLUnlimitedPropagation)(&metas)
+ }
+ return metas
+
+}
+
+// Delete returns a mutator that deletes
+// the value associated with k.
+func Delete(k Key) Mutator {
+ return &mutator{
+ fn: func(m *Map) (*Map, error) {
+ m.delete(k)
+ return m, nil
+ },
+ }
+}
+
+// New returns a new context that contains a tag map
+// originated from the incoming context and modified
+// with the provided mutators.
+func New(ctx context.Context, mutator ...Mutator) (context.Context, error) {
+ m := newMap()
+ orig := FromContext(ctx)
+ if orig != nil {
+ for k, v := range orig.m {
+ if !checkKeyName(k.Name()) {
+ return ctx, fmt.Errorf("key:%q: %v", k, errInvalidKeyName)
+ }
+ if !checkValue(v.value) {
+ return ctx, fmt.Errorf("key:%q value:%q: %v", k.Name(), v, errInvalidValue)
+ }
+ m.insert(k, v.value, v.m)
+ }
+ }
+ var err error
+ for _, mod := range mutator {
+ m, err = mod.Mutate(m)
+ if err != nil {
+ return ctx, err
+ }
+ }
+ return NewContext(ctx, m), nil
+}
+
+// Do is similar to pprof.Do: a convenience for installing the tags
+// from the context as Go profiler labels. This allows you to
+// correlated runtime profiling with stats.
+//
+// It converts the key/values from the given map to Go profiler labels
+// and calls pprof.Do.
+//
+// Do is going to do nothing if your Go version is below 1.9.
+func Do(ctx context.Context, f func(ctx context.Context)) {
+ do(ctx, f)
+}
+
+type mutator struct {
+ fn func(t *Map) (*Map, error)
+}
+
+func (m *mutator) Mutate(t *Map) (*Map, error) {
+ return m.fn(t)
+}
diff --git a/vendor/go.opencensus.io/tag/map_codec.go b/vendor/go.opencensus.io/tag/map_codec.go
new file mode 100644
index 0000000..c242e69
--- /dev/null
+++ b/vendor/go.opencensus.io/tag/map_codec.go
@@ -0,0 +1,239 @@
+// Copyright 2017, OpenCensus Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package tag
+
+import (
+ "encoding/binary"
+ "fmt"
+)
+
+// KeyType defines the types of keys allowed. Currently only keyTypeString is
+// supported.
+type keyType byte
+
+const (
+ keyTypeString keyType = iota
+ keyTypeInt64
+ keyTypeTrue
+ keyTypeFalse
+
+ tagsVersionID = byte(0)
+)
+
+type encoderGRPC struct {
+ buf []byte
+ writeIdx, readIdx int
+}
+
+// writeKeyString writes the fieldID '0' followed by the key string and value
+// string.
+func (eg *encoderGRPC) writeTagString(k, v string) {
+ eg.writeByte(byte(keyTypeString))
+ eg.writeStringWithVarintLen(k)
+ eg.writeStringWithVarintLen(v)
+}
+
+func (eg *encoderGRPC) writeTagUint64(k string, i uint64) {
+ eg.writeByte(byte(keyTypeInt64))
+ eg.writeStringWithVarintLen(k)
+ eg.writeUint64(i)
+}
+
+func (eg *encoderGRPC) writeTagTrue(k string) {
+ eg.writeByte(byte(keyTypeTrue))
+ eg.writeStringWithVarintLen(k)
+}
+
+func (eg *encoderGRPC) writeTagFalse(k string) {
+ eg.writeByte(byte(keyTypeFalse))
+ eg.writeStringWithVarintLen(k)
+}
+
+func (eg *encoderGRPC) writeBytesWithVarintLen(bytes []byte) {
+ length := len(bytes)
+
+ eg.growIfRequired(binary.MaxVarintLen64 + length)
+ eg.writeIdx += binary.PutUvarint(eg.buf[eg.writeIdx:], uint64(length))
+ copy(eg.buf[eg.writeIdx:], bytes)
+ eg.writeIdx += length
+}
+
+func (eg *encoderGRPC) writeStringWithVarintLen(s string) {
+ length := len(s)
+
+ eg.growIfRequired(binary.MaxVarintLen64 + length)
+ eg.writeIdx += binary.PutUvarint(eg.buf[eg.writeIdx:], uint64(length))
+ copy(eg.buf[eg.writeIdx:], s)
+ eg.writeIdx += length
+}
+
+func (eg *encoderGRPC) writeByte(v byte) {
+ eg.growIfRequired(1)
+ eg.buf[eg.writeIdx] = v
+ eg.writeIdx++
+}
+
+func (eg *encoderGRPC) writeUint32(i uint32) {
+ eg.growIfRequired(4)
+ binary.LittleEndian.PutUint32(eg.buf[eg.writeIdx:], i)
+ eg.writeIdx += 4
+}
+
+func (eg *encoderGRPC) writeUint64(i uint64) {
+ eg.growIfRequired(8)
+ binary.LittleEndian.PutUint64(eg.buf[eg.writeIdx:], i)
+ eg.writeIdx += 8
+}
+
+func (eg *encoderGRPC) readByte() byte {
+ b := eg.buf[eg.readIdx]
+ eg.readIdx++
+ return b
+}
+
+func (eg *encoderGRPC) readUint32() uint32 {
+ i := binary.LittleEndian.Uint32(eg.buf[eg.readIdx:])
+ eg.readIdx += 4
+ return i
+}
+
+func (eg *encoderGRPC) readUint64() uint64 {
+ i := binary.LittleEndian.Uint64(eg.buf[eg.readIdx:])
+ eg.readIdx += 8
+ return i
+}
+
+func (eg *encoderGRPC) readBytesWithVarintLen() ([]byte, error) {
+ if eg.readEnded() {
+ return nil, fmt.Errorf("unexpected end while readBytesWithVarintLen '%x' starting at idx '%v'", eg.buf, eg.readIdx)
+ }
+ length, valueStart := binary.Uvarint(eg.buf[eg.readIdx:])
+ if valueStart <= 0 {
+ return nil, fmt.Errorf("unexpected end while readBytesWithVarintLen '%x' starting at idx '%v'", eg.buf, eg.readIdx)
+ }
+
+ valueStart += eg.readIdx
+ valueEnd := valueStart + int(length)
+ if valueEnd > len(eg.buf) {
+ return nil, fmt.Errorf("malformed encoding: length:%v, upper:%v, maxLength:%v", length, valueEnd, len(eg.buf))
+ }
+
+ eg.readIdx = valueEnd
+ return eg.buf[valueStart:valueEnd], nil
+}
+
+func (eg *encoderGRPC) readStringWithVarintLen() (string, error) {
+ bytes, err := eg.readBytesWithVarintLen()
+ if err != nil {
+ return "", err
+ }
+ return string(bytes), nil
+}
+
+func (eg *encoderGRPC) growIfRequired(expected int) {
+ if len(eg.buf)-eg.writeIdx < expected {
+ tmp := make([]byte, 2*(len(eg.buf)+1)+expected)
+ copy(tmp, eg.buf)
+ eg.buf = tmp
+ }
+}
+
+func (eg *encoderGRPC) readEnded() bool {
+ return eg.readIdx >= len(eg.buf)
+}
+
+func (eg *encoderGRPC) bytes() []byte {
+ return eg.buf[:eg.writeIdx]
+}
+
+// Encode encodes the tag map into a []byte. It is useful to propagate
+// the tag maps on wire in binary format.
+func Encode(m *Map) []byte {
+ if m == nil {
+ return nil
+ }
+ eg := &encoderGRPC{
+ buf: make([]byte, len(m.m)),
+ }
+ eg.writeByte(tagsVersionID)
+ for k, v := range m.m {
+ if v.m.ttl.ttl == valueTTLUnlimitedPropagation {
+ eg.writeByte(byte(keyTypeString))
+ eg.writeStringWithVarintLen(k.name)
+ eg.writeBytesWithVarintLen([]byte(v.value))
+ }
+ }
+ return eg.bytes()
+}
+
+// Decode decodes the given []byte into a tag map.
+func Decode(bytes []byte) (*Map, error) {
+ ts := newMap()
+ err := DecodeEach(bytes, ts.upsert)
+ if err != nil {
+ // no partial failures
+ return nil, err
+ }
+ return ts, nil
+}
+
+// DecodeEach decodes the given serialized tag map, calling handler for each
+// tag key and value decoded.
+func DecodeEach(bytes []byte, fn func(key Key, val string, md metadatas)) error {
+ eg := &encoderGRPC{
+ buf: bytes,
+ }
+ if len(eg.buf) == 0 {
+ return nil
+ }
+
+ version := eg.readByte()
+ if version > tagsVersionID {
+ return fmt.Errorf("cannot decode: unsupported version: %q; supports only up to: %q", version, tagsVersionID)
+ }
+
+ for !eg.readEnded() {
+ typ := keyType(eg.readByte())
+
+ if typ != keyTypeString {
+ return fmt.Errorf("cannot decode: invalid key type: %q", typ)
+ }
+
+ k, err := eg.readBytesWithVarintLen()
+ if err != nil {
+ return err
+ }
+
+ v, err := eg.readBytesWithVarintLen()
+ if err != nil {
+ return err
+ }
+
+ key, err := NewKey(string(k))
+ if err != nil {
+ return err
+ }
+ val := string(v)
+ if !checkValue(val) {
+ return errInvalidValue
+ }
+ fn(key, val, createMetadatas(WithTTL(TTLUnlimitedPropagation)))
+ if err != nil {
+ return err
+ }
+ }
+ return nil
+}
diff --git a/vendor/go.opencensus.io/tag/metadata.go b/vendor/go.opencensus.io/tag/metadata.go
new file mode 100644
index 0000000..6571a58
--- /dev/null
+++ b/vendor/go.opencensus.io/tag/metadata.go
@@ -0,0 +1,52 @@
+// Copyright 2019, OpenCensus Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package tag
+
+const (
+ // valueTTLNoPropagation prevents tag from propagating.
+ valueTTLNoPropagation = 0
+
+ // valueTTLUnlimitedPropagation allows tag to propagate without any limits on number of hops.
+ valueTTLUnlimitedPropagation = -1
+)
+
+// TTL is metadata that specifies number of hops a tag can propagate.
+// Details about TTL metadata is specified at https://github.com/census-instrumentation/opencensus-specs/blob/master/tags/TagMap.md#tagmetadata
+type TTL struct {
+ ttl int
+}
+
+var (
+ // TTLUnlimitedPropagation is TTL metadata that allows tag to propagate without any limits on number of hops.
+ TTLUnlimitedPropagation = TTL{ttl: valueTTLUnlimitedPropagation}
+
+ // TTLNoPropagation is TTL metadata that prevents tag from propagating.
+ TTLNoPropagation = TTL{ttl: valueTTLNoPropagation}
+)
+
+type metadatas struct {
+ ttl TTL
+}
+
+// Metadata applies metadatas specified by the function.
+type Metadata func(*metadatas)
+
+// WithTTL applies metadata with provided ttl.
+func WithTTL(ttl TTL) Metadata {
+ return func(m *metadatas) {
+ m.ttl = ttl
+ }
+}
diff --git a/vendor/go.opencensus.io/tag/profile_19.go b/vendor/go.opencensus.io/tag/profile_19.go
new file mode 100644
index 0000000..b34d95e
--- /dev/null
+++ b/vendor/go.opencensus.io/tag/profile_19.go
@@ -0,0 +1,31 @@
+// Copyright 2018, OpenCensus Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// +build go1.9
+
+package tag
+
+import (
+ "context"
+ "runtime/pprof"
+)
+
+func do(ctx context.Context, f func(ctx context.Context)) {
+ m := FromContext(ctx)
+ keyvals := make([]string, 0, 2*len(m.m))
+ for k, v := range m.m {
+ keyvals = append(keyvals, k.Name(), v.value)
+ }
+ pprof.Do(ctx, pprof.Labels(keyvals...), f)
+}
diff --git a/vendor/go.opencensus.io/tag/profile_not19.go b/vendor/go.opencensus.io/tag/profile_not19.go
new file mode 100644
index 0000000..83adbce
--- /dev/null
+++ b/vendor/go.opencensus.io/tag/profile_not19.go
@@ -0,0 +1,23 @@
+// Copyright 2018, OpenCensus Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// +build !go1.9
+
+package tag
+
+import "context"
+
+func do(ctx context.Context, f func(ctx context.Context)) {
+ f(ctx)
+}
diff --git a/vendor/go.opencensus.io/tag/validate.go b/vendor/go.opencensus.io/tag/validate.go
new file mode 100644
index 0000000..0939fc6
--- /dev/null
+++ b/vendor/go.opencensus.io/tag/validate.go
@@ -0,0 +1,56 @@
+// Copyright 2017, OpenCensus Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package tag
+
+import "errors"
+
+const (
+ maxKeyLength = 255
+
+ // valid are restricted to US-ASCII subset (range 0x20 (' ') to 0x7e ('~')).
+ validKeyValueMin = 32
+ validKeyValueMax = 126
+)
+
+var (
+ errInvalidKeyName = errors.New("invalid key name: only ASCII characters accepted; max length must be 255 characters")
+ errInvalidValue = errors.New("invalid value: only ASCII characters accepted; max length must be 255 characters")
+)
+
+func checkKeyName(name string) bool {
+ if len(name) == 0 {
+ return false
+ }
+ if len(name) > maxKeyLength {
+ return false
+ }
+ return isASCII(name)
+}
+
+func isASCII(s string) bool {
+ for _, c := range s {
+ if (c < validKeyValueMin) || (c > validKeyValueMax) {
+ return false
+ }
+ }
+ return true
+}
+
+func checkValue(v string) bool {
+ if len(v) > maxKeyLength {
+ return false
+ }
+ return isASCII(v)
+}
diff --git a/vendor/go.opencensus.io/trace/basetypes.go b/vendor/go.opencensus.io/trace/basetypes.go
new file mode 100644
index 0000000..0c54492
--- /dev/null
+++ b/vendor/go.opencensus.io/trace/basetypes.go
@@ -0,0 +1,119 @@
+// Copyright 2017, OpenCensus Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package trace
+
+import (
+ "fmt"
+ "time"
+)
+
+type (
+ // TraceID is a 16-byte identifier for a set of spans.
+ TraceID [16]byte
+
+ // SpanID is an 8-byte identifier for a single span.
+ SpanID [8]byte
+)
+
+func (t TraceID) String() string {
+ return fmt.Sprintf("%02x", t[:])
+}
+
+func (s SpanID) String() string {
+ return fmt.Sprintf("%02x", s[:])
+}
+
+// Annotation represents a text annotation with a set of attributes and a timestamp.
+type Annotation struct {
+ Time time.Time
+ Message string
+ Attributes map[string]interface{}
+}
+
+// Attribute represents a key-value pair on a span, link or annotation.
+// Construct with one of: BoolAttribute, Int64Attribute, or StringAttribute.
+type Attribute struct {
+ key string
+ value interface{}
+}
+
+// BoolAttribute returns a bool-valued attribute.
+func BoolAttribute(key string, value bool) Attribute {
+ return Attribute{key: key, value: value}
+}
+
+// Int64Attribute returns an int64-valued attribute.
+func Int64Attribute(key string, value int64) Attribute {
+ return Attribute{key: key, value: value}
+}
+
+// Float64Attribute returns a float64-valued attribute.
+func Float64Attribute(key string, value float64) Attribute {
+ return Attribute{key: key, value: value}
+}
+
+// StringAttribute returns a string-valued attribute.
+func StringAttribute(key string, value string) Attribute {
+ return Attribute{key: key, value: value}
+}
+
+// LinkType specifies the relationship between the span that had the link
+// added, and the linked span.
+type LinkType int32
+
+// LinkType values.
+const (
+ LinkTypeUnspecified LinkType = iota // The relationship of the two spans is unknown.
+ LinkTypeChild // The linked span is a child of the current span.
+ LinkTypeParent // The linked span is the parent of the current span.
+)
+
+// Link represents a reference from one span to another span.
+type Link struct {
+ TraceID TraceID
+ SpanID SpanID
+ Type LinkType
+ // Attributes is a set of attributes on the link.
+ Attributes map[string]interface{}
+}
+
+// MessageEventType specifies the type of message event.
+type MessageEventType int32
+
+// MessageEventType values.
+const (
+ MessageEventTypeUnspecified MessageEventType = iota // Unknown event type.
+ MessageEventTypeSent // Indicates a sent RPC message.
+ MessageEventTypeRecv // Indicates a received RPC message.
+)
+
+// MessageEvent represents an event describing a message sent or received on the network.
+type MessageEvent struct {
+ Time time.Time
+ EventType MessageEventType
+ MessageID int64
+ UncompressedByteSize int64
+ CompressedByteSize int64
+}
+
+// Status is the status of a Span.
+type Status struct {
+ // Code is a status code. Zero indicates success.
+ //
+ // If Code will be propagated to Google APIs, it ideally should be a value from
+ // https://github.com/googleapis/googleapis/blob/master/google/rpc/code.proto .
+ Code int32
+ Message string
+}
diff --git a/vendor/go.opencensus.io/trace/config.go b/vendor/go.opencensus.io/trace/config.go
new file mode 100644
index 0000000..775f827
--- /dev/null
+++ b/vendor/go.opencensus.io/trace/config.go
@@ -0,0 +1,86 @@
+// Copyright 2018, OpenCensus Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package trace
+
+import (
+ "sync"
+
+ "go.opencensus.io/trace/internal"
+)
+
+// Config represents the global tracing configuration.
+type Config struct {
+ // DefaultSampler is the default sampler used when creating new spans.
+ DefaultSampler Sampler
+
+ // IDGenerator is for internal use only.
+ IDGenerator internal.IDGenerator
+
+ // MaxAnnotationEventsPerSpan is max number of annotation events per span
+ MaxAnnotationEventsPerSpan int
+
+ // MaxMessageEventsPerSpan is max number of message events per span
+ MaxMessageEventsPerSpan int
+
+ // MaxAnnotationEventsPerSpan is max number of attributes per span
+ MaxAttributesPerSpan int
+
+ // MaxLinksPerSpan is max number of links per span
+ MaxLinksPerSpan int
+}
+
+var configWriteMu sync.Mutex
+
+const (
+ // DefaultMaxAnnotationEventsPerSpan is default max number of annotation events per span
+ DefaultMaxAnnotationEventsPerSpan = 32
+
+ // DefaultMaxMessageEventsPerSpan is default max number of message events per span
+ DefaultMaxMessageEventsPerSpan = 128
+
+ // DefaultMaxAttributesPerSpan is default max number of attributes per span
+ DefaultMaxAttributesPerSpan = 32
+
+ // DefaultMaxLinksPerSpan is default max number of links per span
+ DefaultMaxLinksPerSpan = 32
+)
+
+// ApplyConfig applies changes to the global tracing configuration.
+//
+// Fields not provided in the given config are going to be preserved.
+func ApplyConfig(cfg Config) {
+ configWriteMu.Lock()
+ defer configWriteMu.Unlock()
+ c := *config.Load().(*Config)
+ if cfg.DefaultSampler != nil {
+ c.DefaultSampler = cfg.DefaultSampler
+ }
+ if cfg.IDGenerator != nil {
+ c.IDGenerator = cfg.IDGenerator
+ }
+ if cfg.MaxAnnotationEventsPerSpan > 0 {
+ c.MaxAnnotationEventsPerSpan = cfg.MaxAnnotationEventsPerSpan
+ }
+ if cfg.MaxMessageEventsPerSpan > 0 {
+ c.MaxMessageEventsPerSpan = cfg.MaxMessageEventsPerSpan
+ }
+ if cfg.MaxAttributesPerSpan > 0 {
+ c.MaxAttributesPerSpan = cfg.MaxAttributesPerSpan
+ }
+ if cfg.MaxLinksPerSpan > 0 {
+ c.MaxLinksPerSpan = cfg.MaxLinksPerSpan
+ }
+ config.Store(&c)
+}
diff --git a/vendor/go.opencensus.io/trace/doc.go b/vendor/go.opencensus.io/trace/doc.go
new file mode 100644
index 0000000..04b1ee4
--- /dev/null
+++ b/vendor/go.opencensus.io/trace/doc.go
@@ -0,0 +1,53 @@
+// Copyright 2017, OpenCensus Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/*
+Package trace contains support for OpenCensus distributed tracing.
+
+The following assumes a basic familiarity with OpenCensus concepts.
+See http://opencensus.io
+
+
+Exporting Traces
+
+To export collected tracing data, register at least one exporter. You can use
+one of the provided exporters or write your own.
+
+ trace.RegisterExporter(exporter)
+
+By default, traces will be sampled relatively rarely. To change the sampling
+frequency for your entire program, call ApplyConfig. Use a ProbabilitySampler
+to sample a subset of traces, or use AlwaysSample to collect a trace on every run:
+
+ trace.ApplyConfig(trace.Config{DefaultSampler: trace.AlwaysSample()})
+
+Be careful about using trace.AlwaysSample in a production application with
+significant traffic: a new trace will be started and exported for every request.
+
+Adding Spans to a Trace
+
+A trace consists of a tree of spans. In Go, the current span is carried in a
+context.Context.
+
+It is common to want to capture all the activity of a function call in a span. For
+this to work, the function must take a context.Context as a parameter. Add these two
+lines to the top of the function:
+
+ ctx, span := trace.StartSpan(ctx, "example.com/Run")
+ defer span.End()
+
+StartSpan will create a new top-level span if the context
+doesn't contain another span, otherwise it will create a child span.
+*/
+package trace // import "go.opencensus.io/trace"
diff --git a/vendor/go.opencensus.io/trace/evictedqueue.go b/vendor/go.opencensus.io/trace/evictedqueue.go
new file mode 100644
index 0000000..ffc264f
--- /dev/null
+++ b/vendor/go.opencensus.io/trace/evictedqueue.go
@@ -0,0 +1,38 @@
+// Copyright 2019, OpenCensus Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package trace
+
+type evictedQueue struct {
+ queue []interface{}
+ capacity int
+ droppedCount int
+}
+
+func newEvictedQueue(capacity int) *evictedQueue {
+ eq := &evictedQueue{
+ capacity: capacity,
+ queue: make([]interface{}, 0),
+ }
+
+ return eq
+}
+
+func (eq *evictedQueue) add(value interface{}) {
+ if len(eq.queue) == eq.capacity {
+ eq.queue = eq.queue[1:]
+ eq.droppedCount++
+ }
+ eq.queue = append(eq.queue, value)
+}
diff --git a/vendor/go.opencensus.io/trace/export.go b/vendor/go.opencensus.io/trace/export.go
new file mode 100644
index 0000000..e0d9a4b
--- /dev/null
+++ b/vendor/go.opencensus.io/trace/export.go
@@ -0,0 +1,97 @@
+// Copyright 2017, OpenCensus Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package trace
+
+import (
+ "sync"
+ "sync/atomic"
+ "time"
+)
+
+// Exporter is a type for functions that receive sampled trace spans.
+//
+// The ExportSpan method should be safe for concurrent use and should return
+// quickly; if an Exporter takes a significant amount of time to process a
+// SpanData, that work should be done on another goroutine.
+//
+// The SpanData should not be modified, but a pointer to it can be kept.
+type Exporter interface {
+ ExportSpan(s *SpanData)
+}
+
+type exportersMap map[Exporter]struct{}
+
+var (
+ exporterMu sync.Mutex
+ exporters atomic.Value
+)
+
+// RegisterExporter adds to the list of Exporters that will receive sampled
+// trace spans.
+//
+// Binaries can register exporters, libraries shouldn't register exporters.
+func RegisterExporter(e Exporter) {
+ exporterMu.Lock()
+ new := make(exportersMap)
+ if old, ok := exporters.Load().(exportersMap); ok {
+ for k, v := range old {
+ new[k] = v
+ }
+ }
+ new[e] = struct{}{}
+ exporters.Store(new)
+ exporterMu.Unlock()
+}
+
+// UnregisterExporter removes from the list of Exporters the Exporter that was
+// registered with the given name.
+func UnregisterExporter(e Exporter) {
+ exporterMu.Lock()
+ new := make(exportersMap)
+ if old, ok := exporters.Load().(exportersMap); ok {
+ for k, v := range old {
+ new[k] = v
+ }
+ }
+ delete(new, e)
+ exporters.Store(new)
+ exporterMu.Unlock()
+}
+
+// SpanData contains all the information collected by a Span.
+type SpanData struct {
+ SpanContext
+ ParentSpanID SpanID
+ SpanKind int
+ Name string
+ StartTime time.Time
+ // The wall clock time of EndTime will be adjusted to always be offset
+ // from StartTime by the duration of the span.
+ EndTime time.Time
+ // The values of Attributes each have type string, bool, or int64.
+ Attributes map[string]interface{}
+ Annotations []Annotation
+ MessageEvents []MessageEvent
+ Status
+ Links []Link
+ HasRemoteParent bool
+ DroppedAttributeCount int
+ DroppedAnnotationCount int
+ DroppedMessageEventCount int
+ DroppedLinkCount int
+
+ // ChildSpanCount holds the number of child span created for this span.
+ ChildSpanCount int
+}
diff --git a/vendor/go.opencensus.io/trace/internal/internal.go b/vendor/go.opencensus.io/trace/internal/internal.go
new file mode 100644
index 0000000..7e808d8
--- /dev/null
+++ b/vendor/go.opencensus.io/trace/internal/internal.go
@@ -0,0 +1,22 @@
+// Copyright 2018, OpenCensus Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Package internal provides trace internals.
+package internal
+
+// IDGenerator allows custom generators for TraceId and SpanId.
+type IDGenerator interface {
+ NewTraceID() [16]byte
+ NewSpanID() [8]byte
+}
diff --git a/vendor/go.opencensus.io/trace/lrumap.go b/vendor/go.opencensus.io/trace/lrumap.go
new file mode 100644
index 0000000..dc7a295
--- /dev/null
+++ b/vendor/go.opencensus.io/trace/lrumap.go
@@ -0,0 +1,61 @@
+// Copyright 2019, OpenCensus Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package trace
+
+import (
+ "github.com/golang/groupcache/lru"
+)
+
+// A simple lru.Cache wrapper that tracks the keys of the current contents and
+// the cumulative number of evicted items.
+type lruMap struct {
+ cacheKeys map[lru.Key]bool
+ cache *lru.Cache
+ droppedCount int
+}
+
+func newLruMap(size int) *lruMap {
+ lm := &lruMap{
+ cacheKeys: make(map[lru.Key]bool),
+ cache: lru.New(size),
+ droppedCount: 0,
+ }
+ lm.cache.OnEvicted = func(key lru.Key, value interface{}) {
+ delete(lm.cacheKeys, key)
+ lm.droppedCount++
+ }
+ return lm
+}
+
+func (lm lruMap) len() int {
+ return lm.cache.Len()
+}
+
+func (lm lruMap) keys() []interface{} {
+ keys := []interface{}{}
+ for k := range lm.cacheKeys {
+ keys = append(keys, k)
+ }
+ return keys
+}
+
+func (lm *lruMap) add(key, value interface{}) {
+ lm.cacheKeys[lru.Key(key)] = true
+ lm.cache.Add(lru.Key(key), value)
+}
+
+func (lm *lruMap) get(key interface{}) (interface{}, bool) {
+ return lm.cache.Get(key)
+}
diff --git a/vendor/go.opencensus.io/trace/sampling.go b/vendor/go.opencensus.io/trace/sampling.go
new file mode 100644
index 0000000..71c10f9
--- /dev/null
+++ b/vendor/go.opencensus.io/trace/sampling.go
@@ -0,0 +1,75 @@
+// Copyright 2017, OpenCensus Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package trace
+
+import (
+ "encoding/binary"
+)
+
+const defaultSamplingProbability = 1e-4
+
+// Sampler decides whether a trace should be sampled and exported.
+type Sampler func(SamplingParameters) SamplingDecision
+
+// SamplingParameters contains the values passed to a Sampler.
+type SamplingParameters struct {
+ ParentContext SpanContext
+ TraceID TraceID
+ SpanID SpanID
+ Name string
+ HasRemoteParent bool
+}
+
+// SamplingDecision is the value returned by a Sampler.
+type SamplingDecision struct {
+ Sample bool
+}
+
+// ProbabilitySampler returns a Sampler that samples a given fraction of traces.
+//
+// It also samples spans whose parents are sampled.
+func ProbabilitySampler(fraction float64) Sampler {
+ if !(fraction >= 0) {
+ fraction = 0
+ } else if fraction >= 1 {
+ return AlwaysSample()
+ }
+
+ traceIDUpperBound := uint64(fraction * (1 << 63))
+ return Sampler(func(p SamplingParameters) SamplingDecision {
+ if p.ParentContext.IsSampled() {
+ return SamplingDecision{Sample: true}
+ }
+ x := binary.BigEndian.Uint64(p.TraceID[0:8]) >> 1
+ return SamplingDecision{Sample: x < traceIDUpperBound}
+ })
+}
+
+// AlwaysSample returns a Sampler that samples every trace.
+// Be careful about using this sampler in a production application with
+// significant traffic: a new trace will be started and exported for every
+// request.
+func AlwaysSample() Sampler {
+ return func(p SamplingParameters) SamplingDecision {
+ return SamplingDecision{Sample: true}
+ }
+}
+
+// NeverSample returns a Sampler that samples no traces.
+func NeverSample() Sampler {
+ return func(p SamplingParameters) SamplingDecision {
+ return SamplingDecision{Sample: false}
+ }
+}
diff --git a/vendor/go.opencensus.io/trace/spanbucket.go b/vendor/go.opencensus.io/trace/spanbucket.go
new file mode 100644
index 0000000..fbabad3
--- /dev/null
+++ b/vendor/go.opencensus.io/trace/spanbucket.go
@@ -0,0 +1,130 @@
+// Copyright 2017, OpenCensus Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package trace
+
+import (
+ "time"
+)
+
+// samplePeriod is the minimum time between accepting spans in a single bucket.
+const samplePeriod = time.Second
+
+// defaultLatencies contains the default latency bucket bounds.
+// TODO: consider defaults, make configurable
+var defaultLatencies = [...]time.Duration{
+ 10 * time.Microsecond,
+ 100 * time.Microsecond,
+ time.Millisecond,
+ 10 * time.Millisecond,
+ 100 * time.Millisecond,
+ time.Second,
+ 10 * time.Second,
+ time.Minute,
+}
+
+// bucket is a container for a set of spans for a particular error code or latency range.
+type bucket struct {
+ nextTime time.Time // next time we can accept a span
+ buffer []*SpanData // circular buffer of spans
+ nextIndex int // location next SpanData should be placed in buffer
+ overflow bool // whether the circular buffer has wrapped around
+}
+
+func makeBucket(bufferSize int) bucket {
+ return bucket{
+ buffer: make([]*SpanData, bufferSize),
+ }
+}
+
+// add adds a span to the bucket, if nextTime has been reached.
+func (b *bucket) add(s *SpanData) {
+ if s.EndTime.Before(b.nextTime) {
+ return
+ }
+ if len(b.buffer) == 0 {
+ return
+ }
+ b.nextTime = s.EndTime.Add(samplePeriod)
+ b.buffer[b.nextIndex] = s
+ b.nextIndex++
+ if b.nextIndex == len(b.buffer) {
+ b.nextIndex = 0
+ b.overflow = true
+ }
+}
+
+// size returns the number of spans in the bucket.
+func (b *bucket) size() int {
+ if b.overflow {
+ return len(b.buffer)
+ }
+ return b.nextIndex
+}
+
+// span returns the ith span in the bucket.
+func (b *bucket) span(i int) *SpanData {
+ if !b.overflow {
+ return b.buffer[i]
+ }
+ if i < len(b.buffer)-b.nextIndex {
+ return b.buffer[b.nextIndex+i]
+ }
+ return b.buffer[b.nextIndex+i-len(b.buffer)]
+}
+
+// resize changes the size of the bucket to n, keeping up to n existing spans.
+func (b *bucket) resize(n int) {
+ cur := b.size()
+ newBuffer := make([]*SpanData, n)
+ if cur < n {
+ for i := 0; i < cur; i++ {
+ newBuffer[i] = b.span(i)
+ }
+ b.buffer = newBuffer
+ b.nextIndex = cur
+ b.overflow = false
+ return
+ }
+ for i := 0; i < n; i++ {
+ newBuffer[i] = b.span(i + cur - n)
+ }
+ b.buffer = newBuffer
+ b.nextIndex = 0
+ b.overflow = true
+}
+
+// latencyBucket returns the appropriate bucket number for a given latency.
+func latencyBucket(latency time.Duration) int {
+ i := 0
+ for i < len(defaultLatencies) && latency >= defaultLatencies[i] {
+ i++
+ }
+ return i
+}
+
+// latencyBucketBounds returns the lower and upper bounds for a latency bucket
+// number.
+//
+// The lower bound is inclusive, the upper bound is exclusive (except for the
+// last bucket.)
+func latencyBucketBounds(index int) (lower time.Duration, upper time.Duration) {
+ if index == 0 {
+ return 0, defaultLatencies[index]
+ }
+ if index == len(defaultLatencies) {
+ return defaultLatencies[index-1], 1<<63 - 1
+ }
+ return defaultLatencies[index-1], defaultLatencies[index]
+}
diff --git a/vendor/go.opencensus.io/trace/spanstore.go b/vendor/go.opencensus.io/trace/spanstore.go
new file mode 100644
index 0000000..c442d99
--- /dev/null
+++ b/vendor/go.opencensus.io/trace/spanstore.go
@@ -0,0 +1,306 @@
+// Copyright 2017, OpenCensus Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package trace
+
+import (
+ "sync"
+ "time"
+
+ "go.opencensus.io/internal"
+)
+
+const (
+ maxBucketSize = 100000
+ defaultBucketSize = 10
+)
+
+var (
+ ssmu sync.RWMutex // protects spanStores
+ spanStores = make(map[string]*spanStore)
+)
+
+// This exists purely to avoid exposing internal methods used by z-Pages externally.
+type internalOnly struct{}
+
+func init() {
+ //TODO(#412): remove
+ internal.Trace = &internalOnly{}
+}
+
+// ReportActiveSpans returns the active spans for the given name.
+func (i internalOnly) ReportActiveSpans(name string) []*SpanData {
+ s := spanStoreForName(name)
+ if s == nil {
+ return nil
+ }
+ var out []*SpanData
+ s.mu.Lock()
+ defer s.mu.Unlock()
+ for span := range s.active {
+ out = append(out, span.makeSpanData())
+ }
+ return out
+}
+
+// ReportSpansByError returns a sample of error spans.
+//
+// If code is nonzero, only spans with that status code are returned.
+func (i internalOnly) ReportSpansByError(name string, code int32) []*SpanData {
+ s := spanStoreForName(name)
+ if s == nil {
+ return nil
+ }
+ var out []*SpanData
+ s.mu.Lock()
+ defer s.mu.Unlock()
+ if code != 0 {
+ if b, ok := s.errors[code]; ok {
+ for _, sd := range b.buffer {
+ if sd == nil {
+ break
+ }
+ out = append(out, sd)
+ }
+ }
+ } else {
+ for _, b := range s.errors {
+ for _, sd := range b.buffer {
+ if sd == nil {
+ break
+ }
+ out = append(out, sd)
+ }
+ }
+ }
+ return out
+}
+
+// ConfigureBucketSizes sets the number of spans to keep per latency and error
+// bucket for different span names.
+func (i internalOnly) ConfigureBucketSizes(bcs []internal.BucketConfiguration) {
+ for _, bc := range bcs {
+ latencyBucketSize := bc.MaxRequestsSucceeded
+ if latencyBucketSize < 0 {
+ latencyBucketSize = 0
+ }
+ if latencyBucketSize > maxBucketSize {
+ latencyBucketSize = maxBucketSize
+ }
+ errorBucketSize := bc.MaxRequestsErrors
+ if errorBucketSize < 0 {
+ errorBucketSize = 0
+ }
+ if errorBucketSize > maxBucketSize {
+ errorBucketSize = maxBucketSize
+ }
+ spanStoreSetSize(bc.Name, latencyBucketSize, errorBucketSize)
+ }
+}
+
+// ReportSpansPerMethod returns a summary of what spans are being stored for each span name.
+func (i internalOnly) ReportSpansPerMethod() map[string]internal.PerMethodSummary {
+ out := make(map[string]internal.PerMethodSummary)
+ ssmu.RLock()
+ defer ssmu.RUnlock()
+ for name, s := range spanStores {
+ s.mu.Lock()
+ p := internal.PerMethodSummary{
+ Active: len(s.active),
+ }
+ for code, b := range s.errors {
+ p.ErrorBuckets = append(p.ErrorBuckets, internal.ErrorBucketSummary{
+ ErrorCode: code,
+ Size: b.size(),
+ })
+ }
+ for i, b := range s.latency {
+ min, max := latencyBucketBounds(i)
+ p.LatencyBuckets = append(p.LatencyBuckets, internal.LatencyBucketSummary{
+ MinLatency: min,
+ MaxLatency: max,
+ Size: b.size(),
+ })
+ }
+ s.mu.Unlock()
+ out[name] = p
+ }
+ return out
+}
+
+// ReportSpansByLatency returns a sample of successful spans.
+//
+// minLatency is the minimum latency of spans to be returned.
+// maxLatency, if nonzero, is the maximum latency of spans to be returned.
+func (i internalOnly) ReportSpansByLatency(name string, minLatency, maxLatency time.Duration) []*SpanData {
+ s := spanStoreForName(name)
+ if s == nil {
+ return nil
+ }
+ var out []*SpanData
+ s.mu.Lock()
+ defer s.mu.Unlock()
+ for i, b := range s.latency {
+ min, max := latencyBucketBounds(i)
+ if i+1 != len(s.latency) && max <= minLatency {
+ continue
+ }
+ if maxLatency != 0 && maxLatency < min {
+ continue
+ }
+ for _, sd := range b.buffer {
+ if sd == nil {
+ break
+ }
+ if minLatency != 0 || maxLatency != 0 {
+ d := sd.EndTime.Sub(sd.StartTime)
+ if d < minLatency {
+ continue
+ }
+ if maxLatency != 0 && d > maxLatency {
+ continue
+ }
+ }
+ out = append(out, sd)
+ }
+ }
+ return out
+}
+
+// spanStore keeps track of spans stored for a particular span name.
+//
+// It contains all active spans; a sample of spans for failed requests,
+// categorized by error code; and a sample of spans for successful requests,
+// bucketed by latency.
+type spanStore struct {
+ mu sync.Mutex // protects everything below.
+ active map[*Span]struct{}
+ errors map[int32]*bucket
+ latency []bucket
+ maxSpansPerErrorBucket int
+}
+
+// newSpanStore creates a span store.
+func newSpanStore(name string, latencyBucketSize int, errorBucketSize int) *spanStore {
+ s := &spanStore{
+ active: make(map[*Span]struct{}),
+ latency: make([]bucket, len(defaultLatencies)+1),
+ maxSpansPerErrorBucket: errorBucketSize,
+ }
+ for i := range s.latency {
+ s.latency[i] = makeBucket(latencyBucketSize)
+ }
+ return s
+}
+
+// spanStoreForName returns the spanStore for the given name.
+//
+// It returns nil if it doesn't exist.
+func spanStoreForName(name string) *spanStore {
+ var s *spanStore
+ ssmu.RLock()
+ s, _ = spanStores[name]
+ ssmu.RUnlock()
+ return s
+}
+
+// spanStoreForNameCreateIfNew returns the spanStore for the given name.
+//
+// It creates it if it didn't exist.
+func spanStoreForNameCreateIfNew(name string) *spanStore {
+ ssmu.RLock()
+ s, ok := spanStores[name]
+ ssmu.RUnlock()
+ if ok {
+ return s
+ }
+ ssmu.Lock()
+ defer ssmu.Unlock()
+ s, ok = spanStores[name]
+ if ok {
+ return s
+ }
+ s = newSpanStore(name, defaultBucketSize, defaultBucketSize)
+ spanStores[name] = s
+ return s
+}
+
+// spanStoreSetSize resizes the spanStore for the given name.
+//
+// It creates it if it didn't exist.
+func spanStoreSetSize(name string, latencyBucketSize int, errorBucketSize int) {
+ ssmu.RLock()
+ s, ok := spanStores[name]
+ ssmu.RUnlock()
+ if ok {
+ s.resize(latencyBucketSize, errorBucketSize)
+ return
+ }
+ ssmu.Lock()
+ defer ssmu.Unlock()
+ s, ok = spanStores[name]
+ if ok {
+ s.resize(latencyBucketSize, errorBucketSize)
+ return
+ }
+ s = newSpanStore(name, latencyBucketSize, errorBucketSize)
+ spanStores[name] = s
+}
+
+func (s *spanStore) resize(latencyBucketSize int, errorBucketSize int) {
+ s.mu.Lock()
+ for i := range s.latency {
+ s.latency[i].resize(latencyBucketSize)
+ }
+ for _, b := range s.errors {
+ b.resize(errorBucketSize)
+ }
+ s.maxSpansPerErrorBucket = errorBucketSize
+ s.mu.Unlock()
+}
+
+// add adds a span to the active bucket of the spanStore.
+func (s *spanStore) add(span *Span) {
+ s.mu.Lock()
+ s.active[span] = struct{}{}
+ s.mu.Unlock()
+}
+
+// finished removes a span from the active set, and adds a corresponding
+// SpanData to a latency or error bucket.
+func (s *spanStore) finished(span *Span, sd *SpanData) {
+ latency := sd.EndTime.Sub(sd.StartTime)
+ if latency < 0 {
+ latency = 0
+ }
+ code := sd.Status.Code
+
+ s.mu.Lock()
+ delete(s.active, span)
+ if code == 0 {
+ s.latency[latencyBucket(latency)].add(sd)
+ } else {
+ if s.errors == nil {
+ s.errors = make(map[int32]*bucket)
+ }
+ if b := s.errors[code]; b != nil {
+ b.add(sd)
+ } else {
+ b := makeBucket(s.maxSpansPerErrorBucket)
+ s.errors[code] = &b
+ b.add(sd)
+ }
+ }
+ s.mu.Unlock()
+}
diff --git a/vendor/go.opencensus.io/trace/status_codes.go b/vendor/go.opencensus.io/trace/status_codes.go
new file mode 100644
index 0000000..ec60eff
--- /dev/null
+++ b/vendor/go.opencensus.io/trace/status_codes.go
@@ -0,0 +1,37 @@
+// Copyright 2018, OpenCensus Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package trace
+
+// Status codes for use with Span.SetStatus. These correspond to the status
+// codes used by gRPC defined here: https://github.com/googleapis/googleapis/blob/master/google/rpc/code.proto
+const (
+ StatusCodeOK = 0
+ StatusCodeCancelled = 1
+ StatusCodeUnknown = 2
+ StatusCodeInvalidArgument = 3
+ StatusCodeDeadlineExceeded = 4
+ StatusCodeNotFound = 5
+ StatusCodeAlreadyExists = 6
+ StatusCodePermissionDenied = 7
+ StatusCodeResourceExhausted = 8
+ StatusCodeFailedPrecondition = 9
+ StatusCodeAborted = 10
+ StatusCodeOutOfRange = 11
+ StatusCodeUnimplemented = 12
+ StatusCodeInternal = 13
+ StatusCodeUnavailable = 14
+ StatusCodeDataLoss = 15
+ StatusCodeUnauthenticated = 16
+)
diff --git a/vendor/go.opencensus.io/trace/trace.go b/vendor/go.opencensus.io/trace/trace.go
new file mode 100644
index 0000000..3f8977b
--- /dev/null
+++ b/vendor/go.opencensus.io/trace/trace.go
@@ -0,0 +1,598 @@
+// Copyright 2017, OpenCensus Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package trace
+
+import (
+ "context"
+ crand "crypto/rand"
+ "encoding/binary"
+ "fmt"
+ "math/rand"
+ "sync"
+ "sync/atomic"
+ "time"
+
+ "go.opencensus.io/internal"
+ "go.opencensus.io/trace/tracestate"
+)
+
+// Span represents a span of a trace. It has an associated SpanContext, and
+// stores data accumulated while the span is active.
+//
+// Ideally users should interact with Spans by calling the functions in this
+// package that take a Context parameter.
+type Span struct {
+ // data contains information recorded about the span.
+ //
+ // It will be non-nil if we are exporting the span or recording events for it.
+ // Otherwise, data is nil, and the Span is simply a carrier for the
+ // SpanContext, so that the trace ID is propagated.
+ data *SpanData
+ mu sync.Mutex // protects the contents of *data (but not the pointer value.)
+ spanContext SpanContext
+
+ // lruAttributes are capped at configured limit. When the capacity is reached an oldest entry
+ // is removed to create room for a new entry.
+ lruAttributes *lruMap
+
+ // annotations are stored in FIFO queue capped by configured limit.
+ annotations *evictedQueue
+
+ // messageEvents are stored in FIFO queue capped by configured limit.
+ messageEvents *evictedQueue
+
+ // links are stored in FIFO queue capped by configured limit.
+ links *evictedQueue
+
+ // spanStore is the spanStore this span belongs to, if any, otherwise it is nil.
+ *spanStore
+ endOnce sync.Once
+
+ executionTracerTaskEnd func() // ends the execution tracer span
+}
+
+// IsRecordingEvents returns true if events are being recorded for this span.
+// Use this check to avoid computing expensive annotations when they will never
+// be used.
+func (s *Span) IsRecordingEvents() bool {
+ if s == nil {
+ return false
+ }
+ return s.data != nil
+}
+
+// TraceOptions contains options associated with a trace span.
+type TraceOptions uint32
+
+// IsSampled returns true if the span will be exported.
+func (sc SpanContext) IsSampled() bool {
+ return sc.TraceOptions.IsSampled()
+}
+
+// setIsSampled sets the TraceOptions bit that determines whether the span will be exported.
+func (sc *SpanContext) setIsSampled(sampled bool) {
+ if sampled {
+ sc.TraceOptions |= 1
+ } else {
+ sc.TraceOptions &= ^TraceOptions(1)
+ }
+}
+
+// IsSampled returns true if the span will be exported.
+func (t TraceOptions) IsSampled() bool {
+ return t&1 == 1
+}
+
+// SpanContext contains the state that must propagate across process boundaries.
+//
+// SpanContext is not an implementation of context.Context.
+// TODO: add reference to external Census docs for SpanContext.
+type SpanContext struct {
+ TraceID TraceID
+ SpanID SpanID
+ TraceOptions TraceOptions
+ Tracestate *tracestate.Tracestate
+}
+
+type contextKey struct{}
+
+// FromContext returns the Span stored in a context, or nil if there isn't one.
+func FromContext(ctx context.Context) *Span {
+ s, _ := ctx.Value(contextKey{}).(*Span)
+ return s
+}
+
+// NewContext returns a new context with the given Span attached.
+func NewContext(parent context.Context, s *Span) context.Context {
+ return context.WithValue(parent, contextKey{}, s)
+}
+
+// All available span kinds. Span kind must be either one of these values.
+const (
+ SpanKindUnspecified = iota
+ SpanKindServer
+ SpanKindClient
+)
+
+// StartOptions contains options concerning how a span is started.
+type StartOptions struct {
+ // Sampler to consult for this Span. If provided, it is always consulted.
+ //
+ // If not provided, then the behavior differs based on whether
+ // the parent of this Span is remote, local, or there is no parent.
+ // In the case of a remote parent or no parent, the
+ // default sampler (see Config) will be consulted. Otherwise,
+ // when there is a non-remote parent, no new sampling decision will be made:
+ // we will preserve the sampling of the parent.
+ Sampler Sampler
+
+ // SpanKind represents the kind of a span. If none is set,
+ // SpanKindUnspecified is used.
+ SpanKind int
+}
+
+// StartOption apply changes to StartOptions.
+type StartOption func(*StartOptions)
+
+// WithSpanKind makes new spans to be created with the given kind.
+func WithSpanKind(spanKind int) StartOption {
+ return func(o *StartOptions) {
+ o.SpanKind = spanKind
+ }
+}
+
+// WithSampler makes new spans to be be created with a custom sampler.
+// Otherwise, the global sampler is used.
+func WithSampler(sampler Sampler) StartOption {
+ return func(o *StartOptions) {
+ o.Sampler = sampler
+ }
+}
+
+// StartSpan starts a new child span of the current span in the context. If
+// there is no span in the context, creates a new trace and span.
+//
+// Returned context contains the newly created span. You can use it to
+// propagate the returned span in process.
+func StartSpan(ctx context.Context, name string, o ...StartOption) (context.Context, *Span) {
+ var opts StartOptions
+ var parent SpanContext
+ if p := FromContext(ctx); p != nil {
+ p.addChild()
+ parent = p.spanContext
+ }
+ for _, op := range o {
+ op(&opts)
+ }
+ span := startSpanInternal(name, parent != SpanContext{}, parent, false, opts)
+
+ ctx, end := startExecutionTracerTask(ctx, name)
+ span.executionTracerTaskEnd = end
+ return NewContext(ctx, span), span
+}
+
+// StartSpanWithRemoteParent starts a new child span of the span from the given parent.
+//
+// If the incoming context contains a parent, it ignores. StartSpanWithRemoteParent is
+// preferred for cases where the parent is propagated via an incoming request.
+//
+// Returned context contains the newly created span. You can use it to
+// propagate the returned span in process.
+func StartSpanWithRemoteParent(ctx context.Context, name string, parent SpanContext, o ...StartOption) (context.Context, *Span) {
+ var opts StartOptions
+ for _, op := range o {
+ op(&opts)
+ }
+ span := startSpanInternal(name, parent != SpanContext{}, parent, true, opts)
+ ctx, end := startExecutionTracerTask(ctx, name)
+ span.executionTracerTaskEnd = end
+ return NewContext(ctx, span), span
+}
+
+func startSpanInternal(name string, hasParent bool, parent SpanContext, remoteParent bool, o StartOptions) *Span {
+ span := &Span{}
+ span.spanContext = parent
+
+ cfg := config.Load().(*Config)
+
+ if !hasParent {
+ span.spanContext.TraceID = cfg.IDGenerator.NewTraceID()
+ }
+ span.spanContext.SpanID = cfg.IDGenerator.NewSpanID()
+ sampler := cfg.DefaultSampler
+
+ if !hasParent || remoteParent || o.Sampler != nil {
+ // If this span is the child of a local span and no Sampler is set in the
+ // options, keep the parent's TraceOptions.
+ //
+ // Otherwise, consult the Sampler in the options if it is non-nil, otherwise
+ // the default sampler.
+ if o.Sampler != nil {
+ sampler = o.Sampler
+ }
+ span.spanContext.setIsSampled(sampler(SamplingParameters{
+ ParentContext: parent,
+ TraceID: span.spanContext.TraceID,
+ SpanID: span.spanContext.SpanID,
+ Name: name,
+ HasRemoteParent: remoteParent}).Sample)
+ }
+
+ if !internal.LocalSpanStoreEnabled && !span.spanContext.IsSampled() {
+ return span
+ }
+
+ span.data = &SpanData{
+ SpanContext: span.spanContext,
+ StartTime: time.Now(),
+ SpanKind: o.SpanKind,
+ Name: name,
+ HasRemoteParent: remoteParent,
+ }
+ span.lruAttributes = newLruMap(cfg.MaxAttributesPerSpan)
+ span.annotations = newEvictedQueue(cfg.MaxAnnotationEventsPerSpan)
+ span.messageEvents = newEvictedQueue(cfg.MaxMessageEventsPerSpan)
+ span.links = newEvictedQueue(cfg.MaxLinksPerSpan)
+
+ if hasParent {
+ span.data.ParentSpanID = parent.SpanID
+ }
+ if internal.LocalSpanStoreEnabled {
+ var ss *spanStore
+ ss = spanStoreForNameCreateIfNew(name)
+ if ss != nil {
+ span.spanStore = ss
+ ss.add(span)
+ }
+ }
+
+ return span
+}
+
+// End ends the span.
+func (s *Span) End() {
+ if s == nil {
+ return
+ }
+ if s.executionTracerTaskEnd != nil {
+ s.executionTracerTaskEnd()
+ }
+ if !s.IsRecordingEvents() {
+ return
+ }
+ s.endOnce.Do(func() {
+ exp, _ := exporters.Load().(exportersMap)
+ mustExport := s.spanContext.IsSampled() && len(exp) > 0
+ if s.spanStore != nil || mustExport {
+ sd := s.makeSpanData()
+ sd.EndTime = internal.MonotonicEndTime(sd.StartTime)
+ if s.spanStore != nil {
+ s.spanStore.finished(s, sd)
+ }
+ if mustExport {
+ for e := range exp {
+ e.ExportSpan(sd)
+ }
+ }
+ }
+ })
+}
+
+// makeSpanData produces a SpanData representing the current state of the Span.
+// It requires that s.data is non-nil.
+func (s *Span) makeSpanData() *SpanData {
+ var sd SpanData
+ s.mu.Lock()
+ sd = *s.data
+ if s.lruAttributes.len() > 0 {
+ sd.Attributes = s.lruAttributesToAttributeMap()
+ sd.DroppedAttributeCount = s.lruAttributes.droppedCount
+ }
+ if len(s.annotations.queue) > 0 {
+ sd.Annotations = s.interfaceArrayToAnnotationArray()
+ sd.DroppedAnnotationCount = s.annotations.droppedCount
+ }
+ if len(s.messageEvents.queue) > 0 {
+ sd.MessageEvents = s.interfaceArrayToMessageEventArray()
+ sd.DroppedMessageEventCount = s.messageEvents.droppedCount
+ }
+ if len(s.links.queue) > 0 {
+ sd.Links = s.interfaceArrayToLinksArray()
+ sd.DroppedLinkCount = s.links.droppedCount
+ }
+ s.mu.Unlock()
+ return &sd
+}
+
+// SpanContext returns the SpanContext of the span.
+func (s *Span) SpanContext() SpanContext {
+ if s == nil {
+ return SpanContext{}
+ }
+ return s.spanContext
+}
+
+// SetName sets the name of the span, if it is recording events.
+func (s *Span) SetName(name string) {
+ if !s.IsRecordingEvents() {
+ return
+ }
+ s.mu.Lock()
+ s.data.Name = name
+ s.mu.Unlock()
+}
+
+// SetStatus sets the status of the span, if it is recording events.
+func (s *Span) SetStatus(status Status) {
+ if !s.IsRecordingEvents() {
+ return
+ }
+ s.mu.Lock()
+ s.data.Status = status
+ s.mu.Unlock()
+}
+
+func (s *Span) interfaceArrayToLinksArray() []Link {
+ linksArr := make([]Link, 0)
+ for _, value := range s.links.queue {
+ linksArr = append(linksArr, value.(Link))
+ }
+ return linksArr
+}
+
+func (s *Span) interfaceArrayToMessageEventArray() []MessageEvent {
+ messageEventArr := make([]MessageEvent, 0)
+ for _, value := range s.messageEvents.queue {
+ messageEventArr = append(messageEventArr, value.(MessageEvent))
+ }
+ return messageEventArr
+}
+
+func (s *Span) interfaceArrayToAnnotationArray() []Annotation {
+ annotationArr := make([]Annotation, 0)
+ for _, value := range s.annotations.queue {
+ annotationArr = append(annotationArr, value.(Annotation))
+ }
+ return annotationArr
+}
+
+func (s *Span) lruAttributesToAttributeMap() map[string]interface{} {
+ attributes := make(map[string]interface{})
+ for _, key := range s.lruAttributes.keys() {
+ value, ok := s.lruAttributes.get(key)
+ if ok {
+ keyStr := key.(string)
+ attributes[keyStr] = value
+ }
+ }
+ return attributes
+}
+
+func (s *Span) copyToCappedAttributes(attributes []Attribute) {
+ for _, a := range attributes {
+ s.lruAttributes.add(a.key, a.value)
+ }
+}
+
+func (s *Span) addChild() {
+ if !s.IsRecordingEvents() {
+ return
+ }
+ s.mu.Lock()
+ s.data.ChildSpanCount++
+ s.mu.Unlock()
+}
+
+// AddAttributes sets attributes in the span.
+//
+// Existing attributes whose keys appear in the attributes parameter are overwritten.
+func (s *Span) AddAttributes(attributes ...Attribute) {
+ if !s.IsRecordingEvents() {
+ return
+ }
+ s.mu.Lock()
+ s.copyToCappedAttributes(attributes)
+ s.mu.Unlock()
+}
+
+// copyAttributes copies a slice of Attributes into a map.
+func copyAttributes(m map[string]interface{}, attributes []Attribute) {
+ for _, a := range attributes {
+ m[a.key] = a.value
+ }
+}
+
+func (s *Span) lazyPrintfInternal(attributes []Attribute, format string, a ...interface{}) {
+ now := time.Now()
+ msg := fmt.Sprintf(format, a...)
+ var m map[string]interface{}
+ s.mu.Lock()
+ if len(attributes) != 0 {
+ m = make(map[string]interface{})
+ copyAttributes(m, attributes)
+ }
+ s.annotations.add(Annotation{
+ Time: now,
+ Message: msg,
+ Attributes: m,
+ })
+ s.mu.Unlock()
+}
+
+func (s *Span) printStringInternal(attributes []Attribute, str string) {
+ now := time.Now()
+ var a map[string]interface{}
+ s.mu.Lock()
+ if len(attributes) != 0 {
+ a = make(map[string]interface{})
+ copyAttributes(a, attributes)
+ }
+ s.annotations.add(Annotation{
+ Time: now,
+ Message: str,
+ Attributes: a,
+ })
+ s.mu.Unlock()
+}
+
+// Annotate adds an annotation with attributes.
+// Attributes can be nil.
+func (s *Span) Annotate(attributes []Attribute, str string) {
+ if !s.IsRecordingEvents() {
+ return
+ }
+ s.printStringInternal(attributes, str)
+}
+
+// Annotatef adds an annotation with attributes.
+func (s *Span) Annotatef(attributes []Attribute, format string, a ...interface{}) {
+ if !s.IsRecordingEvents() {
+ return
+ }
+ s.lazyPrintfInternal(attributes, format, a...)
+}
+
+// AddMessageSendEvent adds a message send event to the span.
+//
+// messageID is an identifier for the message, which is recommended to be
+// unique in this span and the same between the send event and the receive
+// event (this allows to identify a message between the sender and receiver).
+// For example, this could be a sequence id.
+func (s *Span) AddMessageSendEvent(messageID, uncompressedByteSize, compressedByteSize int64) {
+ if !s.IsRecordingEvents() {
+ return
+ }
+ now := time.Now()
+ s.mu.Lock()
+ s.messageEvents.add(MessageEvent{
+ Time: now,
+ EventType: MessageEventTypeSent,
+ MessageID: messageID,
+ UncompressedByteSize: uncompressedByteSize,
+ CompressedByteSize: compressedByteSize,
+ })
+ s.mu.Unlock()
+}
+
+// AddMessageReceiveEvent adds a message receive event to the span.
+//
+// messageID is an identifier for the message, which is recommended to be
+// unique in this span and the same between the send event and the receive
+// event (this allows to identify a message between the sender and receiver).
+// For example, this could be a sequence id.
+func (s *Span) AddMessageReceiveEvent(messageID, uncompressedByteSize, compressedByteSize int64) {
+ if !s.IsRecordingEvents() {
+ return
+ }
+ now := time.Now()
+ s.mu.Lock()
+ s.messageEvents.add(MessageEvent{
+ Time: now,
+ EventType: MessageEventTypeRecv,
+ MessageID: messageID,
+ UncompressedByteSize: uncompressedByteSize,
+ CompressedByteSize: compressedByteSize,
+ })
+ s.mu.Unlock()
+}
+
+// AddLink adds a link to the span.
+func (s *Span) AddLink(l Link) {
+ if !s.IsRecordingEvents() {
+ return
+ }
+ s.mu.Lock()
+ s.links.add(l)
+ s.mu.Unlock()
+}
+
+func (s *Span) String() string {
+ if s == nil {
+ return ""
+ }
+ if s.data == nil {
+ return fmt.Sprintf("span %s", s.spanContext.SpanID)
+ }
+ s.mu.Lock()
+ str := fmt.Sprintf("span %s %q", s.spanContext.SpanID, s.data.Name)
+ s.mu.Unlock()
+ return str
+}
+
+var config atomic.Value // access atomically
+
+func init() {
+ gen := &defaultIDGenerator{}
+ // initialize traceID and spanID generators.
+ var rngSeed int64
+ for _, p := range []interface{}{
+ &rngSeed, &gen.traceIDAdd, &gen.nextSpanID, &gen.spanIDInc,
+ } {
+ binary.Read(crand.Reader, binary.LittleEndian, p)
+ }
+ gen.traceIDRand = rand.New(rand.NewSource(rngSeed))
+ gen.spanIDInc |= 1
+
+ config.Store(&Config{
+ DefaultSampler: ProbabilitySampler(defaultSamplingProbability),
+ IDGenerator: gen,
+ MaxAttributesPerSpan: DefaultMaxAttributesPerSpan,
+ MaxAnnotationEventsPerSpan: DefaultMaxAnnotationEventsPerSpan,
+ MaxMessageEventsPerSpan: DefaultMaxMessageEventsPerSpan,
+ MaxLinksPerSpan: DefaultMaxLinksPerSpan,
+ })
+}
+
+type defaultIDGenerator struct {
+ sync.Mutex
+
+ // Please keep these as the first fields
+ // so that these 8 byte fields will be aligned on addresses
+ // divisible by 8, on both 32-bit and 64-bit machines when
+ // performing atomic increments and accesses.
+ // See:
+ // * https://github.com/census-instrumentation/opencensus-go/issues/587
+ // * https://github.com/census-instrumentation/opencensus-go/issues/865
+ // * https://golang.org/pkg/sync/atomic/#pkg-note-BUG
+ nextSpanID uint64
+ spanIDInc uint64
+
+ traceIDAdd [2]uint64
+ traceIDRand *rand.Rand
+}
+
+// NewSpanID returns a non-zero span ID from a randomly-chosen sequence.
+func (gen *defaultIDGenerator) NewSpanID() [8]byte {
+ var id uint64
+ for id == 0 {
+ id = atomic.AddUint64(&gen.nextSpanID, gen.spanIDInc)
+ }
+ var sid [8]byte
+ binary.LittleEndian.PutUint64(sid[:], id)
+ return sid
+}
+
+// NewTraceID returns a non-zero trace ID from a randomly-chosen sequence.
+// mu should be held while this function is called.
+func (gen *defaultIDGenerator) NewTraceID() [16]byte {
+ var tid [16]byte
+ // Construct the trace ID from two outputs of traceIDRand, with a constant
+ // added to each half for additional entropy.
+ gen.Lock()
+ binary.LittleEndian.PutUint64(tid[0:8], gen.traceIDRand.Uint64()+gen.traceIDAdd[0])
+ binary.LittleEndian.PutUint64(tid[8:16], gen.traceIDRand.Uint64()+gen.traceIDAdd[1])
+ gen.Unlock()
+ return tid
+}
diff --git a/vendor/go.opencensus.io/trace/trace_go11.go b/vendor/go.opencensus.io/trace/trace_go11.go
new file mode 100644
index 0000000..b7d8aaf
--- /dev/null
+++ b/vendor/go.opencensus.io/trace/trace_go11.go
@@ -0,0 +1,32 @@
+// Copyright 2018, OpenCensus Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// +build go1.11
+
+package trace
+
+import (
+ "context"
+ t "runtime/trace"
+)
+
+func startExecutionTracerTask(ctx context.Context, name string) (context.Context, func()) {
+ if !t.IsEnabled() {
+ // Avoid additional overhead if
+ // runtime/trace is not enabled.
+ return ctx, func() {}
+ }
+ nctx, task := t.NewTask(ctx, name)
+ return nctx, task.End
+}
diff --git a/vendor/go.opencensus.io/trace/trace_nongo11.go b/vendor/go.opencensus.io/trace/trace_nongo11.go
new file mode 100644
index 0000000..e254198
--- /dev/null
+++ b/vendor/go.opencensus.io/trace/trace_nongo11.go
@@ -0,0 +1,25 @@
+// Copyright 2018, OpenCensus Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// +build !go1.11
+
+package trace
+
+import (
+ "context"
+)
+
+func startExecutionTracerTask(ctx context.Context, name string) (context.Context, func()) {
+ return ctx, func() {}
+}
diff --git a/vendor/go.opencensus.io/trace/tracestate/tracestate.go b/vendor/go.opencensus.io/trace/tracestate/tracestate.go
new file mode 100644
index 0000000..2d6c713
--- /dev/null
+++ b/vendor/go.opencensus.io/trace/tracestate/tracestate.go
@@ -0,0 +1,147 @@
+// Copyright 2018, OpenCensus Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Package tracestate implements support for the Tracestate header of the
+// W3C TraceContext propagation format.
+package tracestate
+
+import (
+ "fmt"
+ "regexp"
+)
+
+const (
+ keyMaxSize = 256
+ valueMaxSize = 256
+ maxKeyValuePairs = 32
+)
+
+const (
+ keyWithoutVendorFormat = `[a-z][_0-9a-z\-\*\/]{0,255}`
+ keyWithVendorFormat = `[a-z][_0-9a-z\-\*\/]{0,240}@[a-z][_0-9a-z\-\*\/]{0,13}`
+ keyFormat = `(` + keyWithoutVendorFormat + `)|(` + keyWithVendorFormat + `)`
+ valueFormat = `[\x20-\x2b\x2d-\x3c\x3e-\x7e]{0,255}[\x21-\x2b\x2d-\x3c\x3e-\x7e]`
+)
+
+var keyValidationRegExp = regexp.MustCompile(`^(` + keyFormat + `)$`)
+var valueValidationRegExp = regexp.MustCompile(`^(` + valueFormat + `)$`)
+
+// Tracestate represents tracing-system specific context in a list of key-value pairs. Tracestate allows different
+// vendors propagate additional information and inter-operate with their legacy Id formats.
+type Tracestate struct {
+ entries []Entry
+}
+
+// Entry represents one key-value pair in a list of key-value pair of Tracestate.
+type Entry struct {
+ // Key is an opaque string up to 256 characters printable. It MUST begin with a lowercase letter,
+ // and can only contain lowercase letters a-z, digits 0-9, underscores _, dashes -, asterisks *, and
+ // forward slashes /.
+ Key string
+
+ // Value is an opaque string up to 256 characters printable ASCII RFC0020 characters (i.e., the
+ // range 0x20 to 0x7E) except comma , and =.
+ Value string
+}
+
+// Entries returns a slice of Entry.
+func (ts *Tracestate) Entries() []Entry {
+ if ts == nil {
+ return nil
+ }
+ return ts.entries
+}
+
+func (ts *Tracestate) remove(key string) *Entry {
+ for index, entry := range ts.entries {
+ if entry.Key == key {
+ ts.entries = append(ts.entries[:index], ts.entries[index+1:]...)
+ return &entry
+ }
+ }
+ return nil
+}
+
+func (ts *Tracestate) add(entries []Entry) error {
+ for _, entry := range entries {
+ ts.remove(entry.Key)
+ }
+ if len(ts.entries)+len(entries) > maxKeyValuePairs {
+ return fmt.Errorf("adding %d key-value pairs to current %d pairs exceeds the limit of %d",
+ len(entries), len(ts.entries), maxKeyValuePairs)
+ }
+ ts.entries = append(entries, ts.entries...)
+ return nil
+}
+
+func isValid(entry Entry) bool {
+ return keyValidationRegExp.MatchString(entry.Key) &&
+ valueValidationRegExp.MatchString(entry.Value)
+}
+
+func containsDuplicateKey(entries ...Entry) (string, bool) {
+ keyMap := make(map[string]int)
+ for _, entry := range entries {
+ if _, ok := keyMap[entry.Key]; ok {
+ return entry.Key, true
+ }
+ keyMap[entry.Key] = 1
+ }
+ return "", false
+}
+
+func areEntriesValid(entries ...Entry) (*Entry, bool) {
+ for _, entry := range entries {
+ if !isValid(entry) {
+ return &entry, false
+ }
+ }
+ return nil, true
+}
+
+// New creates a Tracestate object from a parent and/or entries (key-value pair).
+// Entries from the parent are copied if present. The entries passed to this function
+// are inserted in front of those copied from the parent. If an entry copied from the
+// parent contains the same key as one of the entry in entries then the entry copied
+// from the parent is removed. See add func.
+//
+// An error is returned with nil Tracestate if
+// 1. one or more entry in entries is invalid.
+// 2. two or more entries in the input entries have the same key.
+// 3. the number of entries combined from the parent and the input entries exceeds maxKeyValuePairs.
+// (duplicate entry is counted only once).
+func New(parent *Tracestate, entries ...Entry) (*Tracestate, error) {
+ if parent == nil && len(entries) == 0 {
+ return nil, nil
+ }
+ if entry, ok := areEntriesValid(entries...); !ok {
+ return nil, fmt.Errorf("key-value pair {%s, %s} is invalid", entry.Key, entry.Value)
+ }
+
+ if key, duplicate := containsDuplicateKey(entries...); duplicate {
+ return nil, fmt.Errorf("contains duplicate keys (%s)", key)
+ }
+
+ tracestate := Tracestate{}
+
+ if parent != nil && len(parent.entries) > 0 {
+ tracestate.entries = append([]Entry{}, parent.entries...)
+ }
+
+ err := tracestate.add(entries)
+ if err != nil {
+ return nil, err
+ }
+ return &tracestate, nil
+}
diff --git a/vendor/golang.org/x/net/AUTHORS b/vendor/golang.org/x/net/AUTHORS
new file mode 100644
index 0000000..15167cd
--- /dev/null
+++ b/vendor/golang.org/x/net/AUTHORS
@@ -0,0 +1,3 @@
+# This source code refers to The Go Authors for copyright purposes.
+# The master list of authors is in the main Go distribution,
+# visible at http://tip.golang.org/AUTHORS.
diff --git a/vendor/golang.org/x/net/CONTRIBUTORS b/vendor/golang.org/x/net/CONTRIBUTORS
new file mode 100644
index 0000000..1c4577e
--- /dev/null
+++ b/vendor/golang.org/x/net/CONTRIBUTORS
@@ -0,0 +1,3 @@
+# This source code was written by the Go contributors.
+# The master list of contributors is in the main Go distribution,
+# visible at http://tip.golang.org/CONTRIBUTORS.
diff --git a/vendor/golang.org/x/net/LICENSE b/vendor/golang.org/x/net/LICENSE
new file mode 100644
index 0000000..6a66aea
--- /dev/null
+++ b/vendor/golang.org/x/net/LICENSE
@@ -0,0 +1,27 @@
+Copyright (c) 2009 The Go Authors. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+ * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/vendor/golang.org/x/net/PATENTS b/vendor/golang.org/x/net/PATENTS
new file mode 100644
index 0000000..7330990
--- /dev/null
+++ b/vendor/golang.org/x/net/PATENTS
@@ -0,0 +1,22 @@
+Additional IP Rights Grant (Patents)
+
+"This implementation" means the copyrightable works distributed by
+Google as part of the Go project.
+
+Google hereby grants to You a perpetual, worldwide, non-exclusive,
+no-charge, royalty-free, irrevocable (except as stated in this section)
+patent license to make, have made, use, offer to sell, sell, import,
+transfer and otherwise run, modify and propagate the contents of this
+implementation of Go, where such license applies only to those patent
+claims, both currently owned or controlled by Google and acquired in
+the future, licensable by Google that are necessarily infringed by this
+implementation of Go. This grant does not include claims that would be
+infringed only as a consequence of further modification of this
+implementation. If you or your agent or exclusive licensee institute or
+order or agree to the institution of patent litigation against any
+entity (including a cross-claim or counterclaim in a lawsuit) alleging
+that this implementation of Go or any code incorporated within this
+implementation of Go constitutes direct or contributory patent
+infringement, or inducement of patent infringement, then any patent
+rights granted to you under this License for this implementation of Go
+shall terminate as of the date such litigation is filed.
diff --git a/vendor/golang.org/x/net/http/httpguts/guts.go b/vendor/golang.org/x/net/http/httpguts/guts.go
new file mode 100644
index 0000000..e6cd0ce
--- /dev/null
+++ b/vendor/golang.org/x/net/http/httpguts/guts.go
@@ -0,0 +1,50 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package httpguts provides functions implementing various details
+// of the HTTP specification.
+//
+// This package is shared by the standard library (which vendors it)
+// and x/net/http2. It comes with no API stability promise.
+package httpguts
+
+import (
+ "net/textproto"
+ "strings"
+)
+
+// ValidTrailerHeader reports whether name is a valid header field name to appear
+// in trailers.
+// See RFC 7230, Section 4.1.2
+func ValidTrailerHeader(name string) bool {
+ name = textproto.CanonicalMIMEHeaderKey(name)
+ if strings.HasPrefix(name, "If-") || badTrailer[name] {
+ return false
+ }
+ return true
+}
+
+var badTrailer = map[string]bool{
+ "Authorization": true,
+ "Cache-Control": true,
+ "Connection": true,
+ "Content-Encoding": true,
+ "Content-Length": true,
+ "Content-Range": true,
+ "Content-Type": true,
+ "Expect": true,
+ "Host": true,
+ "Keep-Alive": true,
+ "Max-Forwards": true,
+ "Pragma": true,
+ "Proxy-Authenticate": true,
+ "Proxy-Authorization": true,
+ "Proxy-Connection": true,
+ "Range": true,
+ "Realm": true,
+ "Te": true,
+ "Trailer": true,
+ "Transfer-Encoding": true,
+ "Www-Authenticate": true,
+}
diff --git a/vendor/golang.org/x/net/http/httpguts/httplex.go b/vendor/golang.org/x/net/http/httpguts/httplex.go
new file mode 100644
index 0000000..e7de24e
--- /dev/null
+++ b/vendor/golang.org/x/net/http/httpguts/httplex.go
@@ -0,0 +1,346 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package httpguts
+
+import (
+ "net"
+ "strings"
+ "unicode/utf8"
+
+ "golang.org/x/net/idna"
+)
+
+var isTokenTable = [127]bool{
+ '!': true,
+ '#': true,
+ '$': true,
+ '%': true,
+ '&': true,
+ '\'': true,
+ '*': true,
+ '+': true,
+ '-': true,
+ '.': true,
+ '0': true,
+ '1': true,
+ '2': true,
+ '3': true,
+ '4': true,
+ '5': true,
+ '6': true,
+ '7': true,
+ '8': true,
+ '9': true,
+ 'A': true,
+ 'B': true,
+ 'C': true,
+ 'D': true,
+ 'E': true,
+ 'F': true,
+ 'G': true,
+ 'H': true,
+ 'I': true,
+ 'J': true,
+ 'K': true,
+ 'L': true,
+ 'M': true,
+ 'N': true,
+ 'O': true,
+ 'P': true,
+ 'Q': true,
+ 'R': true,
+ 'S': true,
+ 'T': true,
+ 'U': true,
+ 'W': true,
+ 'V': true,
+ 'X': true,
+ 'Y': true,
+ 'Z': true,
+ '^': true,
+ '_': true,
+ '`': true,
+ 'a': true,
+ 'b': true,
+ 'c': true,
+ 'd': true,
+ 'e': true,
+ 'f': true,
+ 'g': true,
+ 'h': true,
+ 'i': true,
+ 'j': true,
+ 'k': true,
+ 'l': true,
+ 'm': true,
+ 'n': true,
+ 'o': true,
+ 'p': true,
+ 'q': true,
+ 'r': true,
+ 's': true,
+ 't': true,
+ 'u': true,
+ 'v': true,
+ 'w': true,
+ 'x': true,
+ 'y': true,
+ 'z': true,
+ '|': true,
+ '~': true,
+}
+
+func IsTokenRune(r rune) bool {
+ i := int(r)
+ return i < len(isTokenTable) && isTokenTable[i]
+}
+
+func isNotToken(r rune) bool {
+ return !IsTokenRune(r)
+}
+
+// HeaderValuesContainsToken reports whether any string in values
+// contains the provided token, ASCII case-insensitively.
+func HeaderValuesContainsToken(values []string, token string) bool {
+ for _, v := range values {
+ if headerValueContainsToken(v, token) {
+ return true
+ }
+ }
+ return false
+}
+
+// isOWS reports whether b is an optional whitespace byte, as defined
+// by RFC 7230 section 3.2.3.
+func isOWS(b byte) bool { return b == ' ' || b == '\t' }
+
+// trimOWS returns x with all optional whitespace removes from the
+// beginning and end.
+func trimOWS(x string) string {
+ // TODO: consider using strings.Trim(x, " \t") instead,
+ // if and when it's fast enough. See issue 10292.
+ // But this ASCII-only code will probably always beat UTF-8
+ // aware code.
+ for len(x) > 0 && isOWS(x[0]) {
+ x = x[1:]
+ }
+ for len(x) > 0 && isOWS(x[len(x)-1]) {
+ x = x[:len(x)-1]
+ }
+ return x
+}
+
+// headerValueContainsToken reports whether v (assumed to be a
+// 0#element, in the ABNF extension described in RFC 7230 section 7)
+// contains token amongst its comma-separated tokens, ASCII
+// case-insensitively.
+func headerValueContainsToken(v string, token string) bool {
+ v = trimOWS(v)
+ if comma := strings.IndexByte(v, ','); comma != -1 {
+ return tokenEqual(trimOWS(v[:comma]), token) || headerValueContainsToken(v[comma+1:], token)
+ }
+ return tokenEqual(v, token)
+}
+
+// lowerASCII returns the ASCII lowercase version of b.
+func lowerASCII(b byte) byte {
+ if 'A' <= b && b <= 'Z' {
+ return b + ('a' - 'A')
+ }
+ return b
+}
+
+// tokenEqual reports whether t1 and t2 are equal, ASCII case-insensitively.
+func tokenEqual(t1, t2 string) bool {
+ if len(t1) != len(t2) {
+ return false
+ }
+ for i, b := range t1 {
+ if b >= utf8.RuneSelf {
+ // No UTF-8 or non-ASCII allowed in tokens.
+ return false
+ }
+ if lowerASCII(byte(b)) != lowerASCII(t2[i]) {
+ return false
+ }
+ }
+ return true
+}
+
+// isLWS reports whether b is linear white space, according
+// to http://www.w3.org/Protocols/rfc2616/rfc2616-sec2.html#sec2.2
+// LWS = [CRLF] 1*( SP | HT )
+func isLWS(b byte) bool { return b == ' ' || b == '\t' }
+
+// isCTL reports whether b is a control byte, according
+// to http://www.w3.org/Protocols/rfc2616/rfc2616-sec2.html#sec2.2
+// CTL =
+func isCTL(b byte) bool {
+ const del = 0x7f // a CTL
+ return b < ' ' || b == del
+}
+
+// ValidHeaderFieldName reports whether v is a valid HTTP/1.x header name.
+// HTTP/2 imposes the additional restriction that uppercase ASCII
+// letters are not allowed.
+//
+// RFC 7230 says:
+// header-field = field-name ":" OWS field-value OWS
+// field-name = token
+// token = 1*tchar
+// tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*" / "+" / "-" / "." /
+// "^" / "_" / "`" / "|" / "~" / DIGIT / ALPHA
+func ValidHeaderFieldName(v string) bool {
+ if len(v) == 0 {
+ return false
+ }
+ for _, r := range v {
+ if !IsTokenRune(r) {
+ return false
+ }
+ }
+ return true
+}
+
+// ValidHostHeader reports whether h is a valid host header.
+func ValidHostHeader(h string) bool {
+ // The latest spec is actually this:
+ //
+ // http://tools.ietf.org/html/rfc7230#section-5.4
+ // Host = uri-host [ ":" port ]
+ //
+ // Where uri-host is:
+ // http://tools.ietf.org/html/rfc3986#section-3.2.2
+ //
+ // But we're going to be much more lenient for now and just
+ // search for any byte that's not a valid byte in any of those
+ // expressions.
+ for i := 0; i < len(h); i++ {
+ if !validHostByte[h[i]] {
+ return false
+ }
+ }
+ return true
+}
+
+// See the validHostHeader comment.
+var validHostByte = [256]bool{
+ '0': true, '1': true, '2': true, '3': true, '4': true, '5': true, '6': true, '7': true,
+ '8': true, '9': true,
+
+ 'a': true, 'b': true, 'c': true, 'd': true, 'e': true, 'f': true, 'g': true, 'h': true,
+ 'i': true, 'j': true, 'k': true, 'l': true, 'm': true, 'n': true, 'o': true, 'p': true,
+ 'q': true, 'r': true, 's': true, 't': true, 'u': true, 'v': true, 'w': true, 'x': true,
+ 'y': true, 'z': true,
+
+ 'A': true, 'B': true, 'C': true, 'D': true, 'E': true, 'F': true, 'G': true, 'H': true,
+ 'I': true, 'J': true, 'K': true, 'L': true, 'M': true, 'N': true, 'O': true, 'P': true,
+ 'Q': true, 'R': true, 'S': true, 'T': true, 'U': true, 'V': true, 'W': true, 'X': true,
+ 'Y': true, 'Z': true,
+
+ '!': true, // sub-delims
+ '$': true, // sub-delims
+ '%': true, // pct-encoded (and used in IPv6 zones)
+ '&': true, // sub-delims
+ '(': true, // sub-delims
+ ')': true, // sub-delims
+ '*': true, // sub-delims
+ '+': true, // sub-delims
+ ',': true, // sub-delims
+ '-': true, // unreserved
+ '.': true, // unreserved
+ ':': true, // IPv6address + Host expression's optional port
+ ';': true, // sub-delims
+ '=': true, // sub-delims
+ '[': true,
+ '\'': true, // sub-delims
+ ']': true,
+ '_': true, // unreserved
+ '~': true, // unreserved
+}
+
+// ValidHeaderFieldValue reports whether v is a valid "field-value" according to
+// http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2 :
+//
+// message-header = field-name ":" [ field-value ]
+// field-value = *( field-content | LWS )
+// field-content =
+//
+// http://www.w3.org/Protocols/rfc2616/rfc2616-sec2.html#sec2.2 :
+//
+// TEXT =
+// LWS = [CRLF] 1*( SP | HT )
+// CTL =
+//
+// RFC 7230 says:
+// field-value = *( field-content / obs-fold )
+// obj-fold = N/A to http2, and deprecated
+// field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ]
+// field-vchar = VCHAR / obs-text
+// obs-text = %x80-FF
+// VCHAR = "any visible [USASCII] character"
+//
+// http2 further says: "Similarly, HTTP/2 allows header field values
+// that are not valid. While most of the values that can be encoded
+// will not alter header field parsing, carriage return (CR, ASCII
+// 0xd), line feed (LF, ASCII 0xa), and the zero character (NUL, ASCII
+// 0x0) might be exploited by an attacker if they are translated
+// verbatim. Any request or response that contains a character not
+// permitted in a header field value MUST be treated as malformed
+// (Section 8.1.2.6). Valid characters are defined by the
+// field-content ABNF rule in Section 3.2 of [RFC7230]."
+//
+// This function does not (yet?) properly handle the rejection of
+// strings that begin or end with SP or HTAB.
+func ValidHeaderFieldValue(v string) bool {
+ for i := 0; i < len(v); i++ {
+ b := v[i]
+ if isCTL(b) && !isLWS(b) {
+ return false
+ }
+ }
+ return true
+}
+
+func isASCII(s string) bool {
+ for i := 0; i < len(s); i++ {
+ if s[i] >= utf8.RuneSelf {
+ return false
+ }
+ }
+ return true
+}
+
+// PunycodeHostPort returns the IDNA Punycode version
+// of the provided "host" or "host:port" string.
+func PunycodeHostPort(v string) (string, error) {
+ if isASCII(v) {
+ return v, nil
+ }
+
+ host, port, err := net.SplitHostPort(v)
+ if err != nil {
+ // The input 'v' argument was just a "host" argument,
+ // without a port. This error should not be returned
+ // to the caller.
+ host = v
+ port = ""
+ }
+ host, err = idna.ToASCII(host)
+ if err != nil {
+ // Non-UTF-8? Not representable in Punycode, in any
+ // case.
+ return "", err
+ }
+ if port == "" {
+ return host, nil
+ }
+ return net.JoinHostPort(host, port), nil
+}
diff --git a/vendor/golang.org/x/net/http2/.gitignore b/vendor/golang.org/x/net/http2/.gitignore
new file mode 100644
index 0000000..190f122
--- /dev/null
+++ b/vendor/golang.org/x/net/http2/.gitignore
@@ -0,0 +1,2 @@
+*~
+h2i/h2i
diff --git a/vendor/golang.org/x/net/http2/Dockerfile b/vendor/golang.org/x/net/http2/Dockerfile
new file mode 100644
index 0000000..53fc525
--- /dev/null
+++ b/vendor/golang.org/x/net/http2/Dockerfile
@@ -0,0 +1,51 @@
+#
+# This Dockerfile builds a recent curl with HTTP/2 client support, using
+# a recent nghttp2 build.
+#
+# See the Makefile for how to tag it. If Docker and that image is found, the
+# Go tests use this curl binary for integration tests.
+#
+
+FROM ubuntu:trusty
+
+RUN apt-get update && \
+ apt-get upgrade -y && \
+ apt-get install -y git-core build-essential wget
+
+RUN apt-get install -y --no-install-recommends \
+ autotools-dev libtool pkg-config zlib1g-dev \
+ libcunit1-dev libssl-dev libxml2-dev libevent-dev \
+ automake autoconf
+
+# The list of packages nghttp2 recommends for h2load:
+RUN apt-get install -y --no-install-recommends make binutils \
+ autoconf automake autotools-dev \
+ libtool pkg-config zlib1g-dev libcunit1-dev libssl-dev libxml2-dev \
+ libev-dev libevent-dev libjansson-dev libjemalloc-dev \
+ cython python3.4-dev python-setuptools
+
+# Note: setting NGHTTP2_VER before the git clone, so an old git clone isn't cached:
+ENV NGHTTP2_VER 895da9a
+RUN cd /root && git clone https://github.com/tatsuhiro-t/nghttp2.git
+
+WORKDIR /root/nghttp2
+RUN git reset --hard $NGHTTP2_VER
+RUN autoreconf -i
+RUN automake
+RUN autoconf
+RUN ./configure
+RUN make
+RUN make install
+
+WORKDIR /root
+RUN wget http://curl.haxx.se/download/curl-7.45.0.tar.gz
+RUN tar -zxvf curl-7.45.0.tar.gz
+WORKDIR /root/curl-7.45.0
+RUN ./configure --with-ssl --with-nghttp2=/usr/local
+RUN make
+RUN make install
+RUN ldconfig
+
+CMD ["-h"]
+ENTRYPOINT ["/usr/local/bin/curl"]
+
diff --git a/vendor/golang.org/x/net/http2/Makefile b/vendor/golang.org/x/net/http2/Makefile
new file mode 100644
index 0000000..55fd826
--- /dev/null
+++ b/vendor/golang.org/x/net/http2/Makefile
@@ -0,0 +1,3 @@
+curlimage:
+ docker build -t gohttp2/curl .
+
diff --git a/vendor/golang.org/x/net/http2/README b/vendor/golang.org/x/net/http2/README
new file mode 100644
index 0000000..360d5aa
--- /dev/null
+++ b/vendor/golang.org/x/net/http2/README
@@ -0,0 +1,20 @@
+This is a work-in-progress HTTP/2 implementation for Go.
+
+It will eventually live in the Go standard library and won't require
+any changes to your code to use. It will just be automatic.
+
+Status:
+
+* The server support is pretty good. A few things are missing
+ but are being worked on.
+* The client work has just started but shares a lot of code
+ is coming along much quicker.
+
+Docs are at https://godoc.org/golang.org/x/net/http2
+
+Demo test server at https://http2.golang.org/
+
+Help & bug reports welcome!
+
+Contributing: https://golang.org/doc/contribute.html
+Bugs: https://golang.org/issue/new?title=x/net/http2:+
diff --git a/vendor/golang.org/x/net/http2/ciphers.go b/vendor/golang.org/x/net/http2/ciphers.go
new file mode 100644
index 0000000..c9a0cf3
--- /dev/null
+++ b/vendor/golang.org/x/net/http2/ciphers.go
@@ -0,0 +1,641 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package http2
+
+// A list of the possible cipher suite ids. Taken from
+// https://www.iana.org/assignments/tls-parameters/tls-parameters.txt
+
+const (
+ cipher_TLS_NULL_WITH_NULL_NULL uint16 = 0x0000
+ cipher_TLS_RSA_WITH_NULL_MD5 uint16 = 0x0001
+ cipher_TLS_RSA_WITH_NULL_SHA uint16 = 0x0002
+ cipher_TLS_RSA_EXPORT_WITH_RC4_40_MD5 uint16 = 0x0003
+ cipher_TLS_RSA_WITH_RC4_128_MD5 uint16 = 0x0004
+ cipher_TLS_RSA_WITH_RC4_128_SHA uint16 = 0x0005
+ cipher_TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5 uint16 = 0x0006
+ cipher_TLS_RSA_WITH_IDEA_CBC_SHA uint16 = 0x0007
+ cipher_TLS_RSA_EXPORT_WITH_DES40_CBC_SHA uint16 = 0x0008
+ cipher_TLS_RSA_WITH_DES_CBC_SHA uint16 = 0x0009
+ cipher_TLS_RSA_WITH_3DES_EDE_CBC_SHA uint16 = 0x000A
+ cipher_TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA uint16 = 0x000B
+ cipher_TLS_DH_DSS_WITH_DES_CBC_SHA uint16 = 0x000C
+ cipher_TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA uint16 = 0x000D
+ cipher_TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA uint16 = 0x000E
+ cipher_TLS_DH_RSA_WITH_DES_CBC_SHA uint16 = 0x000F
+ cipher_TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA uint16 = 0x0010
+ cipher_TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA uint16 = 0x0011
+ cipher_TLS_DHE_DSS_WITH_DES_CBC_SHA uint16 = 0x0012
+ cipher_TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA uint16 = 0x0013
+ cipher_TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA uint16 = 0x0014
+ cipher_TLS_DHE_RSA_WITH_DES_CBC_SHA uint16 = 0x0015
+ cipher_TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA uint16 = 0x0016
+ cipher_TLS_DH_anon_EXPORT_WITH_RC4_40_MD5 uint16 = 0x0017
+ cipher_TLS_DH_anon_WITH_RC4_128_MD5 uint16 = 0x0018
+ cipher_TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA uint16 = 0x0019
+ cipher_TLS_DH_anon_WITH_DES_CBC_SHA uint16 = 0x001A
+ cipher_TLS_DH_anon_WITH_3DES_EDE_CBC_SHA uint16 = 0x001B
+ // Reserved uint16 = 0x001C-1D
+ cipher_TLS_KRB5_WITH_DES_CBC_SHA uint16 = 0x001E
+ cipher_TLS_KRB5_WITH_3DES_EDE_CBC_SHA uint16 = 0x001F
+ cipher_TLS_KRB5_WITH_RC4_128_SHA uint16 = 0x0020
+ cipher_TLS_KRB5_WITH_IDEA_CBC_SHA uint16 = 0x0021
+ cipher_TLS_KRB5_WITH_DES_CBC_MD5 uint16 = 0x0022
+ cipher_TLS_KRB5_WITH_3DES_EDE_CBC_MD5 uint16 = 0x0023
+ cipher_TLS_KRB5_WITH_RC4_128_MD5 uint16 = 0x0024
+ cipher_TLS_KRB5_WITH_IDEA_CBC_MD5 uint16 = 0x0025
+ cipher_TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA uint16 = 0x0026
+ cipher_TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA uint16 = 0x0027
+ cipher_TLS_KRB5_EXPORT_WITH_RC4_40_SHA uint16 = 0x0028
+ cipher_TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5 uint16 = 0x0029
+ cipher_TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5 uint16 = 0x002A
+ cipher_TLS_KRB5_EXPORT_WITH_RC4_40_MD5 uint16 = 0x002B
+ cipher_TLS_PSK_WITH_NULL_SHA uint16 = 0x002C
+ cipher_TLS_DHE_PSK_WITH_NULL_SHA uint16 = 0x002D
+ cipher_TLS_RSA_PSK_WITH_NULL_SHA uint16 = 0x002E
+ cipher_TLS_RSA_WITH_AES_128_CBC_SHA uint16 = 0x002F
+ cipher_TLS_DH_DSS_WITH_AES_128_CBC_SHA uint16 = 0x0030
+ cipher_TLS_DH_RSA_WITH_AES_128_CBC_SHA uint16 = 0x0031
+ cipher_TLS_DHE_DSS_WITH_AES_128_CBC_SHA uint16 = 0x0032
+ cipher_TLS_DHE_RSA_WITH_AES_128_CBC_SHA uint16 = 0x0033
+ cipher_TLS_DH_anon_WITH_AES_128_CBC_SHA uint16 = 0x0034
+ cipher_TLS_RSA_WITH_AES_256_CBC_SHA uint16 = 0x0035
+ cipher_TLS_DH_DSS_WITH_AES_256_CBC_SHA uint16 = 0x0036
+ cipher_TLS_DH_RSA_WITH_AES_256_CBC_SHA uint16 = 0x0037
+ cipher_TLS_DHE_DSS_WITH_AES_256_CBC_SHA uint16 = 0x0038
+ cipher_TLS_DHE_RSA_WITH_AES_256_CBC_SHA uint16 = 0x0039
+ cipher_TLS_DH_anon_WITH_AES_256_CBC_SHA uint16 = 0x003A
+ cipher_TLS_RSA_WITH_NULL_SHA256 uint16 = 0x003B
+ cipher_TLS_RSA_WITH_AES_128_CBC_SHA256 uint16 = 0x003C
+ cipher_TLS_RSA_WITH_AES_256_CBC_SHA256 uint16 = 0x003D
+ cipher_TLS_DH_DSS_WITH_AES_128_CBC_SHA256 uint16 = 0x003E
+ cipher_TLS_DH_RSA_WITH_AES_128_CBC_SHA256 uint16 = 0x003F
+ cipher_TLS_DHE_DSS_WITH_AES_128_CBC_SHA256 uint16 = 0x0040
+ cipher_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA uint16 = 0x0041
+ cipher_TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA uint16 = 0x0042
+ cipher_TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA uint16 = 0x0043
+ cipher_TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA uint16 = 0x0044
+ cipher_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA uint16 = 0x0045
+ cipher_TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA uint16 = 0x0046
+ // Reserved uint16 = 0x0047-4F
+ // Reserved uint16 = 0x0050-58
+ // Reserved uint16 = 0x0059-5C
+ // Unassigned uint16 = 0x005D-5F
+ // Reserved uint16 = 0x0060-66
+ cipher_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 uint16 = 0x0067
+ cipher_TLS_DH_DSS_WITH_AES_256_CBC_SHA256 uint16 = 0x0068
+ cipher_TLS_DH_RSA_WITH_AES_256_CBC_SHA256 uint16 = 0x0069
+ cipher_TLS_DHE_DSS_WITH_AES_256_CBC_SHA256 uint16 = 0x006A
+ cipher_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 uint16 = 0x006B
+ cipher_TLS_DH_anon_WITH_AES_128_CBC_SHA256 uint16 = 0x006C
+ cipher_TLS_DH_anon_WITH_AES_256_CBC_SHA256 uint16 = 0x006D
+ // Unassigned uint16 = 0x006E-83
+ cipher_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA uint16 = 0x0084
+ cipher_TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA uint16 = 0x0085
+ cipher_TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA uint16 = 0x0086
+ cipher_TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA uint16 = 0x0087
+ cipher_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA uint16 = 0x0088
+ cipher_TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA uint16 = 0x0089
+ cipher_TLS_PSK_WITH_RC4_128_SHA uint16 = 0x008A
+ cipher_TLS_PSK_WITH_3DES_EDE_CBC_SHA uint16 = 0x008B
+ cipher_TLS_PSK_WITH_AES_128_CBC_SHA uint16 = 0x008C
+ cipher_TLS_PSK_WITH_AES_256_CBC_SHA uint16 = 0x008D
+ cipher_TLS_DHE_PSK_WITH_RC4_128_SHA uint16 = 0x008E
+ cipher_TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA uint16 = 0x008F
+ cipher_TLS_DHE_PSK_WITH_AES_128_CBC_SHA uint16 = 0x0090
+ cipher_TLS_DHE_PSK_WITH_AES_256_CBC_SHA uint16 = 0x0091
+ cipher_TLS_RSA_PSK_WITH_RC4_128_SHA uint16 = 0x0092
+ cipher_TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA uint16 = 0x0093
+ cipher_TLS_RSA_PSK_WITH_AES_128_CBC_SHA uint16 = 0x0094
+ cipher_TLS_RSA_PSK_WITH_AES_256_CBC_SHA uint16 = 0x0095
+ cipher_TLS_RSA_WITH_SEED_CBC_SHA uint16 = 0x0096
+ cipher_TLS_DH_DSS_WITH_SEED_CBC_SHA uint16 = 0x0097
+ cipher_TLS_DH_RSA_WITH_SEED_CBC_SHA uint16 = 0x0098
+ cipher_TLS_DHE_DSS_WITH_SEED_CBC_SHA uint16 = 0x0099
+ cipher_TLS_DHE_RSA_WITH_SEED_CBC_SHA uint16 = 0x009A
+ cipher_TLS_DH_anon_WITH_SEED_CBC_SHA uint16 = 0x009B
+ cipher_TLS_RSA_WITH_AES_128_GCM_SHA256 uint16 = 0x009C
+ cipher_TLS_RSA_WITH_AES_256_GCM_SHA384 uint16 = 0x009D
+ cipher_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 uint16 = 0x009E
+ cipher_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 uint16 = 0x009F
+ cipher_TLS_DH_RSA_WITH_AES_128_GCM_SHA256 uint16 = 0x00A0
+ cipher_TLS_DH_RSA_WITH_AES_256_GCM_SHA384 uint16 = 0x00A1
+ cipher_TLS_DHE_DSS_WITH_AES_128_GCM_SHA256 uint16 = 0x00A2
+ cipher_TLS_DHE_DSS_WITH_AES_256_GCM_SHA384 uint16 = 0x00A3
+ cipher_TLS_DH_DSS_WITH_AES_128_GCM_SHA256 uint16 = 0x00A4
+ cipher_TLS_DH_DSS_WITH_AES_256_GCM_SHA384 uint16 = 0x00A5
+ cipher_TLS_DH_anon_WITH_AES_128_GCM_SHA256 uint16 = 0x00A6
+ cipher_TLS_DH_anon_WITH_AES_256_GCM_SHA384 uint16 = 0x00A7
+ cipher_TLS_PSK_WITH_AES_128_GCM_SHA256 uint16 = 0x00A8
+ cipher_TLS_PSK_WITH_AES_256_GCM_SHA384 uint16 = 0x00A9
+ cipher_TLS_DHE_PSK_WITH_AES_128_GCM_SHA256 uint16 = 0x00AA
+ cipher_TLS_DHE_PSK_WITH_AES_256_GCM_SHA384 uint16 = 0x00AB
+ cipher_TLS_RSA_PSK_WITH_AES_128_GCM_SHA256 uint16 = 0x00AC
+ cipher_TLS_RSA_PSK_WITH_AES_256_GCM_SHA384 uint16 = 0x00AD
+ cipher_TLS_PSK_WITH_AES_128_CBC_SHA256 uint16 = 0x00AE
+ cipher_TLS_PSK_WITH_AES_256_CBC_SHA384 uint16 = 0x00AF
+ cipher_TLS_PSK_WITH_NULL_SHA256 uint16 = 0x00B0
+ cipher_TLS_PSK_WITH_NULL_SHA384 uint16 = 0x00B1
+ cipher_TLS_DHE_PSK_WITH_AES_128_CBC_SHA256 uint16 = 0x00B2
+ cipher_TLS_DHE_PSK_WITH_AES_256_CBC_SHA384 uint16 = 0x00B3
+ cipher_TLS_DHE_PSK_WITH_NULL_SHA256 uint16 = 0x00B4
+ cipher_TLS_DHE_PSK_WITH_NULL_SHA384 uint16 = 0x00B5
+ cipher_TLS_RSA_PSK_WITH_AES_128_CBC_SHA256 uint16 = 0x00B6
+ cipher_TLS_RSA_PSK_WITH_AES_256_CBC_SHA384 uint16 = 0x00B7
+ cipher_TLS_RSA_PSK_WITH_NULL_SHA256 uint16 = 0x00B8
+ cipher_TLS_RSA_PSK_WITH_NULL_SHA384 uint16 = 0x00B9
+ cipher_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256 uint16 = 0x00BA
+ cipher_TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256 uint16 = 0x00BB
+ cipher_TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256 uint16 = 0x00BC
+ cipher_TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256 uint16 = 0x00BD
+ cipher_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 uint16 = 0x00BE
+ cipher_TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256 uint16 = 0x00BF
+ cipher_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256 uint16 = 0x00C0
+ cipher_TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256 uint16 = 0x00C1
+ cipher_TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256 uint16 = 0x00C2
+ cipher_TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256 uint16 = 0x00C3
+ cipher_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 uint16 = 0x00C4
+ cipher_TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256 uint16 = 0x00C5
+ // Unassigned uint16 = 0x00C6-FE
+ cipher_TLS_EMPTY_RENEGOTIATION_INFO_SCSV uint16 = 0x00FF
+ // Unassigned uint16 = 0x01-55,*
+ cipher_TLS_FALLBACK_SCSV uint16 = 0x5600
+ // Unassigned uint16 = 0x5601 - 0xC000
+ cipher_TLS_ECDH_ECDSA_WITH_NULL_SHA uint16 = 0xC001
+ cipher_TLS_ECDH_ECDSA_WITH_RC4_128_SHA uint16 = 0xC002
+ cipher_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA uint16 = 0xC003
+ cipher_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA uint16 = 0xC004
+ cipher_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA uint16 = 0xC005
+ cipher_TLS_ECDHE_ECDSA_WITH_NULL_SHA uint16 = 0xC006
+ cipher_TLS_ECDHE_ECDSA_WITH_RC4_128_SHA uint16 = 0xC007
+ cipher_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA uint16 = 0xC008
+ cipher_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA uint16 = 0xC009
+ cipher_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA uint16 = 0xC00A
+ cipher_TLS_ECDH_RSA_WITH_NULL_SHA uint16 = 0xC00B
+ cipher_TLS_ECDH_RSA_WITH_RC4_128_SHA uint16 = 0xC00C
+ cipher_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA uint16 = 0xC00D
+ cipher_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA uint16 = 0xC00E
+ cipher_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA uint16 = 0xC00F
+ cipher_TLS_ECDHE_RSA_WITH_NULL_SHA uint16 = 0xC010
+ cipher_TLS_ECDHE_RSA_WITH_RC4_128_SHA uint16 = 0xC011
+ cipher_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA uint16 = 0xC012
+ cipher_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA uint16 = 0xC013
+ cipher_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA uint16 = 0xC014
+ cipher_TLS_ECDH_anon_WITH_NULL_SHA uint16 = 0xC015
+ cipher_TLS_ECDH_anon_WITH_RC4_128_SHA uint16 = 0xC016
+ cipher_TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA uint16 = 0xC017
+ cipher_TLS_ECDH_anon_WITH_AES_128_CBC_SHA uint16 = 0xC018
+ cipher_TLS_ECDH_anon_WITH_AES_256_CBC_SHA uint16 = 0xC019
+ cipher_TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA uint16 = 0xC01A
+ cipher_TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA uint16 = 0xC01B
+ cipher_TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA uint16 = 0xC01C
+ cipher_TLS_SRP_SHA_WITH_AES_128_CBC_SHA uint16 = 0xC01D
+ cipher_TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA uint16 = 0xC01E
+ cipher_TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA uint16 = 0xC01F
+ cipher_TLS_SRP_SHA_WITH_AES_256_CBC_SHA uint16 = 0xC020
+ cipher_TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA uint16 = 0xC021
+ cipher_TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA uint16 = 0xC022
+ cipher_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 uint16 = 0xC023
+ cipher_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 uint16 = 0xC024
+ cipher_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 uint16 = 0xC025
+ cipher_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 uint16 = 0xC026
+ cipher_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 uint16 = 0xC027
+ cipher_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 uint16 = 0xC028
+ cipher_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 uint16 = 0xC029
+ cipher_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 uint16 = 0xC02A
+ cipher_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 uint16 = 0xC02B
+ cipher_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 uint16 = 0xC02C
+ cipher_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 uint16 = 0xC02D
+ cipher_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 uint16 = 0xC02E
+ cipher_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 uint16 = 0xC02F
+ cipher_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 uint16 = 0xC030
+ cipher_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 uint16 = 0xC031
+ cipher_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 uint16 = 0xC032
+ cipher_TLS_ECDHE_PSK_WITH_RC4_128_SHA uint16 = 0xC033
+ cipher_TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA uint16 = 0xC034
+ cipher_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA uint16 = 0xC035
+ cipher_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA uint16 = 0xC036
+ cipher_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256 uint16 = 0xC037
+ cipher_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384 uint16 = 0xC038
+ cipher_TLS_ECDHE_PSK_WITH_NULL_SHA uint16 = 0xC039
+ cipher_TLS_ECDHE_PSK_WITH_NULL_SHA256 uint16 = 0xC03A
+ cipher_TLS_ECDHE_PSK_WITH_NULL_SHA384 uint16 = 0xC03B
+ cipher_TLS_RSA_WITH_ARIA_128_CBC_SHA256 uint16 = 0xC03C
+ cipher_TLS_RSA_WITH_ARIA_256_CBC_SHA384 uint16 = 0xC03D
+ cipher_TLS_DH_DSS_WITH_ARIA_128_CBC_SHA256 uint16 = 0xC03E
+ cipher_TLS_DH_DSS_WITH_ARIA_256_CBC_SHA384 uint16 = 0xC03F
+ cipher_TLS_DH_RSA_WITH_ARIA_128_CBC_SHA256 uint16 = 0xC040
+ cipher_TLS_DH_RSA_WITH_ARIA_256_CBC_SHA384 uint16 = 0xC041
+ cipher_TLS_DHE_DSS_WITH_ARIA_128_CBC_SHA256 uint16 = 0xC042
+ cipher_TLS_DHE_DSS_WITH_ARIA_256_CBC_SHA384 uint16 = 0xC043
+ cipher_TLS_DHE_RSA_WITH_ARIA_128_CBC_SHA256 uint16 = 0xC044
+ cipher_TLS_DHE_RSA_WITH_ARIA_256_CBC_SHA384 uint16 = 0xC045
+ cipher_TLS_DH_anon_WITH_ARIA_128_CBC_SHA256 uint16 = 0xC046
+ cipher_TLS_DH_anon_WITH_ARIA_256_CBC_SHA384 uint16 = 0xC047
+ cipher_TLS_ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256 uint16 = 0xC048
+ cipher_TLS_ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384 uint16 = 0xC049
+ cipher_TLS_ECDH_ECDSA_WITH_ARIA_128_CBC_SHA256 uint16 = 0xC04A
+ cipher_TLS_ECDH_ECDSA_WITH_ARIA_256_CBC_SHA384 uint16 = 0xC04B
+ cipher_TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256 uint16 = 0xC04C
+ cipher_TLS_ECDHE_RSA_WITH_ARIA_256_CBC_SHA384 uint16 = 0xC04D
+ cipher_TLS_ECDH_RSA_WITH_ARIA_128_CBC_SHA256 uint16 = 0xC04E
+ cipher_TLS_ECDH_RSA_WITH_ARIA_256_CBC_SHA384 uint16 = 0xC04F
+ cipher_TLS_RSA_WITH_ARIA_128_GCM_SHA256 uint16 = 0xC050
+ cipher_TLS_RSA_WITH_ARIA_256_GCM_SHA384 uint16 = 0xC051
+ cipher_TLS_DHE_RSA_WITH_ARIA_128_GCM_SHA256 uint16 = 0xC052
+ cipher_TLS_DHE_RSA_WITH_ARIA_256_GCM_SHA384 uint16 = 0xC053
+ cipher_TLS_DH_RSA_WITH_ARIA_128_GCM_SHA256 uint16 = 0xC054
+ cipher_TLS_DH_RSA_WITH_ARIA_256_GCM_SHA384 uint16 = 0xC055
+ cipher_TLS_DHE_DSS_WITH_ARIA_128_GCM_SHA256 uint16 = 0xC056
+ cipher_TLS_DHE_DSS_WITH_ARIA_256_GCM_SHA384 uint16 = 0xC057
+ cipher_TLS_DH_DSS_WITH_ARIA_128_GCM_SHA256 uint16 = 0xC058
+ cipher_TLS_DH_DSS_WITH_ARIA_256_GCM_SHA384 uint16 = 0xC059
+ cipher_TLS_DH_anon_WITH_ARIA_128_GCM_SHA256 uint16 = 0xC05A
+ cipher_TLS_DH_anon_WITH_ARIA_256_GCM_SHA384 uint16 = 0xC05B
+ cipher_TLS_ECDHE_ECDSA_WITH_ARIA_128_GCM_SHA256 uint16 = 0xC05C
+ cipher_TLS_ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384 uint16 = 0xC05D
+ cipher_TLS_ECDH_ECDSA_WITH_ARIA_128_GCM_SHA256 uint16 = 0xC05E
+ cipher_TLS_ECDH_ECDSA_WITH_ARIA_256_GCM_SHA384 uint16 = 0xC05F
+ cipher_TLS_ECDHE_RSA_WITH_ARIA_128_GCM_SHA256 uint16 = 0xC060
+ cipher_TLS_ECDHE_RSA_WITH_ARIA_256_GCM_SHA384 uint16 = 0xC061
+ cipher_TLS_ECDH_RSA_WITH_ARIA_128_GCM_SHA256 uint16 = 0xC062
+ cipher_TLS_ECDH_RSA_WITH_ARIA_256_GCM_SHA384 uint16 = 0xC063
+ cipher_TLS_PSK_WITH_ARIA_128_CBC_SHA256 uint16 = 0xC064
+ cipher_TLS_PSK_WITH_ARIA_256_CBC_SHA384 uint16 = 0xC065
+ cipher_TLS_DHE_PSK_WITH_ARIA_128_CBC_SHA256 uint16 = 0xC066
+ cipher_TLS_DHE_PSK_WITH_ARIA_256_CBC_SHA384 uint16 = 0xC067
+ cipher_TLS_RSA_PSK_WITH_ARIA_128_CBC_SHA256 uint16 = 0xC068
+ cipher_TLS_RSA_PSK_WITH_ARIA_256_CBC_SHA384 uint16 = 0xC069
+ cipher_TLS_PSK_WITH_ARIA_128_GCM_SHA256 uint16 = 0xC06A
+ cipher_TLS_PSK_WITH_ARIA_256_GCM_SHA384 uint16 = 0xC06B
+ cipher_TLS_DHE_PSK_WITH_ARIA_128_GCM_SHA256 uint16 = 0xC06C
+ cipher_TLS_DHE_PSK_WITH_ARIA_256_GCM_SHA384 uint16 = 0xC06D
+ cipher_TLS_RSA_PSK_WITH_ARIA_128_GCM_SHA256 uint16 = 0xC06E
+ cipher_TLS_RSA_PSK_WITH_ARIA_256_GCM_SHA384 uint16 = 0xC06F
+ cipher_TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256 uint16 = 0xC070
+ cipher_TLS_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384 uint16 = 0xC071
+ cipher_TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 uint16 = 0xC072
+ cipher_TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 uint16 = 0xC073
+ cipher_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 uint16 = 0xC074
+ cipher_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 uint16 = 0xC075
+ cipher_TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 uint16 = 0xC076
+ cipher_TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384 uint16 = 0xC077
+ cipher_TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256 uint16 = 0xC078
+ cipher_TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384 uint16 = 0xC079
+ cipher_TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256 uint16 = 0xC07A
+ cipher_TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384 uint16 = 0xC07B
+ cipher_TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 uint16 = 0xC07C
+ cipher_TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 uint16 = 0xC07D
+ cipher_TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256 uint16 = 0xC07E
+ cipher_TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384 uint16 = 0xC07F
+ cipher_TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256 uint16 = 0xC080
+ cipher_TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384 uint16 = 0xC081
+ cipher_TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256 uint16 = 0xC082
+ cipher_TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384 uint16 = 0xC083
+ cipher_TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256 uint16 = 0xC084
+ cipher_TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384 uint16 = 0xC085
+ cipher_TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 uint16 = 0xC086
+ cipher_TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 uint16 = 0xC087
+ cipher_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 uint16 = 0xC088
+ cipher_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 uint16 = 0xC089
+ cipher_TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 uint16 = 0xC08A
+ cipher_TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 uint16 = 0xC08B
+ cipher_TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256 uint16 = 0xC08C
+ cipher_TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384 uint16 = 0xC08D
+ cipher_TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256 uint16 = 0xC08E
+ cipher_TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384 uint16 = 0xC08F
+ cipher_TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256 uint16 = 0xC090
+ cipher_TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384 uint16 = 0xC091
+ cipher_TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256 uint16 = 0xC092
+ cipher_TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384 uint16 = 0xC093
+ cipher_TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256 uint16 = 0xC094
+ cipher_TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384 uint16 = 0xC095
+ cipher_TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 uint16 = 0xC096
+ cipher_TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 uint16 = 0xC097
+ cipher_TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256 uint16 = 0xC098
+ cipher_TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384 uint16 = 0xC099
+ cipher_TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 uint16 = 0xC09A
+ cipher_TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 uint16 = 0xC09B
+ cipher_TLS_RSA_WITH_AES_128_CCM uint16 = 0xC09C
+ cipher_TLS_RSA_WITH_AES_256_CCM uint16 = 0xC09D
+ cipher_TLS_DHE_RSA_WITH_AES_128_CCM uint16 = 0xC09E
+ cipher_TLS_DHE_RSA_WITH_AES_256_CCM uint16 = 0xC09F
+ cipher_TLS_RSA_WITH_AES_128_CCM_8 uint16 = 0xC0A0
+ cipher_TLS_RSA_WITH_AES_256_CCM_8 uint16 = 0xC0A1
+ cipher_TLS_DHE_RSA_WITH_AES_128_CCM_8 uint16 = 0xC0A2
+ cipher_TLS_DHE_RSA_WITH_AES_256_CCM_8 uint16 = 0xC0A3
+ cipher_TLS_PSK_WITH_AES_128_CCM uint16 = 0xC0A4
+ cipher_TLS_PSK_WITH_AES_256_CCM uint16 = 0xC0A5
+ cipher_TLS_DHE_PSK_WITH_AES_128_CCM uint16 = 0xC0A6
+ cipher_TLS_DHE_PSK_WITH_AES_256_CCM uint16 = 0xC0A7
+ cipher_TLS_PSK_WITH_AES_128_CCM_8 uint16 = 0xC0A8
+ cipher_TLS_PSK_WITH_AES_256_CCM_8 uint16 = 0xC0A9
+ cipher_TLS_PSK_DHE_WITH_AES_128_CCM_8 uint16 = 0xC0AA
+ cipher_TLS_PSK_DHE_WITH_AES_256_CCM_8 uint16 = 0xC0AB
+ cipher_TLS_ECDHE_ECDSA_WITH_AES_128_CCM uint16 = 0xC0AC
+ cipher_TLS_ECDHE_ECDSA_WITH_AES_256_CCM uint16 = 0xC0AD
+ cipher_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 uint16 = 0xC0AE
+ cipher_TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8 uint16 = 0xC0AF
+ // Unassigned uint16 = 0xC0B0-FF
+ // Unassigned uint16 = 0xC1-CB,*
+ // Unassigned uint16 = 0xCC00-A7
+ cipher_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 uint16 = 0xCCA8
+ cipher_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 uint16 = 0xCCA9
+ cipher_TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 uint16 = 0xCCAA
+ cipher_TLS_PSK_WITH_CHACHA20_POLY1305_SHA256 uint16 = 0xCCAB
+ cipher_TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256 uint16 = 0xCCAC
+ cipher_TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256 uint16 = 0xCCAD
+ cipher_TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256 uint16 = 0xCCAE
+)
+
+// isBadCipher reports whether the cipher is blacklisted by the HTTP/2 spec.
+// References:
+// https://tools.ietf.org/html/rfc7540#appendix-A
+// Reject cipher suites from Appendix A.
+// "This list includes those cipher suites that do not
+// offer an ephemeral key exchange and those that are
+// based on the TLS null, stream or block cipher type"
+func isBadCipher(cipher uint16) bool {
+ switch cipher {
+ case cipher_TLS_NULL_WITH_NULL_NULL,
+ cipher_TLS_RSA_WITH_NULL_MD5,
+ cipher_TLS_RSA_WITH_NULL_SHA,
+ cipher_TLS_RSA_EXPORT_WITH_RC4_40_MD5,
+ cipher_TLS_RSA_WITH_RC4_128_MD5,
+ cipher_TLS_RSA_WITH_RC4_128_SHA,
+ cipher_TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5,
+ cipher_TLS_RSA_WITH_IDEA_CBC_SHA,
+ cipher_TLS_RSA_EXPORT_WITH_DES40_CBC_SHA,
+ cipher_TLS_RSA_WITH_DES_CBC_SHA,
+ cipher_TLS_RSA_WITH_3DES_EDE_CBC_SHA,
+ cipher_TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA,
+ cipher_TLS_DH_DSS_WITH_DES_CBC_SHA,
+ cipher_TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA,
+ cipher_TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA,
+ cipher_TLS_DH_RSA_WITH_DES_CBC_SHA,
+ cipher_TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA,
+ cipher_TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA,
+ cipher_TLS_DHE_DSS_WITH_DES_CBC_SHA,
+ cipher_TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA,
+ cipher_TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA,
+ cipher_TLS_DHE_RSA_WITH_DES_CBC_SHA,
+ cipher_TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA,
+ cipher_TLS_DH_anon_EXPORT_WITH_RC4_40_MD5,
+ cipher_TLS_DH_anon_WITH_RC4_128_MD5,
+ cipher_TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA,
+ cipher_TLS_DH_anon_WITH_DES_CBC_SHA,
+ cipher_TLS_DH_anon_WITH_3DES_EDE_CBC_SHA,
+ cipher_TLS_KRB5_WITH_DES_CBC_SHA,
+ cipher_TLS_KRB5_WITH_3DES_EDE_CBC_SHA,
+ cipher_TLS_KRB5_WITH_RC4_128_SHA,
+ cipher_TLS_KRB5_WITH_IDEA_CBC_SHA,
+ cipher_TLS_KRB5_WITH_DES_CBC_MD5,
+ cipher_TLS_KRB5_WITH_3DES_EDE_CBC_MD5,
+ cipher_TLS_KRB5_WITH_RC4_128_MD5,
+ cipher_TLS_KRB5_WITH_IDEA_CBC_MD5,
+ cipher_TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA,
+ cipher_TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA,
+ cipher_TLS_KRB5_EXPORT_WITH_RC4_40_SHA,
+ cipher_TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5,
+ cipher_TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5,
+ cipher_TLS_KRB5_EXPORT_WITH_RC4_40_MD5,
+ cipher_TLS_PSK_WITH_NULL_SHA,
+ cipher_TLS_DHE_PSK_WITH_NULL_SHA,
+ cipher_TLS_RSA_PSK_WITH_NULL_SHA,
+ cipher_TLS_RSA_WITH_AES_128_CBC_SHA,
+ cipher_TLS_DH_DSS_WITH_AES_128_CBC_SHA,
+ cipher_TLS_DH_RSA_WITH_AES_128_CBC_SHA,
+ cipher_TLS_DHE_DSS_WITH_AES_128_CBC_SHA,
+ cipher_TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
+ cipher_TLS_DH_anon_WITH_AES_128_CBC_SHA,
+ cipher_TLS_RSA_WITH_AES_256_CBC_SHA,
+ cipher_TLS_DH_DSS_WITH_AES_256_CBC_SHA,
+ cipher_TLS_DH_RSA_WITH_AES_256_CBC_SHA,
+ cipher_TLS_DHE_DSS_WITH_AES_256_CBC_SHA,
+ cipher_TLS_DHE_RSA_WITH_AES_256_CBC_SHA,
+ cipher_TLS_DH_anon_WITH_AES_256_CBC_SHA,
+ cipher_TLS_RSA_WITH_NULL_SHA256,
+ cipher_TLS_RSA_WITH_AES_128_CBC_SHA256,
+ cipher_TLS_RSA_WITH_AES_256_CBC_SHA256,
+ cipher_TLS_DH_DSS_WITH_AES_128_CBC_SHA256,
+ cipher_TLS_DH_RSA_WITH_AES_128_CBC_SHA256,
+ cipher_TLS_DHE_DSS_WITH_AES_128_CBC_SHA256,
+ cipher_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA,
+ cipher_TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA,
+ cipher_TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA,
+ cipher_TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA,
+ cipher_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA,
+ cipher_TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA,
+ cipher_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,
+ cipher_TLS_DH_DSS_WITH_AES_256_CBC_SHA256,
+ cipher_TLS_DH_RSA_WITH_AES_256_CBC_SHA256,
+ cipher_TLS_DHE_DSS_WITH_AES_256_CBC_SHA256,
+ cipher_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256,
+ cipher_TLS_DH_anon_WITH_AES_128_CBC_SHA256,
+ cipher_TLS_DH_anon_WITH_AES_256_CBC_SHA256,
+ cipher_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA,
+ cipher_TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA,
+ cipher_TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA,
+ cipher_TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA,
+ cipher_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA,
+ cipher_TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA,
+ cipher_TLS_PSK_WITH_RC4_128_SHA,
+ cipher_TLS_PSK_WITH_3DES_EDE_CBC_SHA,
+ cipher_TLS_PSK_WITH_AES_128_CBC_SHA,
+ cipher_TLS_PSK_WITH_AES_256_CBC_SHA,
+ cipher_TLS_DHE_PSK_WITH_RC4_128_SHA,
+ cipher_TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA,
+ cipher_TLS_DHE_PSK_WITH_AES_128_CBC_SHA,
+ cipher_TLS_DHE_PSK_WITH_AES_256_CBC_SHA,
+ cipher_TLS_RSA_PSK_WITH_RC4_128_SHA,
+ cipher_TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA,
+ cipher_TLS_RSA_PSK_WITH_AES_128_CBC_SHA,
+ cipher_TLS_RSA_PSK_WITH_AES_256_CBC_SHA,
+ cipher_TLS_RSA_WITH_SEED_CBC_SHA,
+ cipher_TLS_DH_DSS_WITH_SEED_CBC_SHA,
+ cipher_TLS_DH_RSA_WITH_SEED_CBC_SHA,
+ cipher_TLS_DHE_DSS_WITH_SEED_CBC_SHA,
+ cipher_TLS_DHE_RSA_WITH_SEED_CBC_SHA,
+ cipher_TLS_DH_anon_WITH_SEED_CBC_SHA,
+ cipher_TLS_RSA_WITH_AES_128_GCM_SHA256,
+ cipher_TLS_RSA_WITH_AES_256_GCM_SHA384,
+ cipher_TLS_DH_RSA_WITH_AES_128_GCM_SHA256,
+ cipher_TLS_DH_RSA_WITH_AES_256_GCM_SHA384,
+ cipher_TLS_DH_DSS_WITH_AES_128_GCM_SHA256,
+ cipher_TLS_DH_DSS_WITH_AES_256_GCM_SHA384,
+ cipher_TLS_DH_anon_WITH_AES_128_GCM_SHA256,
+ cipher_TLS_DH_anon_WITH_AES_256_GCM_SHA384,
+ cipher_TLS_PSK_WITH_AES_128_GCM_SHA256,
+ cipher_TLS_PSK_WITH_AES_256_GCM_SHA384,
+ cipher_TLS_RSA_PSK_WITH_AES_128_GCM_SHA256,
+ cipher_TLS_RSA_PSK_WITH_AES_256_GCM_SHA384,
+ cipher_TLS_PSK_WITH_AES_128_CBC_SHA256,
+ cipher_TLS_PSK_WITH_AES_256_CBC_SHA384,
+ cipher_TLS_PSK_WITH_NULL_SHA256,
+ cipher_TLS_PSK_WITH_NULL_SHA384,
+ cipher_TLS_DHE_PSK_WITH_AES_128_CBC_SHA256,
+ cipher_TLS_DHE_PSK_WITH_AES_256_CBC_SHA384,
+ cipher_TLS_DHE_PSK_WITH_NULL_SHA256,
+ cipher_TLS_DHE_PSK_WITH_NULL_SHA384,
+ cipher_TLS_RSA_PSK_WITH_AES_128_CBC_SHA256,
+ cipher_TLS_RSA_PSK_WITH_AES_256_CBC_SHA384,
+ cipher_TLS_RSA_PSK_WITH_NULL_SHA256,
+ cipher_TLS_RSA_PSK_WITH_NULL_SHA384,
+ cipher_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256,
+ cipher_TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256,
+ cipher_TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256,
+ cipher_TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256,
+ cipher_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256,
+ cipher_TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256,
+ cipher_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256,
+ cipher_TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256,
+ cipher_TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256,
+ cipher_TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256,
+ cipher_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256,
+ cipher_TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256,
+ cipher_TLS_EMPTY_RENEGOTIATION_INFO_SCSV,
+ cipher_TLS_ECDH_ECDSA_WITH_NULL_SHA,
+ cipher_TLS_ECDH_ECDSA_WITH_RC4_128_SHA,
+ cipher_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA,
+ cipher_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA,
+ cipher_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA,
+ cipher_TLS_ECDHE_ECDSA_WITH_NULL_SHA,
+ cipher_TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
+ cipher_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,
+ cipher_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
+ cipher_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
+ cipher_TLS_ECDH_RSA_WITH_NULL_SHA,
+ cipher_TLS_ECDH_RSA_WITH_RC4_128_SHA,
+ cipher_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA,
+ cipher_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA,
+ cipher_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA,
+ cipher_TLS_ECDHE_RSA_WITH_NULL_SHA,
+ cipher_TLS_ECDHE_RSA_WITH_RC4_128_SHA,
+ cipher_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
+ cipher_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
+ cipher_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
+ cipher_TLS_ECDH_anon_WITH_NULL_SHA,
+ cipher_TLS_ECDH_anon_WITH_RC4_128_SHA,
+ cipher_TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA,
+ cipher_TLS_ECDH_anon_WITH_AES_128_CBC_SHA,
+ cipher_TLS_ECDH_anon_WITH_AES_256_CBC_SHA,
+ cipher_TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA,
+ cipher_TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA,
+ cipher_TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA,
+ cipher_TLS_SRP_SHA_WITH_AES_128_CBC_SHA,
+ cipher_TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA,
+ cipher_TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA,
+ cipher_TLS_SRP_SHA_WITH_AES_256_CBC_SHA,
+ cipher_TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA,
+ cipher_TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA,
+ cipher_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
+ cipher_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,
+ cipher_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256,
+ cipher_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384,
+ cipher_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
+ cipher_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,
+ cipher_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256,
+ cipher_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384,
+ cipher_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256,
+ cipher_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384,
+ cipher_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256,
+ cipher_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384,
+ cipher_TLS_ECDHE_PSK_WITH_RC4_128_SHA,
+ cipher_TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA,
+ cipher_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA,
+ cipher_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA,
+ cipher_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256,
+ cipher_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384,
+ cipher_TLS_ECDHE_PSK_WITH_NULL_SHA,
+ cipher_TLS_ECDHE_PSK_WITH_NULL_SHA256,
+ cipher_TLS_ECDHE_PSK_WITH_NULL_SHA384,
+ cipher_TLS_RSA_WITH_ARIA_128_CBC_SHA256,
+ cipher_TLS_RSA_WITH_ARIA_256_CBC_SHA384,
+ cipher_TLS_DH_DSS_WITH_ARIA_128_CBC_SHA256,
+ cipher_TLS_DH_DSS_WITH_ARIA_256_CBC_SHA384,
+ cipher_TLS_DH_RSA_WITH_ARIA_128_CBC_SHA256,
+ cipher_TLS_DH_RSA_WITH_ARIA_256_CBC_SHA384,
+ cipher_TLS_DHE_DSS_WITH_ARIA_128_CBC_SHA256,
+ cipher_TLS_DHE_DSS_WITH_ARIA_256_CBC_SHA384,
+ cipher_TLS_DHE_RSA_WITH_ARIA_128_CBC_SHA256,
+ cipher_TLS_DHE_RSA_WITH_ARIA_256_CBC_SHA384,
+ cipher_TLS_DH_anon_WITH_ARIA_128_CBC_SHA256,
+ cipher_TLS_DH_anon_WITH_ARIA_256_CBC_SHA384,
+ cipher_TLS_ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256,
+ cipher_TLS_ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384,
+ cipher_TLS_ECDH_ECDSA_WITH_ARIA_128_CBC_SHA256,
+ cipher_TLS_ECDH_ECDSA_WITH_ARIA_256_CBC_SHA384,
+ cipher_TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256,
+ cipher_TLS_ECDHE_RSA_WITH_ARIA_256_CBC_SHA384,
+ cipher_TLS_ECDH_RSA_WITH_ARIA_128_CBC_SHA256,
+ cipher_TLS_ECDH_RSA_WITH_ARIA_256_CBC_SHA384,
+ cipher_TLS_RSA_WITH_ARIA_128_GCM_SHA256,
+ cipher_TLS_RSA_WITH_ARIA_256_GCM_SHA384,
+ cipher_TLS_DH_RSA_WITH_ARIA_128_GCM_SHA256,
+ cipher_TLS_DH_RSA_WITH_ARIA_256_GCM_SHA384,
+ cipher_TLS_DH_DSS_WITH_ARIA_128_GCM_SHA256,
+ cipher_TLS_DH_DSS_WITH_ARIA_256_GCM_SHA384,
+ cipher_TLS_DH_anon_WITH_ARIA_128_GCM_SHA256,
+ cipher_TLS_DH_anon_WITH_ARIA_256_GCM_SHA384,
+ cipher_TLS_ECDH_ECDSA_WITH_ARIA_128_GCM_SHA256,
+ cipher_TLS_ECDH_ECDSA_WITH_ARIA_256_GCM_SHA384,
+ cipher_TLS_ECDH_RSA_WITH_ARIA_128_GCM_SHA256,
+ cipher_TLS_ECDH_RSA_WITH_ARIA_256_GCM_SHA384,
+ cipher_TLS_PSK_WITH_ARIA_128_CBC_SHA256,
+ cipher_TLS_PSK_WITH_ARIA_256_CBC_SHA384,
+ cipher_TLS_DHE_PSK_WITH_ARIA_128_CBC_SHA256,
+ cipher_TLS_DHE_PSK_WITH_ARIA_256_CBC_SHA384,
+ cipher_TLS_RSA_PSK_WITH_ARIA_128_CBC_SHA256,
+ cipher_TLS_RSA_PSK_WITH_ARIA_256_CBC_SHA384,
+ cipher_TLS_PSK_WITH_ARIA_128_GCM_SHA256,
+ cipher_TLS_PSK_WITH_ARIA_256_GCM_SHA384,
+ cipher_TLS_RSA_PSK_WITH_ARIA_128_GCM_SHA256,
+ cipher_TLS_RSA_PSK_WITH_ARIA_256_GCM_SHA384,
+ cipher_TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256,
+ cipher_TLS_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384,
+ cipher_TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256,
+ cipher_TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384,
+ cipher_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256,
+ cipher_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384,
+ cipher_TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256,
+ cipher_TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384,
+ cipher_TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256,
+ cipher_TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384,
+ cipher_TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256,
+ cipher_TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384,
+ cipher_TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256,
+ cipher_TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384,
+ cipher_TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256,
+ cipher_TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384,
+ cipher_TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256,
+ cipher_TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384,
+ cipher_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256,
+ cipher_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384,
+ cipher_TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256,
+ cipher_TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384,
+ cipher_TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256,
+ cipher_TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384,
+ cipher_TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256,
+ cipher_TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384,
+ cipher_TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256,
+ cipher_TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384,
+ cipher_TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256,
+ cipher_TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384,
+ cipher_TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256,
+ cipher_TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384,
+ cipher_TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256,
+ cipher_TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384,
+ cipher_TLS_RSA_WITH_AES_128_CCM,
+ cipher_TLS_RSA_WITH_AES_256_CCM,
+ cipher_TLS_RSA_WITH_AES_128_CCM_8,
+ cipher_TLS_RSA_WITH_AES_256_CCM_8,
+ cipher_TLS_PSK_WITH_AES_128_CCM,
+ cipher_TLS_PSK_WITH_AES_256_CCM,
+ cipher_TLS_PSK_WITH_AES_128_CCM_8,
+ cipher_TLS_PSK_WITH_AES_256_CCM_8:
+ return true
+ default:
+ return false
+ }
+}
diff --git a/vendor/golang.org/x/net/http2/client_conn_pool.go b/vendor/golang.org/x/net/http2/client_conn_pool.go
new file mode 100644
index 0000000..f4d9b5e
--- /dev/null
+++ b/vendor/golang.org/x/net/http2/client_conn_pool.go
@@ -0,0 +1,282 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Transport code's client connection pooling.
+
+package http2
+
+import (
+ "crypto/tls"
+ "net/http"
+ "sync"
+)
+
+// ClientConnPool manages a pool of HTTP/2 client connections.
+type ClientConnPool interface {
+ GetClientConn(req *http.Request, addr string) (*ClientConn, error)
+ MarkDead(*ClientConn)
+}
+
+// clientConnPoolIdleCloser is the interface implemented by ClientConnPool
+// implementations which can close their idle connections.
+type clientConnPoolIdleCloser interface {
+ ClientConnPool
+ closeIdleConnections()
+}
+
+var (
+ _ clientConnPoolIdleCloser = (*clientConnPool)(nil)
+ _ clientConnPoolIdleCloser = noDialClientConnPool{}
+)
+
+// TODO: use singleflight for dialing and addConnCalls?
+type clientConnPool struct {
+ t *Transport
+
+ mu sync.Mutex // TODO: maybe switch to RWMutex
+ // TODO: add support for sharing conns based on cert names
+ // (e.g. share conn for googleapis.com and appspot.com)
+ conns map[string][]*ClientConn // key is host:port
+ dialing map[string]*dialCall // currently in-flight dials
+ keys map[*ClientConn][]string
+ addConnCalls map[string]*addConnCall // in-flight addConnIfNeede calls
+}
+
+func (p *clientConnPool) GetClientConn(req *http.Request, addr string) (*ClientConn, error) {
+ return p.getClientConn(req, addr, dialOnMiss)
+}
+
+const (
+ dialOnMiss = true
+ noDialOnMiss = false
+)
+
+// shouldTraceGetConn reports whether getClientConn should call any
+// ClientTrace.GetConn hook associated with the http.Request.
+//
+// This complexity is needed to avoid double calls of the GetConn hook
+// during the back-and-forth between net/http and x/net/http2 (when the
+// net/http.Transport is upgraded to also speak http2), as well as support
+// the case where x/net/http2 is being used directly.
+func (p *clientConnPool) shouldTraceGetConn(st clientConnIdleState) bool {
+ // If our Transport wasn't made via ConfigureTransport, always
+ // trace the GetConn hook if provided, because that means the
+ // http2 package is being used directly and it's the one
+ // dialing, as opposed to net/http.
+ if _, ok := p.t.ConnPool.(noDialClientConnPool); !ok {
+ return true
+ }
+ // Otherwise, only use the GetConn hook if this connection has
+ // been used previously for other requests. For fresh
+ // connections, the net/http package does the dialing.
+ return !st.freshConn
+}
+
+func (p *clientConnPool) getClientConn(req *http.Request, addr string, dialOnMiss bool) (*ClientConn, error) {
+ if isConnectionCloseRequest(req) && dialOnMiss {
+ // It gets its own connection.
+ traceGetConn(req, addr)
+ const singleUse = true
+ cc, err := p.t.dialClientConn(addr, singleUse)
+ if err != nil {
+ return nil, err
+ }
+ return cc, nil
+ }
+ p.mu.Lock()
+ for _, cc := range p.conns[addr] {
+ if st := cc.idleState(); st.canTakeNewRequest {
+ if p.shouldTraceGetConn(st) {
+ traceGetConn(req, addr)
+ }
+ p.mu.Unlock()
+ return cc, nil
+ }
+ }
+ if !dialOnMiss {
+ p.mu.Unlock()
+ return nil, ErrNoCachedConn
+ }
+ traceGetConn(req, addr)
+ call := p.getStartDialLocked(addr)
+ p.mu.Unlock()
+ <-call.done
+ return call.res, call.err
+}
+
+// dialCall is an in-flight Transport dial call to a host.
+type dialCall struct {
+ p *clientConnPool
+ done chan struct{} // closed when done
+ res *ClientConn // valid after done is closed
+ err error // valid after done is closed
+}
+
+// requires p.mu is held.
+func (p *clientConnPool) getStartDialLocked(addr string) *dialCall {
+ if call, ok := p.dialing[addr]; ok {
+ // A dial is already in-flight. Don't start another.
+ return call
+ }
+ call := &dialCall{p: p, done: make(chan struct{})}
+ if p.dialing == nil {
+ p.dialing = make(map[string]*dialCall)
+ }
+ p.dialing[addr] = call
+ go call.dial(addr)
+ return call
+}
+
+// run in its own goroutine.
+func (c *dialCall) dial(addr string) {
+ const singleUse = false // shared conn
+ c.res, c.err = c.p.t.dialClientConn(addr, singleUse)
+ close(c.done)
+
+ c.p.mu.Lock()
+ delete(c.p.dialing, addr)
+ if c.err == nil {
+ c.p.addConnLocked(addr, c.res)
+ }
+ c.p.mu.Unlock()
+}
+
+// addConnIfNeeded makes a NewClientConn out of c if a connection for key doesn't
+// already exist. It coalesces concurrent calls with the same key.
+// This is used by the http1 Transport code when it creates a new connection. Because
+// the http1 Transport doesn't de-dup TCP dials to outbound hosts (because it doesn't know
+// the protocol), it can get into a situation where it has multiple TLS connections.
+// This code decides which ones live or die.
+// The return value used is whether c was used.
+// c is never closed.
+func (p *clientConnPool) addConnIfNeeded(key string, t *Transport, c *tls.Conn) (used bool, err error) {
+ p.mu.Lock()
+ for _, cc := range p.conns[key] {
+ if cc.CanTakeNewRequest() {
+ p.mu.Unlock()
+ return false, nil
+ }
+ }
+ call, dup := p.addConnCalls[key]
+ if !dup {
+ if p.addConnCalls == nil {
+ p.addConnCalls = make(map[string]*addConnCall)
+ }
+ call = &addConnCall{
+ p: p,
+ done: make(chan struct{}),
+ }
+ p.addConnCalls[key] = call
+ go call.run(t, key, c)
+ }
+ p.mu.Unlock()
+
+ <-call.done
+ if call.err != nil {
+ return false, call.err
+ }
+ return !dup, nil
+}
+
+type addConnCall struct {
+ p *clientConnPool
+ done chan struct{} // closed when done
+ err error
+}
+
+func (c *addConnCall) run(t *Transport, key string, tc *tls.Conn) {
+ cc, err := t.NewClientConn(tc)
+
+ p := c.p
+ p.mu.Lock()
+ if err != nil {
+ c.err = err
+ } else {
+ p.addConnLocked(key, cc)
+ }
+ delete(p.addConnCalls, key)
+ p.mu.Unlock()
+ close(c.done)
+}
+
+func (p *clientConnPool) addConn(key string, cc *ClientConn) {
+ p.mu.Lock()
+ p.addConnLocked(key, cc)
+ p.mu.Unlock()
+}
+
+// p.mu must be held
+func (p *clientConnPool) addConnLocked(key string, cc *ClientConn) {
+ for _, v := range p.conns[key] {
+ if v == cc {
+ return
+ }
+ }
+ if p.conns == nil {
+ p.conns = make(map[string][]*ClientConn)
+ }
+ if p.keys == nil {
+ p.keys = make(map[*ClientConn][]string)
+ }
+ p.conns[key] = append(p.conns[key], cc)
+ p.keys[cc] = append(p.keys[cc], key)
+}
+
+func (p *clientConnPool) MarkDead(cc *ClientConn) {
+ p.mu.Lock()
+ defer p.mu.Unlock()
+ for _, key := range p.keys[cc] {
+ vv, ok := p.conns[key]
+ if !ok {
+ continue
+ }
+ newList := filterOutClientConn(vv, cc)
+ if len(newList) > 0 {
+ p.conns[key] = newList
+ } else {
+ delete(p.conns, key)
+ }
+ }
+ delete(p.keys, cc)
+}
+
+func (p *clientConnPool) closeIdleConnections() {
+ p.mu.Lock()
+ defer p.mu.Unlock()
+ // TODO: don't close a cc if it was just added to the pool
+ // milliseconds ago and has never been used. There's currently
+ // a small race window with the HTTP/1 Transport's integration
+ // where it can add an idle conn just before using it, and
+ // somebody else can concurrently call CloseIdleConns and
+ // break some caller's RoundTrip.
+ for _, vv := range p.conns {
+ for _, cc := range vv {
+ cc.closeIfIdle()
+ }
+ }
+}
+
+func filterOutClientConn(in []*ClientConn, exclude *ClientConn) []*ClientConn {
+ out := in[:0]
+ for _, v := range in {
+ if v != exclude {
+ out = append(out, v)
+ }
+ }
+ // If we filtered it out, zero out the last item to prevent
+ // the GC from seeing it.
+ if len(in) != len(out) {
+ in[len(in)-1] = nil
+ }
+ return out
+}
+
+// noDialClientConnPool is an implementation of http2.ClientConnPool
+// which never dials. We let the HTTP/1.1 client dial and use its TLS
+// connection instead.
+type noDialClientConnPool struct{ *clientConnPool }
+
+func (p noDialClientConnPool) GetClientConn(req *http.Request, addr string) (*ClientConn, error) {
+ return p.getClientConn(req, addr, noDialOnMiss)
+}
diff --git a/vendor/golang.org/x/net/http2/databuffer.go b/vendor/golang.org/x/net/http2/databuffer.go
new file mode 100644
index 0000000..a3067f8
--- /dev/null
+++ b/vendor/golang.org/x/net/http2/databuffer.go
@@ -0,0 +1,146 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package http2
+
+import (
+ "errors"
+ "fmt"
+ "sync"
+)
+
+// Buffer chunks are allocated from a pool to reduce pressure on GC.
+// The maximum wasted space per dataBuffer is 2x the largest size class,
+// which happens when the dataBuffer has multiple chunks and there is
+// one unread byte in both the first and last chunks. We use a few size
+// classes to minimize overheads for servers that typically receive very
+// small request bodies.
+//
+// TODO: Benchmark to determine if the pools are necessary. The GC may have
+// improved enough that we can instead allocate chunks like this:
+// make([]byte, max(16<<10, expectedBytesRemaining))
+var (
+ dataChunkSizeClasses = []int{
+ 1 << 10,
+ 2 << 10,
+ 4 << 10,
+ 8 << 10,
+ 16 << 10,
+ }
+ dataChunkPools = [...]sync.Pool{
+ {New: func() interface{} { return make([]byte, 1<<10) }},
+ {New: func() interface{} { return make([]byte, 2<<10) }},
+ {New: func() interface{} { return make([]byte, 4<<10) }},
+ {New: func() interface{} { return make([]byte, 8<<10) }},
+ {New: func() interface{} { return make([]byte, 16<<10) }},
+ }
+)
+
+func getDataBufferChunk(size int64) []byte {
+ i := 0
+ for ; i < len(dataChunkSizeClasses)-1; i++ {
+ if size <= int64(dataChunkSizeClasses[i]) {
+ break
+ }
+ }
+ return dataChunkPools[i].Get().([]byte)
+}
+
+func putDataBufferChunk(p []byte) {
+ for i, n := range dataChunkSizeClasses {
+ if len(p) == n {
+ dataChunkPools[i].Put(p)
+ return
+ }
+ }
+ panic(fmt.Sprintf("unexpected buffer len=%v", len(p)))
+}
+
+// dataBuffer is an io.ReadWriter backed by a list of data chunks.
+// Each dataBuffer is used to read DATA frames on a single stream.
+// The buffer is divided into chunks so the server can limit the
+// total memory used by a single connection without limiting the
+// request body size on any single stream.
+type dataBuffer struct {
+ chunks [][]byte
+ r int // next byte to read is chunks[0][r]
+ w int // next byte to write is chunks[len(chunks)-1][w]
+ size int // total buffered bytes
+ expected int64 // we expect at least this many bytes in future Write calls (ignored if <= 0)
+}
+
+var errReadEmpty = errors.New("read from empty dataBuffer")
+
+// Read copies bytes from the buffer into p.
+// It is an error to read when no data is available.
+func (b *dataBuffer) Read(p []byte) (int, error) {
+ if b.size == 0 {
+ return 0, errReadEmpty
+ }
+ var ntotal int
+ for len(p) > 0 && b.size > 0 {
+ readFrom := b.bytesFromFirstChunk()
+ n := copy(p, readFrom)
+ p = p[n:]
+ ntotal += n
+ b.r += n
+ b.size -= n
+ // If the first chunk has been consumed, advance to the next chunk.
+ if b.r == len(b.chunks[0]) {
+ putDataBufferChunk(b.chunks[0])
+ end := len(b.chunks) - 1
+ copy(b.chunks[:end], b.chunks[1:])
+ b.chunks[end] = nil
+ b.chunks = b.chunks[:end]
+ b.r = 0
+ }
+ }
+ return ntotal, nil
+}
+
+func (b *dataBuffer) bytesFromFirstChunk() []byte {
+ if len(b.chunks) == 1 {
+ return b.chunks[0][b.r:b.w]
+ }
+ return b.chunks[0][b.r:]
+}
+
+// Len returns the number of bytes of the unread portion of the buffer.
+func (b *dataBuffer) Len() int {
+ return b.size
+}
+
+// Write appends p to the buffer.
+func (b *dataBuffer) Write(p []byte) (int, error) {
+ ntotal := len(p)
+ for len(p) > 0 {
+ // If the last chunk is empty, allocate a new chunk. Try to allocate
+ // enough to fully copy p plus any additional bytes we expect to
+ // receive. However, this may allocate less than len(p).
+ want := int64(len(p))
+ if b.expected > want {
+ want = b.expected
+ }
+ chunk := b.lastChunkOrAlloc(want)
+ n := copy(chunk[b.w:], p)
+ p = p[n:]
+ b.w += n
+ b.size += n
+ b.expected -= int64(n)
+ }
+ return ntotal, nil
+}
+
+func (b *dataBuffer) lastChunkOrAlloc(want int64) []byte {
+ if len(b.chunks) != 0 {
+ last := b.chunks[len(b.chunks)-1]
+ if b.w < len(last) {
+ return last
+ }
+ }
+ chunk := getDataBufferChunk(want)
+ b.chunks = append(b.chunks, chunk)
+ b.w = 0
+ return chunk
+}
diff --git a/vendor/golang.org/x/net/http2/errors.go b/vendor/golang.org/x/net/http2/errors.go
new file mode 100644
index 0000000..71f2c46
--- /dev/null
+++ b/vendor/golang.org/x/net/http2/errors.go
@@ -0,0 +1,133 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package http2
+
+import (
+ "errors"
+ "fmt"
+)
+
+// An ErrCode is an unsigned 32-bit error code as defined in the HTTP/2 spec.
+type ErrCode uint32
+
+const (
+ ErrCodeNo ErrCode = 0x0
+ ErrCodeProtocol ErrCode = 0x1
+ ErrCodeInternal ErrCode = 0x2
+ ErrCodeFlowControl ErrCode = 0x3
+ ErrCodeSettingsTimeout ErrCode = 0x4
+ ErrCodeStreamClosed ErrCode = 0x5
+ ErrCodeFrameSize ErrCode = 0x6
+ ErrCodeRefusedStream ErrCode = 0x7
+ ErrCodeCancel ErrCode = 0x8
+ ErrCodeCompression ErrCode = 0x9
+ ErrCodeConnect ErrCode = 0xa
+ ErrCodeEnhanceYourCalm ErrCode = 0xb
+ ErrCodeInadequateSecurity ErrCode = 0xc
+ ErrCodeHTTP11Required ErrCode = 0xd
+)
+
+var errCodeName = map[ErrCode]string{
+ ErrCodeNo: "NO_ERROR",
+ ErrCodeProtocol: "PROTOCOL_ERROR",
+ ErrCodeInternal: "INTERNAL_ERROR",
+ ErrCodeFlowControl: "FLOW_CONTROL_ERROR",
+ ErrCodeSettingsTimeout: "SETTINGS_TIMEOUT",
+ ErrCodeStreamClosed: "STREAM_CLOSED",
+ ErrCodeFrameSize: "FRAME_SIZE_ERROR",
+ ErrCodeRefusedStream: "REFUSED_STREAM",
+ ErrCodeCancel: "CANCEL",
+ ErrCodeCompression: "COMPRESSION_ERROR",
+ ErrCodeConnect: "CONNECT_ERROR",
+ ErrCodeEnhanceYourCalm: "ENHANCE_YOUR_CALM",
+ ErrCodeInadequateSecurity: "INADEQUATE_SECURITY",
+ ErrCodeHTTP11Required: "HTTP_1_1_REQUIRED",
+}
+
+func (e ErrCode) String() string {
+ if s, ok := errCodeName[e]; ok {
+ return s
+ }
+ return fmt.Sprintf("unknown error code 0x%x", uint32(e))
+}
+
+// ConnectionError is an error that results in the termination of the
+// entire connection.
+type ConnectionError ErrCode
+
+func (e ConnectionError) Error() string { return fmt.Sprintf("connection error: %s", ErrCode(e)) }
+
+// StreamError is an error that only affects one stream within an
+// HTTP/2 connection.
+type StreamError struct {
+ StreamID uint32
+ Code ErrCode
+ Cause error // optional additional detail
+}
+
+func streamError(id uint32, code ErrCode) StreamError {
+ return StreamError{StreamID: id, Code: code}
+}
+
+func (e StreamError) Error() string {
+ if e.Cause != nil {
+ return fmt.Sprintf("stream error: stream ID %d; %v; %v", e.StreamID, e.Code, e.Cause)
+ }
+ return fmt.Sprintf("stream error: stream ID %d; %v", e.StreamID, e.Code)
+}
+
+// 6.9.1 The Flow Control Window
+// "If a sender receives a WINDOW_UPDATE that causes a flow control
+// window to exceed this maximum it MUST terminate either the stream
+// or the connection, as appropriate. For streams, [...]; for the
+// connection, a GOAWAY frame with a FLOW_CONTROL_ERROR code."
+type goAwayFlowError struct{}
+
+func (goAwayFlowError) Error() string { return "connection exceeded flow control window size" }
+
+// connError represents an HTTP/2 ConnectionError error code, along
+// with a string (for debugging) explaining why.
+//
+// Errors of this type are only returned by the frame parser functions
+// and converted into ConnectionError(Code), after stashing away
+// the Reason into the Framer's errDetail field, accessible via
+// the (*Framer).ErrorDetail method.
+type connError struct {
+ Code ErrCode // the ConnectionError error code
+ Reason string // additional reason
+}
+
+func (e connError) Error() string {
+ return fmt.Sprintf("http2: connection error: %v: %v", e.Code, e.Reason)
+}
+
+type pseudoHeaderError string
+
+func (e pseudoHeaderError) Error() string {
+ return fmt.Sprintf("invalid pseudo-header %q", string(e))
+}
+
+type duplicatePseudoHeaderError string
+
+func (e duplicatePseudoHeaderError) Error() string {
+ return fmt.Sprintf("duplicate pseudo-header %q", string(e))
+}
+
+type headerFieldNameError string
+
+func (e headerFieldNameError) Error() string {
+ return fmt.Sprintf("invalid header field name %q", string(e))
+}
+
+type headerFieldValueError string
+
+func (e headerFieldValueError) Error() string {
+ return fmt.Sprintf("invalid header field value %q", string(e))
+}
+
+var (
+ errMixPseudoHeaderTypes = errors.New("mix of request and response pseudo headers")
+ errPseudoAfterRegular = errors.New("pseudo header field after regular")
+)
diff --git a/vendor/golang.org/x/net/http2/flow.go b/vendor/golang.org/x/net/http2/flow.go
new file mode 100644
index 0000000..cea601f
--- /dev/null
+++ b/vendor/golang.org/x/net/http2/flow.go
@@ -0,0 +1,50 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Flow control
+
+package http2
+
+// flow is the flow control window's size.
+type flow struct {
+ // n is the number of DATA bytes we're allowed to send.
+ // A flow is kept both on a conn and a per-stream.
+ n int32
+
+ // conn points to the shared connection-level flow that is
+ // shared by all streams on that conn. It is nil for the flow
+ // that's on the conn directly.
+ conn *flow
+}
+
+func (f *flow) setConnFlow(cf *flow) { f.conn = cf }
+
+func (f *flow) available() int32 {
+ n := f.n
+ if f.conn != nil && f.conn.n < n {
+ n = f.conn.n
+ }
+ return n
+}
+
+func (f *flow) take(n int32) {
+ if n > f.available() {
+ panic("internal error: took too much")
+ }
+ f.n -= n
+ if f.conn != nil {
+ f.conn.n -= n
+ }
+}
+
+// add adds n bytes (positive or negative) to the flow control window.
+// It returns false if the sum would exceed 2^31-1.
+func (f *flow) add(n int32) bool {
+ sum := f.n + n
+ if (sum > n) == (f.n > 0) {
+ f.n = sum
+ return true
+ }
+ return false
+}
diff --git a/vendor/golang.org/x/net/http2/frame.go b/vendor/golang.org/x/net/http2/frame.go
new file mode 100644
index 0000000..514c126
--- /dev/null
+++ b/vendor/golang.org/x/net/http2/frame.go
@@ -0,0 +1,1614 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package http2
+
+import (
+ "bytes"
+ "encoding/binary"
+ "errors"
+ "fmt"
+ "io"
+ "log"
+ "strings"
+ "sync"
+
+ "golang.org/x/net/http/httpguts"
+ "golang.org/x/net/http2/hpack"
+)
+
+const frameHeaderLen = 9
+
+var padZeros = make([]byte, 255) // zeros for padding
+
+// A FrameType is a registered frame type as defined in
+// http://http2.github.io/http2-spec/#rfc.section.11.2
+type FrameType uint8
+
+const (
+ FrameData FrameType = 0x0
+ FrameHeaders FrameType = 0x1
+ FramePriority FrameType = 0x2
+ FrameRSTStream FrameType = 0x3
+ FrameSettings FrameType = 0x4
+ FramePushPromise FrameType = 0x5
+ FramePing FrameType = 0x6
+ FrameGoAway FrameType = 0x7
+ FrameWindowUpdate FrameType = 0x8
+ FrameContinuation FrameType = 0x9
+)
+
+var frameName = map[FrameType]string{
+ FrameData: "DATA",
+ FrameHeaders: "HEADERS",
+ FramePriority: "PRIORITY",
+ FrameRSTStream: "RST_STREAM",
+ FrameSettings: "SETTINGS",
+ FramePushPromise: "PUSH_PROMISE",
+ FramePing: "PING",
+ FrameGoAway: "GOAWAY",
+ FrameWindowUpdate: "WINDOW_UPDATE",
+ FrameContinuation: "CONTINUATION",
+}
+
+func (t FrameType) String() string {
+ if s, ok := frameName[t]; ok {
+ return s
+ }
+ return fmt.Sprintf("UNKNOWN_FRAME_TYPE_%d", uint8(t))
+}
+
+// Flags is a bitmask of HTTP/2 flags.
+// The meaning of flags varies depending on the frame type.
+type Flags uint8
+
+// Has reports whether f contains all (0 or more) flags in v.
+func (f Flags) Has(v Flags) bool {
+ return (f & v) == v
+}
+
+// Frame-specific FrameHeader flag bits.
+const (
+ // Data Frame
+ FlagDataEndStream Flags = 0x1
+ FlagDataPadded Flags = 0x8
+
+ // Headers Frame
+ FlagHeadersEndStream Flags = 0x1
+ FlagHeadersEndHeaders Flags = 0x4
+ FlagHeadersPadded Flags = 0x8
+ FlagHeadersPriority Flags = 0x20
+
+ // Settings Frame
+ FlagSettingsAck Flags = 0x1
+
+ // Ping Frame
+ FlagPingAck Flags = 0x1
+
+ // Continuation Frame
+ FlagContinuationEndHeaders Flags = 0x4
+
+ FlagPushPromiseEndHeaders Flags = 0x4
+ FlagPushPromisePadded Flags = 0x8
+)
+
+var flagName = map[FrameType]map[Flags]string{
+ FrameData: {
+ FlagDataEndStream: "END_STREAM",
+ FlagDataPadded: "PADDED",
+ },
+ FrameHeaders: {
+ FlagHeadersEndStream: "END_STREAM",
+ FlagHeadersEndHeaders: "END_HEADERS",
+ FlagHeadersPadded: "PADDED",
+ FlagHeadersPriority: "PRIORITY",
+ },
+ FrameSettings: {
+ FlagSettingsAck: "ACK",
+ },
+ FramePing: {
+ FlagPingAck: "ACK",
+ },
+ FrameContinuation: {
+ FlagContinuationEndHeaders: "END_HEADERS",
+ },
+ FramePushPromise: {
+ FlagPushPromiseEndHeaders: "END_HEADERS",
+ FlagPushPromisePadded: "PADDED",
+ },
+}
+
+// a frameParser parses a frame given its FrameHeader and payload
+// bytes. The length of payload will always equal fh.Length (which
+// might be 0).
+type frameParser func(fc *frameCache, fh FrameHeader, payload []byte) (Frame, error)
+
+var frameParsers = map[FrameType]frameParser{
+ FrameData: parseDataFrame,
+ FrameHeaders: parseHeadersFrame,
+ FramePriority: parsePriorityFrame,
+ FrameRSTStream: parseRSTStreamFrame,
+ FrameSettings: parseSettingsFrame,
+ FramePushPromise: parsePushPromise,
+ FramePing: parsePingFrame,
+ FrameGoAway: parseGoAwayFrame,
+ FrameWindowUpdate: parseWindowUpdateFrame,
+ FrameContinuation: parseContinuationFrame,
+}
+
+func typeFrameParser(t FrameType) frameParser {
+ if f := frameParsers[t]; f != nil {
+ return f
+ }
+ return parseUnknownFrame
+}
+
+// A FrameHeader is the 9 byte header of all HTTP/2 frames.
+//
+// See http://http2.github.io/http2-spec/#FrameHeader
+type FrameHeader struct {
+ valid bool // caller can access []byte fields in the Frame
+
+ // Type is the 1 byte frame type. There are ten standard frame
+ // types, but extension frame types may be written by WriteRawFrame
+ // and will be returned by ReadFrame (as UnknownFrame).
+ Type FrameType
+
+ // Flags are the 1 byte of 8 potential bit flags per frame.
+ // They are specific to the frame type.
+ Flags Flags
+
+ // Length is the length of the frame, not including the 9 byte header.
+ // The maximum size is one byte less than 16MB (uint24), but only
+ // frames up to 16KB are allowed without peer agreement.
+ Length uint32
+
+ // StreamID is which stream this frame is for. Certain frames
+ // are not stream-specific, in which case this field is 0.
+ StreamID uint32
+}
+
+// Header returns h. It exists so FrameHeaders can be embedded in other
+// specific frame types and implement the Frame interface.
+func (h FrameHeader) Header() FrameHeader { return h }
+
+func (h FrameHeader) String() string {
+ var buf bytes.Buffer
+ buf.WriteString("[FrameHeader ")
+ h.writeDebug(&buf)
+ buf.WriteByte(']')
+ return buf.String()
+}
+
+func (h FrameHeader) writeDebug(buf *bytes.Buffer) {
+ buf.WriteString(h.Type.String())
+ if h.Flags != 0 {
+ buf.WriteString(" flags=")
+ set := 0
+ for i := uint8(0); i < 8; i++ {
+ if h.Flags&(1< 1 {
+ buf.WriteByte('|')
+ }
+ name := flagName[h.Type][Flags(1<>24),
+ byte(streamID>>16),
+ byte(streamID>>8),
+ byte(streamID))
+}
+
+func (f *Framer) endWrite() error {
+ // Now that we know the final size, fill in the FrameHeader in
+ // the space previously reserved for it. Abuse append.
+ length := len(f.wbuf) - frameHeaderLen
+ if length >= (1 << 24) {
+ return ErrFrameTooLarge
+ }
+ _ = append(f.wbuf[:0],
+ byte(length>>16),
+ byte(length>>8),
+ byte(length))
+ if f.logWrites {
+ f.logWrite()
+ }
+
+ n, err := f.w.Write(f.wbuf)
+ if err == nil && n != len(f.wbuf) {
+ err = io.ErrShortWrite
+ }
+ return err
+}
+
+func (f *Framer) logWrite() {
+ if f.debugFramer == nil {
+ f.debugFramerBuf = new(bytes.Buffer)
+ f.debugFramer = NewFramer(nil, f.debugFramerBuf)
+ f.debugFramer.logReads = false // we log it ourselves, saying "wrote" below
+ // Let us read anything, even if we accidentally wrote it
+ // in the wrong order:
+ f.debugFramer.AllowIllegalReads = true
+ }
+ f.debugFramerBuf.Write(f.wbuf)
+ fr, err := f.debugFramer.ReadFrame()
+ if err != nil {
+ f.debugWriteLoggerf("http2: Framer %p: failed to decode just-written frame", f)
+ return
+ }
+ f.debugWriteLoggerf("http2: Framer %p: wrote %v", f, summarizeFrame(fr))
+}
+
+func (f *Framer) writeByte(v byte) { f.wbuf = append(f.wbuf, v) }
+func (f *Framer) writeBytes(v []byte) { f.wbuf = append(f.wbuf, v...) }
+func (f *Framer) writeUint16(v uint16) { f.wbuf = append(f.wbuf, byte(v>>8), byte(v)) }
+func (f *Framer) writeUint32(v uint32) {
+ f.wbuf = append(f.wbuf, byte(v>>24), byte(v>>16), byte(v>>8), byte(v))
+}
+
+const (
+ minMaxFrameSize = 1 << 14
+ maxFrameSize = 1<<24 - 1
+)
+
+// SetReuseFrames allows the Framer to reuse Frames.
+// If called on a Framer, Frames returned by calls to ReadFrame are only
+// valid until the next call to ReadFrame.
+func (fr *Framer) SetReuseFrames() {
+ if fr.frameCache != nil {
+ return
+ }
+ fr.frameCache = &frameCache{}
+}
+
+type frameCache struct {
+ dataFrame DataFrame
+}
+
+func (fc *frameCache) getDataFrame() *DataFrame {
+ if fc == nil {
+ return &DataFrame{}
+ }
+ return &fc.dataFrame
+}
+
+// NewFramer returns a Framer that writes frames to w and reads them from r.
+func NewFramer(w io.Writer, r io.Reader) *Framer {
+ fr := &Framer{
+ w: w,
+ r: r,
+ logReads: logFrameReads,
+ logWrites: logFrameWrites,
+ debugReadLoggerf: log.Printf,
+ debugWriteLoggerf: log.Printf,
+ }
+ fr.getReadBuf = func(size uint32) []byte {
+ if cap(fr.readBuf) >= int(size) {
+ return fr.readBuf[:size]
+ }
+ fr.readBuf = make([]byte, size)
+ return fr.readBuf
+ }
+ fr.SetMaxReadFrameSize(maxFrameSize)
+ return fr
+}
+
+// SetMaxReadFrameSize sets the maximum size of a frame
+// that will be read by a subsequent call to ReadFrame.
+// It is the caller's responsibility to advertise this
+// limit with a SETTINGS frame.
+func (fr *Framer) SetMaxReadFrameSize(v uint32) {
+ if v > maxFrameSize {
+ v = maxFrameSize
+ }
+ fr.maxReadSize = v
+}
+
+// ErrorDetail returns a more detailed error of the last error
+// returned by Framer.ReadFrame. For instance, if ReadFrame
+// returns a StreamError with code PROTOCOL_ERROR, ErrorDetail
+// will say exactly what was invalid. ErrorDetail is not guaranteed
+// to return a non-nil value and like the rest of the http2 package,
+// its return value is not protected by an API compatibility promise.
+// ErrorDetail is reset after the next call to ReadFrame.
+func (fr *Framer) ErrorDetail() error {
+ return fr.errDetail
+}
+
+// ErrFrameTooLarge is returned from Framer.ReadFrame when the peer
+// sends a frame that is larger than declared with SetMaxReadFrameSize.
+var ErrFrameTooLarge = errors.New("http2: frame too large")
+
+// terminalReadFrameError reports whether err is an unrecoverable
+// error from ReadFrame and no other frames should be read.
+func terminalReadFrameError(err error) bool {
+ if _, ok := err.(StreamError); ok {
+ return false
+ }
+ return err != nil
+}
+
+// ReadFrame reads a single frame. The returned Frame is only valid
+// until the next call to ReadFrame.
+//
+// If the frame is larger than previously set with SetMaxReadFrameSize, the
+// returned error is ErrFrameTooLarge. Other errors may be of type
+// ConnectionError, StreamError, or anything else from the underlying
+// reader.
+func (fr *Framer) ReadFrame() (Frame, error) {
+ fr.errDetail = nil
+ if fr.lastFrame != nil {
+ fr.lastFrame.invalidate()
+ }
+ fh, err := readFrameHeader(fr.headerBuf[:], fr.r)
+ if err != nil {
+ return nil, err
+ }
+ if fh.Length > fr.maxReadSize {
+ return nil, ErrFrameTooLarge
+ }
+ payload := fr.getReadBuf(fh.Length)
+ if _, err := io.ReadFull(fr.r, payload); err != nil {
+ return nil, err
+ }
+ f, err := typeFrameParser(fh.Type)(fr.frameCache, fh, payload)
+ if err != nil {
+ if ce, ok := err.(connError); ok {
+ return nil, fr.connError(ce.Code, ce.Reason)
+ }
+ return nil, err
+ }
+ if err := fr.checkFrameOrder(f); err != nil {
+ return nil, err
+ }
+ if fr.logReads {
+ fr.debugReadLoggerf("http2: Framer %p: read %v", fr, summarizeFrame(f))
+ }
+ if fh.Type == FrameHeaders && fr.ReadMetaHeaders != nil {
+ return fr.readMetaFrame(f.(*HeadersFrame))
+ }
+ return f, nil
+}
+
+// connError returns ConnectionError(code) but first
+// stashes away a public reason to the caller can optionally relay it
+// to the peer before hanging up on them. This might help others debug
+// their implementations.
+func (fr *Framer) connError(code ErrCode, reason string) error {
+ fr.errDetail = errors.New(reason)
+ return ConnectionError(code)
+}
+
+// checkFrameOrder reports an error if f is an invalid frame to return
+// next from ReadFrame. Mostly it checks whether HEADERS and
+// CONTINUATION frames are contiguous.
+func (fr *Framer) checkFrameOrder(f Frame) error {
+ last := fr.lastFrame
+ fr.lastFrame = f
+ if fr.AllowIllegalReads {
+ return nil
+ }
+
+ fh := f.Header()
+ if fr.lastHeaderStream != 0 {
+ if fh.Type != FrameContinuation {
+ return fr.connError(ErrCodeProtocol,
+ fmt.Sprintf("got %s for stream %d; expected CONTINUATION following %s for stream %d",
+ fh.Type, fh.StreamID,
+ last.Header().Type, fr.lastHeaderStream))
+ }
+ if fh.StreamID != fr.lastHeaderStream {
+ return fr.connError(ErrCodeProtocol,
+ fmt.Sprintf("got CONTINUATION for stream %d; expected stream %d",
+ fh.StreamID, fr.lastHeaderStream))
+ }
+ } else if fh.Type == FrameContinuation {
+ return fr.connError(ErrCodeProtocol, fmt.Sprintf("unexpected CONTINUATION for stream %d", fh.StreamID))
+ }
+
+ switch fh.Type {
+ case FrameHeaders, FrameContinuation:
+ if fh.Flags.Has(FlagHeadersEndHeaders) {
+ fr.lastHeaderStream = 0
+ } else {
+ fr.lastHeaderStream = fh.StreamID
+ }
+ }
+
+ return nil
+}
+
+// A DataFrame conveys arbitrary, variable-length sequences of octets
+// associated with a stream.
+// See http://http2.github.io/http2-spec/#rfc.section.6.1
+type DataFrame struct {
+ FrameHeader
+ data []byte
+}
+
+func (f *DataFrame) StreamEnded() bool {
+ return f.FrameHeader.Flags.Has(FlagDataEndStream)
+}
+
+// Data returns the frame's data octets, not including any padding
+// size byte or padding suffix bytes.
+// The caller must not retain the returned memory past the next
+// call to ReadFrame.
+func (f *DataFrame) Data() []byte {
+ f.checkValid()
+ return f.data
+}
+
+func parseDataFrame(fc *frameCache, fh FrameHeader, payload []byte) (Frame, error) {
+ if fh.StreamID == 0 {
+ // DATA frames MUST be associated with a stream. If a
+ // DATA frame is received whose stream identifier
+ // field is 0x0, the recipient MUST respond with a
+ // connection error (Section 5.4.1) of type
+ // PROTOCOL_ERROR.
+ return nil, connError{ErrCodeProtocol, "DATA frame with stream ID 0"}
+ }
+ f := fc.getDataFrame()
+ f.FrameHeader = fh
+
+ var padSize byte
+ if fh.Flags.Has(FlagDataPadded) {
+ var err error
+ payload, padSize, err = readByte(payload)
+ if err != nil {
+ return nil, err
+ }
+ }
+ if int(padSize) > len(payload) {
+ // If the length of the padding is greater than the
+ // length of the frame payload, the recipient MUST
+ // treat this as a connection error.
+ // Filed: https://github.com/http2/http2-spec/issues/610
+ return nil, connError{ErrCodeProtocol, "pad size larger than data payload"}
+ }
+ f.data = payload[:len(payload)-int(padSize)]
+ return f, nil
+}
+
+var (
+ errStreamID = errors.New("invalid stream ID")
+ errDepStreamID = errors.New("invalid dependent stream ID")
+ errPadLength = errors.New("pad length too large")
+ errPadBytes = errors.New("padding bytes must all be zeros unless AllowIllegalWrites is enabled")
+)
+
+func validStreamIDOrZero(streamID uint32) bool {
+ return streamID&(1<<31) == 0
+}
+
+func validStreamID(streamID uint32) bool {
+ return streamID != 0 && streamID&(1<<31) == 0
+}
+
+// WriteData writes a DATA frame.
+//
+// It will perform exactly one Write to the underlying Writer.
+// It is the caller's responsibility not to violate the maximum frame size
+// and to not call other Write methods concurrently.
+func (f *Framer) WriteData(streamID uint32, endStream bool, data []byte) error {
+ return f.WriteDataPadded(streamID, endStream, data, nil)
+}
+
+// WriteDataPadded writes a DATA frame with optional padding.
+//
+// If pad is nil, the padding bit is not sent.
+// The length of pad must not exceed 255 bytes.
+// The bytes of pad must all be zero, unless f.AllowIllegalWrites is set.
+//
+// It will perform exactly one Write to the underlying Writer.
+// It is the caller's responsibility not to violate the maximum frame size
+// and to not call other Write methods concurrently.
+func (f *Framer) WriteDataPadded(streamID uint32, endStream bool, data, pad []byte) error {
+ if !validStreamID(streamID) && !f.AllowIllegalWrites {
+ return errStreamID
+ }
+ if len(pad) > 0 {
+ if len(pad) > 255 {
+ return errPadLength
+ }
+ if !f.AllowIllegalWrites {
+ for _, b := range pad {
+ if b != 0 {
+ // "Padding octets MUST be set to zero when sending."
+ return errPadBytes
+ }
+ }
+ }
+ }
+ var flags Flags
+ if endStream {
+ flags |= FlagDataEndStream
+ }
+ if pad != nil {
+ flags |= FlagDataPadded
+ }
+ f.startWrite(FrameData, flags, streamID)
+ if pad != nil {
+ f.wbuf = append(f.wbuf, byte(len(pad)))
+ }
+ f.wbuf = append(f.wbuf, data...)
+ f.wbuf = append(f.wbuf, pad...)
+ return f.endWrite()
+}
+
+// A SettingsFrame conveys configuration parameters that affect how
+// endpoints communicate, such as preferences and constraints on peer
+// behavior.
+//
+// See http://http2.github.io/http2-spec/#SETTINGS
+type SettingsFrame struct {
+ FrameHeader
+ p []byte
+}
+
+func parseSettingsFrame(_ *frameCache, fh FrameHeader, p []byte) (Frame, error) {
+ if fh.Flags.Has(FlagSettingsAck) && fh.Length > 0 {
+ // When this (ACK 0x1) bit is set, the payload of the
+ // SETTINGS frame MUST be empty. Receipt of a
+ // SETTINGS frame with the ACK flag set and a length
+ // field value other than 0 MUST be treated as a
+ // connection error (Section 5.4.1) of type
+ // FRAME_SIZE_ERROR.
+ return nil, ConnectionError(ErrCodeFrameSize)
+ }
+ if fh.StreamID != 0 {
+ // SETTINGS frames always apply to a connection,
+ // never a single stream. The stream identifier for a
+ // SETTINGS frame MUST be zero (0x0). If an endpoint
+ // receives a SETTINGS frame whose stream identifier
+ // field is anything other than 0x0, the endpoint MUST
+ // respond with a connection error (Section 5.4.1) of
+ // type PROTOCOL_ERROR.
+ return nil, ConnectionError(ErrCodeProtocol)
+ }
+ if len(p)%6 != 0 {
+ // Expecting even number of 6 byte settings.
+ return nil, ConnectionError(ErrCodeFrameSize)
+ }
+ f := &SettingsFrame{FrameHeader: fh, p: p}
+ if v, ok := f.Value(SettingInitialWindowSize); ok && v > (1<<31)-1 {
+ // Values above the maximum flow control window size of 2^31 - 1 MUST
+ // be treated as a connection error (Section 5.4.1) of type
+ // FLOW_CONTROL_ERROR.
+ return nil, ConnectionError(ErrCodeFlowControl)
+ }
+ return f, nil
+}
+
+func (f *SettingsFrame) IsAck() bool {
+ return f.FrameHeader.Flags.Has(FlagSettingsAck)
+}
+
+func (f *SettingsFrame) Value(id SettingID) (v uint32, ok bool) {
+ f.checkValid()
+ for i := 0; i < f.NumSettings(); i++ {
+ if s := f.Setting(i); s.ID == id {
+ return s.Val, true
+ }
+ }
+ return 0, false
+}
+
+// Setting returns the setting from the frame at the given 0-based index.
+// The index must be >= 0 and less than f.NumSettings().
+func (f *SettingsFrame) Setting(i int) Setting {
+ buf := f.p
+ return Setting{
+ ID: SettingID(binary.BigEndian.Uint16(buf[i*6 : i*6+2])),
+ Val: binary.BigEndian.Uint32(buf[i*6+2 : i*6+6]),
+ }
+}
+
+func (f *SettingsFrame) NumSettings() int { return len(f.p) / 6 }
+
+// HasDuplicates reports whether f contains any duplicate setting IDs.
+func (f *SettingsFrame) HasDuplicates() bool {
+ num := f.NumSettings()
+ if num == 0 {
+ return false
+ }
+ // If it's small enough (the common case), just do the n^2
+ // thing and avoid a map allocation.
+ if num < 10 {
+ for i := 0; i < num; i++ {
+ idi := f.Setting(i).ID
+ for j := i + 1; j < num; j++ {
+ idj := f.Setting(j).ID
+ if idi == idj {
+ return true
+ }
+ }
+ }
+ return false
+ }
+ seen := map[SettingID]bool{}
+ for i := 0; i < num; i++ {
+ id := f.Setting(i).ID
+ if seen[id] {
+ return true
+ }
+ seen[id] = true
+ }
+ return false
+}
+
+// ForeachSetting runs fn for each setting.
+// It stops and returns the first error.
+func (f *SettingsFrame) ForeachSetting(fn func(Setting) error) error {
+ f.checkValid()
+ for i := 0; i < f.NumSettings(); i++ {
+ if err := fn(f.Setting(i)); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// WriteSettings writes a SETTINGS frame with zero or more settings
+// specified and the ACK bit not set.
+//
+// It will perform exactly one Write to the underlying Writer.
+// It is the caller's responsibility to not call other Write methods concurrently.
+func (f *Framer) WriteSettings(settings ...Setting) error {
+ f.startWrite(FrameSettings, 0, 0)
+ for _, s := range settings {
+ f.writeUint16(uint16(s.ID))
+ f.writeUint32(s.Val)
+ }
+ return f.endWrite()
+}
+
+// WriteSettingsAck writes an empty SETTINGS frame with the ACK bit set.
+//
+// It will perform exactly one Write to the underlying Writer.
+// It is the caller's responsibility to not call other Write methods concurrently.
+func (f *Framer) WriteSettingsAck() error {
+ f.startWrite(FrameSettings, FlagSettingsAck, 0)
+ return f.endWrite()
+}
+
+// A PingFrame is a mechanism for measuring a minimal round trip time
+// from the sender, as well as determining whether an idle connection
+// is still functional.
+// See http://http2.github.io/http2-spec/#rfc.section.6.7
+type PingFrame struct {
+ FrameHeader
+ Data [8]byte
+}
+
+func (f *PingFrame) IsAck() bool { return f.Flags.Has(FlagPingAck) }
+
+func parsePingFrame(_ *frameCache, fh FrameHeader, payload []byte) (Frame, error) {
+ if len(payload) != 8 {
+ return nil, ConnectionError(ErrCodeFrameSize)
+ }
+ if fh.StreamID != 0 {
+ return nil, ConnectionError(ErrCodeProtocol)
+ }
+ f := &PingFrame{FrameHeader: fh}
+ copy(f.Data[:], payload)
+ return f, nil
+}
+
+func (f *Framer) WritePing(ack bool, data [8]byte) error {
+ var flags Flags
+ if ack {
+ flags = FlagPingAck
+ }
+ f.startWrite(FramePing, flags, 0)
+ f.writeBytes(data[:])
+ return f.endWrite()
+}
+
+// A GoAwayFrame informs the remote peer to stop creating streams on this connection.
+// See http://http2.github.io/http2-spec/#rfc.section.6.8
+type GoAwayFrame struct {
+ FrameHeader
+ LastStreamID uint32
+ ErrCode ErrCode
+ debugData []byte
+}
+
+// DebugData returns any debug data in the GOAWAY frame. Its contents
+// are not defined.
+// The caller must not retain the returned memory past the next
+// call to ReadFrame.
+func (f *GoAwayFrame) DebugData() []byte {
+ f.checkValid()
+ return f.debugData
+}
+
+func parseGoAwayFrame(_ *frameCache, fh FrameHeader, p []byte) (Frame, error) {
+ if fh.StreamID != 0 {
+ return nil, ConnectionError(ErrCodeProtocol)
+ }
+ if len(p) < 8 {
+ return nil, ConnectionError(ErrCodeFrameSize)
+ }
+ return &GoAwayFrame{
+ FrameHeader: fh,
+ LastStreamID: binary.BigEndian.Uint32(p[:4]) & (1<<31 - 1),
+ ErrCode: ErrCode(binary.BigEndian.Uint32(p[4:8])),
+ debugData: p[8:],
+ }, nil
+}
+
+func (f *Framer) WriteGoAway(maxStreamID uint32, code ErrCode, debugData []byte) error {
+ f.startWrite(FrameGoAway, 0, 0)
+ f.writeUint32(maxStreamID & (1<<31 - 1))
+ f.writeUint32(uint32(code))
+ f.writeBytes(debugData)
+ return f.endWrite()
+}
+
+// An UnknownFrame is the frame type returned when the frame type is unknown
+// or no specific frame type parser exists.
+type UnknownFrame struct {
+ FrameHeader
+ p []byte
+}
+
+// Payload returns the frame's payload (after the header). It is not
+// valid to call this method after a subsequent call to
+// Framer.ReadFrame, nor is it valid to retain the returned slice.
+// The memory is owned by the Framer and is invalidated when the next
+// frame is read.
+func (f *UnknownFrame) Payload() []byte {
+ f.checkValid()
+ return f.p
+}
+
+func parseUnknownFrame(_ *frameCache, fh FrameHeader, p []byte) (Frame, error) {
+ return &UnknownFrame{fh, p}, nil
+}
+
+// A WindowUpdateFrame is used to implement flow control.
+// See http://http2.github.io/http2-spec/#rfc.section.6.9
+type WindowUpdateFrame struct {
+ FrameHeader
+ Increment uint32 // never read with high bit set
+}
+
+func parseWindowUpdateFrame(_ *frameCache, fh FrameHeader, p []byte) (Frame, error) {
+ if len(p) != 4 {
+ return nil, ConnectionError(ErrCodeFrameSize)
+ }
+ inc := binary.BigEndian.Uint32(p[:4]) & 0x7fffffff // mask off high reserved bit
+ if inc == 0 {
+ // A receiver MUST treat the receipt of a
+ // WINDOW_UPDATE frame with an flow control window
+ // increment of 0 as a stream error (Section 5.4.2) of
+ // type PROTOCOL_ERROR; errors on the connection flow
+ // control window MUST be treated as a connection
+ // error (Section 5.4.1).
+ if fh.StreamID == 0 {
+ return nil, ConnectionError(ErrCodeProtocol)
+ }
+ return nil, streamError(fh.StreamID, ErrCodeProtocol)
+ }
+ return &WindowUpdateFrame{
+ FrameHeader: fh,
+ Increment: inc,
+ }, nil
+}
+
+// WriteWindowUpdate writes a WINDOW_UPDATE frame.
+// The increment value must be between 1 and 2,147,483,647, inclusive.
+// If the Stream ID is zero, the window update applies to the
+// connection as a whole.
+func (f *Framer) WriteWindowUpdate(streamID, incr uint32) error {
+ // "The legal range for the increment to the flow control window is 1 to 2^31-1 (2,147,483,647) octets."
+ if (incr < 1 || incr > 2147483647) && !f.AllowIllegalWrites {
+ return errors.New("illegal window increment value")
+ }
+ f.startWrite(FrameWindowUpdate, 0, streamID)
+ f.writeUint32(incr)
+ return f.endWrite()
+}
+
+// A HeadersFrame is used to open a stream and additionally carries a
+// header block fragment.
+type HeadersFrame struct {
+ FrameHeader
+
+ // Priority is set if FlagHeadersPriority is set in the FrameHeader.
+ Priority PriorityParam
+
+ headerFragBuf []byte // not owned
+}
+
+func (f *HeadersFrame) HeaderBlockFragment() []byte {
+ f.checkValid()
+ return f.headerFragBuf
+}
+
+func (f *HeadersFrame) HeadersEnded() bool {
+ return f.FrameHeader.Flags.Has(FlagHeadersEndHeaders)
+}
+
+func (f *HeadersFrame) StreamEnded() bool {
+ return f.FrameHeader.Flags.Has(FlagHeadersEndStream)
+}
+
+func (f *HeadersFrame) HasPriority() bool {
+ return f.FrameHeader.Flags.Has(FlagHeadersPriority)
+}
+
+func parseHeadersFrame(_ *frameCache, fh FrameHeader, p []byte) (_ Frame, err error) {
+ hf := &HeadersFrame{
+ FrameHeader: fh,
+ }
+ if fh.StreamID == 0 {
+ // HEADERS frames MUST be associated with a stream. If a HEADERS frame
+ // is received whose stream identifier field is 0x0, the recipient MUST
+ // respond with a connection error (Section 5.4.1) of type
+ // PROTOCOL_ERROR.
+ return nil, connError{ErrCodeProtocol, "HEADERS frame with stream ID 0"}
+ }
+ var padLength uint8
+ if fh.Flags.Has(FlagHeadersPadded) {
+ if p, padLength, err = readByte(p); err != nil {
+ return
+ }
+ }
+ if fh.Flags.Has(FlagHeadersPriority) {
+ var v uint32
+ p, v, err = readUint32(p)
+ if err != nil {
+ return nil, err
+ }
+ hf.Priority.StreamDep = v & 0x7fffffff
+ hf.Priority.Exclusive = (v != hf.Priority.StreamDep) // high bit was set
+ p, hf.Priority.Weight, err = readByte(p)
+ if err != nil {
+ return nil, err
+ }
+ }
+ if len(p)-int(padLength) <= 0 {
+ return nil, streamError(fh.StreamID, ErrCodeProtocol)
+ }
+ hf.headerFragBuf = p[:len(p)-int(padLength)]
+ return hf, nil
+}
+
+// HeadersFrameParam are the parameters for writing a HEADERS frame.
+type HeadersFrameParam struct {
+ // StreamID is the required Stream ID to initiate.
+ StreamID uint32
+ // BlockFragment is part (or all) of a Header Block.
+ BlockFragment []byte
+
+ // EndStream indicates that the header block is the last that
+ // the endpoint will send for the identified stream. Setting
+ // this flag causes the stream to enter one of "half closed"
+ // states.
+ EndStream bool
+
+ // EndHeaders indicates that this frame contains an entire
+ // header block and is not followed by any
+ // CONTINUATION frames.
+ EndHeaders bool
+
+ // PadLength is the optional number of bytes of zeros to add
+ // to this frame.
+ PadLength uint8
+
+ // Priority, if non-zero, includes stream priority information
+ // in the HEADER frame.
+ Priority PriorityParam
+}
+
+// WriteHeaders writes a single HEADERS frame.
+//
+// This is a low-level header writing method. Encoding headers and
+// splitting them into any necessary CONTINUATION frames is handled
+// elsewhere.
+//
+// It will perform exactly one Write to the underlying Writer.
+// It is the caller's responsibility to not call other Write methods concurrently.
+func (f *Framer) WriteHeaders(p HeadersFrameParam) error {
+ if !validStreamID(p.StreamID) && !f.AllowIllegalWrites {
+ return errStreamID
+ }
+ var flags Flags
+ if p.PadLength != 0 {
+ flags |= FlagHeadersPadded
+ }
+ if p.EndStream {
+ flags |= FlagHeadersEndStream
+ }
+ if p.EndHeaders {
+ flags |= FlagHeadersEndHeaders
+ }
+ if !p.Priority.IsZero() {
+ flags |= FlagHeadersPriority
+ }
+ f.startWrite(FrameHeaders, flags, p.StreamID)
+ if p.PadLength != 0 {
+ f.writeByte(p.PadLength)
+ }
+ if !p.Priority.IsZero() {
+ v := p.Priority.StreamDep
+ if !validStreamIDOrZero(v) && !f.AllowIllegalWrites {
+ return errDepStreamID
+ }
+ if p.Priority.Exclusive {
+ v |= 1 << 31
+ }
+ f.writeUint32(v)
+ f.writeByte(p.Priority.Weight)
+ }
+ f.wbuf = append(f.wbuf, p.BlockFragment...)
+ f.wbuf = append(f.wbuf, padZeros[:p.PadLength]...)
+ return f.endWrite()
+}
+
+// A PriorityFrame specifies the sender-advised priority of a stream.
+// See http://http2.github.io/http2-spec/#rfc.section.6.3
+type PriorityFrame struct {
+ FrameHeader
+ PriorityParam
+}
+
+// PriorityParam are the stream prioritzation parameters.
+type PriorityParam struct {
+ // StreamDep is a 31-bit stream identifier for the
+ // stream that this stream depends on. Zero means no
+ // dependency.
+ StreamDep uint32
+
+ // Exclusive is whether the dependency is exclusive.
+ Exclusive bool
+
+ // Weight is the stream's zero-indexed weight. It should be
+ // set together with StreamDep, or neither should be set. Per
+ // the spec, "Add one to the value to obtain a weight between
+ // 1 and 256."
+ Weight uint8
+}
+
+func (p PriorityParam) IsZero() bool {
+ return p == PriorityParam{}
+}
+
+func parsePriorityFrame(_ *frameCache, fh FrameHeader, payload []byte) (Frame, error) {
+ if fh.StreamID == 0 {
+ return nil, connError{ErrCodeProtocol, "PRIORITY frame with stream ID 0"}
+ }
+ if len(payload) != 5 {
+ return nil, connError{ErrCodeFrameSize, fmt.Sprintf("PRIORITY frame payload size was %d; want 5", len(payload))}
+ }
+ v := binary.BigEndian.Uint32(payload[:4])
+ streamID := v & 0x7fffffff // mask off high bit
+ return &PriorityFrame{
+ FrameHeader: fh,
+ PriorityParam: PriorityParam{
+ Weight: payload[4],
+ StreamDep: streamID,
+ Exclusive: streamID != v, // was high bit set?
+ },
+ }, nil
+}
+
+// WritePriority writes a PRIORITY frame.
+//
+// It will perform exactly one Write to the underlying Writer.
+// It is the caller's responsibility to not call other Write methods concurrently.
+func (f *Framer) WritePriority(streamID uint32, p PriorityParam) error {
+ if !validStreamID(streamID) && !f.AllowIllegalWrites {
+ return errStreamID
+ }
+ if !validStreamIDOrZero(p.StreamDep) {
+ return errDepStreamID
+ }
+ f.startWrite(FramePriority, 0, streamID)
+ v := p.StreamDep
+ if p.Exclusive {
+ v |= 1 << 31
+ }
+ f.writeUint32(v)
+ f.writeByte(p.Weight)
+ return f.endWrite()
+}
+
+// A RSTStreamFrame allows for abnormal termination of a stream.
+// See http://http2.github.io/http2-spec/#rfc.section.6.4
+type RSTStreamFrame struct {
+ FrameHeader
+ ErrCode ErrCode
+}
+
+func parseRSTStreamFrame(_ *frameCache, fh FrameHeader, p []byte) (Frame, error) {
+ if len(p) != 4 {
+ return nil, ConnectionError(ErrCodeFrameSize)
+ }
+ if fh.StreamID == 0 {
+ return nil, ConnectionError(ErrCodeProtocol)
+ }
+ return &RSTStreamFrame{fh, ErrCode(binary.BigEndian.Uint32(p[:4]))}, nil
+}
+
+// WriteRSTStream writes a RST_STREAM frame.
+//
+// It will perform exactly one Write to the underlying Writer.
+// It is the caller's responsibility to not call other Write methods concurrently.
+func (f *Framer) WriteRSTStream(streamID uint32, code ErrCode) error {
+ if !validStreamID(streamID) && !f.AllowIllegalWrites {
+ return errStreamID
+ }
+ f.startWrite(FrameRSTStream, 0, streamID)
+ f.writeUint32(uint32(code))
+ return f.endWrite()
+}
+
+// A ContinuationFrame is used to continue a sequence of header block fragments.
+// See http://http2.github.io/http2-spec/#rfc.section.6.10
+type ContinuationFrame struct {
+ FrameHeader
+ headerFragBuf []byte
+}
+
+func parseContinuationFrame(_ *frameCache, fh FrameHeader, p []byte) (Frame, error) {
+ if fh.StreamID == 0 {
+ return nil, connError{ErrCodeProtocol, "CONTINUATION frame with stream ID 0"}
+ }
+ return &ContinuationFrame{fh, p}, nil
+}
+
+func (f *ContinuationFrame) HeaderBlockFragment() []byte {
+ f.checkValid()
+ return f.headerFragBuf
+}
+
+func (f *ContinuationFrame) HeadersEnded() bool {
+ return f.FrameHeader.Flags.Has(FlagContinuationEndHeaders)
+}
+
+// WriteContinuation writes a CONTINUATION frame.
+//
+// It will perform exactly one Write to the underlying Writer.
+// It is the caller's responsibility to not call other Write methods concurrently.
+func (f *Framer) WriteContinuation(streamID uint32, endHeaders bool, headerBlockFragment []byte) error {
+ if !validStreamID(streamID) && !f.AllowIllegalWrites {
+ return errStreamID
+ }
+ var flags Flags
+ if endHeaders {
+ flags |= FlagContinuationEndHeaders
+ }
+ f.startWrite(FrameContinuation, flags, streamID)
+ f.wbuf = append(f.wbuf, headerBlockFragment...)
+ return f.endWrite()
+}
+
+// A PushPromiseFrame is used to initiate a server stream.
+// See http://http2.github.io/http2-spec/#rfc.section.6.6
+type PushPromiseFrame struct {
+ FrameHeader
+ PromiseID uint32
+ headerFragBuf []byte // not owned
+}
+
+func (f *PushPromiseFrame) HeaderBlockFragment() []byte {
+ f.checkValid()
+ return f.headerFragBuf
+}
+
+func (f *PushPromiseFrame) HeadersEnded() bool {
+ return f.FrameHeader.Flags.Has(FlagPushPromiseEndHeaders)
+}
+
+func parsePushPromise(_ *frameCache, fh FrameHeader, p []byte) (_ Frame, err error) {
+ pp := &PushPromiseFrame{
+ FrameHeader: fh,
+ }
+ if pp.StreamID == 0 {
+ // PUSH_PROMISE frames MUST be associated with an existing,
+ // peer-initiated stream. The stream identifier of a
+ // PUSH_PROMISE frame indicates the stream it is associated
+ // with. If the stream identifier field specifies the value
+ // 0x0, a recipient MUST respond with a connection error
+ // (Section 5.4.1) of type PROTOCOL_ERROR.
+ return nil, ConnectionError(ErrCodeProtocol)
+ }
+ // The PUSH_PROMISE frame includes optional padding.
+ // Padding fields and flags are identical to those defined for DATA frames
+ var padLength uint8
+ if fh.Flags.Has(FlagPushPromisePadded) {
+ if p, padLength, err = readByte(p); err != nil {
+ return
+ }
+ }
+
+ p, pp.PromiseID, err = readUint32(p)
+ if err != nil {
+ return
+ }
+ pp.PromiseID = pp.PromiseID & (1<<31 - 1)
+
+ if int(padLength) > len(p) {
+ // like the DATA frame, error out if padding is longer than the body.
+ return nil, ConnectionError(ErrCodeProtocol)
+ }
+ pp.headerFragBuf = p[:len(p)-int(padLength)]
+ return pp, nil
+}
+
+// PushPromiseParam are the parameters for writing a PUSH_PROMISE frame.
+type PushPromiseParam struct {
+ // StreamID is the required Stream ID to initiate.
+ StreamID uint32
+
+ // PromiseID is the required Stream ID which this
+ // Push Promises
+ PromiseID uint32
+
+ // BlockFragment is part (or all) of a Header Block.
+ BlockFragment []byte
+
+ // EndHeaders indicates that this frame contains an entire
+ // header block and is not followed by any
+ // CONTINUATION frames.
+ EndHeaders bool
+
+ // PadLength is the optional number of bytes of zeros to add
+ // to this frame.
+ PadLength uint8
+}
+
+// WritePushPromise writes a single PushPromise Frame.
+//
+// As with Header Frames, This is the low level call for writing
+// individual frames. Continuation frames are handled elsewhere.
+//
+// It will perform exactly one Write to the underlying Writer.
+// It is the caller's responsibility to not call other Write methods concurrently.
+func (f *Framer) WritePushPromise(p PushPromiseParam) error {
+ if !validStreamID(p.StreamID) && !f.AllowIllegalWrites {
+ return errStreamID
+ }
+ var flags Flags
+ if p.PadLength != 0 {
+ flags |= FlagPushPromisePadded
+ }
+ if p.EndHeaders {
+ flags |= FlagPushPromiseEndHeaders
+ }
+ f.startWrite(FramePushPromise, flags, p.StreamID)
+ if p.PadLength != 0 {
+ f.writeByte(p.PadLength)
+ }
+ if !validStreamID(p.PromiseID) && !f.AllowIllegalWrites {
+ return errStreamID
+ }
+ f.writeUint32(p.PromiseID)
+ f.wbuf = append(f.wbuf, p.BlockFragment...)
+ f.wbuf = append(f.wbuf, padZeros[:p.PadLength]...)
+ return f.endWrite()
+}
+
+// WriteRawFrame writes a raw frame. This can be used to write
+// extension frames unknown to this package.
+func (f *Framer) WriteRawFrame(t FrameType, flags Flags, streamID uint32, payload []byte) error {
+ f.startWrite(t, flags, streamID)
+ f.writeBytes(payload)
+ return f.endWrite()
+}
+
+func readByte(p []byte) (remain []byte, b byte, err error) {
+ if len(p) == 0 {
+ return nil, 0, io.ErrUnexpectedEOF
+ }
+ return p[1:], p[0], nil
+}
+
+func readUint32(p []byte) (remain []byte, v uint32, err error) {
+ if len(p) < 4 {
+ return nil, 0, io.ErrUnexpectedEOF
+ }
+ return p[4:], binary.BigEndian.Uint32(p[:4]), nil
+}
+
+type streamEnder interface {
+ StreamEnded() bool
+}
+
+type headersEnder interface {
+ HeadersEnded() bool
+}
+
+type headersOrContinuation interface {
+ headersEnder
+ HeaderBlockFragment() []byte
+}
+
+// A MetaHeadersFrame is the representation of one HEADERS frame and
+// zero or more contiguous CONTINUATION frames and the decoding of
+// their HPACK-encoded contents.
+//
+// This type of frame does not appear on the wire and is only returned
+// by the Framer when Framer.ReadMetaHeaders is set.
+type MetaHeadersFrame struct {
+ *HeadersFrame
+
+ // Fields are the fields contained in the HEADERS and
+ // CONTINUATION frames. The underlying slice is owned by the
+ // Framer and must not be retained after the next call to
+ // ReadFrame.
+ //
+ // Fields are guaranteed to be in the correct http2 order and
+ // not have unknown pseudo header fields or invalid header
+ // field names or values. Required pseudo header fields may be
+ // missing, however. Use the MetaHeadersFrame.Pseudo accessor
+ // method access pseudo headers.
+ Fields []hpack.HeaderField
+
+ // Truncated is whether the max header list size limit was hit
+ // and Fields is incomplete. The hpack decoder state is still
+ // valid, however.
+ Truncated bool
+}
+
+// PseudoValue returns the given pseudo header field's value.
+// The provided pseudo field should not contain the leading colon.
+func (mh *MetaHeadersFrame) PseudoValue(pseudo string) string {
+ for _, hf := range mh.Fields {
+ if !hf.IsPseudo() {
+ return ""
+ }
+ if hf.Name[1:] == pseudo {
+ return hf.Value
+ }
+ }
+ return ""
+}
+
+// RegularFields returns the regular (non-pseudo) header fields of mh.
+// The caller does not own the returned slice.
+func (mh *MetaHeadersFrame) RegularFields() []hpack.HeaderField {
+ for i, hf := range mh.Fields {
+ if !hf.IsPseudo() {
+ return mh.Fields[i:]
+ }
+ }
+ return nil
+}
+
+// PseudoFields returns the pseudo header fields of mh.
+// The caller does not own the returned slice.
+func (mh *MetaHeadersFrame) PseudoFields() []hpack.HeaderField {
+ for i, hf := range mh.Fields {
+ if !hf.IsPseudo() {
+ return mh.Fields[:i]
+ }
+ }
+ return mh.Fields
+}
+
+func (mh *MetaHeadersFrame) checkPseudos() error {
+ var isRequest, isResponse bool
+ pf := mh.PseudoFields()
+ for i, hf := range pf {
+ switch hf.Name {
+ case ":method", ":path", ":scheme", ":authority":
+ isRequest = true
+ case ":status":
+ isResponse = true
+ default:
+ return pseudoHeaderError(hf.Name)
+ }
+ // Check for duplicates.
+ // This would be a bad algorithm, but N is 4.
+ // And this doesn't allocate.
+ for _, hf2 := range pf[:i] {
+ if hf.Name == hf2.Name {
+ return duplicatePseudoHeaderError(hf.Name)
+ }
+ }
+ }
+ if isRequest && isResponse {
+ return errMixPseudoHeaderTypes
+ }
+ return nil
+}
+
+func (fr *Framer) maxHeaderStringLen() int {
+ v := fr.maxHeaderListSize()
+ if uint32(int(v)) == v {
+ return int(v)
+ }
+ // They had a crazy big number for MaxHeaderBytes anyway,
+ // so give them unlimited header lengths:
+ return 0
+}
+
+// readMetaFrame returns 0 or more CONTINUATION frames from fr and
+// merge them into the provided hf and returns a MetaHeadersFrame
+// with the decoded hpack values.
+func (fr *Framer) readMetaFrame(hf *HeadersFrame) (*MetaHeadersFrame, error) {
+ if fr.AllowIllegalReads {
+ return nil, errors.New("illegal use of AllowIllegalReads with ReadMetaHeaders")
+ }
+ mh := &MetaHeadersFrame{
+ HeadersFrame: hf,
+ }
+ var remainSize = fr.maxHeaderListSize()
+ var sawRegular bool
+
+ var invalid error // pseudo header field errors
+ hdec := fr.ReadMetaHeaders
+ hdec.SetEmitEnabled(true)
+ hdec.SetMaxStringLength(fr.maxHeaderStringLen())
+ hdec.SetEmitFunc(func(hf hpack.HeaderField) {
+ if VerboseLogs && fr.logReads {
+ fr.debugReadLoggerf("http2: decoded hpack field %+v", hf)
+ }
+ if !httpguts.ValidHeaderFieldValue(hf.Value) {
+ invalid = headerFieldValueError(hf.Value)
+ }
+ isPseudo := strings.HasPrefix(hf.Name, ":")
+ if isPseudo {
+ if sawRegular {
+ invalid = errPseudoAfterRegular
+ }
+ } else {
+ sawRegular = true
+ if !validWireHeaderFieldName(hf.Name) {
+ invalid = headerFieldNameError(hf.Name)
+ }
+ }
+
+ if invalid != nil {
+ hdec.SetEmitEnabled(false)
+ return
+ }
+
+ size := hf.Size()
+ if size > remainSize {
+ hdec.SetEmitEnabled(false)
+ mh.Truncated = true
+ return
+ }
+ remainSize -= size
+
+ mh.Fields = append(mh.Fields, hf)
+ })
+ // Lose reference to MetaHeadersFrame:
+ defer hdec.SetEmitFunc(func(hf hpack.HeaderField) {})
+
+ var hc headersOrContinuation = hf
+ for {
+ frag := hc.HeaderBlockFragment()
+ if _, err := hdec.Write(frag); err != nil {
+ return nil, ConnectionError(ErrCodeCompression)
+ }
+
+ if hc.HeadersEnded() {
+ break
+ }
+ if f, err := fr.ReadFrame(); err != nil {
+ return nil, err
+ } else {
+ hc = f.(*ContinuationFrame) // guaranteed by checkFrameOrder
+ }
+ }
+
+ mh.HeadersFrame.headerFragBuf = nil
+ mh.HeadersFrame.invalidate()
+
+ if err := hdec.Close(); err != nil {
+ return nil, ConnectionError(ErrCodeCompression)
+ }
+ if invalid != nil {
+ fr.errDetail = invalid
+ if VerboseLogs {
+ log.Printf("http2: invalid header: %v", invalid)
+ }
+ return nil, StreamError{mh.StreamID, ErrCodeProtocol, invalid}
+ }
+ if err := mh.checkPseudos(); err != nil {
+ fr.errDetail = err
+ if VerboseLogs {
+ log.Printf("http2: invalid pseudo headers: %v", err)
+ }
+ return nil, StreamError{mh.StreamID, ErrCodeProtocol, err}
+ }
+ return mh, nil
+}
+
+func summarizeFrame(f Frame) string {
+ var buf bytes.Buffer
+ f.Header().writeDebug(&buf)
+ switch f := f.(type) {
+ case *SettingsFrame:
+ n := 0
+ f.ForeachSetting(func(s Setting) error {
+ n++
+ if n == 1 {
+ buf.WriteString(", settings:")
+ }
+ fmt.Fprintf(&buf, " %v=%v,", s.ID, s.Val)
+ return nil
+ })
+ if n > 0 {
+ buf.Truncate(buf.Len() - 1) // remove trailing comma
+ }
+ case *DataFrame:
+ data := f.Data()
+ const max = 256
+ if len(data) > max {
+ data = data[:max]
+ }
+ fmt.Fprintf(&buf, " data=%q", data)
+ if len(f.Data()) > max {
+ fmt.Fprintf(&buf, " (%d bytes omitted)", len(f.Data())-max)
+ }
+ case *WindowUpdateFrame:
+ if f.StreamID == 0 {
+ buf.WriteString(" (conn)")
+ }
+ fmt.Fprintf(&buf, " incr=%v", f.Increment)
+ case *PingFrame:
+ fmt.Fprintf(&buf, " ping=%q", f.Data[:])
+ case *GoAwayFrame:
+ fmt.Fprintf(&buf, " LastStreamID=%v ErrCode=%v Debug=%q",
+ f.LastStreamID, f.ErrCode, f.debugData)
+ case *RSTStreamFrame:
+ fmt.Fprintf(&buf, " ErrCode=%v", f.ErrCode)
+ }
+ return buf.String()
+}
diff --git a/vendor/golang.org/x/net/http2/go111.go b/vendor/golang.org/x/net/http2/go111.go
new file mode 100644
index 0000000..3a13101
--- /dev/null
+++ b/vendor/golang.org/x/net/http2/go111.go
@@ -0,0 +1,29 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build go1.11
+
+package http2
+
+import (
+ "net/http/httptrace"
+ "net/textproto"
+)
+
+func traceHasWroteHeaderField(trace *httptrace.ClientTrace) bool {
+ return trace != nil && trace.WroteHeaderField != nil
+}
+
+func traceWroteHeaderField(trace *httptrace.ClientTrace, k, v string) {
+ if trace != nil && trace.WroteHeaderField != nil {
+ trace.WroteHeaderField(k, []string{v})
+ }
+}
+
+func traceGot1xxResponseFunc(trace *httptrace.ClientTrace) func(int, textproto.MIMEHeader) error {
+ if trace != nil {
+ return trace.Got1xxResponse
+ }
+ return nil
+}
diff --git a/vendor/golang.org/x/net/http2/gotrack.go b/vendor/golang.org/x/net/http2/gotrack.go
new file mode 100644
index 0000000..9933c9f
--- /dev/null
+++ b/vendor/golang.org/x/net/http2/gotrack.go
@@ -0,0 +1,170 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Defensive debug-only utility to track that functions run on the
+// goroutine that they're supposed to.
+
+package http2
+
+import (
+ "bytes"
+ "errors"
+ "fmt"
+ "os"
+ "runtime"
+ "strconv"
+ "sync"
+)
+
+var DebugGoroutines = os.Getenv("DEBUG_HTTP2_GOROUTINES") == "1"
+
+type goroutineLock uint64
+
+func newGoroutineLock() goroutineLock {
+ if !DebugGoroutines {
+ return 0
+ }
+ return goroutineLock(curGoroutineID())
+}
+
+func (g goroutineLock) check() {
+ if !DebugGoroutines {
+ return
+ }
+ if curGoroutineID() != uint64(g) {
+ panic("running on the wrong goroutine")
+ }
+}
+
+func (g goroutineLock) checkNotOn() {
+ if !DebugGoroutines {
+ return
+ }
+ if curGoroutineID() == uint64(g) {
+ panic("running on the wrong goroutine")
+ }
+}
+
+var goroutineSpace = []byte("goroutine ")
+
+func curGoroutineID() uint64 {
+ bp := littleBuf.Get().(*[]byte)
+ defer littleBuf.Put(bp)
+ b := *bp
+ b = b[:runtime.Stack(b, false)]
+ // Parse the 4707 out of "goroutine 4707 ["
+ b = bytes.TrimPrefix(b, goroutineSpace)
+ i := bytes.IndexByte(b, ' ')
+ if i < 0 {
+ panic(fmt.Sprintf("No space found in %q", b))
+ }
+ b = b[:i]
+ n, err := parseUintBytes(b, 10, 64)
+ if err != nil {
+ panic(fmt.Sprintf("Failed to parse goroutine ID out of %q: %v", b, err))
+ }
+ return n
+}
+
+var littleBuf = sync.Pool{
+ New: func() interface{} {
+ buf := make([]byte, 64)
+ return &buf
+ },
+}
+
+// parseUintBytes is like strconv.ParseUint, but using a []byte.
+func parseUintBytes(s []byte, base int, bitSize int) (n uint64, err error) {
+ var cutoff, maxVal uint64
+
+ if bitSize == 0 {
+ bitSize = int(strconv.IntSize)
+ }
+
+ s0 := s
+ switch {
+ case len(s) < 1:
+ err = strconv.ErrSyntax
+ goto Error
+
+ case 2 <= base && base <= 36:
+ // valid base; nothing to do
+
+ case base == 0:
+ // Look for octal, hex prefix.
+ switch {
+ case s[0] == '0' && len(s) > 1 && (s[1] == 'x' || s[1] == 'X'):
+ base = 16
+ s = s[2:]
+ if len(s) < 1 {
+ err = strconv.ErrSyntax
+ goto Error
+ }
+ case s[0] == '0':
+ base = 8
+ default:
+ base = 10
+ }
+
+ default:
+ err = errors.New("invalid base " + strconv.Itoa(base))
+ goto Error
+ }
+
+ n = 0
+ cutoff = cutoff64(base)
+ maxVal = 1<= base {
+ n = 0
+ err = strconv.ErrSyntax
+ goto Error
+ }
+
+ if n >= cutoff {
+ // n*base overflows
+ n = 1<<64 - 1
+ err = strconv.ErrRange
+ goto Error
+ }
+ n *= uint64(base)
+
+ n1 := n + uint64(v)
+ if n1 < n || n1 > maxVal {
+ // n+v overflows
+ n = 1<<64 - 1
+ err = strconv.ErrRange
+ goto Error
+ }
+ n = n1
+ }
+
+ return n, nil
+
+Error:
+ return n, &strconv.NumError{Func: "ParseUint", Num: string(s0), Err: err}
+}
+
+// Return the first number n such that n*base >= 1<<64.
+func cutoff64(base int) uint64 {
+ if base < 2 {
+ return 0
+ }
+ return (1<<64-1)/uint64(base) + 1
+}
diff --git a/vendor/golang.org/x/net/http2/headermap.go b/vendor/golang.org/x/net/http2/headermap.go
new file mode 100644
index 0000000..c3ff3fa
--- /dev/null
+++ b/vendor/golang.org/x/net/http2/headermap.go
@@ -0,0 +1,88 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package http2
+
+import (
+ "net/http"
+ "strings"
+ "sync"
+)
+
+var (
+ commonBuildOnce sync.Once
+ commonLowerHeader map[string]string // Go-Canonical-Case -> lower-case
+ commonCanonHeader map[string]string // lower-case -> Go-Canonical-Case
+)
+
+func buildCommonHeaderMapsOnce() {
+ commonBuildOnce.Do(buildCommonHeaderMaps)
+}
+
+func buildCommonHeaderMaps() {
+ common := []string{
+ "accept",
+ "accept-charset",
+ "accept-encoding",
+ "accept-language",
+ "accept-ranges",
+ "age",
+ "access-control-allow-origin",
+ "allow",
+ "authorization",
+ "cache-control",
+ "content-disposition",
+ "content-encoding",
+ "content-language",
+ "content-length",
+ "content-location",
+ "content-range",
+ "content-type",
+ "cookie",
+ "date",
+ "etag",
+ "expect",
+ "expires",
+ "from",
+ "host",
+ "if-match",
+ "if-modified-since",
+ "if-none-match",
+ "if-unmodified-since",
+ "last-modified",
+ "link",
+ "location",
+ "max-forwards",
+ "proxy-authenticate",
+ "proxy-authorization",
+ "range",
+ "referer",
+ "refresh",
+ "retry-after",
+ "server",
+ "set-cookie",
+ "strict-transport-security",
+ "trailer",
+ "transfer-encoding",
+ "user-agent",
+ "vary",
+ "via",
+ "www-authenticate",
+ }
+ commonLowerHeader = make(map[string]string, len(common))
+ commonCanonHeader = make(map[string]string, len(common))
+ for _, v := range common {
+ chk := http.CanonicalHeaderKey(v)
+ commonLowerHeader[chk] = v
+ commonCanonHeader[v] = chk
+ }
+}
+
+func lowerHeader(v string) string {
+ buildCommonHeaderMapsOnce()
+ if s, ok := commonLowerHeader[v]; ok {
+ return s
+ }
+ return strings.ToLower(v)
+}
diff --git a/vendor/golang.org/x/net/http2/hpack/encode.go b/vendor/golang.org/x/net/http2/hpack/encode.go
new file mode 100644
index 0000000..97f1783
--- /dev/null
+++ b/vendor/golang.org/x/net/http2/hpack/encode.go
@@ -0,0 +1,240 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package hpack
+
+import (
+ "io"
+)
+
+const (
+ uint32Max = ^uint32(0)
+ initialHeaderTableSize = 4096
+)
+
+type Encoder struct {
+ dynTab dynamicTable
+ // minSize is the minimum table size set by
+ // SetMaxDynamicTableSize after the previous Header Table Size
+ // Update.
+ minSize uint32
+ // maxSizeLimit is the maximum table size this encoder
+ // supports. This will protect the encoder from too large
+ // size.
+ maxSizeLimit uint32
+ // tableSizeUpdate indicates whether "Header Table Size
+ // Update" is required.
+ tableSizeUpdate bool
+ w io.Writer
+ buf []byte
+}
+
+// NewEncoder returns a new Encoder which performs HPACK encoding. An
+// encoded data is written to w.
+func NewEncoder(w io.Writer) *Encoder {
+ e := &Encoder{
+ minSize: uint32Max,
+ maxSizeLimit: initialHeaderTableSize,
+ tableSizeUpdate: false,
+ w: w,
+ }
+ e.dynTab.table.init()
+ e.dynTab.setMaxSize(initialHeaderTableSize)
+ return e
+}
+
+// WriteField encodes f into a single Write to e's underlying Writer.
+// This function may also produce bytes for "Header Table Size Update"
+// if necessary. If produced, it is done before encoding f.
+func (e *Encoder) WriteField(f HeaderField) error {
+ e.buf = e.buf[:0]
+
+ if e.tableSizeUpdate {
+ e.tableSizeUpdate = false
+ if e.minSize < e.dynTab.maxSize {
+ e.buf = appendTableSize(e.buf, e.minSize)
+ }
+ e.minSize = uint32Max
+ e.buf = appendTableSize(e.buf, e.dynTab.maxSize)
+ }
+
+ idx, nameValueMatch := e.searchTable(f)
+ if nameValueMatch {
+ e.buf = appendIndexed(e.buf, idx)
+ } else {
+ indexing := e.shouldIndex(f)
+ if indexing {
+ e.dynTab.add(f)
+ }
+
+ if idx == 0 {
+ e.buf = appendNewName(e.buf, f, indexing)
+ } else {
+ e.buf = appendIndexedName(e.buf, f, idx, indexing)
+ }
+ }
+ n, err := e.w.Write(e.buf)
+ if err == nil && n != len(e.buf) {
+ err = io.ErrShortWrite
+ }
+ return err
+}
+
+// searchTable searches f in both stable and dynamic header tables.
+// The static header table is searched first. Only when there is no
+// exact match for both name and value, the dynamic header table is
+// then searched. If there is no match, i is 0. If both name and value
+// match, i is the matched index and nameValueMatch becomes true. If
+// only name matches, i points to that index and nameValueMatch
+// becomes false.
+func (e *Encoder) searchTable(f HeaderField) (i uint64, nameValueMatch bool) {
+ i, nameValueMatch = staticTable.search(f)
+ if nameValueMatch {
+ return i, true
+ }
+
+ j, nameValueMatch := e.dynTab.table.search(f)
+ if nameValueMatch || (i == 0 && j != 0) {
+ return j + uint64(staticTable.len()), nameValueMatch
+ }
+
+ return i, false
+}
+
+// SetMaxDynamicTableSize changes the dynamic header table size to v.
+// The actual size is bounded by the value passed to
+// SetMaxDynamicTableSizeLimit.
+func (e *Encoder) SetMaxDynamicTableSize(v uint32) {
+ if v > e.maxSizeLimit {
+ v = e.maxSizeLimit
+ }
+ if v < e.minSize {
+ e.minSize = v
+ }
+ e.tableSizeUpdate = true
+ e.dynTab.setMaxSize(v)
+}
+
+// SetMaxDynamicTableSizeLimit changes the maximum value that can be
+// specified in SetMaxDynamicTableSize to v. By default, it is set to
+// 4096, which is the same size of the default dynamic header table
+// size described in HPACK specification. If the current maximum
+// dynamic header table size is strictly greater than v, "Header Table
+// Size Update" will be done in the next WriteField call and the
+// maximum dynamic header table size is truncated to v.
+func (e *Encoder) SetMaxDynamicTableSizeLimit(v uint32) {
+ e.maxSizeLimit = v
+ if e.dynTab.maxSize > v {
+ e.tableSizeUpdate = true
+ e.dynTab.setMaxSize(v)
+ }
+}
+
+// shouldIndex reports whether f should be indexed.
+func (e *Encoder) shouldIndex(f HeaderField) bool {
+ return !f.Sensitive && f.Size() <= e.dynTab.maxSize
+}
+
+// appendIndexed appends index i, as encoded in "Indexed Header Field"
+// representation, to dst and returns the extended buffer.
+func appendIndexed(dst []byte, i uint64) []byte {
+ first := len(dst)
+ dst = appendVarInt(dst, 7, i)
+ dst[first] |= 0x80
+ return dst
+}
+
+// appendNewName appends f, as encoded in one of "Literal Header field
+// - New Name" representation variants, to dst and returns the
+// extended buffer.
+//
+// If f.Sensitive is true, "Never Indexed" representation is used. If
+// f.Sensitive is false and indexing is true, "Incremental Indexing"
+// representation is used.
+func appendNewName(dst []byte, f HeaderField, indexing bool) []byte {
+ dst = append(dst, encodeTypeByte(indexing, f.Sensitive))
+ dst = appendHpackString(dst, f.Name)
+ return appendHpackString(dst, f.Value)
+}
+
+// appendIndexedName appends f and index i referring indexed name
+// entry, as encoded in one of "Literal Header field - Indexed Name"
+// representation variants, to dst and returns the extended buffer.
+//
+// If f.Sensitive is true, "Never Indexed" representation is used. If
+// f.Sensitive is false and indexing is true, "Incremental Indexing"
+// representation is used.
+func appendIndexedName(dst []byte, f HeaderField, i uint64, indexing bool) []byte {
+ first := len(dst)
+ var n byte
+ if indexing {
+ n = 6
+ } else {
+ n = 4
+ }
+ dst = appendVarInt(dst, n, i)
+ dst[first] |= encodeTypeByte(indexing, f.Sensitive)
+ return appendHpackString(dst, f.Value)
+}
+
+// appendTableSize appends v, as encoded in "Header Table Size Update"
+// representation, to dst and returns the extended buffer.
+func appendTableSize(dst []byte, v uint32) []byte {
+ first := len(dst)
+ dst = appendVarInt(dst, 5, uint64(v))
+ dst[first] |= 0x20
+ return dst
+}
+
+// appendVarInt appends i, as encoded in variable integer form using n
+// bit prefix, to dst and returns the extended buffer.
+//
+// See
+// http://http2.github.io/http2-spec/compression.html#integer.representation
+func appendVarInt(dst []byte, n byte, i uint64) []byte {
+ k := uint64((1 << n) - 1)
+ if i < k {
+ return append(dst, byte(i))
+ }
+ dst = append(dst, byte(k))
+ i -= k
+ for ; i >= 128; i >>= 7 {
+ dst = append(dst, byte(0x80|(i&0x7f)))
+ }
+ return append(dst, byte(i))
+}
+
+// appendHpackString appends s, as encoded in "String Literal"
+// representation, to dst and returns the extended buffer.
+//
+// s will be encoded in Huffman codes only when it produces strictly
+// shorter byte string.
+func appendHpackString(dst []byte, s string) []byte {
+ huffmanLength := HuffmanEncodeLength(s)
+ if huffmanLength < uint64(len(s)) {
+ first := len(dst)
+ dst = appendVarInt(dst, 7, huffmanLength)
+ dst = AppendHuffmanString(dst, s)
+ dst[first] |= 0x80
+ } else {
+ dst = appendVarInt(dst, 7, uint64(len(s)))
+ dst = append(dst, s...)
+ }
+ return dst
+}
+
+// encodeTypeByte returns type byte. If sensitive is true, type byte
+// for "Never Indexed" representation is returned. If sensitive is
+// false and indexing is true, type byte for "Incremental Indexing"
+// representation is returned. Otherwise, type byte for "Without
+// Indexing" is returned.
+func encodeTypeByte(indexing, sensitive bool) byte {
+ if sensitive {
+ return 0x10
+ }
+ if indexing {
+ return 0x40
+ }
+ return 0
+}
diff --git a/vendor/golang.org/x/net/http2/hpack/hpack.go b/vendor/golang.org/x/net/http2/hpack/hpack.go
new file mode 100644
index 0000000..85f18a2
--- /dev/null
+++ b/vendor/golang.org/x/net/http2/hpack/hpack.go
@@ -0,0 +1,504 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package hpack implements HPACK, a compression format for
+// efficiently representing HTTP header fields in the context of HTTP/2.
+//
+// See http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-09
+package hpack
+
+import (
+ "bytes"
+ "errors"
+ "fmt"
+)
+
+// A DecodingError is something the spec defines as a decoding error.
+type DecodingError struct {
+ Err error
+}
+
+func (de DecodingError) Error() string {
+ return fmt.Sprintf("decoding error: %v", de.Err)
+}
+
+// An InvalidIndexError is returned when an encoder references a table
+// entry before the static table or after the end of the dynamic table.
+type InvalidIndexError int
+
+func (e InvalidIndexError) Error() string {
+ return fmt.Sprintf("invalid indexed representation index %d", int(e))
+}
+
+// A HeaderField is a name-value pair. Both the name and value are
+// treated as opaque sequences of octets.
+type HeaderField struct {
+ Name, Value string
+
+ // Sensitive means that this header field should never be
+ // indexed.
+ Sensitive bool
+}
+
+// IsPseudo reports whether the header field is an http2 pseudo header.
+// That is, it reports whether it starts with a colon.
+// It is not otherwise guaranteed to be a valid pseudo header field,
+// though.
+func (hf HeaderField) IsPseudo() bool {
+ return len(hf.Name) != 0 && hf.Name[0] == ':'
+}
+
+func (hf HeaderField) String() string {
+ var suffix string
+ if hf.Sensitive {
+ suffix = " (sensitive)"
+ }
+ return fmt.Sprintf("header field %q = %q%s", hf.Name, hf.Value, suffix)
+}
+
+// Size returns the size of an entry per RFC 7541 section 4.1.
+func (hf HeaderField) Size() uint32 {
+ // http://http2.github.io/http2-spec/compression.html#rfc.section.4.1
+ // "The size of the dynamic table is the sum of the size of
+ // its entries. The size of an entry is the sum of its name's
+ // length in octets (as defined in Section 5.2), its value's
+ // length in octets (see Section 5.2), plus 32. The size of
+ // an entry is calculated using the length of the name and
+ // value without any Huffman encoding applied."
+
+ // This can overflow if somebody makes a large HeaderField
+ // Name and/or Value by hand, but we don't care, because that
+ // won't happen on the wire because the encoding doesn't allow
+ // it.
+ return uint32(len(hf.Name) + len(hf.Value) + 32)
+}
+
+// A Decoder is the decoding context for incremental processing of
+// header blocks.
+type Decoder struct {
+ dynTab dynamicTable
+ emit func(f HeaderField)
+
+ emitEnabled bool // whether calls to emit are enabled
+ maxStrLen int // 0 means unlimited
+
+ // buf is the unparsed buffer. It's only written to
+ // saveBuf if it was truncated in the middle of a header
+ // block. Because it's usually not owned, we can only
+ // process it under Write.
+ buf []byte // not owned; only valid during Write
+
+ // saveBuf is previous data passed to Write which we weren't able
+ // to fully parse before. Unlike buf, we own this data.
+ saveBuf bytes.Buffer
+
+ firstField bool // processing the first field of the header block
+}
+
+// NewDecoder returns a new decoder with the provided maximum dynamic
+// table size. The emitFunc will be called for each valid field
+// parsed, in the same goroutine as calls to Write, before Write returns.
+func NewDecoder(maxDynamicTableSize uint32, emitFunc func(f HeaderField)) *Decoder {
+ d := &Decoder{
+ emit: emitFunc,
+ emitEnabled: true,
+ firstField: true,
+ }
+ d.dynTab.table.init()
+ d.dynTab.allowedMaxSize = maxDynamicTableSize
+ d.dynTab.setMaxSize(maxDynamicTableSize)
+ return d
+}
+
+// ErrStringLength is returned by Decoder.Write when the max string length
+// (as configured by Decoder.SetMaxStringLength) would be violated.
+var ErrStringLength = errors.New("hpack: string too long")
+
+// SetMaxStringLength sets the maximum size of a HeaderField name or
+// value string. If a string exceeds this length (even after any
+// decompression), Write will return ErrStringLength.
+// A value of 0 means unlimited and is the default from NewDecoder.
+func (d *Decoder) SetMaxStringLength(n int) {
+ d.maxStrLen = n
+}
+
+// SetEmitFunc changes the callback used when new header fields
+// are decoded.
+// It must be non-nil. It does not affect EmitEnabled.
+func (d *Decoder) SetEmitFunc(emitFunc func(f HeaderField)) {
+ d.emit = emitFunc
+}
+
+// SetEmitEnabled controls whether the emitFunc provided to NewDecoder
+// should be called. The default is true.
+//
+// This facility exists to let servers enforce MAX_HEADER_LIST_SIZE
+// while still decoding and keeping in-sync with decoder state, but
+// without doing unnecessary decompression or generating unnecessary
+// garbage for header fields past the limit.
+func (d *Decoder) SetEmitEnabled(v bool) { d.emitEnabled = v }
+
+// EmitEnabled reports whether calls to the emitFunc provided to NewDecoder
+// are currently enabled. The default is true.
+func (d *Decoder) EmitEnabled() bool { return d.emitEnabled }
+
+// TODO: add method *Decoder.Reset(maxSize, emitFunc) to let callers re-use Decoders and their
+// underlying buffers for garbage reasons.
+
+func (d *Decoder) SetMaxDynamicTableSize(v uint32) {
+ d.dynTab.setMaxSize(v)
+}
+
+// SetAllowedMaxDynamicTableSize sets the upper bound that the encoded
+// stream (via dynamic table size updates) may set the maximum size
+// to.
+func (d *Decoder) SetAllowedMaxDynamicTableSize(v uint32) {
+ d.dynTab.allowedMaxSize = v
+}
+
+type dynamicTable struct {
+ // http://http2.github.io/http2-spec/compression.html#rfc.section.2.3.2
+ table headerFieldTable
+ size uint32 // in bytes
+ maxSize uint32 // current maxSize
+ allowedMaxSize uint32 // maxSize may go up to this, inclusive
+}
+
+func (dt *dynamicTable) setMaxSize(v uint32) {
+ dt.maxSize = v
+ dt.evict()
+}
+
+func (dt *dynamicTable) add(f HeaderField) {
+ dt.table.addEntry(f)
+ dt.size += f.Size()
+ dt.evict()
+}
+
+// If we're too big, evict old stuff.
+func (dt *dynamicTable) evict() {
+ var n int
+ for dt.size > dt.maxSize && n < dt.table.len() {
+ dt.size -= dt.table.ents[n].Size()
+ n++
+ }
+ dt.table.evictOldest(n)
+}
+
+func (d *Decoder) maxTableIndex() int {
+ // This should never overflow. RFC 7540 Section 6.5.2 limits the size of
+ // the dynamic table to 2^32 bytes, where each entry will occupy more than
+ // one byte. Further, the staticTable has a fixed, small length.
+ return d.dynTab.table.len() + staticTable.len()
+}
+
+func (d *Decoder) at(i uint64) (hf HeaderField, ok bool) {
+ // See Section 2.3.3.
+ if i == 0 {
+ return
+ }
+ if i <= uint64(staticTable.len()) {
+ return staticTable.ents[i-1], true
+ }
+ if i > uint64(d.maxTableIndex()) {
+ return
+ }
+ // In the dynamic table, newer entries have lower indices.
+ // However, dt.ents[0] is the oldest entry. Hence, dt.ents is
+ // the reversed dynamic table.
+ dt := d.dynTab.table
+ return dt.ents[dt.len()-(int(i)-staticTable.len())], true
+}
+
+// Decode decodes an entire block.
+//
+// TODO: remove this method and make it incremental later? This is
+// easier for debugging now.
+func (d *Decoder) DecodeFull(p []byte) ([]HeaderField, error) {
+ var hf []HeaderField
+ saveFunc := d.emit
+ defer func() { d.emit = saveFunc }()
+ d.emit = func(f HeaderField) { hf = append(hf, f) }
+ if _, err := d.Write(p); err != nil {
+ return nil, err
+ }
+ if err := d.Close(); err != nil {
+ return nil, err
+ }
+ return hf, nil
+}
+
+// Close declares that the decoding is complete and resets the Decoder
+// to be reused again for a new header block. If there is any remaining
+// data in the decoder's buffer, Close returns an error.
+func (d *Decoder) Close() error {
+ if d.saveBuf.Len() > 0 {
+ d.saveBuf.Reset()
+ return DecodingError{errors.New("truncated headers")}
+ }
+ d.firstField = true
+ return nil
+}
+
+func (d *Decoder) Write(p []byte) (n int, err error) {
+ if len(p) == 0 {
+ // Prevent state machine CPU attacks (making us redo
+ // work up to the point of finding out we don't have
+ // enough data)
+ return
+ }
+ // Only copy the data if we have to. Optimistically assume
+ // that p will contain a complete header block.
+ if d.saveBuf.Len() == 0 {
+ d.buf = p
+ } else {
+ d.saveBuf.Write(p)
+ d.buf = d.saveBuf.Bytes()
+ d.saveBuf.Reset()
+ }
+
+ for len(d.buf) > 0 {
+ err = d.parseHeaderFieldRepr()
+ if err == errNeedMore {
+ // Extra paranoia, making sure saveBuf won't
+ // get too large. All the varint and string
+ // reading code earlier should already catch
+ // overlong things and return ErrStringLength,
+ // but keep this as a last resort.
+ const varIntOverhead = 8 // conservative
+ if d.maxStrLen != 0 && int64(len(d.buf)) > 2*(int64(d.maxStrLen)+varIntOverhead) {
+ return 0, ErrStringLength
+ }
+ d.saveBuf.Write(d.buf)
+ return len(p), nil
+ }
+ d.firstField = false
+ if err != nil {
+ break
+ }
+ }
+ return len(p), err
+}
+
+// errNeedMore is an internal sentinel error value that means the
+// buffer is truncated and we need to read more data before we can
+// continue parsing.
+var errNeedMore = errors.New("need more data")
+
+type indexType int
+
+const (
+ indexedTrue indexType = iota
+ indexedFalse
+ indexedNever
+)
+
+func (v indexType) indexed() bool { return v == indexedTrue }
+func (v indexType) sensitive() bool { return v == indexedNever }
+
+// returns errNeedMore if there isn't enough data available.
+// any other error is fatal.
+// consumes d.buf iff it returns nil.
+// precondition: must be called with len(d.buf) > 0
+func (d *Decoder) parseHeaderFieldRepr() error {
+ b := d.buf[0]
+ switch {
+ case b&128 != 0:
+ // Indexed representation.
+ // High bit set?
+ // http://http2.github.io/http2-spec/compression.html#rfc.section.6.1
+ return d.parseFieldIndexed()
+ case b&192 == 64:
+ // 6.2.1 Literal Header Field with Incremental Indexing
+ // 0b10xxxxxx: top two bits are 10
+ // http://http2.github.io/http2-spec/compression.html#rfc.section.6.2.1
+ return d.parseFieldLiteral(6, indexedTrue)
+ case b&240 == 0:
+ // 6.2.2 Literal Header Field without Indexing
+ // 0b0000xxxx: top four bits are 0000
+ // http://http2.github.io/http2-spec/compression.html#rfc.section.6.2.2
+ return d.parseFieldLiteral(4, indexedFalse)
+ case b&240 == 16:
+ // 6.2.3 Literal Header Field never Indexed
+ // 0b0001xxxx: top four bits are 0001
+ // http://http2.github.io/http2-spec/compression.html#rfc.section.6.2.3
+ return d.parseFieldLiteral(4, indexedNever)
+ case b&224 == 32:
+ // 6.3 Dynamic Table Size Update
+ // Top three bits are '001'.
+ // http://http2.github.io/http2-spec/compression.html#rfc.section.6.3
+ return d.parseDynamicTableSizeUpdate()
+ }
+
+ return DecodingError{errors.New("invalid encoding")}
+}
+
+// (same invariants and behavior as parseHeaderFieldRepr)
+func (d *Decoder) parseFieldIndexed() error {
+ buf := d.buf
+ idx, buf, err := readVarInt(7, buf)
+ if err != nil {
+ return err
+ }
+ hf, ok := d.at(idx)
+ if !ok {
+ return DecodingError{InvalidIndexError(idx)}
+ }
+ d.buf = buf
+ return d.callEmit(HeaderField{Name: hf.Name, Value: hf.Value})
+}
+
+// (same invariants and behavior as parseHeaderFieldRepr)
+func (d *Decoder) parseFieldLiteral(n uint8, it indexType) error {
+ buf := d.buf
+ nameIdx, buf, err := readVarInt(n, buf)
+ if err != nil {
+ return err
+ }
+
+ var hf HeaderField
+ wantStr := d.emitEnabled || it.indexed()
+ if nameIdx > 0 {
+ ihf, ok := d.at(nameIdx)
+ if !ok {
+ return DecodingError{InvalidIndexError(nameIdx)}
+ }
+ hf.Name = ihf.Name
+ } else {
+ hf.Name, buf, err = d.readString(buf, wantStr)
+ if err != nil {
+ return err
+ }
+ }
+ hf.Value, buf, err = d.readString(buf, wantStr)
+ if err != nil {
+ return err
+ }
+ d.buf = buf
+ if it.indexed() {
+ d.dynTab.add(hf)
+ }
+ hf.Sensitive = it.sensitive()
+ return d.callEmit(hf)
+}
+
+func (d *Decoder) callEmit(hf HeaderField) error {
+ if d.maxStrLen != 0 {
+ if len(hf.Name) > d.maxStrLen || len(hf.Value) > d.maxStrLen {
+ return ErrStringLength
+ }
+ }
+ if d.emitEnabled {
+ d.emit(hf)
+ }
+ return nil
+}
+
+// (same invariants and behavior as parseHeaderFieldRepr)
+func (d *Decoder) parseDynamicTableSizeUpdate() error {
+ // RFC 7541, sec 4.2: This dynamic table size update MUST occur at the
+ // beginning of the first header block following the change to the dynamic table size.
+ if !d.firstField && d.dynTab.size > 0 {
+ return DecodingError{errors.New("dynamic table size update MUST occur at the beginning of a header block")}
+ }
+
+ buf := d.buf
+ size, buf, err := readVarInt(5, buf)
+ if err != nil {
+ return err
+ }
+ if size > uint64(d.dynTab.allowedMaxSize) {
+ return DecodingError{errors.New("dynamic table size update too large")}
+ }
+ d.dynTab.setMaxSize(uint32(size))
+ d.buf = buf
+ return nil
+}
+
+var errVarintOverflow = DecodingError{errors.New("varint integer overflow")}
+
+// readVarInt reads an unsigned variable length integer off the
+// beginning of p. n is the parameter as described in
+// http://http2.github.io/http2-spec/compression.html#rfc.section.5.1.
+//
+// n must always be between 1 and 8.
+//
+// The returned remain buffer is either a smaller suffix of p, or err != nil.
+// The error is errNeedMore if p doesn't contain a complete integer.
+func readVarInt(n byte, p []byte) (i uint64, remain []byte, err error) {
+ if n < 1 || n > 8 {
+ panic("bad n")
+ }
+ if len(p) == 0 {
+ return 0, p, errNeedMore
+ }
+ i = uint64(p[0])
+ if n < 8 {
+ i &= (1 << uint64(n)) - 1
+ }
+ if i < (1< 0 {
+ b := p[0]
+ p = p[1:]
+ i += uint64(b&127) << m
+ if b&128 == 0 {
+ return i, p, nil
+ }
+ m += 7
+ if m >= 63 { // TODO: proper overflow check. making this up.
+ return 0, origP, errVarintOverflow
+ }
+ }
+ return 0, origP, errNeedMore
+}
+
+// readString decodes an hpack string from p.
+//
+// wantStr is whether s will be used. If false, decompression and
+// []byte->string garbage are skipped if s will be ignored
+// anyway. This does mean that huffman decoding errors for non-indexed
+// strings past the MAX_HEADER_LIST_SIZE are ignored, but the server
+// is returning an error anyway, and because they're not indexed, the error
+// won't affect the decoding state.
+func (d *Decoder) readString(p []byte, wantStr bool) (s string, remain []byte, err error) {
+ if len(p) == 0 {
+ return "", p, errNeedMore
+ }
+ isHuff := p[0]&128 != 0
+ strLen, p, err := readVarInt(7, p)
+ if err != nil {
+ return "", p, err
+ }
+ if d.maxStrLen != 0 && strLen > uint64(d.maxStrLen) {
+ return "", nil, ErrStringLength
+ }
+ if uint64(len(p)) < strLen {
+ return "", p, errNeedMore
+ }
+ if !isHuff {
+ if wantStr {
+ s = string(p[:strLen])
+ }
+ return s, p[strLen:], nil
+ }
+
+ if wantStr {
+ buf := bufPool.Get().(*bytes.Buffer)
+ buf.Reset() // don't trust others
+ defer bufPool.Put(buf)
+ if err := huffmanDecode(buf, d.maxStrLen, p[:strLen]); err != nil {
+ buf.Reset()
+ return "", nil, err
+ }
+ s = buf.String()
+ buf.Reset() // be nice to GC
+ }
+ return s, p[strLen:], nil
+}
diff --git a/vendor/golang.org/x/net/http2/hpack/huffman.go b/vendor/golang.org/x/net/http2/hpack/huffman.go
new file mode 100644
index 0000000..b412a96
--- /dev/null
+++ b/vendor/golang.org/x/net/http2/hpack/huffman.go
@@ -0,0 +1,222 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package hpack
+
+import (
+ "bytes"
+ "errors"
+ "io"
+ "sync"
+)
+
+var bufPool = sync.Pool{
+ New: func() interface{} { return new(bytes.Buffer) },
+}
+
+// HuffmanDecode decodes the string in v and writes the expanded
+// result to w, returning the number of bytes written to w and the
+// Write call's return value. At most one Write call is made.
+func HuffmanDecode(w io.Writer, v []byte) (int, error) {
+ buf := bufPool.Get().(*bytes.Buffer)
+ buf.Reset()
+ defer bufPool.Put(buf)
+ if err := huffmanDecode(buf, 0, v); err != nil {
+ return 0, err
+ }
+ return w.Write(buf.Bytes())
+}
+
+// HuffmanDecodeToString decodes the string in v.
+func HuffmanDecodeToString(v []byte) (string, error) {
+ buf := bufPool.Get().(*bytes.Buffer)
+ buf.Reset()
+ defer bufPool.Put(buf)
+ if err := huffmanDecode(buf, 0, v); err != nil {
+ return "", err
+ }
+ return buf.String(), nil
+}
+
+// ErrInvalidHuffman is returned for errors found decoding
+// Huffman-encoded strings.
+var ErrInvalidHuffman = errors.New("hpack: invalid Huffman-encoded data")
+
+// huffmanDecode decodes v to buf.
+// If maxLen is greater than 0, attempts to write more to buf than
+// maxLen bytes will return ErrStringLength.
+func huffmanDecode(buf *bytes.Buffer, maxLen int, v []byte) error {
+ rootHuffmanNode := getRootHuffmanNode()
+ n := rootHuffmanNode
+ // cur is the bit buffer that has not been fed into n.
+ // cbits is the number of low order bits in cur that are valid.
+ // sbits is the number of bits of the symbol prefix being decoded.
+ cur, cbits, sbits := uint(0), uint8(0), uint8(0)
+ for _, b := range v {
+ cur = cur<<8 | uint(b)
+ cbits += 8
+ sbits += 8
+ for cbits >= 8 {
+ idx := byte(cur >> (cbits - 8))
+ n = n.children[idx]
+ if n == nil {
+ return ErrInvalidHuffman
+ }
+ if n.children == nil {
+ if maxLen != 0 && buf.Len() == maxLen {
+ return ErrStringLength
+ }
+ buf.WriteByte(n.sym)
+ cbits -= n.codeLen
+ n = rootHuffmanNode
+ sbits = cbits
+ } else {
+ cbits -= 8
+ }
+ }
+ }
+ for cbits > 0 {
+ n = n.children[byte(cur<<(8-cbits))]
+ if n == nil {
+ return ErrInvalidHuffman
+ }
+ if n.children != nil || n.codeLen > cbits {
+ break
+ }
+ if maxLen != 0 && buf.Len() == maxLen {
+ return ErrStringLength
+ }
+ buf.WriteByte(n.sym)
+ cbits -= n.codeLen
+ n = rootHuffmanNode
+ sbits = cbits
+ }
+ if sbits > 7 {
+ // Either there was an incomplete symbol, or overlong padding.
+ // Both are decoding errors per RFC 7541 section 5.2.
+ return ErrInvalidHuffman
+ }
+ if mask := uint(1< 8 {
+ codeLen -= 8
+ i := uint8(code >> codeLen)
+ if cur.children[i] == nil {
+ cur.children[i] = newInternalNode()
+ }
+ cur = cur.children[i]
+ }
+ shift := 8 - codeLen
+ start, end := int(uint8(code<> (nbits - rembits))
+ dst[len(dst)-1] |= t
+ }
+
+ return dst
+}
+
+// HuffmanEncodeLength returns the number of bytes required to encode
+// s in Huffman codes. The result is round up to byte boundary.
+func HuffmanEncodeLength(s string) uint64 {
+ n := uint64(0)
+ for i := 0; i < len(s); i++ {
+ n += uint64(huffmanCodeLen[s[i]])
+ }
+ return (n + 7) / 8
+}
+
+// appendByteToHuffmanCode appends Huffman code for c to dst and
+// returns the extended buffer and the remaining bits in the last
+// element. The appending is not byte aligned and the remaining bits
+// in the last element of dst is given in rembits.
+func appendByteToHuffmanCode(dst []byte, rembits uint8, c byte) ([]byte, uint8) {
+ code := huffmanCodes[c]
+ nbits := huffmanCodeLen[c]
+
+ for {
+ if rembits > nbits {
+ t := uint8(code << (rembits - nbits))
+ dst[len(dst)-1] |= t
+ rembits -= nbits
+ break
+ }
+
+ t := uint8(code >> (nbits - rembits))
+ dst[len(dst)-1] |= t
+
+ nbits -= rembits
+ rembits = 8
+
+ if nbits == 0 {
+ break
+ }
+
+ dst = append(dst, 0)
+ }
+
+ return dst, rembits
+}
diff --git a/vendor/golang.org/x/net/http2/hpack/tables.go b/vendor/golang.org/x/net/http2/hpack/tables.go
new file mode 100644
index 0000000..a66cfbe
--- /dev/null
+++ b/vendor/golang.org/x/net/http2/hpack/tables.go
@@ -0,0 +1,479 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package hpack
+
+import (
+ "fmt"
+)
+
+// headerFieldTable implements a list of HeaderFields.
+// This is used to implement the static and dynamic tables.
+type headerFieldTable struct {
+ // For static tables, entries are never evicted.
+ //
+ // For dynamic tables, entries are evicted from ents[0] and added to the end.
+ // Each entry has a unique id that starts at one and increments for each
+ // entry that is added. This unique id is stable across evictions, meaning
+ // it can be used as a pointer to a specific entry. As in hpack, unique ids
+ // are 1-based. The unique id for ents[k] is k + evictCount + 1.
+ //
+ // Zero is not a valid unique id.
+ //
+ // evictCount should not overflow in any remotely practical situation. In
+ // practice, we will have one dynamic table per HTTP/2 connection. If we
+ // assume a very powerful server that handles 1M QPS per connection and each
+ // request adds (then evicts) 100 entries from the table, it would still take
+ // 2M years for evictCount to overflow.
+ ents []HeaderField
+ evictCount uint64
+
+ // byName maps a HeaderField name to the unique id of the newest entry with
+ // the same name. See above for a definition of "unique id".
+ byName map[string]uint64
+
+ // byNameValue maps a HeaderField name/value pair to the unique id of the newest
+ // entry with the same name and value. See above for a definition of "unique id".
+ byNameValue map[pairNameValue]uint64
+}
+
+type pairNameValue struct {
+ name, value string
+}
+
+func (t *headerFieldTable) init() {
+ t.byName = make(map[string]uint64)
+ t.byNameValue = make(map[pairNameValue]uint64)
+}
+
+// len reports the number of entries in the table.
+func (t *headerFieldTable) len() int {
+ return len(t.ents)
+}
+
+// addEntry adds a new entry.
+func (t *headerFieldTable) addEntry(f HeaderField) {
+ id := uint64(t.len()) + t.evictCount + 1
+ t.byName[f.Name] = id
+ t.byNameValue[pairNameValue{f.Name, f.Value}] = id
+ t.ents = append(t.ents, f)
+}
+
+// evictOldest evicts the n oldest entries in the table.
+func (t *headerFieldTable) evictOldest(n int) {
+ if n > t.len() {
+ panic(fmt.Sprintf("evictOldest(%v) on table with %v entries", n, t.len()))
+ }
+ for k := 0; k < n; k++ {
+ f := t.ents[k]
+ id := t.evictCount + uint64(k) + 1
+ if t.byName[f.Name] == id {
+ delete(t.byName, f.Name)
+ }
+ if p := (pairNameValue{f.Name, f.Value}); t.byNameValue[p] == id {
+ delete(t.byNameValue, p)
+ }
+ }
+ copy(t.ents, t.ents[n:])
+ for k := t.len() - n; k < t.len(); k++ {
+ t.ents[k] = HeaderField{} // so strings can be garbage collected
+ }
+ t.ents = t.ents[:t.len()-n]
+ if t.evictCount+uint64(n) < t.evictCount {
+ panic("evictCount overflow")
+ }
+ t.evictCount += uint64(n)
+}
+
+// search finds f in the table. If there is no match, i is 0.
+// If both name and value match, i is the matched index and nameValueMatch
+// becomes true. If only name matches, i points to that index and
+// nameValueMatch becomes false.
+//
+// The returned index is a 1-based HPACK index. For dynamic tables, HPACK says
+// that index 1 should be the newest entry, but t.ents[0] is the oldest entry,
+// meaning t.ents is reversed for dynamic tables. Hence, when t is a dynamic
+// table, the return value i actually refers to the entry t.ents[t.len()-i].
+//
+// All tables are assumed to be a dynamic tables except for the global
+// staticTable pointer.
+//
+// See Section 2.3.3.
+func (t *headerFieldTable) search(f HeaderField) (i uint64, nameValueMatch bool) {
+ if !f.Sensitive {
+ if id := t.byNameValue[pairNameValue{f.Name, f.Value}]; id != 0 {
+ return t.idToIndex(id), true
+ }
+ }
+ if id := t.byName[f.Name]; id != 0 {
+ return t.idToIndex(id), false
+ }
+ return 0, false
+}
+
+// idToIndex converts a unique id to an HPACK index.
+// See Section 2.3.3.
+func (t *headerFieldTable) idToIndex(id uint64) uint64 {
+ if id <= t.evictCount {
+ panic(fmt.Sprintf("id (%v) <= evictCount (%v)", id, t.evictCount))
+ }
+ k := id - t.evictCount - 1 // convert id to an index t.ents[k]
+ if t != staticTable {
+ return uint64(t.len()) - k // dynamic table
+ }
+ return k + 1
+}
+
+// http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-07#appendix-B
+var staticTable = newStaticTable()
+var staticTableEntries = [...]HeaderField{
+ {Name: ":authority"},
+ {Name: ":method", Value: "GET"},
+ {Name: ":method", Value: "POST"},
+ {Name: ":path", Value: "/"},
+ {Name: ":path", Value: "/index.html"},
+ {Name: ":scheme", Value: "http"},
+ {Name: ":scheme", Value: "https"},
+ {Name: ":status", Value: "200"},
+ {Name: ":status", Value: "204"},
+ {Name: ":status", Value: "206"},
+ {Name: ":status", Value: "304"},
+ {Name: ":status", Value: "400"},
+ {Name: ":status", Value: "404"},
+ {Name: ":status", Value: "500"},
+ {Name: "accept-charset"},
+ {Name: "accept-encoding", Value: "gzip, deflate"},
+ {Name: "accept-language"},
+ {Name: "accept-ranges"},
+ {Name: "accept"},
+ {Name: "access-control-allow-origin"},
+ {Name: "age"},
+ {Name: "allow"},
+ {Name: "authorization"},
+ {Name: "cache-control"},
+ {Name: "content-disposition"},
+ {Name: "content-encoding"},
+ {Name: "content-language"},
+ {Name: "content-length"},
+ {Name: "content-location"},
+ {Name: "content-range"},
+ {Name: "content-type"},
+ {Name: "cookie"},
+ {Name: "date"},
+ {Name: "etag"},
+ {Name: "expect"},
+ {Name: "expires"},
+ {Name: "from"},
+ {Name: "host"},
+ {Name: "if-match"},
+ {Name: "if-modified-since"},
+ {Name: "if-none-match"},
+ {Name: "if-range"},
+ {Name: "if-unmodified-since"},
+ {Name: "last-modified"},
+ {Name: "link"},
+ {Name: "location"},
+ {Name: "max-forwards"},
+ {Name: "proxy-authenticate"},
+ {Name: "proxy-authorization"},
+ {Name: "range"},
+ {Name: "referer"},
+ {Name: "refresh"},
+ {Name: "retry-after"},
+ {Name: "server"},
+ {Name: "set-cookie"},
+ {Name: "strict-transport-security"},
+ {Name: "transfer-encoding"},
+ {Name: "user-agent"},
+ {Name: "vary"},
+ {Name: "via"},
+ {Name: "www-authenticate"},
+}
+
+func newStaticTable() *headerFieldTable {
+ t := &headerFieldTable{}
+ t.init()
+ for _, e := range staticTableEntries[:] {
+ t.addEntry(e)
+ }
+ return t
+}
+
+var huffmanCodes = [256]uint32{
+ 0x1ff8,
+ 0x7fffd8,
+ 0xfffffe2,
+ 0xfffffe3,
+ 0xfffffe4,
+ 0xfffffe5,
+ 0xfffffe6,
+ 0xfffffe7,
+ 0xfffffe8,
+ 0xffffea,
+ 0x3ffffffc,
+ 0xfffffe9,
+ 0xfffffea,
+ 0x3ffffffd,
+ 0xfffffeb,
+ 0xfffffec,
+ 0xfffffed,
+ 0xfffffee,
+ 0xfffffef,
+ 0xffffff0,
+ 0xffffff1,
+ 0xffffff2,
+ 0x3ffffffe,
+ 0xffffff3,
+ 0xffffff4,
+ 0xffffff5,
+ 0xffffff6,
+ 0xffffff7,
+ 0xffffff8,
+ 0xffffff9,
+ 0xffffffa,
+ 0xffffffb,
+ 0x14,
+ 0x3f8,
+ 0x3f9,
+ 0xffa,
+ 0x1ff9,
+ 0x15,
+ 0xf8,
+ 0x7fa,
+ 0x3fa,
+ 0x3fb,
+ 0xf9,
+ 0x7fb,
+ 0xfa,
+ 0x16,
+ 0x17,
+ 0x18,
+ 0x0,
+ 0x1,
+ 0x2,
+ 0x19,
+ 0x1a,
+ 0x1b,
+ 0x1c,
+ 0x1d,
+ 0x1e,
+ 0x1f,
+ 0x5c,
+ 0xfb,
+ 0x7ffc,
+ 0x20,
+ 0xffb,
+ 0x3fc,
+ 0x1ffa,
+ 0x21,
+ 0x5d,
+ 0x5e,
+ 0x5f,
+ 0x60,
+ 0x61,
+ 0x62,
+ 0x63,
+ 0x64,
+ 0x65,
+ 0x66,
+ 0x67,
+ 0x68,
+ 0x69,
+ 0x6a,
+ 0x6b,
+ 0x6c,
+ 0x6d,
+ 0x6e,
+ 0x6f,
+ 0x70,
+ 0x71,
+ 0x72,
+ 0xfc,
+ 0x73,
+ 0xfd,
+ 0x1ffb,
+ 0x7fff0,
+ 0x1ffc,
+ 0x3ffc,
+ 0x22,
+ 0x7ffd,
+ 0x3,
+ 0x23,
+ 0x4,
+ 0x24,
+ 0x5,
+ 0x25,
+ 0x26,
+ 0x27,
+ 0x6,
+ 0x74,
+ 0x75,
+ 0x28,
+ 0x29,
+ 0x2a,
+ 0x7,
+ 0x2b,
+ 0x76,
+ 0x2c,
+ 0x8,
+ 0x9,
+ 0x2d,
+ 0x77,
+ 0x78,
+ 0x79,
+ 0x7a,
+ 0x7b,
+ 0x7ffe,
+ 0x7fc,
+ 0x3ffd,
+ 0x1ffd,
+ 0xffffffc,
+ 0xfffe6,
+ 0x3fffd2,
+ 0xfffe7,
+ 0xfffe8,
+ 0x3fffd3,
+ 0x3fffd4,
+ 0x3fffd5,
+ 0x7fffd9,
+ 0x3fffd6,
+ 0x7fffda,
+ 0x7fffdb,
+ 0x7fffdc,
+ 0x7fffdd,
+ 0x7fffde,
+ 0xffffeb,
+ 0x7fffdf,
+ 0xffffec,
+ 0xffffed,
+ 0x3fffd7,
+ 0x7fffe0,
+ 0xffffee,
+ 0x7fffe1,
+ 0x7fffe2,
+ 0x7fffe3,
+ 0x7fffe4,
+ 0x1fffdc,
+ 0x3fffd8,
+ 0x7fffe5,
+ 0x3fffd9,
+ 0x7fffe6,
+ 0x7fffe7,
+ 0xffffef,
+ 0x3fffda,
+ 0x1fffdd,
+ 0xfffe9,
+ 0x3fffdb,
+ 0x3fffdc,
+ 0x7fffe8,
+ 0x7fffe9,
+ 0x1fffde,
+ 0x7fffea,
+ 0x3fffdd,
+ 0x3fffde,
+ 0xfffff0,
+ 0x1fffdf,
+ 0x3fffdf,
+ 0x7fffeb,
+ 0x7fffec,
+ 0x1fffe0,
+ 0x1fffe1,
+ 0x3fffe0,
+ 0x1fffe2,
+ 0x7fffed,
+ 0x3fffe1,
+ 0x7fffee,
+ 0x7fffef,
+ 0xfffea,
+ 0x3fffe2,
+ 0x3fffe3,
+ 0x3fffe4,
+ 0x7ffff0,
+ 0x3fffe5,
+ 0x3fffe6,
+ 0x7ffff1,
+ 0x3ffffe0,
+ 0x3ffffe1,
+ 0xfffeb,
+ 0x7fff1,
+ 0x3fffe7,
+ 0x7ffff2,
+ 0x3fffe8,
+ 0x1ffffec,
+ 0x3ffffe2,
+ 0x3ffffe3,
+ 0x3ffffe4,
+ 0x7ffffde,
+ 0x7ffffdf,
+ 0x3ffffe5,
+ 0xfffff1,
+ 0x1ffffed,
+ 0x7fff2,
+ 0x1fffe3,
+ 0x3ffffe6,
+ 0x7ffffe0,
+ 0x7ffffe1,
+ 0x3ffffe7,
+ 0x7ffffe2,
+ 0xfffff2,
+ 0x1fffe4,
+ 0x1fffe5,
+ 0x3ffffe8,
+ 0x3ffffe9,
+ 0xffffffd,
+ 0x7ffffe3,
+ 0x7ffffe4,
+ 0x7ffffe5,
+ 0xfffec,
+ 0xfffff3,
+ 0xfffed,
+ 0x1fffe6,
+ 0x3fffe9,
+ 0x1fffe7,
+ 0x1fffe8,
+ 0x7ffff3,
+ 0x3fffea,
+ 0x3fffeb,
+ 0x1ffffee,
+ 0x1ffffef,
+ 0xfffff4,
+ 0xfffff5,
+ 0x3ffffea,
+ 0x7ffff4,
+ 0x3ffffeb,
+ 0x7ffffe6,
+ 0x3ffffec,
+ 0x3ffffed,
+ 0x7ffffe7,
+ 0x7ffffe8,
+ 0x7ffffe9,
+ 0x7ffffea,
+ 0x7ffffeb,
+ 0xffffffe,
+ 0x7ffffec,
+ 0x7ffffed,
+ 0x7ffffee,
+ 0x7ffffef,
+ 0x7fffff0,
+ 0x3ffffee,
+}
+
+var huffmanCodeLen = [256]uint8{
+ 13, 23, 28, 28, 28, 28, 28, 28, 28, 24, 30, 28, 28, 30, 28, 28,
+ 28, 28, 28, 28, 28, 28, 30, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+ 6, 10, 10, 12, 13, 6, 8, 11, 10, 10, 8, 11, 8, 6, 6, 6,
+ 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 7, 8, 15, 6, 12, 10,
+ 13, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 8, 7, 8, 13, 19, 13, 14, 6,
+ 15, 5, 6, 5, 6, 5, 6, 6, 6, 5, 7, 7, 6, 6, 6, 5,
+ 6, 7, 6, 5, 5, 6, 7, 7, 7, 7, 7, 15, 11, 14, 13, 28,
+ 20, 22, 20, 20, 22, 22, 22, 23, 22, 23, 23, 23, 23, 23, 24, 23,
+ 24, 24, 22, 23, 24, 23, 23, 23, 23, 21, 22, 23, 22, 23, 23, 24,
+ 22, 21, 20, 22, 22, 23, 23, 21, 23, 22, 22, 24, 21, 22, 23, 23,
+ 21, 21, 22, 21, 23, 22, 23, 23, 20, 22, 22, 22, 23, 22, 22, 23,
+ 26, 26, 20, 19, 22, 23, 22, 25, 26, 26, 26, 27, 27, 26, 24, 25,
+ 19, 21, 26, 27, 27, 26, 27, 24, 21, 21, 26, 26, 28, 27, 27, 27,
+ 20, 24, 20, 21, 22, 21, 21, 23, 22, 22, 25, 25, 24, 24, 26, 23,
+ 26, 27, 26, 26, 27, 27, 27, 27, 27, 28, 27, 27, 27, 27, 27, 26,
+}
diff --git a/vendor/golang.org/x/net/http2/http2.go b/vendor/golang.org/x/net/http2/http2.go
new file mode 100644
index 0000000..bdaba1d
--- /dev/null
+++ b/vendor/golang.org/x/net/http2/http2.go
@@ -0,0 +1,384 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package http2 implements the HTTP/2 protocol.
+//
+// This package is low-level and intended to be used directly by very
+// few people. Most users will use it indirectly through the automatic
+// use by the net/http package (from Go 1.6 and later).
+// For use in earlier Go versions see ConfigureServer. (Transport support
+// requires Go 1.6 or later)
+//
+// See https://http2.github.io/ for more information on HTTP/2.
+//
+// See https://http2.golang.org/ for a test server running this code.
+//
+package http2 // import "golang.org/x/net/http2"
+
+import (
+ "bufio"
+ "crypto/tls"
+ "errors"
+ "fmt"
+ "io"
+ "net/http"
+ "os"
+ "sort"
+ "strconv"
+ "strings"
+ "sync"
+
+ "golang.org/x/net/http/httpguts"
+)
+
+var (
+ VerboseLogs bool
+ logFrameWrites bool
+ logFrameReads bool
+ inTests bool
+)
+
+func init() {
+ e := os.Getenv("GODEBUG")
+ if strings.Contains(e, "http2debug=1") {
+ VerboseLogs = true
+ }
+ if strings.Contains(e, "http2debug=2") {
+ VerboseLogs = true
+ logFrameWrites = true
+ logFrameReads = true
+ }
+}
+
+const (
+ // ClientPreface is the string that must be sent by new
+ // connections from clients.
+ ClientPreface = "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"
+
+ // SETTINGS_MAX_FRAME_SIZE default
+ // http://http2.github.io/http2-spec/#rfc.section.6.5.2
+ initialMaxFrameSize = 16384
+
+ // NextProtoTLS is the NPN/ALPN protocol negotiated during
+ // HTTP/2's TLS setup.
+ NextProtoTLS = "h2"
+
+ // http://http2.github.io/http2-spec/#SettingValues
+ initialHeaderTableSize = 4096
+
+ initialWindowSize = 65535 // 6.9.2 Initial Flow Control Window Size
+
+ defaultMaxReadFrameSize = 1 << 20
+)
+
+var (
+ clientPreface = []byte(ClientPreface)
+)
+
+type streamState int
+
+// HTTP/2 stream states.
+//
+// See http://tools.ietf.org/html/rfc7540#section-5.1.
+//
+// For simplicity, the server code merges "reserved (local)" into
+// "half-closed (remote)". This is one less state transition to track.
+// The only downside is that we send PUSH_PROMISEs slightly less
+// liberally than allowable. More discussion here:
+// https://lists.w3.org/Archives/Public/ietf-http-wg/2016JulSep/0599.html
+//
+// "reserved (remote)" is omitted since the client code does not
+// support server push.
+const (
+ stateIdle streamState = iota
+ stateOpen
+ stateHalfClosedLocal
+ stateHalfClosedRemote
+ stateClosed
+)
+
+var stateName = [...]string{
+ stateIdle: "Idle",
+ stateOpen: "Open",
+ stateHalfClosedLocal: "HalfClosedLocal",
+ stateHalfClosedRemote: "HalfClosedRemote",
+ stateClosed: "Closed",
+}
+
+func (st streamState) String() string {
+ return stateName[st]
+}
+
+// Setting is a setting parameter: which setting it is, and its value.
+type Setting struct {
+ // ID is which setting is being set.
+ // See http://http2.github.io/http2-spec/#SettingValues
+ ID SettingID
+
+ // Val is the value.
+ Val uint32
+}
+
+func (s Setting) String() string {
+ return fmt.Sprintf("[%v = %d]", s.ID, s.Val)
+}
+
+// Valid reports whether the setting is valid.
+func (s Setting) Valid() error {
+ // Limits and error codes from 6.5.2 Defined SETTINGS Parameters
+ switch s.ID {
+ case SettingEnablePush:
+ if s.Val != 1 && s.Val != 0 {
+ return ConnectionError(ErrCodeProtocol)
+ }
+ case SettingInitialWindowSize:
+ if s.Val > 1<<31-1 {
+ return ConnectionError(ErrCodeFlowControl)
+ }
+ case SettingMaxFrameSize:
+ if s.Val < 16384 || s.Val > 1<<24-1 {
+ return ConnectionError(ErrCodeProtocol)
+ }
+ }
+ return nil
+}
+
+// A SettingID is an HTTP/2 setting as defined in
+// http://http2.github.io/http2-spec/#iana-settings
+type SettingID uint16
+
+const (
+ SettingHeaderTableSize SettingID = 0x1
+ SettingEnablePush SettingID = 0x2
+ SettingMaxConcurrentStreams SettingID = 0x3
+ SettingInitialWindowSize SettingID = 0x4
+ SettingMaxFrameSize SettingID = 0x5
+ SettingMaxHeaderListSize SettingID = 0x6
+)
+
+var settingName = map[SettingID]string{
+ SettingHeaderTableSize: "HEADER_TABLE_SIZE",
+ SettingEnablePush: "ENABLE_PUSH",
+ SettingMaxConcurrentStreams: "MAX_CONCURRENT_STREAMS",
+ SettingInitialWindowSize: "INITIAL_WINDOW_SIZE",
+ SettingMaxFrameSize: "MAX_FRAME_SIZE",
+ SettingMaxHeaderListSize: "MAX_HEADER_LIST_SIZE",
+}
+
+func (s SettingID) String() string {
+ if v, ok := settingName[s]; ok {
+ return v
+ }
+ return fmt.Sprintf("UNKNOWN_SETTING_%d", uint16(s))
+}
+
+var (
+ errInvalidHeaderFieldName = errors.New("http2: invalid header field name")
+ errInvalidHeaderFieldValue = errors.New("http2: invalid header field value")
+)
+
+// validWireHeaderFieldName reports whether v is a valid header field
+// name (key). See httpguts.ValidHeaderName for the base rules.
+//
+// Further, http2 says:
+// "Just as in HTTP/1.x, header field names are strings of ASCII
+// characters that are compared in a case-insensitive
+// fashion. However, header field names MUST be converted to
+// lowercase prior to their encoding in HTTP/2. "
+func validWireHeaderFieldName(v string) bool {
+ if len(v) == 0 {
+ return false
+ }
+ for _, r := range v {
+ if !httpguts.IsTokenRune(r) {
+ return false
+ }
+ if 'A' <= r && r <= 'Z' {
+ return false
+ }
+ }
+ return true
+}
+
+func httpCodeString(code int) string {
+ switch code {
+ case 200:
+ return "200"
+ case 404:
+ return "404"
+ }
+ return strconv.Itoa(code)
+}
+
+// from pkg io
+type stringWriter interface {
+ WriteString(s string) (n int, err error)
+}
+
+// A gate lets two goroutines coordinate their activities.
+type gate chan struct{}
+
+func (g gate) Done() { g <- struct{}{} }
+func (g gate) Wait() { <-g }
+
+// A closeWaiter is like a sync.WaitGroup but only goes 1 to 0 (open to closed).
+type closeWaiter chan struct{}
+
+// Init makes a closeWaiter usable.
+// It exists because so a closeWaiter value can be placed inside a
+// larger struct and have the Mutex and Cond's memory in the same
+// allocation.
+func (cw *closeWaiter) Init() {
+ *cw = make(chan struct{})
+}
+
+// Close marks the closeWaiter as closed and unblocks any waiters.
+func (cw closeWaiter) Close() {
+ close(cw)
+}
+
+// Wait waits for the closeWaiter to become closed.
+func (cw closeWaiter) Wait() {
+ <-cw
+}
+
+// bufferedWriter is a buffered writer that writes to w.
+// Its buffered writer is lazily allocated as needed, to minimize
+// idle memory usage with many connections.
+type bufferedWriter struct {
+ w io.Writer // immutable
+ bw *bufio.Writer // non-nil when data is buffered
+}
+
+func newBufferedWriter(w io.Writer) *bufferedWriter {
+ return &bufferedWriter{w: w}
+}
+
+// bufWriterPoolBufferSize is the size of bufio.Writer's
+// buffers created using bufWriterPool.
+//
+// TODO: pick a less arbitrary value? this is a bit under
+// (3 x typical 1500 byte MTU) at least. Other than that,
+// not much thought went into it.
+const bufWriterPoolBufferSize = 4 << 10
+
+var bufWriterPool = sync.Pool{
+ New: func() interface{} {
+ return bufio.NewWriterSize(nil, bufWriterPoolBufferSize)
+ },
+}
+
+func (w *bufferedWriter) Available() int {
+ if w.bw == nil {
+ return bufWriterPoolBufferSize
+ }
+ return w.bw.Available()
+}
+
+func (w *bufferedWriter) Write(p []byte) (n int, err error) {
+ if w.bw == nil {
+ bw := bufWriterPool.Get().(*bufio.Writer)
+ bw.Reset(w.w)
+ w.bw = bw
+ }
+ return w.bw.Write(p)
+}
+
+func (w *bufferedWriter) Flush() error {
+ bw := w.bw
+ if bw == nil {
+ return nil
+ }
+ err := bw.Flush()
+ bw.Reset(nil)
+ bufWriterPool.Put(bw)
+ w.bw = nil
+ return err
+}
+
+func mustUint31(v int32) uint32 {
+ if v < 0 || v > 2147483647 {
+ panic("out of range")
+ }
+ return uint32(v)
+}
+
+// bodyAllowedForStatus reports whether a given response status code
+// permits a body. See RFC 7230, section 3.3.
+func bodyAllowedForStatus(status int) bool {
+ switch {
+ case status >= 100 && status <= 199:
+ return false
+ case status == 204:
+ return false
+ case status == 304:
+ return false
+ }
+ return true
+}
+
+type httpError struct {
+ msg string
+ timeout bool
+}
+
+func (e *httpError) Error() string { return e.msg }
+func (e *httpError) Timeout() bool { return e.timeout }
+func (e *httpError) Temporary() bool { return true }
+
+var errTimeout error = &httpError{msg: "http2: timeout awaiting response headers", timeout: true}
+
+type connectionStater interface {
+ ConnectionState() tls.ConnectionState
+}
+
+var sorterPool = sync.Pool{New: func() interface{} { return new(sorter) }}
+
+type sorter struct {
+ v []string // owned by sorter
+}
+
+func (s *sorter) Len() int { return len(s.v) }
+func (s *sorter) Swap(i, j int) { s.v[i], s.v[j] = s.v[j], s.v[i] }
+func (s *sorter) Less(i, j int) bool { return s.v[i] < s.v[j] }
+
+// Keys returns the sorted keys of h.
+//
+// The returned slice is only valid until s used again or returned to
+// its pool.
+func (s *sorter) Keys(h http.Header) []string {
+ keys := s.v[:0]
+ for k := range h {
+ keys = append(keys, k)
+ }
+ s.v = keys
+ sort.Sort(s)
+ return keys
+}
+
+func (s *sorter) SortStrings(ss []string) {
+ // Our sorter works on s.v, which sorter owns, so
+ // stash it away while we sort the user's buffer.
+ save := s.v
+ s.v = ss
+ sort.Sort(s)
+ s.v = save
+}
+
+// validPseudoPath reports whether v is a valid :path pseudo-header
+// value. It must be either:
+//
+// *) a non-empty string starting with '/'
+// *) the string '*', for OPTIONS requests.
+//
+// For now this is only used a quick check for deciding when to clean
+// up Opaque URLs before sending requests from the Transport.
+// See golang.org/issue/16847
+//
+// We used to enforce that the path also didn't start with "//", but
+// Google's GFE accepts such paths and Chrome sends them, so ignore
+// that part of the spec. See golang.org/issue/19103.
+func validPseudoPath(v string) bool {
+ return (len(v) > 0 && v[0] == '/') || v == "*"
+}
diff --git a/vendor/golang.org/x/net/http2/not_go111.go b/vendor/golang.org/x/net/http2/not_go111.go
new file mode 100644
index 0000000..161bca7
--- /dev/null
+++ b/vendor/golang.org/x/net/http2/not_go111.go
@@ -0,0 +1,20 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !go1.11
+
+package http2
+
+import (
+ "net/http/httptrace"
+ "net/textproto"
+)
+
+func traceHasWroteHeaderField(trace *httptrace.ClientTrace) bool { return false }
+
+func traceWroteHeaderField(trace *httptrace.ClientTrace, k, v string) {}
+
+func traceGot1xxResponseFunc(trace *httptrace.ClientTrace) func(int, textproto.MIMEHeader) error {
+ return nil
+}
diff --git a/vendor/golang.org/x/net/http2/pipe.go b/vendor/golang.org/x/net/http2/pipe.go
new file mode 100644
index 0000000..a614009
--- /dev/null
+++ b/vendor/golang.org/x/net/http2/pipe.go
@@ -0,0 +1,163 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package http2
+
+import (
+ "errors"
+ "io"
+ "sync"
+)
+
+// pipe is a goroutine-safe io.Reader/io.Writer pair. It's like
+// io.Pipe except there are no PipeReader/PipeWriter halves, and the
+// underlying buffer is an interface. (io.Pipe is always unbuffered)
+type pipe struct {
+ mu sync.Mutex
+ c sync.Cond // c.L lazily initialized to &p.mu
+ b pipeBuffer // nil when done reading
+ err error // read error once empty. non-nil means closed.
+ breakErr error // immediate read error (caller doesn't see rest of b)
+ donec chan struct{} // closed on error
+ readFn func() // optional code to run in Read before error
+}
+
+type pipeBuffer interface {
+ Len() int
+ io.Writer
+ io.Reader
+}
+
+func (p *pipe) Len() int {
+ p.mu.Lock()
+ defer p.mu.Unlock()
+ if p.b == nil {
+ return 0
+ }
+ return p.b.Len()
+}
+
+// Read waits until data is available and copies bytes
+// from the buffer into p.
+func (p *pipe) Read(d []byte) (n int, err error) {
+ p.mu.Lock()
+ defer p.mu.Unlock()
+ if p.c.L == nil {
+ p.c.L = &p.mu
+ }
+ for {
+ if p.breakErr != nil {
+ return 0, p.breakErr
+ }
+ if p.b != nil && p.b.Len() > 0 {
+ return p.b.Read(d)
+ }
+ if p.err != nil {
+ if p.readFn != nil {
+ p.readFn() // e.g. copy trailers
+ p.readFn = nil // not sticky like p.err
+ }
+ p.b = nil
+ return 0, p.err
+ }
+ p.c.Wait()
+ }
+}
+
+var errClosedPipeWrite = errors.New("write on closed buffer")
+
+// Write copies bytes from p into the buffer and wakes a reader.
+// It is an error to write more data than the buffer can hold.
+func (p *pipe) Write(d []byte) (n int, err error) {
+ p.mu.Lock()
+ defer p.mu.Unlock()
+ if p.c.L == nil {
+ p.c.L = &p.mu
+ }
+ defer p.c.Signal()
+ if p.err != nil {
+ return 0, errClosedPipeWrite
+ }
+ if p.breakErr != nil {
+ return len(d), nil // discard when there is no reader
+ }
+ return p.b.Write(d)
+}
+
+// CloseWithError causes the next Read (waking up a current blocked
+// Read if needed) to return the provided err after all data has been
+// read.
+//
+// The error must be non-nil.
+func (p *pipe) CloseWithError(err error) { p.closeWithError(&p.err, err, nil) }
+
+// BreakWithError causes the next Read (waking up a current blocked
+// Read if needed) to return the provided err immediately, without
+// waiting for unread data.
+func (p *pipe) BreakWithError(err error) { p.closeWithError(&p.breakErr, err, nil) }
+
+// closeWithErrorAndCode is like CloseWithError but also sets some code to run
+// in the caller's goroutine before returning the error.
+func (p *pipe) closeWithErrorAndCode(err error, fn func()) { p.closeWithError(&p.err, err, fn) }
+
+func (p *pipe) closeWithError(dst *error, err error, fn func()) {
+ if err == nil {
+ panic("err must be non-nil")
+ }
+ p.mu.Lock()
+ defer p.mu.Unlock()
+ if p.c.L == nil {
+ p.c.L = &p.mu
+ }
+ defer p.c.Signal()
+ if *dst != nil {
+ // Already been done.
+ return
+ }
+ p.readFn = fn
+ if dst == &p.breakErr {
+ p.b = nil
+ }
+ *dst = err
+ p.closeDoneLocked()
+}
+
+// requires p.mu be held.
+func (p *pipe) closeDoneLocked() {
+ if p.donec == nil {
+ return
+ }
+ // Close if unclosed. This isn't racy since we always
+ // hold p.mu while closing.
+ select {
+ case <-p.donec:
+ default:
+ close(p.donec)
+ }
+}
+
+// Err returns the error (if any) first set by BreakWithError or CloseWithError.
+func (p *pipe) Err() error {
+ p.mu.Lock()
+ defer p.mu.Unlock()
+ if p.breakErr != nil {
+ return p.breakErr
+ }
+ return p.err
+}
+
+// Done returns a channel which is closed if and when this pipe is closed
+// with CloseWithError.
+func (p *pipe) Done() <-chan struct{} {
+ p.mu.Lock()
+ defer p.mu.Unlock()
+ if p.donec == nil {
+ p.donec = make(chan struct{})
+ if p.err != nil || p.breakErr != nil {
+ // Already hit an error.
+ p.closeDoneLocked()
+ }
+ }
+ return p.donec
+}
diff --git a/vendor/golang.org/x/net/http2/server.go b/vendor/golang.org/x/net/http2/server.go
new file mode 100644
index 0000000..b7524ba
--- /dev/null
+++ b/vendor/golang.org/x/net/http2/server.go
@@ -0,0 +1,2961 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// TODO: turn off the serve goroutine when idle, so
+// an idle conn only has the readFrames goroutine active. (which could
+// also be optimized probably to pin less memory in crypto/tls). This
+// would involve tracking when the serve goroutine is active (atomic
+// int32 read/CAS probably?) and starting it up when frames arrive,
+// and shutting it down when all handlers exit. the occasional PING
+// packets could use time.AfterFunc to call sc.wakeStartServeLoop()
+// (which is a no-op if already running) and then queue the PING write
+// as normal. The serve loop would then exit in most cases (if no
+// Handlers running) and not be woken up again until the PING packet
+// returns.
+
+// TODO (maybe): add a mechanism for Handlers to going into
+// half-closed-local mode (rw.(io.Closer) test?) but not exit their
+// handler, and continue to be able to read from the
+// Request.Body. This would be a somewhat semantic change from HTTP/1
+// (or at least what we expose in net/http), so I'd probably want to
+// add it there too. For now, this package says that returning from
+// the Handler ServeHTTP function means you're both done reading and
+// done writing, without a way to stop just one or the other.
+
+package http2
+
+import (
+ "bufio"
+ "bytes"
+ "context"
+ "crypto/tls"
+ "errors"
+ "fmt"
+ "io"
+ "log"
+ "math"
+ "net"
+ "net/http"
+ "net/textproto"
+ "net/url"
+ "os"
+ "reflect"
+ "runtime"
+ "strconv"
+ "strings"
+ "sync"
+ "time"
+
+ "golang.org/x/net/http/httpguts"
+ "golang.org/x/net/http2/hpack"
+)
+
+const (
+ prefaceTimeout = 10 * time.Second
+ firstSettingsTimeout = 2 * time.Second // should be in-flight with preface anyway
+ handlerChunkWriteSize = 4 << 10
+ defaultMaxStreams = 250 // TODO: make this 100 as the GFE seems to?
+ maxQueuedControlFrames = 10000
+)
+
+var (
+ errClientDisconnected = errors.New("client disconnected")
+ errClosedBody = errors.New("body closed by handler")
+ errHandlerComplete = errors.New("http2: request body closed due to handler exiting")
+ errStreamClosed = errors.New("http2: stream closed")
+)
+
+var responseWriterStatePool = sync.Pool{
+ New: func() interface{} {
+ rws := &responseWriterState{}
+ rws.bw = bufio.NewWriterSize(chunkWriter{rws}, handlerChunkWriteSize)
+ return rws
+ },
+}
+
+// Test hooks.
+var (
+ testHookOnConn func()
+ testHookGetServerConn func(*serverConn)
+ testHookOnPanicMu *sync.Mutex // nil except in tests
+ testHookOnPanic func(sc *serverConn, panicVal interface{}) (rePanic bool)
+)
+
+// Server is an HTTP/2 server.
+type Server struct {
+ // MaxHandlers limits the number of http.Handler ServeHTTP goroutines
+ // which may run at a time over all connections.
+ // Negative or zero no limit.
+ // TODO: implement
+ MaxHandlers int
+
+ // MaxConcurrentStreams optionally specifies the number of
+ // concurrent streams that each client may have open at a
+ // time. This is unrelated to the number of http.Handler goroutines
+ // which may be active globally, which is MaxHandlers.
+ // If zero, MaxConcurrentStreams defaults to at least 100, per
+ // the HTTP/2 spec's recommendations.
+ MaxConcurrentStreams uint32
+
+ // MaxReadFrameSize optionally specifies the largest frame
+ // this server is willing to read. A valid value is between
+ // 16k and 16M, inclusive. If zero or otherwise invalid, a
+ // default value is used.
+ MaxReadFrameSize uint32
+
+ // PermitProhibitedCipherSuites, if true, permits the use of
+ // cipher suites prohibited by the HTTP/2 spec.
+ PermitProhibitedCipherSuites bool
+
+ // IdleTimeout specifies how long until idle clients should be
+ // closed with a GOAWAY frame. PING frames are not considered
+ // activity for the purposes of IdleTimeout.
+ IdleTimeout time.Duration
+
+ // MaxUploadBufferPerConnection is the size of the initial flow
+ // control window for each connections. The HTTP/2 spec does not
+ // allow this to be smaller than 65535 or larger than 2^32-1.
+ // If the value is outside this range, a default value will be
+ // used instead.
+ MaxUploadBufferPerConnection int32
+
+ // MaxUploadBufferPerStream is the size of the initial flow control
+ // window for each stream. The HTTP/2 spec does not allow this to
+ // be larger than 2^32-1. If the value is zero or larger than the
+ // maximum, a default value will be used instead.
+ MaxUploadBufferPerStream int32
+
+ // NewWriteScheduler constructs a write scheduler for a connection.
+ // If nil, a default scheduler is chosen.
+ NewWriteScheduler func() WriteScheduler
+
+ // Internal state. This is a pointer (rather than embedded directly)
+ // so that we don't embed a Mutex in this struct, which will make the
+ // struct non-copyable, which might break some callers.
+ state *serverInternalState
+}
+
+func (s *Server) initialConnRecvWindowSize() int32 {
+ if s.MaxUploadBufferPerConnection > initialWindowSize {
+ return s.MaxUploadBufferPerConnection
+ }
+ return 1 << 20
+}
+
+func (s *Server) initialStreamRecvWindowSize() int32 {
+ if s.MaxUploadBufferPerStream > 0 {
+ return s.MaxUploadBufferPerStream
+ }
+ return 1 << 20
+}
+
+func (s *Server) maxReadFrameSize() uint32 {
+ if v := s.MaxReadFrameSize; v >= minMaxFrameSize && v <= maxFrameSize {
+ return v
+ }
+ return defaultMaxReadFrameSize
+}
+
+func (s *Server) maxConcurrentStreams() uint32 {
+ if v := s.MaxConcurrentStreams; v > 0 {
+ return v
+ }
+ return defaultMaxStreams
+}
+
+// maxQueuedControlFrames is the maximum number of control frames like
+// SETTINGS, PING and RST_STREAM that will be queued for writing before
+// the connection is closed to prevent memory exhaustion attacks.
+func (s *Server) maxQueuedControlFrames() int {
+ // TODO: if anybody asks, add a Server field, and remember to define the
+ // behavior of negative values.
+ return maxQueuedControlFrames
+}
+
+type serverInternalState struct {
+ mu sync.Mutex
+ activeConns map[*serverConn]struct{}
+}
+
+func (s *serverInternalState) registerConn(sc *serverConn) {
+ if s == nil {
+ return // if the Server was used without calling ConfigureServer
+ }
+ s.mu.Lock()
+ s.activeConns[sc] = struct{}{}
+ s.mu.Unlock()
+}
+
+func (s *serverInternalState) unregisterConn(sc *serverConn) {
+ if s == nil {
+ return // if the Server was used without calling ConfigureServer
+ }
+ s.mu.Lock()
+ delete(s.activeConns, sc)
+ s.mu.Unlock()
+}
+
+func (s *serverInternalState) startGracefulShutdown() {
+ if s == nil {
+ return // if the Server was used without calling ConfigureServer
+ }
+ s.mu.Lock()
+ for sc := range s.activeConns {
+ sc.startGracefulShutdown()
+ }
+ s.mu.Unlock()
+}
+
+// ConfigureServer adds HTTP/2 support to a net/http Server.
+//
+// The configuration conf may be nil.
+//
+// ConfigureServer must be called before s begins serving.
+func ConfigureServer(s *http.Server, conf *Server) error {
+ if s == nil {
+ panic("nil *http.Server")
+ }
+ if conf == nil {
+ conf = new(Server)
+ }
+ conf.state = &serverInternalState{activeConns: make(map[*serverConn]struct{})}
+ if h1, h2 := s, conf; h2.IdleTimeout == 0 {
+ if h1.IdleTimeout != 0 {
+ h2.IdleTimeout = h1.IdleTimeout
+ } else {
+ h2.IdleTimeout = h1.ReadTimeout
+ }
+ }
+ s.RegisterOnShutdown(conf.state.startGracefulShutdown)
+
+ if s.TLSConfig == nil {
+ s.TLSConfig = new(tls.Config)
+ } else if s.TLSConfig.CipherSuites != nil {
+ // If they already provided a CipherSuite list, return
+ // an error if it has a bad order or is missing
+ // ECDHE_RSA_WITH_AES_128_GCM_SHA256 or ECDHE_ECDSA_WITH_AES_128_GCM_SHA256.
+ haveRequired := false
+ sawBad := false
+ for i, cs := range s.TLSConfig.CipherSuites {
+ switch cs {
+ case tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+ // Alternative MTI cipher to not discourage ECDSA-only servers.
+ // See http://golang.org/cl/30721 for further information.
+ tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:
+ haveRequired = true
+ }
+ if isBadCipher(cs) {
+ sawBad = true
+ } else if sawBad {
+ return fmt.Errorf("http2: TLSConfig.CipherSuites index %d contains an HTTP/2-approved cipher suite (%#04x), but it comes after unapproved cipher suites. With this configuration, clients that don't support previous, approved cipher suites may be given an unapproved one and reject the connection.", i, cs)
+ }
+ }
+ if !haveRequired {
+ return fmt.Errorf("http2: TLSConfig.CipherSuites is missing an HTTP/2-required AES_128_GCM_SHA256 cipher.")
+ }
+ }
+
+ // Note: not setting MinVersion to tls.VersionTLS12,
+ // as we don't want to interfere with HTTP/1.1 traffic
+ // on the user's server. We enforce TLS 1.2 later once
+ // we accept a connection. Ideally this should be done
+ // during next-proto selection, but using TLS <1.2 with
+ // HTTP/2 is still the client's bug.
+
+ s.TLSConfig.PreferServerCipherSuites = true
+
+ haveNPN := false
+ for _, p := range s.TLSConfig.NextProtos {
+ if p == NextProtoTLS {
+ haveNPN = true
+ break
+ }
+ }
+ if !haveNPN {
+ s.TLSConfig.NextProtos = append(s.TLSConfig.NextProtos, NextProtoTLS)
+ }
+
+ if s.TLSNextProto == nil {
+ s.TLSNextProto = map[string]func(*http.Server, *tls.Conn, http.Handler){}
+ }
+ protoHandler := func(hs *http.Server, c *tls.Conn, h http.Handler) {
+ if testHookOnConn != nil {
+ testHookOnConn()
+ }
+ // The TLSNextProto interface predates contexts, so
+ // the net/http package passes down its per-connection
+ // base context via an exported but unadvertised
+ // method on the Handler. This is for internal
+ // net/http<=>http2 use only.
+ var ctx context.Context
+ type baseContexter interface {
+ BaseContext() context.Context
+ }
+ if bc, ok := h.(baseContexter); ok {
+ ctx = bc.BaseContext()
+ }
+ conf.ServeConn(c, &ServeConnOpts{
+ Context: ctx,
+ Handler: h,
+ BaseConfig: hs,
+ })
+ }
+ s.TLSNextProto[NextProtoTLS] = protoHandler
+ return nil
+}
+
+// ServeConnOpts are options for the Server.ServeConn method.
+type ServeConnOpts struct {
+ // Context is the base context to use.
+ // If nil, context.Background is used.
+ Context context.Context
+
+ // BaseConfig optionally sets the base configuration
+ // for values. If nil, defaults are used.
+ BaseConfig *http.Server
+
+ // Handler specifies which handler to use for processing
+ // requests. If nil, BaseConfig.Handler is used. If BaseConfig
+ // or BaseConfig.Handler is nil, http.DefaultServeMux is used.
+ Handler http.Handler
+}
+
+func (o *ServeConnOpts) context() context.Context {
+ if o != nil && o.Context != nil {
+ return o.Context
+ }
+ return context.Background()
+}
+
+func (o *ServeConnOpts) baseConfig() *http.Server {
+ if o != nil && o.BaseConfig != nil {
+ return o.BaseConfig
+ }
+ return new(http.Server)
+}
+
+func (o *ServeConnOpts) handler() http.Handler {
+ if o != nil {
+ if o.Handler != nil {
+ return o.Handler
+ }
+ if o.BaseConfig != nil && o.BaseConfig.Handler != nil {
+ return o.BaseConfig.Handler
+ }
+ }
+ return http.DefaultServeMux
+}
+
+// ServeConn serves HTTP/2 requests on the provided connection and
+// blocks until the connection is no longer readable.
+//
+// ServeConn starts speaking HTTP/2 assuming that c has not had any
+// reads or writes. It writes its initial settings frame and expects
+// to be able to read the preface and settings frame from the
+// client. If c has a ConnectionState method like a *tls.Conn, the
+// ConnectionState is used to verify the TLS ciphersuite and to set
+// the Request.TLS field in Handlers.
+//
+// ServeConn does not support h2c by itself. Any h2c support must be
+// implemented in terms of providing a suitably-behaving net.Conn.
+//
+// The opts parameter is optional. If nil, default values are used.
+func (s *Server) ServeConn(c net.Conn, opts *ServeConnOpts) {
+ baseCtx, cancel := serverConnBaseContext(c, opts)
+ defer cancel()
+
+ sc := &serverConn{
+ srv: s,
+ hs: opts.baseConfig(),
+ conn: c,
+ baseCtx: baseCtx,
+ remoteAddrStr: c.RemoteAddr().String(),
+ bw: newBufferedWriter(c),
+ handler: opts.handler(),
+ streams: make(map[uint32]*stream),
+ readFrameCh: make(chan readFrameResult),
+ wantWriteFrameCh: make(chan FrameWriteRequest, 8),
+ serveMsgCh: make(chan interface{}, 8),
+ wroteFrameCh: make(chan frameWriteResult, 1), // buffered; one send in writeFrameAsync
+ bodyReadCh: make(chan bodyReadMsg), // buffering doesn't matter either way
+ doneServing: make(chan struct{}),
+ clientMaxStreams: math.MaxUint32, // Section 6.5.2: "Initially, there is no limit to this value"
+ advMaxStreams: s.maxConcurrentStreams(),
+ initialStreamSendWindowSize: initialWindowSize,
+ maxFrameSize: initialMaxFrameSize,
+ headerTableSize: initialHeaderTableSize,
+ serveG: newGoroutineLock(),
+ pushEnabled: true,
+ }
+
+ s.state.registerConn(sc)
+ defer s.state.unregisterConn(sc)
+
+ // The net/http package sets the write deadline from the
+ // http.Server.WriteTimeout during the TLS handshake, but then
+ // passes the connection off to us with the deadline already set.
+ // Write deadlines are set per stream in serverConn.newStream.
+ // Disarm the net.Conn write deadline here.
+ if sc.hs.WriteTimeout != 0 {
+ sc.conn.SetWriteDeadline(time.Time{})
+ }
+
+ if s.NewWriteScheduler != nil {
+ sc.writeSched = s.NewWriteScheduler()
+ } else {
+ sc.writeSched = NewRandomWriteScheduler()
+ }
+
+ // These start at the RFC-specified defaults. If there is a higher
+ // configured value for inflow, that will be updated when we send a
+ // WINDOW_UPDATE shortly after sending SETTINGS.
+ sc.flow.add(initialWindowSize)
+ sc.inflow.add(initialWindowSize)
+ sc.hpackEncoder = hpack.NewEncoder(&sc.headerWriteBuf)
+
+ fr := NewFramer(sc.bw, c)
+ fr.ReadMetaHeaders = hpack.NewDecoder(initialHeaderTableSize, nil)
+ fr.MaxHeaderListSize = sc.maxHeaderListSize()
+ fr.SetMaxReadFrameSize(s.maxReadFrameSize())
+ sc.framer = fr
+
+ if tc, ok := c.(connectionStater); ok {
+ sc.tlsState = new(tls.ConnectionState)
+ *sc.tlsState = tc.ConnectionState()
+ // 9.2 Use of TLS Features
+ // An implementation of HTTP/2 over TLS MUST use TLS
+ // 1.2 or higher with the restrictions on feature set
+ // and cipher suite described in this section. Due to
+ // implementation limitations, it might not be
+ // possible to fail TLS negotiation. An endpoint MUST
+ // immediately terminate an HTTP/2 connection that
+ // does not meet the TLS requirements described in
+ // this section with a connection error (Section
+ // 5.4.1) of type INADEQUATE_SECURITY.
+ if sc.tlsState.Version < tls.VersionTLS12 {
+ sc.rejectConn(ErrCodeInadequateSecurity, "TLS version too low")
+ return
+ }
+
+ if sc.tlsState.ServerName == "" {
+ // Client must use SNI, but we don't enforce that anymore,
+ // since it was causing problems when connecting to bare IP
+ // addresses during development.
+ //
+ // TODO: optionally enforce? Or enforce at the time we receive
+ // a new request, and verify the ServerName matches the :authority?
+ // But that precludes proxy situations, perhaps.
+ //
+ // So for now, do nothing here again.
+ }
+
+ if !s.PermitProhibitedCipherSuites && isBadCipher(sc.tlsState.CipherSuite) {
+ // "Endpoints MAY choose to generate a connection error
+ // (Section 5.4.1) of type INADEQUATE_SECURITY if one of
+ // the prohibited cipher suites are negotiated."
+ //
+ // We choose that. In my opinion, the spec is weak
+ // here. It also says both parties must support at least
+ // TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 so there's no
+ // excuses here. If we really must, we could allow an
+ // "AllowInsecureWeakCiphers" option on the server later.
+ // Let's see how it plays out first.
+ sc.rejectConn(ErrCodeInadequateSecurity, fmt.Sprintf("Prohibited TLS 1.2 Cipher Suite: %x", sc.tlsState.CipherSuite))
+ return
+ }
+ }
+
+ if hook := testHookGetServerConn; hook != nil {
+ hook(sc)
+ }
+ sc.serve()
+}
+
+func serverConnBaseContext(c net.Conn, opts *ServeConnOpts) (ctx context.Context, cancel func()) {
+ ctx, cancel = context.WithCancel(opts.context())
+ ctx = context.WithValue(ctx, http.LocalAddrContextKey, c.LocalAddr())
+ if hs := opts.baseConfig(); hs != nil {
+ ctx = context.WithValue(ctx, http.ServerContextKey, hs)
+ }
+ return
+}
+
+func (sc *serverConn) rejectConn(err ErrCode, debug string) {
+ sc.vlogf("http2: server rejecting conn: %v, %s", err, debug)
+ // ignoring errors. hanging up anyway.
+ sc.framer.WriteGoAway(0, err, []byte(debug))
+ sc.bw.Flush()
+ sc.conn.Close()
+}
+
+type serverConn struct {
+ // Immutable:
+ srv *Server
+ hs *http.Server
+ conn net.Conn
+ bw *bufferedWriter // writing to conn
+ handler http.Handler
+ baseCtx context.Context
+ framer *Framer
+ doneServing chan struct{} // closed when serverConn.serve ends
+ readFrameCh chan readFrameResult // written by serverConn.readFrames
+ wantWriteFrameCh chan FrameWriteRequest // from handlers -> serve
+ wroteFrameCh chan frameWriteResult // from writeFrameAsync -> serve, tickles more frame writes
+ bodyReadCh chan bodyReadMsg // from handlers -> serve
+ serveMsgCh chan interface{} // misc messages & code to send to / run on the serve loop
+ flow flow // conn-wide (not stream-specific) outbound flow control
+ inflow flow // conn-wide inbound flow control
+ tlsState *tls.ConnectionState // shared by all handlers, like net/http
+ remoteAddrStr string
+ writeSched WriteScheduler
+
+ // Everything following is owned by the serve loop; use serveG.check():
+ serveG goroutineLock // used to verify funcs are on serve()
+ pushEnabled bool
+ sawFirstSettings bool // got the initial SETTINGS frame after the preface
+ needToSendSettingsAck bool
+ unackedSettings int // how many SETTINGS have we sent without ACKs?
+ queuedControlFrames int // control frames in the writeSched queue
+ clientMaxStreams uint32 // SETTINGS_MAX_CONCURRENT_STREAMS from client (our PUSH_PROMISE limit)
+ advMaxStreams uint32 // our SETTINGS_MAX_CONCURRENT_STREAMS advertised the client
+ curClientStreams uint32 // number of open streams initiated by the client
+ curPushedStreams uint32 // number of open streams initiated by server push
+ maxClientStreamID uint32 // max ever seen from client (odd), or 0 if there have been no client requests
+ maxPushPromiseID uint32 // ID of the last push promise (even), or 0 if there have been no pushes
+ streams map[uint32]*stream
+ initialStreamSendWindowSize int32
+ maxFrameSize int32
+ headerTableSize uint32
+ peerMaxHeaderListSize uint32 // zero means unknown (default)
+ canonHeader map[string]string // http2-lower-case -> Go-Canonical-Case
+ writingFrame bool // started writing a frame (on serve goroutine or separate)
+ writingFrameAsync bool // started a frame on its own goroutine but haven't heard back on wroteFrameCh
+ needsFrameFlush bool // last frame write wasn't a flush
+ inGoAway bool // we've started to or sent GOAWAY
+ inFrameScheduleLoop bool // whether we're in the scheduleFrameWrite loop
+ needToSendGoAway bool // we need to schedule a GOAWAY frame write
+ goAwayCode ErrCode
+ shutdownTimer *time.Timer // nil until used
+ idleTimer *time.Timer // nil if unused
+
+ // Owned by the writeFrameAsync goroutine:
+ headerWriteBuf bytes.Buffer
+ hpackEncoder *hpack.Encoder
+
+ // Used by startGracefulShutdown.
+ shutdownOnce sync.Once
+}
+
+func (sc *serverConn) maxHeaderListSize() uint32 {
+ n := sc.hs.MaxHeaderBytes
+ if n <= 0 {
+ n = http.DefaultMaxHeaderBytes
+ }
+ // http2's count is in a slightly different unit and includes 32 bytes per pair.
+ // So, take the net/http.Server value and pad it up a bit, assuming 10 headers.
+ const perFieldOverhead = 32 // per http2 spec
+ const typicalHeaders = 10 // conservative
+ return uint32(n + typicalHeaders*perFieldOverhead)
+}
+
+func (sc *serverConn) curOpenStreams() uint32 {
+ sc.serveG.check()
+ return sc.curClientStreams + sc.curPushedStreams
+}
+
+// stream represents a stream. This is the minimal metadata needed by
+// the serve goroutine. Most of the actual stream state is owned by
+// the http.Handler's goroutine in the responseWriter. Because the
+// responseWriter's responseWriterState is recycled at the end of a
+// handler, this struct intentionally has no pointer to the
+// *responseWriter{,State} itself, as the Handler ending nils out the
+// responseWriter's state field.
+type stream struct {
+ // immutable:
+ sc *serverConn
+ id uint32
+ body *pipe // non-nil if expecting DATA frames
+ cw closeWaiter // closed wait stream transitions to closed state
+ ctx context.Context
+ cancelCtx func()
+
+ // owned by serverConn's serve loop:
+ bodyBytes int64 // body bytes seen so far
+ declBodyBytes int64 // or -1 if undeclared
+ flow flow // limits writing from Handler to client
+ inflow flow // what the client is allowed to POST/etc to us
+ parent *stream // or nil
+ numTrailerValues int64
+ weight uint8
+ state streamState
+ resetQueued bool // RST_STREAM queued for write; set by sc.resetStream
+ gotTrailerHeader bool // HEADER frame for trailers was seen
+ wroteHeaders bool // whether we wrote headers (not status 100)
+ writeDeadline *time.Timer // nil if unused
+
+ trailer http.Header // accumulated trailers
+ reqTrailer http.Header // handler's Request.Trailer
+}
+
+func (sc *serverConn) Framer() *Framer { return sc.framer }
+func (sc *serverConn) CloseConn() error { return sc.conn.Close() }
+func (sc *serverConn) Flush() error { return sc.bw.Flush() }
+func (sc *serverConn) HeaderEncoder() (*hpack.Encoder, *bytes.Buffer) {
+ return sc.hpackEncoder, &sc.headerWriteBuf
+}
+
+func (sc *serverConn) state(streamID uint32) (streamState, *stream) {
+ sc.serveG.check()
+ // http://tools.ietf.org/html/rfc7540#section-5.1
+ if st, ok := sc.streams[streamID]; ok {
+ return st.state, st
+ }
+ // "The first use of a new stream identifier implicitly closes all
+ // streams in the "idle" state that might have been initiated by
+ // that peer with a lower-valued stream identifier. For example, if
+ // a client sends a HEADERS frame on stream 7 without ever sending a
+ // frame on stream 5, then stream 5 transitions to the "closed"
+ // state when the first frame for stream 7 is sent or received."
+ if streamID%2 == 1 {
+ if streamID <= sc.maxClientStreamID {
+ return stateClosed, nil
+ }
+ } else {
+ if streamID <= sc.maxPushPromiseID {
+ return stateClosed, nil
+ }
+ }
+ return stateIdle, nil
+}
+
+// setConnState calls the net/http ConnState hook for this connection, if configured.
+// Note that the net/http package does StateNew and StateClosed for us.
+// There is currently no plan for StateHijacked or hijacking HTTP/2 connections.
+func (sc *serverConn) setConnState(state http.ConnState) {
+ if sc.hs.ConnState != nil {
+ sc.hs.ConnState(sc.conn, state)
+ }
+}
+
+func (sc *serverConn) vlogf(format string, args ...interface{}) {
+ if VerboseLogs {
+ sc.logf(format, args...)
+ }
+}
+
+func (sc *serverConn) logf(format string, args ...interface{}) {
+ if lg := sc.hs.ErrorLog; lg != nil {
+ lg.Printf(format, args...)
+ } else {
+ log.Printf(format, args...)
+ }
+}
+
+// errno returns v's underlying uintptr, else 0.
+//
+// TODO: remove this helper function once http2 can use build
+// tags. See comment in isClosedConnError.
+func errno(v error) uintptr {
+ if rv := reflect.ValueOf(v); rv.Kind() == reflect.Uintptr {
+ return uintptr(rv.Uint())
+ }
+ return 0
+}
+
+// isClosedConnError reports whether err is an error from use of a closed
+// network connection.
+func isClosedConnError(err error) bool {
+ if err == nil {
+ return false
+ }
+
+ // TODO: remove this string search and be more like the Windows
+ // case below. That might involve modifying the standard library
+ // to return better error types.
+ str := err.Error()
+ if strings.Contains(str, "use of closed network connection") {
+ return true
+ }
+
+ // TODO(bradfitz): x/tools/cmd/bundle doesn't really support
+ // build tags, so I can't make an http2_windows.go file with
+ // Windows-specific stuff. Fix that and move this, once we
+ // have a way to bundle this into std's net/http somehow.
+ if runtime.GOOS == "windows" {
+ if oe, ok := err.(*net.OpError); ok && oe.Op == "read" {
+ if se, ok := oe.Err.(*os.SyscallError); ok && se.Syscall == "wsarecv" {
+ const WSAECONNABORTED = 10053
+ const WSAECONNRESET = 10054
+ if n := errno(se.Err); n == WSAECONNRESET || n == WSAECONNABORTED {
+ return true
+ }
+ }
+ }
+ }
+ return false
+}
+
+func (sc *serverConn) condlogf(err error, format string, args ...interface{}) {
+ if err == nil {
+ return
+ }
+ if err == io.EOF || err == io.ErrUnexpectedEOF || isClosedConnError(err) || err == errPrefaceTimeout {
+ // Boring, expected errors.
+ sc.vlogf(format, args...)
+ } else {
+ sc.logf(format, args...)
+ }
+}
+
+func (sc *serverConn) canonicalHeader(v string) string {
+ sc.serveG.check()
+ buildCommonHeaderMapsOnce()
+ cv, ok := commonCanonHeader[v]
+ if ok {
+ return cv
+ }
+ cv, ok = sc.canonHeader[v]
+ if ok {
+ return cv
+ }
+ if sc.canonHeader == nil {
+ sc.canonHeader = make(map[string]string)
+ }
+ cv = http.CanonicalHeaderKey(v)
+ sc.canonHeader[v] = cv
+ return cv
+}
+
+type readFrameResult struct {
+ f Frame // valid until readMore is called
+ err error
+
+ // readMore should be called once the consumer no longer needs or
+ // retains f. After readMore, f is invalid and more frames can be
+ // read.
+ readMore func()
+}
+
+// readFrames is the loop that reads incoming frames.
+// It takes care to only read one frame at a time, blocking until the
+// consumer is done with the frame.
+// It's run on its own goroutine.
+func (sc *serverConn) readFrames() {
+ gate := make(gate)
+ gateDone := gate.Done
+ for {
+ f, err := sc.framer.ReadFrame()
+ select {
+ case sc.readFrameCh <- readFrameResult{f, err, gateDone}:
+ case <-sc.doneServing:
+ return
+ }
+ select {
+ case <-gate:
+ case <-sc.doneServing:
+ return
+ }
+ if terminalReadFrameError(err) {
+ return
+ }
+ }
+}
+
+// frameWriteResult is the message passed from writeFrameAsync to the serve goroutine.
+type frameWriteResult struct {
+ wr FrameWriteRequest // what was written (or attempted)
+ err error // result of the writeFrame call
+}
+
+// writeFrameAsync runs in its own goroutine and writes a single frame
+// and then reports when it's done.
+// At most one goroutine can be running writeFrameAsync at a time per
+// serverConn.
+func (sc *serverConn) writeFrameAsync(wr FrameWriteRequest) {
+ err := wr.write.writeFrame(sc)
+ sc.wroteFrameCh <- frameWriteResult{wr, err}
+}
+
+func (sc *serverConn) closeAllStreamsOnConnClose() {
+ sc.serveG.check()
+ for _, st := range sc.streams {
+ sc.closeStream(st, errClientDisconnected)
+ }
+}
+
+func (sc *serverConn) stopShutdownTimer() {
+ sc.serveG.check()
+ if t := sc.shutdownTimer; t != nil {
+ t.Stop()
+ }
+}
+
+func (sc *serverConn) notePanic() {
+ // Note: this is for serverConn.serve panicking, not http.Handler code.
+ if testHookOnPanicMu != nil {
+ testHookOnPanicMu.Lock()
+ defer testHookOnPanicMu.Unlock()
+ }
+ if testHookOnPanic != nil {
+ if e := recover(); e != nil {
+ if testHookOnPanic(sc, e) {
+ panic(e)
+ }
+ }
+ }
+}
+
+func (sc *serverConn) serve() {
+ sc.serveG.check()
+ defer sc.notePanic()
+ defer sc.conn.Close()
+ defer sc.closeAllStreamsOnConnClose()
+ defer sc.stopShutdownTimer()
+ defer close(sc.doneServing) // unblocks handlers trying to send
+
+ if VerboseLogs {
+ sc.vlogf("http2: server connection from %v on %p", sc.conn.RemoteAddr(), sc.hs)
+ }
+
+ sc.writeFrame(FrameWriteRequest{
+ write: writeSettings{
+ {SettingMaxFrameSize, sc.srv.maxReadFrameSize()},
+ {SettingMaxConcurrentStreams, sc.advMaxStreams},
+ {SettingMaxHeaderListSize, sc.maxHeaderListSize()},
+ {SettingInitialWindowSize, uint32(sc.srv.initialStreamRecvWindowSize())},
+ },
+ })
+ sc.unackedSettings++
+
+ // Each connection starts with intialWindowSize inflow tokens.
+ // If a higher value is configured, we add more tokens.
+ if diff := sc.srv.initialConnRecvWindowSize() - initialWindowSize; diff > 0 {
+ sc.sendWindowUpdate(nil, int(diff))
+ }
+
+ if err := sc.readPreface(); err != nil {
+ sc.condlogf(err, "http2: server: error reading preface from client %v: %v", sc.conn.RemoteAddr(), err)
+ return
+ }
+ // Now that we've got the preface, get us out of the
+ // "StateNew" state. We can't go directly to idle, though.
+ // Active means we read some data and anticipate a request. We'll
+ // do another Active when we get a HEADERS frame.
+ sc.setConnState(http.StateActive)
+ sc.setConnState(http.StateIdle)
+
+ if sc.srv.IdleTimeout != 0 {
+ sc.idleTimer = time.AfterFunc(sc.srv.IdleTimeout, sc.onIdleTimer)
+ defer sc.idleTimer.Stop()
+ }
+
+ go sc.readFrames() // closed by defer sc.conn.Close above
+
+ settingsTimer := time.AfterFunc(firstSettingsTimeout, sc.onSettingsTimer)
+ defer settingsTimer.Stop()
+
+ loopNum := 0
+ for {
+ loopNum++
+ select {
+ case wr := <-sc.wantWriteFrameCh:
+ if se, ok := wr.write.(StreamError); ok {
+ sc.resetStream(se)
+ break
+ }
+ sc.writeFrame(wr)
+ case res := <-sc.wroteFrameCh:
+ sc.wroteFrame(res)
+ case res := <-sc.readFrameCh:
+ if !sc.processFrameFromReader(res) {
+ return
+ }
+ res.readMore()
+ if settingsTimer != nil {
+ settingsTimer.Stop()
+ settingsTimer = nil
+ }
+ case m := <-sc.bodyReadCh:
+ sc.noteBodyRead(m.st, m.n)
+ case msg := <-sc.serveMsgCh:
+ switch v := msg.(type) {
+ case func(int):
+ v(loopNum) // for testing
+ case *serverMessage:
+ switch v {
+ case settingsTimerMsg:
+ sc.logf("timeout waiting for SETTINGS frames from %v", sc.conn.RemoteAddr())
+ return
+ case idleTimerMsg:
+ sc.vlogf("connection is idle")
+ sc.goAway(ErrCodeNo)
+ case shutdownTimerMsg:
+ sc.vlogf("GOAWAY close timer fired; closing conn from %v", sc.conn.RemoteAddr())
+ return
+ case gracefulShutdownMsg:
+ sc.startGracefulShutdownInternal()
+ default:
+ panic("unknown timer")
+ }
+ case *startPushRequest:
+ sc.startPush(v)
+ default:
+ panic(fmt.Sprintf("unexpected type %T", v))
+ }
+ }
+
+ // If the peer is causing us to generate a lot of control frames,
+ // but not reading them from us, assume they are trying to make us
+ // run out of memory.
+ if sc.queuedControlFrames > sc.srv.maxQueuedControlFrames() {
+ sc.vlogf("http2: too many control frames in send queue, closing connection")
+ return
+ }
+
+ // Start the shutdown timer after sending a GOAWAY. When sending GOAWAY
+ // with no error code (graceful shutdown), don't start the timer until
+ // all open streams have been completed.
+ sentGoAway := sc.inGoAway && !sc.needToSendGoAway && !sc.writingFrame
+ gracefulShutdownComplete := sc.goAwayCode == ErrCodeNo && sc.curOpenStreams() == 0
+ if sentGoAway && sc.shutdownTimer == nil && (sc.goAwayCode != ErrCodeNo || gracefulShutdownComplete) {
+ sc.shutDownIn(goAwayTimeout)
+ }
+ }
+}
+
+func (sc *serverConn) awaitGracefulShutdown(sharedCh <-chan struct{}, privateCh chan struct{}) {
+ select {
+ case <-sc.doneServing:
+ case <-sharedCh:
+ close(privateCh)
+ }
+}
+
+type serverMessage int
+
+// Message values sent to serveMsgCh.
+var (
+ settingsTimerMsg = new(serverMessage)
+ idleTimerMsg = new(serverMessage)
+ shutdownTimerMsg = new(serverMessage)
+ gracefulShutdownMsg = new(serverMessage)
+)
+
+func (sc *serverConn) onSettingsTimer() { sc.sendServeMsg(settingsTimerMsg) }
+func (sc *serverConn) onIdleTimer() { sc.sendServeMsg(idleTimerMsg) }
+func (sc *serverConn) onShutdownTimer() { sc.sendServeMsg(shutdownTimerMsg) }
+
+func (sc *serverConn) sendServeMsg(msg interface{}) {
+ sc.serveG.checkNotOn() // NOT
+ select {
+ case sc.serveMsgCh <- msg:
+ case <-sc.doneServing:
+ }
+}
+
+var errPrefaceTimeout = errors.New("timeout waiting for client preface")
+
+// readPreface reads the ClientPreface greeting from the peer or
+// returns errPrefaceTimeout on timeout, or an error if the greeting
+// is invalid.
+func (sc *serverConn) readPreface() error {
+ errc := make(chan error, 1)
+ go func() {
+ // Read the client preface
+ buf := make([]byte, len(ClientPreface))
+ if _, err := io.ReadFull(sc.conn, buf); err != nil {
+ errc <- err
+ } else if !bytes.Equal(buf, clientPreface) {
+ errc <- fmt.Errorf("bogus greeting %q", buf)
+ } else {
+ errc <- nil
+ }
+ }()
+ timer := time.NewTimer(prefaceTimeout) // TODO: configurable on *Server?
+ defer timer.Stop()
+ select {
+ case <-timer.C:
+ return errPrefaceTimeout
+ case err := <-errc:
+ if err == nil {
+ if VerboseLogs {
+ sc.vlogf("http2: server: client %v said hello", sc.conn.RemoteAddr())
+ }
+ }
+ return err
+ }
+}
+
+var errChanPool = sync.Pool{
+ New: func() interface{} { return make(chan error, 1) },
+}
+
+var writeDataPool = sync.Pool{
+ New: func() interface{} { return new(writeData) },
+}
+
+// writeDataFromHandler writes DATA response frames from a handler on
+// the given stream.
+func (sc *serverConn) writeDataFromHandler(stream *stream, data []byte, endStream bool) error {
+ ch := errChanPool.Get().(chan error)
+ writeArg := writeDataPool.Get().(*writeData)
+ *writeArg = writeData{stream.id, data, endStream}
+ err := sc.writeFrameFromHandler(FrameWriteRequest{
+ write: writeArg,
+ stream: stream,
+ done: ch,
+ })
+ if err != nil {
+ return err
+ }
+ var frameWriteDone bool // the frame write is done (successfully or not)
+ select {
+ case err = <-ch:
+ frameWriteDone = true
+ case <-sc.doneServing:
+ return errClientDisconnected
+ case <-stream.cw:
+ // If both ch and stream.cw were ready (as might
+ // happen on the final Write after an http.Handler
+ // ends), prefer the write result. Otherwise this
+ // might just be us successfully closing the stream.
+ // The writeFrameAsync and serve goroutines guarantee
+ // that the ch send will happen before the stream.cw
+ // close.
+ select {
+ case err = <-ch:
+ frameWriteDone = true
+ default:
+ return errStreamClosed
+ }
+ }
+ errChanPool.Put(ch)
+ if frameWriteDone {
+ writeDataPool.Put(writeArg)
+ }
+ return err
+}
+
+// writeFrameFromHandler sends wr to sc.wantWriteFrameCh, but aborts
+// if the connection has gone away.
+//
+// This must not be run from the serve goroutine itself, else it might
+// deadlock writing to sc.wantWriteFrameCh (which is only mildly
+// buffered and is read by serve itself). If you're on the serve
+// goroutine, call writeFrame instead.
+func (sc *serverConn) writeFrameFromHandler(wr FrameWriteRequest) error {
+ sc.serveG.checkNotOn() // NOT
+ select {
+ case sc.wantWriteFrameCh <- wr:
+ return nil
+ case <-sc.doneServing:
+ // Serve loop is gone.
+ // Client has closed their connection to the server.
+ return errClientDisconnected
+ }
+}
+
+// writeFrame schedules a frame to write and sends it if there's nothing
+// already being written.
+//
+// There is no pushback here (the serve goroutine never blocks). It's
+// the http.Handlers that block, waiting for their previous frames to
+// make it onto the wire
+//
+// If you're not on the serve goroutine, use writeFrameFromHandler instead.
+func (sc *serverConn) writeFrame(wr FrameWriteRequest) {
+ sc.serveG.check()
+
+ // If true, wr will not be written and wr.done will not be signaled.
+ var ignoreWrite bool
+
+ // We are not allowed to write frames on closed streams. RFC 7540 Section
+ // 5.1.1 says: "An endpoint MUST NOT send frames other than PRIORITY on
+ // a closed stream." Our server never sends PRIORITY, so that exception
+ // does not apply.
+ //
+ // The serverConn might close an open stream while the stream's handler
+ // is still running. For example, the server might close a stream when it
+ // receives bad data from the client. If this happens, the handler might
+ // attempt to write a frame after the stream has been closed (since the
+ // handler hasn't yet been notified of the close). In this case, we simply
+ // ignore the frame. The handler will notice that the stream is closed when
+ // it waits for the frame to be written.
+ //
+ // As an exception to this rule, we allow sending RST_STREAM after close.
+ // This allows us to immediately reject new streams without tracking any
+ // state for those streams (except for the queued RST_STREAM frame). This
+ // may result in duplicate RST_STREAMs in some cases, but the client should
+ // ignore those.
+ if wr.StreamID() != 0 {
+ _, isReset := wr.write.(StreamError)
+ if state, _ := sc.state(wr.StreamID()); state == stateClosed && !isReset {
+ ignoreWrite = true
+ }
+ }
+
+ // Don't send a 100-continue response if we've already sent headers.
+ // See golang.org/issue/14030.
+ switch wr.write.(type) {
+ case *writeResHeaders:
+ wr.stream.wroteHeaders = true
+ case write100ContinueHeadersFrame:
+ if wr.stream.wroteHeaders {
+ // We do not need to notify wr.done because this frame is
+ // never written with wr.done != nil.
+ if wr.done != nil {
+ panic("wr.done != nil for write100ContinueHeadersFrame")
+ }
+ ignoreWrite = true
+ }
+ }
+
+ if !ignoreWrite {
+ if wr.isControl() {
+ sc.queuedControlFrames++
+ // For extra safety, detect wraparounds, which should not happen,
+ // and pull the plug.
+ if sc.queuedControlFrames < 0 {
+ sc.conn.Close()
+ }
+ }
+ sc.writeSched.Push(wr)
+ }
+ sc.scheduleFrameWrite()
+}
+
+// startFrameWrite starts a goroutine to write wr (in a separate
+// goroutine since that might block on the network), and updates the
+// serve goroutine's state about the world, updated from info in wr.
+func (sc *serverConn) startFrameWrite(wr FrameWriteRequest) {
+ sc.serveG.check()
+ if sc.writingFrame {
+ panic("internal error: can only be writing one frame at a time")
+ }
+
+ st := wr.stream
+ if st != nil {
+ switch st.state {
+ case stateHalfClosedLocal:
+ switch wr.write.(type) {
+ case StreamError, handlerPanicRST, writeWindowUpdate:
+ // RFC 7540 Section 5.1 allows sending RST_STREAM, PRIORITY, and WINDOW_UPDATE
+ // in this state. (We never send PRIORITY from the server, so that is not checked.)
+ default:
+ panic(fmt.Sprintf("internal error: attempt to send frame on a half-closed-local stream: %v", wr))
+ }
+ case stateClosed:
+ panic(fmt.Sprintf("internal error: attempt to send frame on a closed stream: %v", wr))
+ }
+ }
+ if wpp, ok := wr.write.(*writePushPromise); ok {
+ var err error
+ wpp.promisedID, err = wpp.allocatePromisedID()
+ if err != nil {
+ sc.writingFrameAsync = false
+ wr.replyToWriter(err)
+ return
+ }
+ }
+
+ sc.writingFrame = true
+ sc.needsFrameFlush = true
+ if wr.write.staysWithinBuffer(sc.bw.Available()) {
+ sc.writingFrameAsync = false
+ err := wr.write.writeFrame(sc)
+ sc.wroteFrame(frameWriteResult{wr, err})
+ } else {
+ sc.writingFrameAsync = true
+ go sc.writeFrameAsync(wr)
+ }
+}
+
+// errHandlerPanicked is the error given to any callers blocked in a read from
+// Request.Body when the main goroutine panics. Since most handlers read in the
+// main ServeHTTP goroutine, this will show up rarely.
+var errHandlerPanicked = errors.New("http2: handler panicked")
+
+// wroteFrame is called on the serve goroutine with the result of
+// whatever happened on writeFrameAsync.
+func (sc *serverConn) wroteFrame(res frameWriteResult) {
+ sc.serveG.check()
+ if !sc.writingFrame {
+ panic("internal error: expected to be already writing a frame")
+ }
+ sc.writingFrame = false
+ sc.writingFrameAsync = false
+
+ wr := res.wr
+
+ if writeEndsStream(wr.write) {
+ st := wr.stream
+ if st == nil {
+ panic("internal error: expecting non-nil stream")
+ }
+ switch st.state {
+ case stateOpen:
+ // Here we would go to stateHalfClosedLocal in
+ // theory, but since our handler is done and
+ // the net/http package provides no mechanism
+ // for closing a ResponseWriter while still
+ // reading data (see possible TODO at top of
+ // this file), we go into closed state here
+ // anyway, after telling the peer we're
+ // hanging up on them. We'll transition to
+ // stateClosed after the RST_STREAM frame is
+ // written.
+ st.state = stateHalfClosedLocal
+ // Section 8.1: a server MAY request that the client abort
+ // transmission of a request without error by sending a
+ // RST_STREAM with an error code of NO_ERROR after sending
+ // a complete response.
+ sc.resetStream(streamError(st.id, ErrCodeNo))
+ case stateHalfClosedRemote:
+ sc.closeStream(st, errHandlerComplete)
+ }
+ } else {
+ switch v := wr.write.(type) {
+ case StreamError:
+ // st may be unknown if the RST_STREAM was generated to reject bad input.
+ if st, ok := sc.streams[v.StreamID]; ok {
+ sc.closeStream(st, v)
+ }
+ case handlerPanicRST:
+ sc.closeStream(wr.stream, errHandlerPanicked)
+ }
+ }
+
+ // Reply (if requested) to unblock the ServeHTTP goroutine.
+ wr.replyToWriter(res.err)
+
+ sc.scheduleFrameWrite()
+}
+
+// scheduleFrameWrite tickles the frame writing scheduler.
+//
+// If a frame is already being written, nothing happens. This will be called again
+// when the frame is done being written.
+//
+// If a frame isn't being written and we need to send one, the best frame
+// to send is selected by writeSched.
+//
+// If a frame isn't being written and there's nothing else to send, we
+// flush the write buffer.
+func (sc *serverConn) scheduleFrameWrite() {
+ sc.serveG.check()
+ if sc.writingFrame || sc.inFrameScheduleLoop {
+ return
+ }
+ sc.inFrameScheduleLoop = true
+ for !sc.writingFrameAsync {
+ if sc.needToSendGoAway {
+ sc.needToSendGoAway = false
+ sc.startFrameWrite(FrameWriteRequest{
+ write: &writeGoAway{
+ maxStreamID: sc.maxClientStreamID,
+ code: sc.goAwayCode,
+ },
+ })
+ continue
+ }
+ if sc.needToSendSettingsAck {
+ sc.needToSendSettingsAck = false
+ sc.startFrameWrite(FrameWriteRequest{write: writeSettingsAck{}})
+ continue
+ }
+ if !sc.inGoAway || sc.goAwayCode == ErrCodeNo {
+ if wr, ok := sc.writeSched.Pop(); ok {
+ if wr.isControl() {
+ sc.queuedControlFrames--
+ }
+ sc.startFrameWrite(wr)
+ continue
+ }
+ }
+ if sc.needsFrameFlush {
+ sc.startFrameWrite(FrameWriteRequest{write: flushFrameWriter{}})
+ sc.needsFrameFlush = false // after startFrameWrite, since it sets this true
+ continue
+ }
+ break
+ }
+ sc.inFrameScheduleLoop = false
+}
+
+// startGracefulShutdown gracefully shuts down a connection. This
+// sends GOAWAY with ErrCodeNo to tell the client we're gracefully
+// shutting down. The connection isn't closed until all current
+// streams are done.
+//
+// startGracefulShutdown returns immediately; it does not wait until
+// the connection has shut down.
+func (sc *serverConn) startGracefulShutdown() {
+ sc.serveG.checkNotOn() // NOT
+ sc.shutdownOnce.Do(func() { sc.sendServeMsg(gracefulShutdownMsg) })
+}
+
+// After sending GOAWAY, the connection will close after goAwayTimeout.
+// If we close the connection immediately after sending GOAWAY, there may
+// be unsent data in our kernel receive buffer, which will cause the kernel
+// to send a TCP RST on close() instead of a FIN. This RST will abort the
+// connection immediately, whether or not the client had received the GOAWAY.
+//
+// Ideally we should delay for at least 1 RTT + epsilon so the client has
+// a chance to read the GOAWAY and stop sending messages. Measuring RTT
+// is hard, so we approximate with 1 second. See golang.org/issue/18701.
+//
+// This is a var so it can be shorter in tests, where all requests uses the
+// loopback interface making the expected RTT very small.
+//
+// TODO: configurable?
+var goAwayTimeout = 1 * time.Second
+
+func (sc *serverConn) startGracefulShutdownInternal() {
+ sc.goAway(ErrCodeNo)
+}
+
+func (sc *serverConn) goAway(code ErrCode) {
+ sc.serveG.check()
+ if sc.inGoAway {
+ return
+ }
+ sc.inGoAway = true
+ sc.needToSendGoAway = true
+ sc.goAwayCode = code
+ sc.scheduleFrameWrite()
+}
+
+func (sc *serverConn) shutDownIn(d time.Duration) {
+ sc.serveG.check()
+ sc.shutdownTimer = time.AfterFunc(d, sc.onShutdownTimer)
+}
+
+func (sc *serverConn) resetStream(se StreamError) {
+ sc.serveG.check()
+ sc.writeFrame(FrameWriteRequest{write: se})
+ if st, ok := sc.streams[se.StreamID]; ok {
+ st.resetQueued = true
+ }
+}
+
+// processFrameFromReader processes the serve loop's read from readFrameCh from the
+// frame-reading goroutine.
+// processFrameFromReader returns whether the connection should be kept open.
+func (sc *serverConn) processFrameFromReader(res readFrameResult) bool {
+ sc.serveG.check()
+ err := res.err
+ if err != nil {
+ if err == ErrFrameTooLarge {
+ sc.goAway(ErrCodeFrameSize)
+ return true // goAway will close the loop
+ }
+ clientGone := err == io.EOF || err == io.ErrUnexpectedEOF || isClosedConnError(err)
+ if clientGone {
+ // TODO: could we also get into this state if
+ // the peer does a half close
+ // (e.g. CloseWrite) because they're done
+ // sending frames but they're still wanting
+ // our open replies? Investigate.
+ // TODO: add CloseWrite to crypto/tls.Conn first
+ // so we have a way to test this? I suppose
+ // just for testing we could have a non-TLS mode.
+ return false
+ }
+ } else {
+ f := res.f
+ if VerboseLogs {
+ sc.vlogf("http2: server read frame %v", summarizeFrame(f))
+ }
+ err = sc.processFrame(f)
+ if err == nil {
+ return true
+ }
+ }
+
+ switch ev := err.(type) {
+ case StreamError:
+ sc.resetStream(ev)
+ return true
+ case goAwayFlowError:
+ sc.goAway(ErrCodeFlowControl)
+ return true
+ case ConnectionError:
+ sc.logf("http2: server connection error from %v: %v", sc.conn.RemoteAddr(), ev)
+ sc.goAway(ErrCode(ev))
+ return true // goAway will handle shutdown
+ default:
+ if res.err != nil {
+ sc.vlogf("http2: server closing client connection; error reading frame from client %s: %v", sc.conn.RemoteAddr(), err)
+ } else {
+ sc.logf("http2: server closing client connection: %v", err)
+ }
+ return false
+ }
+}
+
+func (sc *serverConn) processFrame(f Frame) error {
+ sc.serveG.check()
+
+ // First frame received must be SETTINGS.
+ if !sc.sawFirstSettings {
+ if _, ok := f.(*SettingsFrame); !ok {
+ return ConnectionError(ErrCodeProtocol)
+ }
+ sc.sawFirstSettings = true
+ }
+
+ switch f := f.(type) {
+ case *SettingsFrame:
+ return sc.processSettings(f)
+ case *MetaHeadersFrame:
+ return sc.processHeaders(f)
+ case *WindowUpdateFrame:
+ return sc.processWindowUpdate(f)
+ case *PingFrame:
+ return sc.processPing(f)
+ case *DataFrame:
+ return sc.processData(f)
+ case *RSTStreamFrame:
+ return sc.processResetStream(f)
+ case *PriorityFrame:
+ return sc.processPriority(f)
+ case *GoAwayFrame:
+ return sc.processGoAway(f)
+ case *PushPromiseFrame:
+ // A client cannot push. Thus, servers MUST treat the receipt of a PUSH_PROMISE
+ // frame as a connection error (Section 5.4.1) of type PROTOCOL_ERROR.
+ return ConnectionError(ErrCodeProtocol)
+ default:
+ sc.vlogf("http2: server ignoring frame: %v", f.Header())
+ return nil
+ }
+}
+
+func (sc *serverConn) processPing(f *PingFrame) error {
+ sc.serveG.check()
+ if f.IsAck() {
+ // 6.7 PING: " An endpoint MUST NOT respond to PING frames
+ // containing this flag."
+ return nil
+ }
+ if f.StreamID != 0 {
+ // "PING frames are not associated with any individual
+ // stream. If a PING frame is received with a stream
+ // identifier field value other than 0x0, the recipient MUST
+ // respond with a connection error (Section 5.4.1) of type
+ // PROTOCOL_ERROR."
+ return ConnectionError(ErrCodeProtocol)
+ }
+ if sc.inGoAway && sc.goAwayCode != ErrCodeNo {
+ return nil
+ }
+ sc.writeFrame(FrameWriteRequest{write: writePingAck{f}})
+ return nil
+}
+
+func (sc *serverConn) processWindowUpdate(f *WindowUpdateFrame) error {
+ sc.serveG.check()
+ switch {
+ case f.StreamID != 0: // stream-level flow control
+ state, st := sc.state(f.StreamID)
+ if state == stateIdle {
+ // Section 5.1: "Receiving any frame other than HEADERS
+ // or PRIORITY on a stream in this state MUST be
+ // treated as a connection error (Section 5.4.1) of
+ // type PROTOCOL_ERROR."
+ return ConnectionError(ErrCodeProtocol)
+ }
+ if st == nil {
+ // "WINDOW_UPDATE can be sent by a peer that has sent a
+ // frame bearing the END_STREAM flag. This means that a
+ // receiver could receive a WINDOW_UPDATE frame on a "half
+ // closed (remote)" or "closed" stream. A receiver MUST
+ // NOT treat this as an error, see Section 5.1."
+ return nil
+ }
+ if !st.flow.add(int32(f.Increment)) {
+ return streamError(f.StreamID, ErrCodeFlowControl)
+ }
+ default: // connection-level flow control
+ if !sc.flow.add(int32(f.Increment)) {
+ return goAwayFlowError{}
+ }
+ }
+ sc.scheduleFrameWrite()
+ return nil
+}
+
+func (sc *serverConn) processResetStream(f *RSTStreamFrame) error {
+ sc.serveG.check()
+
+ state, st := sc.state(f.StreamID)
+ if state == stateIdle {
+ // 6.4 "RST_STREAM frames MUST NOT be sent for a
+ // stream in the "idle" state. If a RST_STREAM frame
+ // identifying an idle stream is received, the
+ // recipient MUST treat this as a connection error
+ // (Section 5.4.1) of type PROTOCOL_ERROR.
+ return ConnectionError(ErrCodeProtocol)
+ }
+ if st != nil {
+ st.cancelCtx()
+ sc.closeStream(st, streamError(f.StreamID, f.ErrCode))
+ }
+ return nil
+}
+
+func (sc *serverConn) closeStream(st *stream, err error) {
+ sc.serveG.check()
+ if st.state == stateIdle || st.state == stateClosed {
+ panic(fmt.Sprintf("invariant; can't close stream in state %v", st.state))
+ }
+ st.state = stateClosed
+ if st.writeDeadline != nil {
+ st.writeDeadline.Stop()
+ }
+ if st.isPushed() {
+ sc.curPushedStreams--
+ } else {
+ sc.curClientStreams--
+ }
+ delete(sc.streams, st.id)
+ if len(sc.streams) == 0 {
+ sc.setConnState(http.StateIdle)
+ if sc.srv.IdleTimeout != 0 {
+ sc.idleTimer.Reset(sc.srv.IdleTimeout)
+ }
+ if h1ServerKeepAlivesDisabled(sc.hs) {
+ sc.startGracefulShutdownInternal()
+ }
+ }
+ if p := st.body; p != nil {
+ // Return any buffered unread bytes worth of conn-level flow control.
+ // See golang.org/issue/16481
+ sc.sendWindowUpdate(nil, p.Len())
+
+ p.CloseWithError(err)
+ }
+ st.cw.Close() // signals Handler's CloseNotifier, unblocks writes, etc
+ sc.writeSched.CloseStream(st.id)
+}
+
+func (sc *serverConn) processSettings(f *SettingsFrame) error {
+ sc.serveG.check()
+ if f.IsAck() {
+ sc.unackedSettings--
+ if sc.unackedSettings < 0 {
+ // Why is the peer ACKing settings we never sent?
+ // The spec doesn't mention this case, but
+ // hang up on them anyway.
+ return ConnectionError(ErrCodeProtocol)
+ }
+ return nil
+ }
+ if f.NumSettings() > 100 || f.HasDuplicates() {
+ // This isn't actually in the spec, but hang up on
+ // suspiciously large settings frames or those with
+ // duplicate entries.
+ return ConnectionError(ErrCodeProtocol)
+ }
+ if err := f.ForeachSetting(sc.processSetting); err != nil {
+ return err
+ }
+ // TODO: judging by RFC 7540, Section 6.5.3 each SETTINGS frame should be
+ // acknowledged individually, even if multiple are received before the ACK.
+ sc.needToSendSettingsAck = true
+ sc.scheduleFrameWrite()
+ return nil
+}
+
+func (sc *serverConn) processSetting(s Setting) error {
+ sc.serveG.check()
+ if err := s.Valid(); err != nil {
+ return err
+ }
+ if VerboseLogs {
+ sc.vlogf("http2: server processing setting %v", s)
+ }
+ switch s.ID {
+ case SettingHeaderTableSize:
+ sc.headerTableSize = s.Val
+ sc.hpackEncoder.SetMaxDynamicTableSize(s.Val)
+ case SettingEnablePush:
+ sc.pushEnabled = s.Val != 0
+ case SettingMaxConcurrentStreams:
+ sc.clientMaxStreams = s.Val
+ case SettingInitialWindowSize:
+ return sc.processSettingInitialWindowSize(s.Val)
+ case SettingMaxFrameSize:
+ sc.maxFrameSize = int32(s.Val) // the maximum valid s.Val is < 2^31
+ case SettingMaxHeaderListSize:
+ sc.peerMaxHeaderListSize = s.Val
+ default:
+ // Unknown setting: "An endpoint that receives a SETTINGS
+ // frame with any unknown or unsupported identifier MUST
+ // ignore that setting."
+ if VerboseLogs {
+ sc.vlogf("http2: server ignoring unknown setting %v", s)
+ }
+ }
+ return nil
+}
+
+func (sc *serverConn) processSettingInitialWindowSize(val uint32) error {
+ sc.serveG.check()
+ // Note: val already validated to be within range by
+ // processSetting's Valid call.
+
+ // "A SETTINGS frame can alter the initial flow control window
+ // size for all current streams. When the value of
+ // SETTINGS_INITIAL_WINDOW_SIZE changes, a receiver MUST
+ // adjust the size of all stream flow control windows that it
+ // maintains by the difference between the new value and the
+ // old value."
+ old := sc.initialStreamSendWindowSize
+ sc.initialStreamSendWindowSize = int32(val)
+ growth := int32(val) - old // may be negative
+ for _, st := range sc.streams {
+ if !st.flow.add(growth) {
+ // 6.9.2 Initial Flow Control Window Size
+ // "An endpoint MUST treat a change to
+ // SETTINGS_INITIAL_WINDOW_SIZE that causes any flow
+ // control window to exceed the maximum size as a
+ // connection error (Section 5.4.1) of type
+ // FLOW_CONTROL_ERROR."
+ return ConnectionError(ErrCodeFlowControl)
+ }
+ }
+ return nil
+}
+
+func (sc *serverConn) processData(f *DataFrame) error {
+ sc.serveG.check()
+ if sc.inGoAway && sc.goAwayCode != ErrCodeNo {
+ return nil
+ }
+ data := f.Data()
+
+ // "If a DATA frame is received whose stream is not in "open"
+ // or "half closed (local)" state, the recipient MUST respond
+ // with a stream error (Section 5.4.2) of type STREAM_CLOSED."
+ id := f.Header().StreamID
+ state, st := sc.state(id)
+ if id == 0 || state == stateIdle {
+ // Section 5.1: "Receiving any frame other than HEADERS
+ // or PRIORITY on a stream in this state MUST be
+ // treated as a connection error (Section 5.4.1) of
+ // type PROTOCOL_ERROR."
+ return ConnectionError(ErrCodeProtocol)
+ }
+ if st == nil || state != stateOpen || st.gotTrailerHeader || st.resetQueued {
+ // This includes sending a RST_STREAM if the stream is
+ // in stateHalfClosedLocal (which currently means that
+ // the http.Handler returned, so it's done reading &
+ // done writing). Try to stop the client from sending
+ // more DATA.
+
+ // But still enforce their connection-level flow control,
+ // and return any flow control bytes since we're not going
+ // to consume them.
+ if sc.inflow.available() < int32(f.Length) {
+ return streamError(id, ErrCodeFlowControl)
+ }
+ // Deduct the flow control from inflow, since we're
+ // going to immediately add it back in
+ // sendWindowUpdate, which also schedules sending the
+ // frames.
+ sc.inflow.take(int32(f.Length))
+ sc.sendWindowUpdate(nil, int(f.Length)) // conn-level
+
+ if st != nil && st.resetQueued {
+ // Already have a stream error in flight. Don't send another.
+ return nil
+ }
+ return streamError(id, ErrCodeStreamClosed)
+ }
+ if st.body == nil {
+ panic("internal error: should have a body in this state")
+ }
+
+ // Sender sending more than they'd declared?
+ if st.declBodyBytes != -1 && st.bodyBytes+int64(len(data)) > st.declBodyBytes {
+ st.body.CloseWithError(fmt.Errorf("sender tried to send more than declared Content-Length of %d bytes", st.declBodyBytes))
+ // RFC 7540, sec 8.1.2.6: A request or response is also malformed if the
+ // value of a content-length header field does not equal the sum of the
+ // DATA frame payload lengths that form the body.
+ return streamError(id, ErrCodeProtocol)
+ }
+ if f.Length > 0 {
+ // Check whether the client has flow control quota.
+ if st.inflow.available() < int32(f.Length) {
+ return streamError(id, ErrCodeFlowControl)
+ }
+ st.inflow.take(int32(f.Length))
+
+ if len(data) > 0 {
+ wrote, err := st.body.Write(data)
+ if err != nil {
+ return streamError(id, ErrCodeStreamClosed)
+ }
+ if wrote != len(data) {
+ panic("internal error: bad Writer")
+ }
+ st.bodyBytes += int64(len(data))
+ }
+
+ // Return any padded flow control now, since we won't
+ // refund it later on body reads.
+ if pad := int32(f.Length) - int32(len(data)); pad > 0 {
+ sc.sendWindowUpdate32(nil, pad)
+ sc.sendWindowUpdate32(st, pad)
+ }
+ }
+ if f.StreamEnded() {
+ st.endStream()
+ }
+ return nil
+}
+
+func (sc *serverConn) processGoAway(f *GoAwayFrame) error {
+ sc.serveG.check()
+ if f.ErrCode != ErrCodeNo {
+ sc.logf("http2: received GOAWAY %+v, starting graceful shutdown", f)
+ } else {
+ sc.vlogf("http2: received GOAWAY %+v, starting graceful shutdown", f)
+ }
+ sc.startGracefulShutdownInternal()
+ // http://tools.ietf.org/html/rfc7540#section-6.8
+ // We should not create any new streams, which means we should disable push.
+ sc.pushEnabled = false
+ return nil
+}
+
+// isPushed reports whether the stream is server-initiated.
+func (st *stream) isPushed() bool {
+ return st.id%2 == 0
+}
+
+// endStream closes a Request.Body's pipe. It is called when a DATA
+// frame says a request body is over (or after trailers).
+func (st *stream) endStream() {
+ sc := st.sc
+ sc.serveG.check()
+
+ if st.declBodyBytes != -1 && st.declBodyBytes != st.bodyBytes {
+ st.body.CloseWithError(fmt.Errorf("request declared a Content-Length of %d but only wrote %d bytes",
+ st.declBodyBytes, st.bodyBytes))
+ } else {
+ st.body.closeWithErrorAndCode(io.EOF, st.copyTrailersToHandlerRequest)
+ st.body.CloseWithError(io.EOF)
+ }
+ st.state = stateHalfClosedRemote
+}
+
+// copyTrailersToHandlerRequest is run in the Handler's goroutine in
+// its Request.Body.Read just before it gets io.EOF.
+func (st *stream) copyTrailersToHandlerRequest() {
+ for k, vv := range st.trailer {
+ if _, ok := st.reqTrailer[k]; ok {
+ // Only copy it over it was pre-declared.
+ st.reqTrailer[k] = vv
+ }
+ }
+}
+
+// onWriteTimeout is run on its own goroutine (from time.AfterFunc)
+// when the stream's WriteTimeout has fired.
+func (st *stream) onWriteTimeout() {
+ st.sc.writeFrameFromHandler(FrameWriteRequest{write: streamError(st.id, ErrCodeInternal)})
+}
+
+func (sc *serverConn) processHeaders(f *MetaHeadersFrame) error {
+ sc.serveG.check()
+ id := f.StreamID
+ if sc.inGoAway {
+ // Ignore.
+ return nil
+ }
+ // http://tools.ietf.org/html/rfc7540#section-5.1.1
+ // Streams initiated by a client MUST use odd-numbered stream
+ // identifiers. [...] An endpoint that receives an unexpected
+ // stream identifier MUST respond with a connection error
+ // (Section 5.4.1) of type PROTOCOL_ERROR.
+ if id%2 != 1 {
+ return ConnectionError(ErrCodeProtocol)
+ }
+ // A HEADERS frame can be used to create a new stream or
+ // send a trailer for an open one. If we already have a stream
+ // open, let it process its own HEADERS frame (trailers at this
+ // point, if it's valid).
+ if st := sc.streams[f.StreamID]; st != nil {
+ if st.resetQueued {
+ // We're sending RST_STREAM to close the stream, so don't bother
+ // processing this frame.
+ return nil
+ }
+ // RFC 7540, sec 5.1: If an endpoint receives additional frames, other than
+ // WINDOW_UPDATE, PRIORITY, or RST_STREAM, for a stream that is in
+ // this state, it MUST respond with a stream error (Section 5.4.2) of
+ // type STREAM_CLOSED.
+ if st.state == stateHalfClosedRemote {
+ return streamError(id, ErrCodeStreamClosed)
+ }
+ return st.processTrailerHeaders(f)
+ }
+
+ // [...] The identifier of a newly established stream MUST be
+ // numerically greater than all streams that the initiating
+ // endpoint has opened or reserved. [...] An endpoint that
+ // receives an unexpected stream identifier MUST respond with
+ // a connection error (Section 5.4.1) of type PROTOCOL_ERROR.
+ if id <= sc.maxClientStreamID {
+ return ConnectionError(ErrCodeProtocol)
+ }
+ sc.maxClientStreamID = id
+
+ if sc.idleTimer != nil {
+ sc.idleTimer.Stop()
+ }
+
+ // http://tools.ietf.org/html/rfc7540#section-5.1.2
+ // [...] Endpoints MUST NOT exceed the limit set by their peer. An
+ // endpoint that receives a HEADERS frame that causes their
+ // advertised concurrent stream limit to be exceeded MUST treat
+ // this as a stream error (Section 5.4.2) of type PROTOCOL_ERROR
+ // or REFUSED_STREAM.
+ if sc.curClientStreams+1 > sc.advMaxStreams {
+ if sc.unackedSettings == 0 {
+ // They should know better.
+ return streamError(id, ErrCodeProtocol)
+ }
+ // Assume it's a network race, where they just haven't
+ // received our last SETTINGS update. But actually
+ // this can't happen yet, because we don't yet provide
+ // a way for users to adjust server parameters at
+ // runtime.
+ return streamError(id, ErrCodeRefusedStream)
+ }
+
+ initialState := stateOpen
+ if f.StreamEnded() {
+ initialState = stateHalfClosedRemote
+ }
+ st := sc.newStream(id, 0, initialState)
+
+ if f.HasPriority() {
+ if err := checkPriority(f.StreamID, f.Priority); err != nil {
+ return err
+ }
+ sc.writeSched.AdjustStream(st.id, f.Priority)
+ }
+
+ rw, req, err := sc.newWriterAndRequest(st, f)
+ if err != nil {
+ return err
+ }
+ st.reqTrailer = req.Trailer
+ if st.reqTrailer != nil {
+ st.trailer = make(http.Header)
+ }
+ st.body = req.Body.(*requestBody).pipe // may be nil
+ st.declBodyBytes = req.ContentLength
+
+ handler := sc.handler.ServeHTTP
+ if f.Truncated {
+ // Their header list was too long. Send a 431 error.
+ handler = handleHeaderListTooLong
+ } else if err := checkValidHTTP2RequestHeaders(req.Header); err != nil {
+ handler = new400Handler(err)
+ }
+
+ // The net/http package sets the read deadline from the
+ // http.Server.ReadTimeout during the TLS handshake, but then
+ // passes the connection off to us with the deadline already
+ // set. Disarm it here after the request headers are read,
+ // similar to how the http1 server works. Here it's
+ // technically more like the http1 Server's ReadHeaderTimeout
+ // (in Go 1.8), though. That's a more sane option anyway.
+ if sc.hs.ReadTimeout != 0 {
+ sc.conn.SetReadDeadline(time.Time{})
+ }
+
+ go sc.runHandler(rw, req, handler)
+ return nil
+}
+
+func (st *stream) processTrailerHeaders(f *MetaHeadersFrame) error {
+ sc := st.sc
+ sc.serveG.check()
+ if st.gotTrailerHeader {
+ return ConnectionError(ErrCodeProtocol)
+ }
+ st.gotTrailerHeader = true
+ if !f.StreamEnded() {
+ return streamError(st.id, ErrCodeProtocol)
+ }
+
+ if len(f.PseudoFields()) > 0 {
+ return streamError(st.id, ErrCodeProtocol)
+ }
+ if st.trailer != nil {
+ for _, hf := range f.RegularFields() {
+ key := sc.canonicalHeader(hf.Name)
+ if !httpguts.ValidTrailerHeader(key) {
+ // TODO: send more details to the peer somehow. But http2 has
+ // no way to send debug data at a stream level. Discuss with
+ // HTTP folk.
+ return streamError(st.id, ErrCodeProtocol)
+ }
+ st.trailer[key] = append(st.trailer[key], hf.Value)
+ }
+ }
+ st.endStream()
+ return nil
+}
+
+func checkPriority(streamID uint32, p PriorityParam) error {
+ if streamID == p.StreamDep {
+ // Section 5.3.1: "A stream cannot depend on itself. An endpoint MUST treat
+ // this as a stream error (Section 5.4.2) of type PROTOCOL_ERROR."
+ // Section 5.3.3 says that a stream can depend on one of its dependencies,
+ // so it's only self-dependencies that are forbidden.
+ return streamError(streamID, ErrCodeProtocol)
+ }
+ return nil
+}
+
+func (sc *serverConn) processPriority(f *PriorityFrame) error {
+ if sc.inGoAway {
+ return nil
+ }
+ if err := checkPriority(f.StreamID, f.PriorityParam); err != nil {
+ return err
+ }
+ sc.writeSched.AdjustStream(f.StreamID, f.PriorityParam)
+ return nil
+}
+
+func (sc *serverConn) newStream(id, pusherID uint32, state streamState) *stream {
+ sc.serveG.check()
+ if id == 0 {
+ panic("internal error: cannot create stream with id 0")
+ }
+
+ ctx, cancelCtx := context.WithCancel(sc.baseCtx)
+ st := &stream{
+ sc: sc,
+ id: id,
+ state: state,
+ ctx: ctx,
+ cancelCtx: cancelCtx,
+ }
+ st.cw.Init()
+ st.flow.conn = &sc.flow // link to conn-level counter
+ st.flow.add(sc.initialStreamSendWindowSize)
+ st.inflow.conn = &sc.inflow // link to conn-level counter
+ st.inflow.add(sc.srv.initialStreamRecvWindowSize())
+ if sc.hs.WriteTimeout != 0 {
+ st.writeDeadline = time.AfterFunc(sc.hs.WriteTimeout, st.onWriteTimeout)
+ }
+
+ sc.streams[id] = st
+ sc.writeSched.OpenStream(st.id, OpenStreamOptions{PusherID: pusherID})
+ if st.isPushed() {
+ sc.curPushedStreams++
+ } else {
+ sc.curClientStreams++
+ }
+ if sc.curOpenStreams() == 1 {
+ sc.setConnState(http.StateActive)
+ }
+
+ return st
+}
+
+func (sc *serverConn) newWriterAndRequest(st *stream, f *MetaHeadersFrame) (*responseWriter, *http.Request, error) {
+ sc.serveG.check()
+
+ rp := requestParam{
+ method: f.PseudoValue("method"),
+ scheme: f.PseudoValue("scheme"),
+ authority: f.PseudoValue("authority"),
+ path: f.PseudoValue("path"),
+ }
+
+ isConnect := rp.method == "CONNECT"
+ if isConnect {
+ if rp.path != "" || rp.scheme != "" || rp.authority == "" {
+ return nil, nil, streamError(f.StreamID, ErrCodeProtocol)
+ }
+ } else if rp.method == "" || rp.path == "" || (rp.scheme != "https" && rp.scheme != "http") {
+ // See 8.1.2.6 Malformed Requests and Responses:
+ //
+ // Malformed requests or responses that are detected
+ // MUST be treated as a stream error (Section 5.4.2)
+ // of type PROTOCOL_ERROR."
+ //
+ // 8.1.2.3 Request Pseudo-Header Fields
+ // "All HTTP/2 requests MUST include exactly one valid
+ // value for the :method, :scheme, and :path
+ // pseudo-header fields"
+ return nil, nil, streamError(f.StreamID, ErrCodeProtocol)
+ }
+
+ bodyOpen := !f.StreamEnded()
+ if rp.method == "HEAD" && bodyOpen {
+ // HEAD requests can't have bodies
+ return nil, nil, streamError(f.StreamID, ErrCodeProtocol)
+ }
+
+ rp.header = make(http.Header)
+ for _, hf := range f.RegularFields() {
+ rp.header.Add(sc.canonicalHeader(hf.Name), hf.Value)
+ }
+ if rp.authority == "" {
+ rp.authority = rp.header.Get("Host")
+ }
+
+ rw, req, err := sc.newWriterAndRequestNoBody(st, rp)
+ if err != nil {
+ return nil, nil, err
+ }
+ if bodyOpen {
+ if vv, ok := rp.header["Content-Length"]; ok {
+ req.ContentLength, _ = strconv.ParseInt(vv[0], 10, 64)
+ } else {
+ req.ContentLength = -1
+ }
+ req.Body.(*requestBody).pipe = &pipe{
+ b: &dataBuffer{expected: req.ContentLength},
+ }
+ }
+ return rw, req, nil
+}
+
+type requestParam struct {
+ method string
+ scheme, authority, path string
+ header http.Header
+}
+
+func (sc *serverConn) newWriterAndRequestNoBody(st *stream, rp requestParam) (*responseWriter, *http.Request, error) {
+ sc.serveG.check()
+
+ var tlsState *tls.ConnectionState // nil if not scheme https
+ if rp.scheme == "https" {
+ tlsState = sc.tlsState
+ }
+
+ needsContinue := rp.header.Get("Expect") == "100-continue"
+ if needsContinue {
+ rp.header.Del("Expect")
+ }
+ // Merge Cookie headers into one "; "-delimited value.
+ if cookies := rp.header["Cookie"]; len(cookies) > 1 {
+ rp.header.Set("Cookie", strings.Join(cookies, "; "))
+ }
+
+ // Setup Trailers
+ var trailer http.Header
+ for _, v := range rp.header["Trailer"] {
+ for _, key := range strings.Split(v, ",") {
+ key = http.CanonicalHeaderKey(strings.TrimSpace(key))
+ switch key {
+ case "Transfer-Encoding", "Trailer", "Content-Length":
+ // Bogus. (copy of http1 rules)
+ // Ignore.
+ default:
+ if trailer == nil {
+ trailer = make(http.Header)
+ }
+ trailer[key] = nil
+ }
+ }
+ }
+ delete(rp.header, "Trailer")
+
+ var url_ *url.URL
+ var requestURI string
+ if rp.method == "CONNECT" {
+ url_ = &url.URL{Host: rp.authority}
+ requestURI = rp.authority // mimic HTTP/1 server behavior
+ } else {
+ var err error
+ url_, err = url.ParseRequestURI(rp.path)
+ if err != nil {
+ return nil, nil, streamError(st.id, ErrCodeProtocol)
+ }
+ requestURI = rp.path
+ }
+
+ body := &requestBody{
+ conn: sc,
+ stream: st,
+ needsContinue: needsContinue,
+ }
+ req := &http.Request{
+ Method: rp.method,
+ URL: url_,
+ RemoteAddr: sc.remoteAddrStr,
+ Header: rp.header,
+ RequestURI: requestURI,
+ Proto: "HTTP/2.0",
+ ProtoMajor: 2,
+ ProtoMinor: 0,
+ TLS: tlsState,
+ Host: rp.authority,
+ Body: body,
+ Trailer: trailer,
+ }
+ req = req.WithContext(st.ctx)
+
+ rws := responseWriterStatePool.Get().(*responseWriterState)
+ bwSave := rws.bw
+ *rws = responseWriterState{} // zero all the fields
+ rws.conn = sc
+ rws.bw = bwSave
+ rws.bw.Reset(chunkWriter{rws})
+ rws.stream = st
+ rws.req = req
+ rws.body = body
+
+ rw := &responseWriter{rws: rws}
+ return rw, req, nil
+}
+
+// Run on its own goroutine.
+func (sc *serverConn) runHandler(rw *responseWriter, req *http.Request, handler func(http.ResponseWriter, *http.Request)) {
+ didPanic := true
+ defer func() {
+ rw.rws.stream.cancelCtx()
+ if didPanic {
+ e := recover()
+ sc.writeFrameFromHandler(FrameWriteRequest{
+ write: handlerPanicRST{rw.rws.stream.id},
+ stream: rw.rws.stream,
+ })
+ // Same as net/http:
+ if e != nil && e != http.ErrAbortHandler {
+ const size = 64 << 10
+ buf := make([]byte, size)
+ buf = buf[:runtime.Stack(buf, false)]
+ sc.logf("http2: panic serving %v: %v\n%s", sc.conn.RemoteAddr(), e, buf)
+ }
+ return
+ }
+ rw.handlerDone()
+ }()
+ handler(rw, req)
+ didPanic = false
+}
+
+func handleHeaderListTooLong(w http.ResponseWriter, r *http.Request) {
+ // 10.5.1 Limits on Header Block Size:
+ // .. "A server that receives a larger header block than it is
+ // willing to handle can send an HTTP 431 (Request Header Fields Too
+ // Large) status code"
+ const statusRequestHeaderFieldsTooLarge = 431 // only in Go 1.6+
+ w.WriteHeader(statusRequestHeaderFieldsTooLarge)
+ io.WriteString(w, "
+{{end}}
+
+
+`
diff --git a/vendor/golang.org/x/net/trace/histogram.go b/vendor/golang.org/x/net/trace/histogram.go
new file mode 100644
index 0000000..9bf4286
--- /dev/null
+++ b/vendor/golang.org/x/net/trace/histogram.go
@@ -0,0 +1,365 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package trace
+
+// This file implements histogramming for RPC statistics collection.
+
+import (
+ "bytes"
+ "fmt"
+ "html/template"
+ "log"
+ "math"
+ "sync"
+
+ "golang.org/x/net/internal/timeseries"
+)
+
+const (
+ bucketCount = 38
+)
+
+// histogram keeps counts of values in buckets that are spaced
+// out in powers of 2: 0-1, 2-3, 4-7...
+// histogram implements timeseries.Observable
+type histogram struct {
+ sum int64 // running total of measurements
+ sumOfSquares float64 // square of running total
+ buckets []int64 // bucketed values for histogram
+ value int // holds a single value as an optimization
+ valueCount int64 // number of values recorded for single value
+}
+
+// AddMeasurement records a value measurement observation to the histogram.
+func (h *histogram) addMeasurement(value int64) {
+ // TODO: assert invariant
+ h.sum += value
+ h.sumOfSquares += float64(value) * float64(value)
+
+ bucketIndex := getBucket(value)
+
+ if h.valueCount == 0 || (h.valueCount > 0 && h.value == bucketIndex) {
+ h.value = bucketIndex
+ h.valueCount++
+ } else {
+ h.allocateBuckets()
+ h.buckets[bucketIndex]++
+ }
+}
+
+func (h *histogram) allocateBuckets() {
+ if h.buckets == nil {
+ h.buckets = make([]int64, bucketCount)
+ h.buckets[h.value] = h.valueCount
+ h.value = 0
+ h.valueCount = -1
+ }
+}
+
+func log2(i int64) int {
+ n := 0
+ for ; i >= 0x100; i >>= 8 {
+ n += 8
+ }
+ for ; i > 0; i >>= 1 {
+ n += 1
+ }
+ return n
+}
+
+func getBucket(i int64) (index int) {
+ index = log2(i) - 1
+ if index < 0 {
+ index = 0
+ }
+ if index >= bucketCount {
+ index = bucketCount - 1
+ }
+ return
+}
+
+// Total returns the number of recorded observations.
+func (h *histogram) total() (total int64) {
+ if h.valueCount >= 0 {
+ total = h.valueCount
+ }
+ for _, val := range h.buckets {
+ total += int64(val)
+ }
+ return
+}
+
+// Average returns the average value of recorded observations.
+func (h *histogram) average() float64 {
+ t := h.total()
+ if t == 0 {
+ return 0
+ }
+ return float64(h.sum) / float64(t)
+}
+
+// Variance returns the variance of recorded observations.
+func (h *histogram) variance() float64 {
+ t := float64(h.total())
+ if t == 0 {
+ return 0
+ }
+ s := float64(h.sum) / t
+ return h.sumOfSquares/t - s*s
+}
+
+// StandardDeviation returns the standard deviation of recorded observations.
+func (h *histogram) standardDeviation() float64 {
+ return math.Sqrt(h.variance())
+}
+
+// PercentileBoundary estimates the value that the given fraction of recorded
+// observations are less than.
+func (h *histogram) percentileBoundary(percentile float64) int64 {
+ total := h.total()
+
+ // Corner cases (make sure result is strictly less than Total())
+ if total == 0 {
+ return 0
+ } else if total == 1 {
+ return int64(h.average())
+ }
+
+ percentOfTotal := round(float64(total) * percentile)
+ var runningTotal int64
+
+ for i := range h.buckets {
+ value := h.buckets[i]
+ runningTotal += value
+ if runningTotal == percentOfTotal {
+ // We hit an exact bucket boundary. If the next bucket has data, it is a
+ // good estimate of the value. If the bucket is empty, we interpolate the
+ // midpoint between the next bucket's boundary and the next non-zero
+ // bucket. If the remaining buckets are all empty, then we use the
+ // boundary for the next bucket as the estimate.
+ j := uint8(i + 1)
+ min := bucketBoundary(j)
+ if runningTotal < total {
+ for h.buckets[j] == 0 {
+ j++
+ }
+ }
+ max := bucketBoundary(j)
+ return min + round(float64(max-min)/2)
+ } else if runningTotal > percentOfTotal {
+ // The value is in this bucket. Interpolate the value.
+ delta := runningTotal - percentOfTotal
+ percentBucket := float64(value-delta) / float64(value)
+ bucketMin := bucketBoundary(uint8(i))
+ nextBucketMin := bucketBoundary(uint8(i + 1))
+ bucketSize := nextBucketMin - bucketMin
+ return bucketMin + round(percentBucket*float64(bucketSize))
+ }
+ }
+ return bucketBoundary(bucketCount - 1)
+}
+
+// Median returns the estimated median of the observed values.
+func (h *histogram) median() int64 {
+ return h.percentileBoundary(0.5)
+}
+
+// Add adds other to h.
+func (h *histogram) Add(other timeseries.Observable) {
+ o := other.(*histogram)
+ if o.valueCount == 0 {
+ // Other histogram is empty
+ } else if h.valueCount >= 0 && o.valueCount > 0 && h.value == o.value {
+ // Both have a single bucketed value, aggregate them
+ h.valueCount += o.valueCount
+ } else {
+ // Two different values necessitate buckets in this histogram
+ h.allocateBuckets()
+ if o.valueCount >= 0 {
+ h.buckets[o.value] += o.valueCount
+ } else {
+ for i := range h.buckets {
+ h.buckets[i] += o.buckets[i]
+ }
+ }
+ }
+ h.sumOfSquares += o.sumOfSquares
+ h.sum += o.sum
+}
+
+// Clear resets the histogram to an empty state, removing all observed values.
+func (h *histogram) Clear() {
+ h.buckets = nil
+ h.value = 0
+ h.valueCount = 0
+ h.sum = 0
+ h.sumOfSquares = 0
+}
+
+// CopyFrom copies from other, which must be a *histogram, into h.
+func (h *histogram) CopyFrom(other timeseries.Observable) {
+ o := other.(*histogram)
+ if o.valueCount == -1 {
+ h.allocateBuckets()
+ copy(h.buckets, o.buckets)
+ }
+ h.sum = o.sum
+ h.sumOfSquares = o.sumOfSquares
+ h.value = o.value
+ h.valueCount = o.valueCount
+}
+
+// Multiply scales the histogram by the specified ratio.
+func (h *histogram) Multiply(ratio float64) {
+ if h.valueCount == -1 {
+ for i := range h.buckets {
+ h.buckets[i] = int64(float64(h.buckets[i]) * ratio)
+ }
+ } else {
+ h.valueCount = int64(float64(h.valueCount) * ratio)
+ }
+ h.sum = int64(float64(h.sum) * ratio)
+ h.sumOfSquares = h.sumOfSquares * ratio
+}
+
+// New creates a new histogram.
+func (h *histogram) New() timeseries.Observable {
+ r := new(histogram)
+ r.Clear()
+ return r
+}
+
+func (h *histogram) String() string {
+ return fmt.Sprintf("%d, %f, %d, %d, %v",
+ h.sum, h.sumOfSquares, h.value, h.valueCount, h.buckets)
+}
+
+// round returns the closest int64 to the argument
+func round(in float64) int64 {
+ return int64(math.Floor(in + 0.5))
+}
+
+// bucketBoundary returns the first value in the bucket.
+func bucketBoundary(bucket uint8) int64 {
+ if bucket == 0 {
+ return 0
+ }
+ return 1 << bucket
+}
+
+// bucketData holds data about a specific bucket for use in distTmpl.
+type bucketData struct {
+ Lower, Upper int64
+ N int64
+ Pct, CumulativePct float64
+ GraphWidth int
+}
+
+// data holds data about a Distribution for use in distTmpl.
+type data struct {
+ Buckets []*bucketData
+ Count, Median int64
+ Mean, StandardDeviation float64
+}
+
+// maxHTMLBarWidth is the maximum width of the HTML bar for visualizing buckets.
+const maxHTMLBarWidth = 350.0
+
+// newData returns data representing h for use in distTmpl.
+func (h *histogram) newData() *data {
+ // Force the allocation of buckets to simplify the rendering implementation
+ h.allocateBuckets()
+ // We scale the bars on the right so that the largest bar is
+ // maxHTMLBarWidth pixels in width.
+ maxBucket := int64(0)
+ for _, n := range h.buckets {
+ if n > maxBucket {
+ maxBucket = n
+ }
+ }
+ total := h.total()
+ barsizeMult := maxHTMLBarWidth / float64(maxBucket)
+ var pctMult float64
+ if total == 0 {
+ pctMult = 1.0
+ } else {
+ pctMult = 100.0 / float64(total)
+ }
+
+ buckets := make([]*bucketData, len(h.buckets))
+ runningTotal := int64(0)
+ for i, n := range h.buckets {
+ if n == 0 {
+ continue
+ }
+ runningTotal += n
+ var upperBound int64
+ if i < bucketCount-1 {
+ upperBound = bucketBoundary(uint8(i + 1))
+ } else {
+ upperBound = math.MaxInt64
+ }
+ buckets[i] = &bucketData{
+ Lower: bucketBoundary(uint8(i)),
+ Upper: upperBound,
+ N: n,
+ Pct: float64(n) * pctMult,
+ CumulativePct: float64(runningTotal) * pctMult,
+ GraphWidth: int(float64(n) * barsizeMult),
+ }
+ }
+ return &data{
+ Buckets: buckets,
+ Count: total,
+ Median: h.median(),
+ Mean: h.average(),
+ StandardDeviation: h.standardDeviation(),
+ }
+}
+
+func (h *histogram) html() template.HTML {
+ buf := new(bytes.Buffer)
+ if err := distTmpl().Execute(buf, h.newData()); err != nil {
+ buf.Reset()
+ log.Printf("net/trace: couldn't execute template: %v", err)
+ }
+ return template.HTML(buf.String())
+}
+
+var distTmplCache *template.Template
+var distTmplOnce sync.Once
+
+func distTmpl() *template.Template {
+ distTmplOnce.Do(func() {
+ // Input: data
+ distTmplCache = template.Must(template.New("distTmpl").Parse(`
+
+
+
Count: {{.Count}}
+
Mean: {{printf "%.0f" .Mean}}
+
StdDev: {{printf "%.0f" .StandardDeviation}}
+
Median: {{.Median}}
+
+
+
+
+{{range $b := .Buckets}}
+{{if $b}}
+
+
[
+
{{.Lower}},
+
{{.Upper}})
+
{{.N}}
+
{{printf "%#.3f" .Pct}}%
+
{{printf "%#.3f" .CumulativePct}}%
+
+
+{{end}}
+{{end}}
+
+`))
+ })
+ return distTmplCache
+}
diff --git a/vendor/golang.org/x/net/trace/trace.go b/vendor/golang.org/x/net/trace/trace.go
new file mode 100644
index 0000000..3ebf6f2
--- /dev/null
+++ b/vendor/golang.org/x/net/trace/trace.go
@@ -0,0 +1,1130 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+Package trace implements tracing of requests and long-lived objects.
+It exports HTTP interfaces on /debug/requests and /debug/events.
+
+A trace.Trace provides tracing for short-lived objects, usually requests.
+A request handler might be implemented like this:
+
+ func fooHandler(w http.ResponseWriter, req *http.Request) {
+ tr := trace.New("mypkg.Foo", req.URL.Path)
+ defer tr.Finish()
+ ...
+ tr.LazyPrintf("some event %q happened", str)
+ ...
+ if err := somethingImportant(); err != nil {
+ tr.LazyPrintf("somethingImportant failed: %v", err)
+ tr.SetError()
+ }
+ }
+
+The /debug/requests HTTP endpoint organizes the traces by family,
+errors, and duration. It also provides histogram of request duration
+for each family.
+
+A trace.EventLog provides tracing for long-lived objects, such as RPC
+connections.
+
+ // A Fetcher fetches URL paths for a single domain.
+ type Fetcher struct {
+ domain string
+ events trace.EventLog
+ }
+
+ func NewFetcher(domain string) *Fetcher {
+ return &Fetcher{
+ domain,
+ trace.NewEventLog("mypkg.Fetcher", domain),
+ }
+ }
+
+ func (f *Fetcher) Fetch(path string) (string, error) {
+ resp, err := http.Get("http://" + f.domain + "/" + path)
+ if err != nil {
+ f.events.Errorf("Get(%q) = %v", path, err)
+ return "", err
+ }
+ f.events.Printf("Get(%q) = %s", path, resp.Status)
+ ...
+ }
+
+ func (f *Fetcher) Close() error {
+ f.events.Finish()
+ return nil
+ }
+
+The /debug/events HTTP endpoint organizes the event logs by family and
+by time since the last error. The expanded view displays recent log
+entries and the log's call stack.
+*/
+package trace // import "golang.org/x/net/trace"
+
+import (
+ "bytes"
+ "context"
+ "fmt"
+ "html/template"
+ "io"
+ "log"
+ "net"
+ "net/http"
+ "net/url"
+ "runtime"
+ "sort"
+ "strconv"
+ "sync"
+ "sync/atomic"
+ "time"
+
+ "golang.org/x/net/internal/timeseries"
+)
+
+// DebugUseAfterFinish controls whether to debug uses of Trace values after finishing.
+// FOR DEBUGGING ONLY. This will slow down the program.
+var DebugUseAfterFinish = false
+
+// HTTP ServeMux paths.
+const (
+ debugRequestsPath = "/debug/requests"
+ debugEventsPath = "/debug/events"
+)
+
+// AuthRequest determines whether a specific request is permitted to load the
+// /debug/requests or /debug/events pages.
+//
+// It returns two bools; the first indicates whether the page may be viewed at all,
+// and the second indicates whether sensitive events will be shown.
+//
+// AuthRequest may be replaced by a program to customize its authorization requirements.
+//
+// The default AuthRequest function returns (true, true) if and only if the request
+// comes from localhost/127.0.0.1/[::1].
+var AuthRequest = func(req *http.Request) (any, sensitive bool) {
+ // RemoteAddr is commonly in the form "IP" or "IP:port".
+ // If it is in the form "IP:port", split off the port.
+ host, _, err := net.SplitHostPort(req.RemoteAddr)
+ if err != nil {
+ host = req.RemoteAddr
+ }
+ switch host {
+ case "localhost", "127.0.0.1", "::1":
+ return true, true
+ default:
+ return false, false
+ }
+}
+
+func init() {
+ _, pat := http.DefaultServeMux.Handler(&http.Request{URL: &url.URL{Path: debugRequestsPath}})
+ if pat == debugRequestsPath {
+ panic("/debug/requests is already registered. You may have two independent copies of " +
+ "golang.org/x/net/trace in your binary, trying to maintain separate state. This may " +
+ "involve a vendored copy of golang.org/x/net/trace.")
+ }
+
+ // TODO(jbd): Serve Traces from /debug/traces in the future?
+ // There is no requirement for a request to be present to have traces.
+ http.HandleFunc(debugRequestsPath, Traces)
+ http.HandleFunc(debugEventsPath, Events)
+}
+
+// NewContext returns a copy of the parent context
+// and associates it with a Trace.
+func NewContext(ctx context.Context, tr Trace) context.Context {
+ return context.WithValue(ctx, contextKey, tr)
+}
+
+// FromContext returns the Trace bound to the context, if any.
+func FromContext(ctx context.Context) (tr Trace, ok bool) {
+ tr, ok = ctx.Value(contextKey).(Trace)
+ return
+}
+
+// Traces responds with traces from the program.
+// The package initialization registers it in http.DefaultServeMux
+// at /debug/requests.
+//
+// It performs authorization by running AuthRequest.
+func Traces(w http.ResponseWriter, req *http.Request) {
+ any, sensitive := AuthRequest(req)
+ if !any {
+ http.Error(w, "not allowed", http.StatusUnauthorized)
+ return
+ }
+ w.Header().Set("Content-Type", "text/html; charset=utf-8")
+ Render(w, req, sensitive)
+}
+
+// Events responds with a page of events collected by EventLogs.
+// The package initialization registers it in http.DefaultServeMux
+// at /debug/events.
+//
+// It performs authorization by running AuthRequest.
+func Events(w http.ResponseWriter, req *http.Request) {
+ any, sensitive := AuthRequest(req)
+ if !any {
+ http.Error(w, "not allowed", http.StatusUnauthorized)
+ return
+ }
+ w.Header().Set("Content-Type", "text/html; charset=utf-8")
+ RenderEvents(w, req, sensitive)
+}
+
+// Render renders the HTML page typically served at /debug/requests.
+// It does not do any auth checking. The request may be nil.
+//
+// Most users will use the Traces handler.
+func Render(w io.Writer, req *http.Request, sensitive bool) {
+ data := &struct {
+ Families []string
+ ActiveTraceCount map[string]int
+ CompletedTraces map[string]*family
+
+ // Set when a bucket has been selected.
+ Traces traceList
+ Family string
+ Bucket int
+ Expanded bool
+ Traced bool
+ Active bool
+ ShowSensitive bool // whether to show sensitive events
+
+ Histogram template.HTML
+ HistogramWindow string // e.g. "last minute", "last hour", "all time"
+
+ // If non-zero, the set of traces is a partial set,
+ // and this is the total number.
+ Total int
+ }{
+ CompletedTraces: completedTraces,
+ }
+
+ data.ShowSensitive = sensitive
+ if req != nil {
+ // Allow show_sensitive=0 to force hiding of sensitive data for testing.
+ // This only goes one way; you can't use show_sensitive=1 to see things.
+ if req.FormValue("show_sensitive") == "0" {
+ data.ShowSensitive = false
+ }
+
+ if exp, err := strconv.ParseBool(req.FormValue("exp")); err == nil {
+ data.Expanded = exp
+ }
+ if exp, err := strconv.ParseBool(req.FormValue("rtraced")); err == nil {
+ data.Traced = exp
+ }
+ }
+
+ completedMu.RLock()
+ data.Families = make([]string, 0, len(completedTraces))
+ for fam := range completedTraces {
+ data.Families = append(data.Families, fam)
+ }
+ completedMu.RUnlock()
+ sort.Strings(data.Families)
+
+ // We are careful here to minimize the time spent locking activeMu,
+ // since that lock is required every time an RPC starts and finishes.
+ data.ActiveTraceCount = make(map[string]int, len(data.Families))
+ activeMu.RLock()
+ for fam, s := range activeTraces {
+ data.ActiveTraceCount[fam] = s.Len()
+ }
+ activeMu.RUnlock()
+
+ var ok bool
+ data.Family, data.Bucket, ok = parseArgs(req)
+ switch {
+ case !ok:
+ // No-op
+ case data.Bucket == -1:
+ data.Active = true
+ n := data.ActiveTraceCount[data.Family]
+ data.Traces = getActiveTraces(data.Family)
+ if len(data.Traces) < n {
+ data.Total = n
+ }
+ case data.Bucket < bucketsPerFamily:
+ if b := lookupBucket(data.Family, data.Bucket); b != nil {
+ data.Traces = b.Copy(data.Traced)
+ }
+ default:
+ if f := getFamily(data.Family, false); f != nil {
+ var obs timeseries.Observable
+ f.LatencyMu.RLock()
+ switch o := data.Bucket - bucketsPerFamily; o {
+ case 0:
+ obs = f.Latency.Minute()
+ data.HistogramWindow = "last minute"
+ case 1:
+ obs = f.Latency.Hour()
+ data.HistogramWindow = "last hour"
+ case 2:
+ obs = f.Latency.Total()
+ data.HistogramWindow = "all time"
+ }
+ f.LatencyMu.RUnlock()
+ if obs != nil {
+ data.Histogram = obs.(*histogram).html()
+ }
+ }
+ }
+
+ if data.Traces != nil {
+ defer data.Traces.Free()
+ sort.Sort(data.Traces)
+ }
+
+ completedMu.RLock()
+ defer completedMu.RUnlock()
+ if err := pageTmpl().ExecuteTemplate(w, "Page", data); err != nil {
+ log.Printf("net/trace: Failed executing template: %v", err)
+ }
+}
+
+func parseArgs(req *http.Request) (fam string, b int, ok bool) {
+ if req == nil {
+ return "", 0, false
+ }
+ fam, bStr := req.FormValue("fam"), req.FormValue("b")
+ if fam == "" || bStr == "" {
+ return "", 0, false
+ }
+ b, err := strconv.Atoi(bStr)
+ if err != nil || b < -1 {
+ return "", 0, false
+ }
+
+ return fam, b, true
+}
+
+func lookupBucket(fam string, b int) *traceBucket {
+ f := getFamily(fam, false)
+ if f == nil || b < 0 || b >= len(f.Buckets) {
+ return nil
+ }
+ return f.Buckets[b]
+}
+
+type contextKeyT string
+
+var contextKey = contextKeyT("golang.org/x/net/trace.Trace")
+
+// Trace represents an active request.
+type Trace interface {
+ // LazyLog adds x to the event log. It will be evaluated each time the
+ // /debug/requests page is rendered. Any memory referenced by x will be
+ // pinned until the trace is finished and later discarded.
+ LazyLog(x fmt.Stringer, sensitive bool)
+
+ // LazyPrintf evaluates its arguments with fmt.Sprintf each time the
+ // /debug/requests page is rendered. Any memory referenced by a will be
+ // pinned until the trace is finished and later discarded.
+ LazyPrintf(format string, a ...interface{})
+
+ // SetError declares that this trace resulted in an error.
+ SetError()
+
+ // SetRecycler sets a recycler for the trace.
+ // f will be called for each event passed to LazyLog at a time when
+ // it is no longer required, whether while the trace is still active
+ // and the event is discarded, or when a completed trace is discarded.
+ SetRecycler(f func(interface{}))
+
+ // SetTraceInfo sets the trace info for the trace.
+ // This is currently unused.
+ SetTraceInfo(traceID, spanID uint64)
+
+ // SetMaxEvents sets the maximum number of events that will be stored
+ // in the trace. This has no effect if any events have already been
+ // added to the trace.
+ SetMaxEvents(m int)
+
+ // Finish declares that this trace is complete.
+ // The trace should not be used after calling this method.
+ Finish()
+}
+
+type lazySprintf struct {
+ format string
+ a []interface{}
+}
+
+func (l *lazySprintf) String() string {
+ return fmt.Sprintf(l.format, l.a...)
+}
+
+// New returns a new Trace with the specified family and title.
+func New(family, title string) Trace {
+ tr := newTrace()
+ tr.ref()
+ tr.Family, tr.Title = family, title
+ tr.Start = time.Now()
+ tr.maxEvents = maxEventsPerTrace
+ tr.events = tr.eventsBuf[:0]
+
+ activeMu.RLock()
+ s := activeTraces[tr.Family]
+ activeMu.RUnlock()
+ if s == nil {
+ activeMu.Lock()
+ s = activeTraces[tr.Family] // check again
+ if s == nil {
+ s = new(traceSet)
+ activeTraces[tr.Family] = s
+ }
+ activeMu.Unlock()
+ }
+ s.Add(tr)
+
+ // Trigger allocation of the completed trace structure for this family.
+ // This will cause the family to be present in the request page during
+ // the first trace of this family. We don't care about the return value,
+ // nor is there any need for this to run inline, so we execute it in its
+ // own goroutine, but only if the family isn't allocated yet.
+ completedMu.RLock()
+ if _, ok := completedTraces[tr.Family]; !ok {
+ go allocFamily(tr.Family)
+ }
+ completedMu.RUnlock()
+
+ return tr
+}
+
+func (tr *trace) Finish() {
+ elapsed := time.Now().Sub(tr.Start)
+ tr.mu.Lock()
+ tr.Elapsed = elapsed
+ tr.mu.Unlock()
+
+ if DebugUseAfterFinish {
+ buf := make([]byte, 4<<10) // 4 KB should be enough
+ n := runtime.Stack(buf, false)
+ tr.finishStack = buf[:n]
+ }
+
+ activeMu.RLock()
+ m := activeTraces[tr.Family]
+ activeMu.RUnlock()
+ m.Remove(tr)
+
+ f := getFamily(tr.Family, true)
+ tr.mu.RLock() // protects tr fields in Cond.match calls
+ for _, b := range f.Buckets {
+ if b.Cond.match(tr) {
+ b.Add(tr)
+ }
+ }
+ tr.mu.RUnlock()
+
+ // Add a sample of elapsed time as microseconds to the family's timeseries
+ h := new(histogram)
+ h.addMeasurement(elapsed.Nanoseconds() / 1e3)
+ f.LatencyMu.Lock()
+ f.Latency.Add(h)
+ f.LatencyMu.Unlock()
+
+ tr.unref() // matches ref in New
+}
+
+const (
+ bucketsPerFamily = 9
+ tracesPerBucket = 10
+ maxActiveTraces = 20 // Maximum number of active traces to show.
+ maxEventsPerTrace = 10
+ numHistogramBuckets = 38
+)
+
+var (
+ // The active traces.
+ activeMu sync.RWMutex
+ activeTraces = make(map[string]*traceSet) // family -> traces
+
+ // Families of completed traces.
+ completedMu sync.RWMutex
+ completedTraces = make(map[string]*family) // family -> traces
+)
+
+type traceSet struct {
+ mu sync.RWMutex
+ m map[*trace]bool
+
+ // We could avoid the entire map scan in FirstN by having a slice of all the traces
+ // ordered by start time, and an index into that from the trace struct, with a periodic
+ // repack of the slice after enough traces finish; we could also use a skip list or similar.
+ // However, that would shift some of the expense from /debug/requests time to RPC time,
+ // which is probably the wrong trade-off.
+}
+
+func (ts *traceSet) Len() int {
+ ts.mu.RLock()
+ defer ts.mu.RUnlock()
+ return len(ts.m)
+}
+
+func (ts *traceSet) Add(tr *trace) {
+ ts.mu.Lock()
+ if ts.m == nil {
+ ts.m = make(map[*trace]bool)
+ }
+ ts.m[tr] = true
+ ts.mu.Unlock()
+}
+
+func (ts *traceSet) Remove(tr *trace) {
+ ts.mu.Lock()
+ delete(ts.m, tr)
+ ts.mu.Unlock()
+}
+
+// FirstN returns the first n traces ordered by time.
+func (ts *traceSet) FirstN(n int) traceList {
+ ts.mu.RLock()
+ defer ts.mu.RUnlock()
+
+ if n > len(ts.m) {
+ n = len(ts.m)
+ }
+ trl := make(traceList, 0, n)
+
+ // Fast path for when no selectivity is needed.
+ if n == len(ts.m) {
+ for tr := range ts.m {
+ tr.ref()
+ trl = append(trl, tr)
+ }
+ sort.Sort(trl)
+ return trl
+ }
+
+ // Pick the oldest n traces.
+ // This is inefficient. See the comment in the traceSet struct.
+ for tr := range ts.m {
+ // Put the first n traces into trl in the order they occur.
+ // When we have n, sort trl, and thereafter maintain its order.
+ if len(trl) < n {
+ tr.ref()
+ trl = append(trl, tr)
+ if len(trl) == n {
+ // This is guaranteed to happen exactly once during this loop.
+ sort.Sort(trl)
+ }
+ continue
+ }
+ if tr.Start.After(trl[n-1].Start) {
+ continue
+ }
+
+ // Find where to insert this one.
+ tr.ref()
+ i := sort.Search(n, func(i int) bool { return trl[i].Start.After(tr.Start) })
+ trl[n-1].unref()
+ copy(trl[i+1:], trl[i:])
+ trl[i] = tr
+ }
+
+ return trl
+}
+
+func getActiveTraces(fam string) traceList {
+ activeMu.RLock()
+ s := activeTraces[fam]
+ activeMu.RUnlock()
+ if s == nil {
+ return nil
+ }
+ return s.FirstN(maxActiveTraces)
+}
+
+func getFamily(fam string, allocNew bool) *family {
+ completedMu.RLock()
+ f := completedTraces[fam]
+ completedMu.RUnlock()
+ if f == nil && allocNew {
+ f = allocFamily(fam)
+ }
+ return f
+}
+
+func allocFamily(fam string) *family {
+ completedMu.Lock()
+ defer completedMu.Unlock()
+ f := completedTraces[fam]
+ if f == nil {
+ f = newFamily()
+ completedTraces[fam] = f
+ }
+ return f
+}
+
+// family represents a set of trace buckets and associated latency information.
+type family struct {
+ // traces may occur in multiple buckets.
+ Buckets [bucketsPerFamily]*traceBucket
+
+ // latency time series
+ LatencyMu sync.RWMutex
+ Latency *timeseries.MinuteHourSeries
+}
+
+func newFamily() *family {
+ return &family{
+ Buckets: [bucketsPerFamily]*traceBucket{
+ {Cond: minCond(0)},
+ {Cond: minCond(50 * time.Millisecond)},
+ {Cond: minCond(100 * time.Millisecond)},
+ {Cond: minCond(200 * time.Millisecond)},
+ {Cond: minCond(500 * time.Millisecond)},
+ {Cond: minCond(1 * time.Second)},
+ {Cond: minCond(10 * time.Second)},
+ {Cond: minCond(100 * time.Second)},
+ {Cond: errorCond{}},
+ },
+ Latency: timeseries.NewMinuteHourSeries(func() timeseries.Observable { return new(histogram) }),
+ }
+}
+
+// traceBucket represents a size-capped bucket of historic traces,
+// along with a condition for a trace to belong to the bucket.
+type traceBucket struct {
+ Cond cond
+
+ // Ring buffer implementation of a fixed-size FIFO queue.
+ mu sync.RWMutex
+ buf [tracesPerBucket]*trace
+ start int // < tracesPerBucket
+ length int // <= tracesPerBucket
+}
+
+func (b *traceBucket) Add(tr *trace) {
+ b.mu.Lock()
+ defer b.mu.Unlock()
+
+ i := b.start + b.length
+ if i >= tracesPerBucket {
+ i -= tracesPerBucket
+ }
+ if b.length == tracesPerBucket {
+ // "Remove" an element from the bucket.
+ b.buf[i].unref()
+ b.start++
+ if b.start == tracesPerBucket {
+ b.start = 0
+ }
+ }
+ b.buf[i] = tr
+ if b.length < tracesPerBucket {
+ b.length++
+ }
+ tr.ref()
+}
+
+// Copy returns a copy of the traces in the bucket.
+// If tracedOnly is true, only the traces with trace information will be returned.
+// The logs will be ref'd before returning; the caller should call
+// the Free method when it is done with them.
+// TODO(dsymonds): keep track of traced requests in separate buckets.
+func (b *traceBucket) Copy(tracedOnly bool) traceList {
+ b.mu.RLock()
+ defer b.mu.RUnlock()
+
+ trl := make(traceList, 0, b.length)
+ for i, x := 0, b.start; i < b.length; i++ {
+ tr := b.buf[x]
+ if !tracedOnly || tr.spanID != 0 {
+ tr.ref()
+ trl = append(trl, tr)
+ }
+ x++
+ if x == b.length {
+ x = 0
+ }
+ }
+ return trl
+}
+
+func (b *traceBucket) Empty() bool {
+ b.mu.RLock()
+ defer b.mu.RUnlock()
+ return b.length == 0
+}
+
+// cond represents a condition on a trace.
+type cond interface {
+ match(t *trace) bool
+ String() string
+}
+
+type minCond time.Duration
+
+func (m minCond) match(t *trace) bool { return t.Elapsed >= time.Duration(m) }
+func (m minCond) String() string { return fmt.Sprintf("≥%gs", time.Duration(m).Seconds()) }
+
+type errorCond struct{}
+
+func (e errorCond) match(t *trace) bool { return t.IsError }
+func (e errorCond) String() string { return "errors" }
+
+type traceList []*trace
+
+// Free calls unref on each element of the list.
+func (trl traceList) Free() {
+ for _, t := range trl {
+ t.unref()
+ }
+}
+
+// traceList may be sorted in reverse chronological order.
+func (trl traceList) Len() int { return len(trl) }
+func (trl traceList) Less(i, j int) bool { return trl[i].Start.After(trl[j].Start) }
+func (trl traceList) Swap(i, j int) { trl[i], trl[j] = trl[j], trl[i] }
+
+// An event is a timestamped log entry in a trace.
+type event struct {
+ When time.Time
+ Elapsed time.Duration // since previous event in trace
+ NewDay bool // whether this event is on a different day to the previous event
+ Recyclable bool // whether this event was passed via LazyLog
+ Sensitive bool // whether this event contains sensitive information
+ What interface{} // string or fmt.Stringer
+}
+
+// WhenString returns a string representation of the elapsed time of the event.
+// It will include the date if midnight was crossed.
+func (e event) WhenString() string {
+ if e.NewDay {
+ return e.When.Format("2006/01/02 15:04:05.000000")
+ }
+ return e.When.Format("15:04:05.000000")
+}
+
+// discarded represents a number of discarded events.
+// It is stored as *discarded to make it easier to update in-place.
+type discarded int
+
+func (d *discarded) String() string {
+ return fmt.Sprintf("(%d events discarded)", int(*d))
+}
+
+// trace represents an active or complete request,
+// either sent or received by this program.
+type trace struct {
+ // Family is the top-level grouping of traces to which this belongs.
+ Family string
+
+ // Title is the title of this trace.
+ Title string
+
+ // Start time of the this trace.
+ Start time.Time
+
+ mu sync.RWMutex
+ events []event // Append-only sequence of events (modulo discards).
+ maxEvents int
+ recycler func(interface{})
+ IsError bool // Whether this trace resulted in an error.
+ Elapsed time.Duration // Elapsed time for this trace, zero while active.
+ traceID uint64 // Trace information if non-zero.
+ spanID uint64
+
+ refs int32 // how many buckets this is in
+ disc discarded // scratch space to avoid allocation
+
+ finishStack []byte // where finish was called, if DebugUseAfterFinish is set
+
+ eventsBuf [4]event // preallocated buffer in case we only log a few events
+}
+
+func (tr *trace) reset() {
+ // Clear all but the mutex. Mutexes may not be copied, even when unlocked.
+ tr.Family = ""
+ tr.Title = ""
+ tr.Start = time.Time{}
+
+ tr.mu.Lock()
+ tr.Elapsed = 0
+ tr.traceID = 0
+ tr.spanID = 0
+ tr.IsError = false
+ tr.maxEvents = 0
+ tr.events = nil
+ tr.recycler = nil
+ tr.mu.Unlock()
+
+ tr.refs = 0
+ tr.disc = 0
+ tr.finishStack = nil
+ for i := range tr.eventsBuf {
+ tr.eventsBuf[i] = event{}
+ }
+}
+
+// delta returns the elapsed time since the last event or the trace start,
+// and whether it spans midnight.
+// L >= tr.mu
+func (tr *trace) delta(t time.Time) (time.Duration, bool) {
+ if len(tr.events) == 0 {
+ return t.Sub(tr.Start), false
+ }
+ prev := tr.events[len(tr.events)-1].When
+ return t.Sub(prev), prev.Day() != t.Day()
+}
+
+func (tr *trace) addEvent(x interface{}, recyclable, sensitive bool) {
+ if DebugUseAfterFinish && tr.finishStack != nil {
+ buf := make([]byte, 4<<10) // 4 KB should be enough
+ n := runtime.Stack(buf, false)
+ log.Printf("net/trace: trace used after finish:\nFinished at:\n%s\nUsed at:\n%s", tr.finishStack, buf[:n])
+ }
+
+ /*
+ NOTE TO DEBUGGERS
+
+ If you are here because your program panicked in this code,
+ it is almost definitely the fault of code using this package,
+ and very unlikely to be the fault of this code.
+
+ The most likely scenario is that some code elsewhere is using
+ a trace.Trace after its Finish method is called.
+ You can temporarily set the DebugUseAfterFinish var
+ to help discover where that is; do not leave that var set,
+ since it makes this package much less efficient.
+ */
+
+ e := event{When: time.Now(), What: x, Recyclable: recyclable, Sensitive: sensitive}
+ tr.mu.Lock()
+ e.Elapsed, e.NewDay = tr.delta(e.When)
+ if len(tr.events) < tr.maxEvents {
+ tr.events = append(tr.events, e)
+ } else {
+ // Discard the middle events.
+ di := int((tr.maxEvents - 1) / 2)
+ if d, ok := tr.events[di].What.(*discarded); ok {
+ (*d)++
+ } else {
+ // disc starts at two to count for the event it is replacing,
+ // plus the next one that we are about to drop.
+ tr.disc = 2
+ if tr.recycler != nil && tr.events[di].Recyclable {
+ go tr.recycler(tr.events[di].What)
+ }
+ tr.events[di].What = &tr.disc
+ }
+ // The timestamp of the discarded meta-event should be
+ // the time of the last event it is representing.
+ tr.events[di].When = tr.events[di+1].When
+
+ if tr.recycler != nil && tr.events[di+1].Recyclable {
+ go tr.recycler(tr.events[di+1].What)
+ }
+ copy(tr.events[di+1:], tr.events[di+2:])
+ tr.events[tr.maxEvents-1] = e
+ }
+ tr.mu.Unlock()
+}
+
+func (tr *trace) LazyLog(x fmt.Stringer, sensitive bool) {
+ tr.addEvent(x, true, sensitive)
+}
+
+func (tr *trace) LazyPrintf(format string, a ...interface{}) {
+ tr.addEvent(&lazySprintf{format, a}, false, false)
+}
+
+func (tr *trace) SetError() {
+ tr.mu.Lock()
+ tr.IsError = true
+ tr.mu.Unlock()
+}
+
+func (tr *trace) SetRecycler(f func(interface{})) {
+ tr.mu.Lock()
+ tr.recycler = f
+ tr.mu.Unlock()
+}
+
+func (tr *trace) SetTraceInfo(traceID, spanID uint64) {
+ tr.mu.Lock()
+ tr.traceID, tr.spanID = traceID, spanID
+ tr.mu.Unlock()
+}
+
+func (tr *trace) SetMaxEvents(m int) {
+ tr.mu.Lock()
+ // Always keep at least three events: first, discarded count, last.
+ if len(tr.events) == 0 && m > 3 {
+ tr.maxEvents = m
+ }
+ tr.mu.Unlock()
+}
+
+func (tr *trace) ref() {
+ atomic.AddInt32(&tr.refs, 1)
+}
+
+func (tr *trace) unref() {
+ if atomic.AddInt32(&tr.refs, -1) == 0 {
+ tr.mu.RLock()
+ if tr.recycler != nil {
+ // freeTrace clears tr, so we hold tr.recycler and tr.events here.
+ go func(f func(interface{}), es []event) {
+ for _, e := range es {
+ if e.Recyclable {
+ f(e.What)
+ }
+ }
+ }(tr.recycler, tr.events)
+ }
+ tr.mu.RUnlock()
+
+ freeTrace(tr)
+ }
+}
+
+func (tr *trace) When() string {
+ return tr.Start.Format("2006/01/02 15:04:05.000000")
+}
+
+func (tr *trace) ElapsedTime() string {
+ tr.mu.RLock()
+ t := tr.Elapsed
+ tr.mu.RUnlock()
+
+ if t == 0 {
+ // Active trace.
+ t = time.Since(tr.Start)
+ }
+ return fmt.Sprintf("%.6f", t.Seconds())
+}
+
+func (tr *trace) Events() []event {
+ tr.mu.RLock()
+ defer tr.mu.RUnlock()
+ return tr.events
+}
+
+var traceFreeList = make(chan *trace, 1000) // TODO(dsymonds): Use sync.Pool?
+
+// newTrace returns a trace ready to use.
+func newTrace() *trace {
+ select {
+ case tr := <-traceFreeList:
+ return tr
+ default:
+ return new(trace)
+ }
+}
+
+// freeTrace adds tr to traceFreeList if there's room.
+// This is non-blocking.
+func freeTrace(tr *trace) {
+ if DebugUseAfterFinish {
+ return // never reuse
+ }
+ tr.reset()
+ select {
+ case traceFreeList <- tr:
+ default:
+ }
+}
+
+func elapsed(d time.Duration) string {
+ b := []byte(fmt.Sprintf("%.6f", d.Seconds()))
+
+ // For subsecond durations, blank all zeros before decimal point,
+ // and all zeros between the decimal point and the first non-zero digit.
+ if d < time.Second {
+ dot := bytes.IndexByte(b, '.')
+ for i := 0; i < dot; i++ {
+ b[i] = ' '
+ }
+ for i := dot + 1; i < len(b); i++ {
+ if b[i] == '0' {
+ b[i] = ' '
+ } else {
+ break
+ }
+ }
+ }
+
+ return string(b)
+}
+
+var pageTmplCache *template.Template
+var pageTmplOnce sync.Once
+
+func pageTmpl() *template.Template {
+ pageTmplOnce.Do(func() {
+ pageTmplCache = template.Must(template.New("Page").Funcs(template.FuncMap{
+ "elapsed": elapsed,
+ "add": func(a, b int) int { return a + b },
+ }).Parse(pageHTML))
+ })
+ return pageTmplCache
+}
+
+const pageHTML = `
+{{template "Prolog" .}}
+{{template "StatusTable" .}}
+{{template "Epilog" .}}
+
+{{define "Prolog"}}
+
+
+ /debug/requests
+
+
+
+
+
/debug/requests
+{{end}} {{/* end of Prolog */}}
+
+{{define "StatusTable"}}
+
{{if or $.ShowSensitive (not .Sensitive)}}... {{.What}}{{else}}[redacted]{{end}}
+
+ {{end}}
+ {{end}}
+ {{end}}
+
+{{end}} {{/* if $.Traces */}}
+
+{{if $.Histogram}}
+
Latency (µs) of {{$.Family}} over {{$.HistogramWindow}}
+{{$.Histogram}}
+{{end}} {{/* if $.Histogram */}}
+
+
+
+{{end}} {{/* end of Epilog */}}
+`
diff --git a/vendor/golang.org/x/sys/AUTHORS b/vendor/golang.org/x/sys/AUTHORS
new file mode 100644
index 0000000..15167cd
--- /dev/null
+++ b/vendor/golang.org/x/sys/AUTHORS
@@ -0,0 +1,3 @@
+# This source code refers to The Go Authors for copyright purposes.
+# The master list of authors is in the main Go distribution,
+# visible at http://tip.golang.org/AUTHORS.
diff --git a/vendor/golang.org/x/sys/CONTRIBUTORS b/vendor/golang.org/x/sys/CONTRIBUTORS
new file mode 100644
index 0000000..1c4577e
--- /dev/null
+++ b/vendor/golang.org/x/sys/CONTRIBUTORS
@@ -0,0 +1,3 @@
+# This source code was written by the Go contributors.
+# The master list of contributors is in the main Go distribution,
+# visible at http://tip.golang.org/CONTRIBUTORS.
diff --git a/vendor/golang.org/x/sys/LICENSE b/vendor/golang.org/x/sys/LICENSE
new file mode 100644
index 0000000..6a66aea
--- /dev/null
+++ b/vendor/golang.org/x/sys/LICENSE
@@ -0,0 +1,27 @@
+Copyright (c) 2009 The Go Authors. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+ * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/vendor/golang.org/x/sys/PATENTS b/vendor/golang.org/x/sys/PATENTS
new file mode 100644
index 0000000..7330990
--- /dev/null
+++ b/vendor/golang.org/x/sys/PATENTS
@@ -0,0 +1,22 @@
+Additional IP Rights Grant (Patents)
+
+"This implementation" means the copyrightable works distributed by
+Google as part of the Go project.
+
+Google hereby grants to You a perpetual, worldwide, non-exclusive,
+no-charge, royalty-free, irrevocable (except as stated in this section)
+patent license to make, have made, use, offer to sell, sell, import,
+transfer and otherwise run, modify and propagate the contents of this
+implementation of Go, where such license applies only to those patent
+claims, both currently owned or controlled by Google and acquired in
+the future, licensable by Google that are necessarily infringed by this
+implementation of Go. This grant does not include claims that would be
+infringed only as a consequence of further modification of this
+implementation. If you or your agent or exclusive licensee institute or
+order or agree to the institution of patent litigation against any
+entity (including a cross-claim or counterclaim in a lawsuit) alleging
+that this implementation of Go or any code incorporated within this
+implementation of Go constitutes direct or contributory patent
+infringement, or inducement of patent infringement, then any patent
+rights granted to you under this License for this implementation of Go
+shall terminate as of the date such litigation is filed.
diff --git a/vendor/golang.org/x/sys/unix/.gitignore b/vendor/golang.org/x/sys/unix/.gitignore
new file mode 100644
index 0000000..e3e0fc6
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/.gitignore
@@ -0,0 +1,2 @@
+_obj/
+unix.test
diff --git a/vendor/golang.org/x/sys/unix/README.md b/vendor/golang.org/x/sys/unix/README.md
new file mode 100644
index 0000000..eb2f78a
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/README.md
@@ -0,0 +1,173 @@
+# Building `sys/unix`
+
+The sys/unix package provides access to the raw system call interface of the
+underlying operating system. See: https://godoc.org/golang.org/x/sys/unix
+
+Porting Go to a new architecture/OS combination or adding syscalls, types, or
+constants to an existing architecture/OS pair requires some manual effort;
+however, there are tools that automate much of the process.
+
+## Build Systems
+
+There are currently two ways we generate the necessary files. We are currently
+migrating the build system to use containers so the builds are reproducible.
+This is being done on an OS-by-OS basis. Please update this documentation as
+components of the build system change.
+
+### Old Build System (currently for `GOOS != "linux"`)
+
+The old build system generates the Go files based on the C header files
+present on your system. This means that files
+for a given GOOS/GOARCH pair must be generated on a system with that OS and
+architecture. This also means that the generated code can differ from system
+to system, based on differences in the header files.
+
+To avoid this, if you are using the old build system, only generate the Go
+files on an installation with unmodified header files. It is also important to
+keep track of which version of the OS the files were generated from (ex.
+Darwin 14 vs Darwin 15). This makes it easier to track the progress of changes
+and have each OS upgrade correspond to a single change.
+
+To build the files for your current OS and architecture, make sure GOOS and
+GOARCH are set correctly and run `mkall.sh`. This will generate the files for
+your specific system. Running `mkall.sh -n` shows the commands that will be run.
+
+Requirements: bash, go
+
+### New Build System (currently for `GOOS == "linux"`)
+
+The new build system uses a Docker container to generate the go files directly
+from source checkouts of the kernel and various system libraries. This means
+that on any platform that supports Docker, all the files using the new build
+system can be generated at once, and generated files will not change based on
+what the person running the scripts has installed on their computer.
+
+The OS specific files for the new build system are located in the `${GOOS}`
+directory, and the build is coordinated by the `${GOOS}/mkall.go` program. When
+the kernel or system library updates, modify the Dockerfile at
+`${GOOS}/Dockerfile` to checkout the new release of the source.
+
+To build all the files under the new build system, you must be on an amd64/Linux
+system and have your GOOS and GOARCH set accordingly. Running `mkall.sh` will
+then generate all of the files for all of the GOOS/GOARCH pairs in the new build
+system. Running `mkall.sh -n` shows the commands that will be run.
+
+Requirements: bash, go, docker
+
+## Component files
+
+This section describes the various files used in the code generation process.
+It also contains instructions on how to modify these files to add a new
+architecture/OS or to add additional syscalls, types, or constants. Note that
+if you are using the new build system, the scripts/programs cannot be called normally.
+They must be called from within the docker container.
+
+### asm files
+
+The hand-written assembly file at `asm_${GOOS}_${GOARCH}.s` implements system
+call dispatch. There are three entry points:
+```
+ func Syscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr)
+ func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr)
+ func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr)
+```
+The first and second are the standard ones; they differ only in how many
+arguments can be passed to the kernel. The third is for low-level use by the
+ForkExec wrapper. Unlike the first two, it does not call into the scheduler to
+let it know that a system call is running.
+
+When porting Go to an new architecture/OS, this file must be implemented for
+each GOOS/GOARCH pair.
+
+### mksysnum
+
+Mksysnum is a Go program located at `${GOOS}/mksysnum.go` (or `mksysnum_${GOOS}.go`
+for the old system). This program takes in a list of header files containing the
+syscall number declarations and parses them to produce the corresponding list of
+Go numeric constants. See `zsysnum_${GOOS}_${GOARCH}.go` for the generated
+constants.
+
+Adding new syscall numbers is mostly done by running the build on a sufficiently
+new installation of the target OS (or updating the source checkouts for the
+new build system). However, depending on the OS, you make need to update the
+parsing in mksysnum.
+
+### mksyscall.go
+
+The `syscall.go`, `syscall_${GOOS}.go`, `syscall_${GOOS}_${GOARCH}.go` are
+hand-written Go files which implement system calls (for unix, the specific OS,
+or the specific OS/Architecture pair respectively) that need special handling
+and list `//sys` comments giving prototypes for ones that can be generated.
+
+The mksyscall.go program takes the `//sys` and `//sysnb` comments and converts
+them into syscalls. This requires the name of the prototype in the comment to
+match a syscall number in the `zsysnum_${GOOS}_${GOARCH}.go` file. The function
+prototype can be exported (capitalized) or not.
+
+Adding a new syscall often just requires adding a new `//sys` function prototype
+with the desired arguments and a capitalized name so it is exported. However, if
+you want the interface to the syscall to be different, often one will make an
+unexported `//sys` prototype, an then write a custom wrapper in
+`syscall_${GOOS}.go`.
+
+### types files
+
+For each OS, there is a hand-written Go file at `${GOOS}/types.go` (or
+`types_${GOOS}.go` on the old system). This file includes standard C headers and
+creates Go type aliases to the corresponding C types. The file is then fed
+through godef to get the Go compatible definitions. Finally, the generated code
+is fed though mkpost.go to format the code correctly and remove any hidden or
+private identifiers. This cleaned-up code is written to
+`ztypes_${GOOS}_${GOARCH}.go`.
+
+The hardest part about preparing this file is figuring out which headers to
+include and which symbols need to be `#define`d to get the actual data
+structures that pass through to the kernel system calls. Some C libraries
+preset alternate versions for binary compatibility and translate them on the
+way in and out of system calls, but there is almost always a `#define` that can
+get the real ones.
+See `types_darwin.go` and `linux/types.go` for examples.
+
+To add a new type, add in the necessary include statement at the top of the
+file (if it is not already there) and add in a type alias line. Note that if
+your type is significantly different on different architectures, you may need
+some `#if/#elif` macros in your include statements.
+
+### mkerrors.sh
+
+This script is used to generate the system's various constants. This doesn't
+just include the error numbers and error strings, but also the signal numbers
+an a wide variety of miscellaneous constants. The constants come from the list
+of include files in the `includes_${uname}` variable. A regex then picks out
+the desired `#define` statements, and generates the corresponding Go constants.
+The error numbers and strings are generated from `#include `, and the
+signal numbers and strings are generated from `#include `. All of
+these constants are written to `zerrors_${GOOS}_${GOARCH}.go` via a C program,
+`_errors.c`, which prints out all the constants.
+
+To add a constant, add the header that includes it to the appropriate variable.
+Then, edit the regex (if necessary) to match the desired constant. Avoid making
+the regex too broad to avoid matching unintended constants.
+
+
+## Generated files
+
+### `zerror_${GOOS}_${GOARCH}.go`
+
+A file containing all of the system's generated error numbers, error strings,
+signal numbers, and constants. Generated by `mkerrors.sh` (see above).
+
+### `zsyscall_${GOOS}_${GOARCH}.go`
+
+A file containing all the generated syscalls for a specific GOOS and GOARCH.
+Generated by `mksyscall.go` (see above).
+
+### `zsysnum_${GOOS}_${GOARCH}.go`
+
+A list of numeric constants for all the syscall number of the specific GOOS
+and GOARCH. Generated by mksysnum (see above).
+
+### `ztypes_${GOOS}_${GOARCH}.go`
+
+A file containing Go types for passing into (or returning from) syscalls.
+Generated by godefs and the types file (see above).
diff --git a/vendor/golang.org/x/sys/unix/affinity_linux.go b/vendor/golang.org/x/sys/unix/affinity_linux.go
new file mode 100644
index 0000000..14e4d5c
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/affinity_linux.go
@@ -0,0 +1,128 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// CPU affinity functions
+
+package unix
+
+import (
+ "unsafe"
+)
+
+const cpuSetSize = _CPU_SETSIZE / _NCPUBITS
+
+// CPUSet represents a CPU affinity mask.
+type CPUSet [cpuSetSize]cpuMask
+
+func schedAffinity(trap uintptr, pid int, set *CPUSet) error {
+ _, _, e := RawSyscall(trap, uintptr(pid), uintptr(unsafe.Sizeof(*set)), uintptr(unsafe.Pointer(set)))
+ if e != 0 {
+ return errnoErr(e)
+ }
+ return nil
+}
+
+// SchedGetaffinity gets the CPU affinity mask of the thread specified by pid.
+// If pid is 0 the calling thread is used.
+func SchedGetaffinity(pid int, set *CPUSet) error {
+ return schedAffinity(SYS_SCHED_GETAFFINITY, pid, set)
+}
+
+// SchedSetaffinity sets the CPU affinity mask of the thread specified by pid.
+// If pid is 0 the calling thread is used.
+func SchedSetaffinity(pid int, set *CPUSet) error {
+ return schedAffinity(SYS_SCHED_SETAFFINITY, pid, set)
+}
+
+// Zero clears the set s, so that it contains no CPUs.
+func (s *CPUSet) Zero() {
+ for i := range s {
+ s[i] = 0
+ }
+}
+
+func cpuBitsIndex(cpu int) int {
+ return cpu / _NCPUBITS
+}
+
+func cpuBitsMask(cpu int) cpuMask {
+ return cpuMask(1 << (uint(cpu) % _NCPUBITS))
+}
+
+// Set adds cpu to the set s.
+func (s *CPUSet) Set(cpu int) {
+ i := cpuBitsIndex(cpu)
+ if i < len(s) {
+ s[i] |= cpuBitsMask(cpu)
+ }
+}
+
+// Clear removes cpu from the set s.
+func (s *CPUSet) Clear(cpu int) {
+ i := cpuBitsIndex(cpu)
+ if i < len(s) {
+ s[i] &^= cpuBitsMask(cpu)
+ }
+}
+
+// IsSet reports whether cpu is in the set s.
+func (s *CPUSet) IsSet(cpu int) bool {
+ i := cpuBitsIndex(cpu)
+ if i < len(s) {
+ return s[i]&cpuBitsMask(cpu) != 0
+ }
+ return false
+}
+
+// Count returns the number of CPUs in the set s.
+func (s *CPUSet) Count() int {
+ c := 0
+ for _, b := range s {
+ c += onesCount64(uint64(b))
+ }
+ return c
+}
+
+// onesCount64 is a copy of Go 1.9's math/bits.OnesCount64.
+// Once this package can require Go 1.9, we can delete this
+// and update the caller to use bits.OnesCount64.
+func onesCount64(x uint64) int {
+ const m0 = 0x5555555555555555 // 01010101 ...
+ const m1 = 0x3333333333333333 // 00110011 ...
+ const m2 = 0x0f0f0f0f0f0f0f0f // 00001111 ...
+
+ // Unused in this function, but definitions preserved for
+ // documentation purposes:
+ //
+ // const m3 = 0x00ff00ff00ff00ff // etc.
+ // const m4 = 0x0000ffff0000ffff
+ //
+ // Implementation: Parallel summing of adjacent bits.
+ // See "Hacker's Delight", Chap. 5: Counting Bits.
+ // The following pattern shows the general approach:
+ //
+ // x = x>>1&(m0&m) + x&(m0&m)
+ // x = x>>2&(m1&m) + x&(m1&m)
+ // x = x>>4&(m2&m) + x&(m2&m)
+ // x = x>>8&(m3&m) + x&(m3&m)
+ // x = x>>16&(m4&m) + x&(m4&m)
+ // x = x>>32&(m5&m) + x&(m5&m)
+ // return int(x)
+ //
+ // Masking (& operations) can be left away when there's no
+ // danger that a field's sum will carry over into the next
+ // field: Since the result cannot be > 64, 8 bits is enough
+ // and we can ignore the masks for the shifts by 8 and up.
+ // Per "Hacker's Delight", the first line can be simplified
+ // more, but it saves at best one instruction, so we leave
+ // it alone for clarity.
+ const m = 1<<64 - 1
+ x = x>>1&(m0&m) + x&(m0&m)
+ x = x>>2&(m1&m) + x&(m1&m)
+ x = (x>>4 + x) & (m2 & m)
+ x += x >> 8
+ x += x >> 16
+ x += x >> 32
+ return int(x) & (1<<7 - 1)
+}
diff --git a/vendor/golang.org/x/sys/unix/aliases.go b/vendor/golang.org/x/sys/unix/aliases.go
new file mode 100644
index 0000000..951fce4
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/aliases.go
@@ -0,0 +1,14 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
+// +build go1.9
+
+package unix
+
+import "syscall"
+
+type Signal = syscall.Signal
+type Errno = syscall.Errno
+type SysProcAttr = syscall.SysProcAttr
diff --git a/vendor/golang.org/x/sys/unix/asm_aix_ppc64.s b/vendor/golang.org/x/sys/unix/asm_aix_ppc64.s
new file mode 100644
index 0000000..06f84b8
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/asm_aix_ppc64.s
@@ -0,0 +1,17 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !gccgo
+
+#include "textflag.h"
+
+//
+// System calls for ppc64, AIX are implemented in runtime/syscall_aix.go
+//
+
+TEXT ·syscall6(SB),NOSPLIT,$0-88
+ JMP syscall·syscall6(SB)
+
+TEXT ·rawSyscall6(SB),NOSPLIT,$0-88
+ JMP syscall·rawSyscall6(SB)
diff --git a/vendor/golang.org/x/sys/unix/asm_darwin_386.s b/vendor/golang.org/x/sys/unix/asm_darwin_386.s
new file mode 100644
index 0000000..8a72783
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/asm_darwin_386.s
@@ -0,0 +1,29 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !gccgo
+
+#include "textflag.h"
+
+//
+// System call support for 386, Darwin
+//
+
+// Just jump to package syscall's implementation for all these functions.
+// The runtime may know about them.
+
+TEXT ·Syscall(SB),NOSPLIT,$0-28
+ JMP syscall·Syscall(SB)
+
+TEXT ·Syscall6(SB),NOSPLIT,$0-40
+ JMP syscall·Syscall6(SB)
+
+TEXT ·Syscall9(SB),NOSPLIT,$0-52
+ JMP syscall·Syscall9(SB)
+
+TEXT ·RawSyscall(SB),NOSPLIT,$0-28
+ JMP syscall·RawSyscall(SB)
+
+TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
+ JMP syscall·RawSyscall6(SB)
diff --git a/vendor/golang.org/x/sys/unix/asm_darwin_amd64.s b/vendor/golang.org/x/sys/unix/asm_darwin_amd64.s
new file mode 100644
index 0000000..6321421
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/asm_darwin_amd64.s
@@ -0,0 +1,29 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !gccgo
+
+#include "textflag.h"
+
+//
+// System call support for AMD64, Darwin
+//
+
+// Just jump to package syscall's implementation for all these functions.
+// The runtime may know about them.
+
+TEXT ·Syscall(SB),NOSPLIT,$0-56
+ JMP syscall·Syscall(SB)
+
+TEXT ·Syscall6(SB),NOSPLIT,$0-80
+ JMP syscall·Syscall6(SB)
+
+TEXT ·Syscall9(SB),NOSPLIT,$0-104
+ JMP syscall·Syscall9(SB)
+
+TEXT ·RawSyscall(SB),NOSPLIT,$0-56
+ JMP syscall·RawSyscall(SB)
+
+TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
+ JMP syscall·RawSyscall6(SB)
diff --git a/vendor/golang.org/x/sys/unix/asm_darwin_arm.s b/vendor/golang.org/x/sys/unix/asm_darwin_arm.s
new file mode 100644
index 0000000..333242d
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/asm_darwin_arm.s
@@ -0,0 +1,30 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !gccgo
+// +build arm,darwin
+
+#include "textflag.h"
+
+//
+// System call support for ARM, Darwin
+//
+
+// Just jump to package syscall's implementation for all these functions.
+// The runtime may know about them.
+
+TEXT ·Syscall(SB),NOSPLIT,$0-28
+ B syscall·Syscall(SB)
+
+TEXT ·Syscall6(SB),NOSPLIT,$0-40
+ B syscall·Syscall6(SB)
+
+TEXT ·Syscall9(SB),NOSPLIT,$0-52
+ B syscall·Syscall9(SB)
+
+TEXT ·RawSyscall(SB),NOSPLIT,$0-28
+ B syscall·RawSyscall(SB)
+
+TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
+ B syscall·RawSyscall6(SB)
diff --git a/vendor/golang.org/x/sys/unix/asm_darwin_arm64.s b/vendor/golang.org/x/sys/unix/asm_darwin_arm64.s
new file mode 100644
index 0000000..97e0174
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/asm_darwin_arm64.s
@@ -0,0 +1,30 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !gccgo
+// +build arm64,darwin
+
+#include "textflag.h"
+
+//
+// System call support for AMD64, Darwin
+//
+
+// Just jump to package syscall's implementation for all these functions.
+// The runtime may know about them.
+
+TEXT ·Syscall(SB),NOSPLIT,$0-56
+ B syscall·Syscall(SB)
+
+TEXT ·Syscall6(SB),NOSPLIT,$0-80
+ B syscall·Syscall6(SB)
+
+TEXT ·Syscall9(SB),NOSPLIT,$0-104
+ B syscall·Syscall9(SB)
+
+TEXT ·RawSyscall(SB),NOSPLIT,$0-56
+ B syscall·RawSyscall(SB)
+
+TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
+ B syscall·RawSyscall6(SB)
diff --git a/vendor/golang.org/x/sys/unix/asm_dragonfly_amd64.s b/vendor/golang.org/x/sys/unix/asm_dragonfly_amd64.s
new file mode 100644
index 0000000..603dd57
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/asm_dragonfly_amd64.s
@@ -0,0 +1,29 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !gccgo
+
+#include "textflag.h"
+
+//
+// System call support for AMD64, DragonFly
+//
+
+// Just jump to package syscall's implementation for all these functions.
+// The runtime may know about them.
+
+TEXT ·Syscall(SB),NOSPLIT,$0-56
+ JMP syscall·Syscall(SB)
+
+TEXT ·Syscall6(SB),NOSPLIT,$0-80
+ JMP syscall·Syscall6(SB)
+
+TEXT ·Syscall9(SB),NOSPLIT,$0-104
+ JMP syscall·Syscall9(SB)
+
+TEXT ·RawSyscall(SB),NOSPLIT,$0-56
+ JMP syscall·RawSyscall(SB)
+
+TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
+ JMP syscall·RawSyscall6(SB)
diff --git a/vendor/golang.org/x/sys/unix/asm_freebsd_386.s b/vendor/golang.org/x/sys/unix/asm_freebsd_386.s
new file mode 100644
index 0000000..c9a0a26
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/asm_freebsd_386.s
@@ -0,0 +1,29 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !gccgo
+
+#include "textflag.h"
+
+//
+// System call support for 386, FreeBSD
+//
+
+// Just jump to package syscall's implementation for all these functions.
+// The runtime may know about them.
+
+TEXT ·Syscall(SB),NOSPLIT,$0-28
+ JMP syscall·Syscall(SB)
+
+TEXT ·Syscall6(SB),NOSPLIT,$0-40
+ JMP syscall·Syscall6(SB)
+
+TEXT ·Syscall9(SB),NOSPLIT,$0-52
+ JMP syscall·Syscall9(SB)
+
+TEXT ·RawSyscall(SB),NOSPLIT,$0-28
+ JMP syscall·RawSyscall(SB)
+
+TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
+ JMP syscall·RawSyscall6(SB)
diff --git a/vendor/golang.org/x/sys/unix/asm_freebsd_amd64.s b/vendor/golang.org/x/sys/unix/asm_freebsd_amd64.s
new file mode 100644
index 0000000..3517247
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/asm_freebsd_amd64.s
@@ -0,0 +1,29 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !gccgo
+
+#include "textflag.h"
+
+//
+// System call support for AMD64, FreeBSD
+//
+
+// Just jump to package syscall's implementation for all these functions.
+// The runtime may know about them.
+
+TEXT ·Syscall(SB),NOSPLIT,$0-56
+ JMP syscall·Syscall(SB)
+
+TEXT ·Syscall6(SB),NOSPLIT,$0-80
+ JMP syscall·Syscall6(SB)
+
+TEXT ·Syscall9(SB),NOSPLIT,$0-104
+ JMP syscall·Syscall9(SB)
+
+TEXT ·RawSyscall(SB),NOSPLIT,$0-56
+ JMP syscall·RawSyscall(SB)
+
+TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
+ JMP syscall·RawSyscall6(SB)
diff --git a/vendor/golang.org/x/sys/unix/asm_freebsd_arm.s b/vendor/golang.org/x/sys/unix/asm_freebsd_arm.s
new file mode 100644
index 0000000..9227c87
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/asm_freebsd_arm.s
@@ -0,0 +1,29 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !gccgo
+
+#include "textflag.h"
+
+//
+// System call support for ARM, FreeBSD
+//
+
+// Just jump to package syscall's implementation for all these functions.
+// The runtime may know about them.
+
+TEXT ·Syscall(SB),NOSPLIT,$0-28
+ B syscall·Syscall(SB)
+
+TEXT ·Syscall6(SB),NOSPLIT,$0-40
+ B syscall·Syscall6(SB)
+
+TEXT ·Syscall9(SB),NOSPLIT,$0-52
+ B syscall·Syscall9(SB)
+
+TEXT ·RawSyscall(SB),NOSPLIT,$0-28
+ B syscall·RawSyscall(SB)
+
+TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
+ B syscall·RawSyscall6(SB)
diff --git a/vendor/golang.org/x/sys/unix/asm_freebsd_arm64.s b/vendor/golang.org/x/sys/unix/asm_freebsd_arm64.s
new file mode 100644
index 0000000..d9318cb
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/asm_freebsd_arm64.s
@@ -0,0 +1,29 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !gccgo
+
+#include "textflag.h"
+
+//
+// System call support for ARM64, FreeBSD
+//
+
+// Just jump to package syscall's implementation for all these functions.
+// The runtime may know about them.
+
+TEXT ·Syscall(SB),NOSPLIT,$0-56
+ JMP syscall·Syscall(SB)
+
+TEXT ·Syscall6(SB),NOSPLIT,$0-80
+ JMP syscall·Syscall6(SB)
+
+TEXT ·Syscall9(SB),NOSPLIT,$0-104
+ JMP syscall·Syscall9(SB)
+
+TEXT ·RawSyscall(SB),NOSPLIT,$0-56
+ JMP syscall·RawSyscall(SB)
+
+TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
+ JMP syscall·RawSyscall6(SB)
diff --git a/vendor/golang.org/x/sys/unix/asm_linux_386.s b/vendor/golang.org/x/sys/unix/asm_linux_386.s
new file mode 100644
index 0000000..448bebb
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/asm_linux_386.s
@@ -0,0 +1,65 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !gccgo
+
+#include "textflag.h"
+
+//
+// System calls for 386, Linux
+//
+
+// See ../runtime/sys_linux_386.s for the reason why we always use int 0x80
+// instead of the glibc-specific "CALL 0x10(GS)".
+#define INVOKE_SYSCALL INT $0x80
+
+// Just jump to package syscall's implementation for all these functions.
+// The runtime may know about them.
+
+TEXT ·Syscall(SB),NOSPLIT,$0-28
+ JMP syscall·Syscall(SB)
+
+TEXT ·Syscall6(SB),NOSPLIT,$0-40
+ JMP syscall·Syscall6(SB)
+
+TEXT ·SyscallNoError(SB),NOSPLIT,$0-24
+ CALL runtime·entersyscall(SB)
+ MOVL trap+0(FP), AX // syscall entry
+ MOVL a1+4(FP), BX
+ MOVL a2+8(FP), CX
+ MOVL a3+12(FP), DX
+ MOVL $0, SI
+ MOVL $0, DI
+ INVOKE_SYSCALL
+ MOVL AX, r1+16(FP)
+ MOVL DX, r2+20(FP)
+ CALL runtime·exitsyscall(SB)
+ RET
+
+TEXT ·RawSyscall(SB),NOSPLIT,$0-28
+ JMP syscall·RawSyscall(SB)
+
+TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
+ JMP syscall·RawSyscall6(SB)
+
+TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-24
+ MOVL trap+0(FP), AX // syscall entry
+ MOVL a1+4(FP), BX
+ MOVL a2+8(FP), CX
+ MOVL a3+12(FP), DX
+ MOVL $0, SI
+ MOVL $0, DI
+ INVOKE_SYSCALL
+ MOVL AX, r1+16(FP)
+ MOVL DX, r2+20(FP)
+ RET
+
+TEXT ·socketcall(SB),NOSPLIT,$0-36
+ JMP syscall·socketcall(SB)
+
+TEXT ·rawsocketcall(SB),NOSPLIT,$0-36
+ JMP syscall·rawsocketcall(SB)
+
+TEXT ·seek(SB),NOSPLIT,$0-28
+ JMP syscall·seek(SB)
diff --git a/vendor/golang.org/x/sys/unix/asm_linux_amd64.s b/vendor/golang.org/x/sys/unix/asm_linux_amd64.s
new file mode 100644
index 0000000..c6468a9
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/asm_linux_amd64.s
@@ -0,0 +1,57 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !gccgo
+
+#include "textflag.h"
+
+//
+// System calls for AMD64, Linux
+//
+
+// Just jump to package syscall's implementation for all these functions.
+// The runtime may know about them.
+
+TEXT ·Syscall(SB),NOSPLIT,$0-56
+ JMP syscall·Syscall(SB)
+
+TEXT ·Syscall6(SB),NOSPLIT,$0-80
+ JMP syscall·Syscall6(SB)
+
+TEXT ·SyscallNoError(SB),NOSPLIT,$0-48
+ CALL runtime·entersyscall(SB)
+ MOVQ a1+8(FP), DI
+ MOVQ a2+16(FP), SI
+ MOVQ a3+24(FP), DX
+ MOVQ $0, R10
+ MOVQ $0, R8
+ MOVQ $0, R9
+ MOVQ trap+0(FP), AX // syscall entry
+ SYSCALL
+ MOVQ AX, r1+32(FP)
+ MOVQ DX, r2+40(FP)
+ CALL runtime·exitsyscall(SB)
+ RET
+
+TEXT ·RawSyscall(SB),NOSPLIT,$0-56
+ JMP syscall·RawSyscall(SB)
+
+TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
+ JMP syscall·RawSyscall6(SB)
+
+TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-48
+ MOVQ a1+8(FP), DI
+ MOVQ a2+16(FP), SI
+ MOVQ a3+24(FP), DX
+ MOVQ $0, R10
+ MOVQ $0, R8
+ MOVQ $0, R9
+ MOVQ trap+0(FP), AX // syscall entry
+ SYSCALL
+ MOVQ AX, r1+32(FP)
+ MOVQ DX, r2+40(FP)
+ RET
+
+TEXT ·gettimeofday(SB),NOSPLIT,$0-16
+ JMP syscall·gettimeofday(SB)
diff --git a/vendor/golang.org/x/sys/unix/asm_linux_arm.s b/vendor/golang.org/x/sys/unix/asm_linux_arm.s
new file mode 100644
index 0000000..cf0f357
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/asm_linux_arm.s
@@ -0,0 +1,56 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !gccgo
+
+#include "textflag.h"
+
+//
+// System calls for arm, Linux
+//
+
+// Just jump to package syscall's implementation for all these functions.
+// The runtime may know about them.
+
+TEXT ·Syscall(SB),NOSPLIT,$0-28
+ B syscall·Syscall(SB)
+
+TEXT ·Syscall6(SB),NOSPLIT,$0-40
+ B syscall·Syscall6(SB)
+
+TEXT ·SyscallNoError(SB),NOSPLIT,$0-24
+ BL runtime·entersyscall(SB)
+ MOVW trap+0(FP), R7
+ MOVW a1+4(FP), R0
+ MOVW a2+8(FP), R1
+ MOVW a3+12(FP), R2
+ MOVW $0, R3
+ MOVW $0, R4
+ MOVW $0, R5
+ SWI $0
+ MOVW R0, r1+16(FP)
+ MOVW $0, R0
+ MOVW R0, r2+20(FP)
+ BL runtime·exitsyscall(SB)
+ RET
+
+TEXT ·RawSyscall(SB),NOSPLIT,$0-28
+ B syscall·RawSyscall(SB)
+
+TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
+ B syscall·RawSyscall6(SB)
+
+TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-24
+ MOVW trap+0(FP), R7 // syscall entry
+ MOVW a1+4(FP), R0
+ MOVW a2+8(FP), R1
+ MOVW a3+12(FP), R2
+ SWI $0
+ MOVW R0, r1+16(FP)
+ MOVW $0, R0
+ MOVW R0, r2+20(FP)
+ RET
+
+TEXT ·seek(SB),NOSPLIT,$0-28
+ B syscall·seek(SB)
diff --git a/vendor/golang.org/x/sys/unix/asm_linux_arm64.s b/vendor/golang.org/x/sys/unix/asm_linux_arm64.s
new file mode 100644
index 0000000..afe6fdf
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/asm_linux_arm64.s
@@ -0,0 +1,52 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build linux
+// +build arm64
+// +build !gccgo
+
+#include "textflag.h"
+
+// Just jump to package syscall's implementation for all these functions.
+// The runtime may know about them.
+
+TEXT ·Syscall(SB),NOSPLIT,$0-56
+ B syscall·Syscall(SB)
+
+TEXT ·Syscall6(SB),NOSPLIT,$0-80
+ B syscall·Syscall6(SB)
+
+TEXT ·SyscallNoError(SB),NOSPLIT,$0-48
+ BL runtime·entersyscall(SB)
+ MOVD a1+8(FP), R0
+ MOVD a2+16(FP), R1
+ MOVD a3+24(FP), R2
+ MOVD $0, R3
+ MOVD $0, R4
+ MOVD $0, R5
+ MOVD trap+0(FP), R8 // syscall entry
+ SVC
+ MOVD R0, r1+32(FP) // r1
+ MOVD R1, r2+40(FP) // r2
+ BL runtime·exitsyscall(SB)
+ RET
+
+TEXT ·RawSyscall(SB),NOSPLIT,$0-56
+ B syscall·RawSyscall(SB)
+
+TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
+ B syscall·RawSyscall6(SB)
+
+TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-48
+ MOVD a1+8(FP), R0
+ MOVD a2+16(FP), R1
+ MOVD a3+24(FP), R2
+ MOVD $0, R3
+ MOVD $0, R4
+ MOVD $0, R5
+ MOVD trap+0(FP), R8 // syscall entry
+ SVC
+ MOVD R0, r1+32(FP)
+ MOVD R1, r2+40(FP)
+ RET
diff --git a/vendor/golang.org/x/sys/unix/asm_linux_mips64x.s b/vendor/golang.org/x/sys/unix/asm_linux_mips64x.s
new file mode 100644
index 0000000..ab9d638
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/asm_linux_mips64x.s
@@ -0,0 +1,56 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build linux
+// +build mips64 mips64le
+// +build !gccgo
+
+#include "textflag.h"
+
+//
+// System calls for mips64, Linux
+//
+
+// Just jump to package syscall's implementation for all these functions.
+// The runtime may know about them.
+
+TEXT ·Syscall(SB),NOSPLIT,$0-56
+ JMP syscall·Syscall(SB)
+
+TEXT ·Syscall6(SB),NOSPLIT,$0-80
+ JMP syscall·Syscall6(SB)
+
+TEXT ·SyscallNoError(SB),NOSPLIT,$0-48
+ JAL runtime·entersyscall(SB)
+ MOVV a1+8(FP), R4
+ MOVV a2+16(FP), R5
+ MOVV a3+24(FP), R6
+ MOVV R0, R7
+ MOVV R0, R8
+ MOVV R0, R9
+ MOVV trap+0(FP), R2 // syscall entry
+ SYSCALL
+ MOVV R2, r1+32(FP)
+ MOVV R3, r2+40(FP)
+ JAL runtime·exitsyscall(SB)
+ RET
+
+TEXT ·RawSyscall(SB),NOSPLIT,$0-56
+ JMP syscall·RawSyscall(SB)
+
+TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
+ JMP syscall·RawSyscall6(SB)
+
+TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-48
+ MOVV a1+8(FP), R4
+ MOVV a2+16(FP), R5
+ MOVV a3+24(FP), R6
+ MOVV R0, R7
+ MOVV R0, R8
+ MOVV R0, R9
+ MOVV trap+0(FP), R2 // syscall entry
+ SYSCALL
+ MOVV R2, r1+32(FP)
+ MOVV R3, r2+40(FP)
+ RET
diff --git a/vendor/golang.org/x/sys/unix/asm_linux_mipsx.s b/vendor/golang.org/x/sys/unix/asm_linux_mipsx.s
new file mode 100644
index 0000000..99e5399
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/asm_linux_mipsx.s
@@ -0,0 +1,54 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build linux
+// +build mips mipsle
+// +build !gccgo
+
+#include "textflag.h"
+
+//
+// System calls for mips, Linux
+//
+
+// Just jump to package syscall's implementation for all these functions.
+// The runtime may know about them.
+
+TEXT ·Syscall(SB),NOSPLIT,$0-28
+ JMP syscall·Syscall(SB)
+
+TEXT ·Syscall6(SB),NOSPLIT,$0-40
+ JMP syscall·Syscall6(SB)
+
+TEXT ·Syscall9(SB),NOSPLIT,$0-52
+ JMP syscall·Syscall9(SB)
+
+TEXT ·SyscallNoError(SB),NOSPLIT,$0-24
+ JAL runtime·entersyscall(SB)
+ MOVW a1+4(FP), R4
+ MOVW a2+8(FP), R5
+ MOVW a3+12(FP), R6
+ MOVW R0, R7
+ MOVW trap+0(FP), R2 // syscall entry
+ SYSCALL
+ MOVW R2, r1+16(FP) // r1
+ MOVW R3, r2+20(FP) // r2
+ JAL runtime·exitsyscall(SB)
+ RET
+
+TEXT ·RawSyscall(SB),NOSPLIT,$0-28
+ JMP syscall·RawSyscall(SB)
+
+TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
+ JMP syscall·RawSyscall6(SB)
+
+TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-24
+ MOVW a1+4(FP), R4
+ MOVW a2+8(FP), R5
+ MOVW a3+12(FP), R6
+ MOVW trap+0(FP), R2 // syscall entry
+ SYSCALL
+ MOVW R2, r1+16(FP)
+ MOVW R3, r2+20(FP)
+ RET
diff --git a/vendor/golang.org/x/sys/unix/asm_linux_ppc64x.s b/vendor/golang.org/x/sys/unix/asm_linux_ppc64x.s
new file mode 100644
index 0000000..88f7125
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/asm_linux_ppc64x.s
@@ -0,0 +1,44 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build linux
+// +build ppc64 ppc64le
+// +build !gccgo
+
+#include "textflag.h"
+
+//
+// System calls for ppc64, Linux
+//
+
+// Just jump to package syscall's implementation for all these functions.
+// The runtime may know about them.
+
+TEXT ·SyscallNoError(SB),NOSPLIT,$0-48
+ BL runtime·entersyscall(SB)
+ MOVD a1+8(FP), R3
+ MOVD a2+16(FP), R4
+ MOVD a3+24(FP), R5
+ MOVD R0, R6
+ MOVD R0, R7
+ MOVD R0, R8
+ MOVD trap+0(FP), R9 // syscall entry
+ SYSCALL R9
+ MOVD R3, r1+32(FP)
+ MOVD R4, r2+40(FP)
+ BL runtime·exitsyscall(SB)
+ RET
+
+TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-48
+ MOVD a1+8(FP), R3
+ MOVD a2+16(FP), R4
+ MOVD a3+24(FP), R5
+ MOVD R0, R6
+ MOVD R0, R7
+ MOVD R0, R8
+ MOVD trap+0(FP), R9 // syscall entry
+ SYSCALL R9
+ MOVD R3, r1+32(FP)
+ MOVD R4, r2+40(FP)
+ RET
diff --git a/vendor/golang.org/x/sys/unix/asm_linux_riscv64.s b/vendor/golang.org/x/sys/unix/asm_linux_riscv64.s
new file mode 100644
index 0000000..6db717d
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/asm_linux_riscv64.s
@@ -0,0 +1,54 @@
+// Copyright 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build riscv64,!gccgo
+
+#include "textflag.h"
+
+//
+// System calls for linux/riscv64.
+//
+// Where available, just jump to package syscall's implementation of
+// these functions.
+
+TEXT ·Syscall(SB),NOSPLIT,$0-56
+ JMP syscall·Syscall(SB)
+
+TEXT ·Syscall6(SB),NOSPLIT,$0-80
+ JMP syscall·Syscall6(SB)
+
+TEXT ·SyscallNoError(SB),NOSPLIT,$0-48
+ CALL runtime·entersyscall(SB)
+ MOV a1+8(FP), A0
+ MOV a2+16(FP), A1
+ MOV a3+24(FP), A2
+ MOV $0, A3
+ MOV $0, A4
+ MOV $0, A5
+ MOV $0, A6
+ MOV trap+0(FP), A7 // syscall entry
+ ECALL
+ MOV A0, r1+32(FP) // r1
+ MOV A1, r2+40(FP) // r2
+ CALL runtime·exitsyscall(SB)
+ RET
+
+TEXT ·RawSyscall(SB),NOSPLIT,$0-56
+ JMP syscall·RawSyscall(SB)
+
+TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
+ JMP syscall·RawSyscall6(SB)
+
+TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-48
+ MOV a1+8(FP), A0
+ MOV a2+16(FP), A1
+ MOV a3+24(FP), A2
+ MOV ZERO, A3
+ MOV ZERO, A4
+ MOV ZERO, A5
+ MOV trap+0(FP), A7 // syscall entry
+ ECALL
+ MOV A0, r1+32(FP)
+ MOV A1, r2+40(FP)
+ RET
diff --git a/vendor/golang.org/x/sys/unix/asm_linux_s390x.s b/vendor/golang.org/x/sys/unix/asm_linux_s390x.s
new file mode 100644
index 0000000..a5a863c
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/asm_linux_s390x.s
@@ -0,0 +1,56 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build s390x
+// +build linux
+// +build !gccgo
+
+#include "textflag.h"
+
+//
+// System calls for s390x, Linux
+//
+
+// Just jump to package syscall's implementation for all these functions.
+// The runtime may know about them.
+
+TEXT ·Syscall(SB),NOSPLIT,$0-56
+ BR syscall·Syscall(SB)
+
+TEXT ·Syscall6(SB),NOSPLIT,$0-80
+ BR syscall·Syscall6(SB)
+
+TEXT ·SyscallNoError(SB),NOSPLIT,$0-48
+ BL runtime·entersyscall(SB)
+ MOVD a1+8(FP), R2
+ MOVD a2+16(FP), R3
+ MOVD a3+24(FP), R4
+ MOVD $0, R5
+ MOVD $0, R6
+ MOVD $0, R7
+ MOVD trap+0(FP), R1 // syscall entry
+ SYSCALL
+ MOVD R2, r1+32(FP)
+ MOVD R3, r2+40(FP)
+ BL runtime·exitsyscall(SB)
+ RET
+
+TEXT ·RawSyscall(SB),NOSPLIT,$0-56
+ BR syscall·RawSyscall(SB)
+
+TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
+ BR syscall·RawSyscall6(SB)
+
+TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-48
+ MOVD a1+8(FP), R2
+ MOVD a2+16(FP), R3
+ MOVD a3+24(FP), R4
+ MOVD $0, R5
+ MOVD $0, R6
+ MOVD $0, R7
+ MOVD trap+0(FP), R1 // syscall entry
+ SYSCALL
+ MOVD R2, r1+32(FP)
+ MOVD R3, r2+40(FP)
+ RET
diff --git a/vendor/golang.org/x/sys/unix/asm_netbsd_386.s b/vendor/golang.org/x/sys/unix/asm_netbsd_386.s
new file mode 100644
index 0000000..48bdcd7
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/asm_netbsd_386.s
@@ -0,0 +1,29 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !gccgo
+
+#include "textflag.h"
+
+//
+// System call support for 386, NetBSD
+//
+
+// Just jump to package syscall's implementation for all these functions.
+// The runtime may know about them.
+
+TEXT ·Syscall(SB),NOSPLIT,$0-28
+ JMP syscall·Syscall(SB)
+
+TEXT ·Syscall6(SB),NOSPLIT,$0-40
+ JMP syscall·Syscall6(SB)
+
+TEXT ·Syscall9(SB),NOSPLIT,$0-52
+ JMP syscall·Syscall9(SB)
+
+TEXT ·RawSyscall(SB),NOSPLIT,$0-28
+ JMP syscall·RawSyscall(SB)
+
+TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
+ JMP syscall·RawSyscall6(SB)
diff --git a/vendor/golang.org/x/sys/unix/asm_netbsd_amd64.s b/vendor/golang.org/x/sys/unix/asm_netbsd_amd64.s
new file mode 100644
index 0000000..2ede05c
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/asm_netbsd_amd64.s
@@ -0,0 +1,29 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !gccgo
+
+#include "textflag.h"
+
+//
+// System call support for AMD64, NetBSD
+//
+
+// Just jump to package syscall's implementation for all these functions.
+// The runtime may know about them.
+
+TEXT ·Syscall(SB),NOSPLIT,$0-56
+ JMP syscall·Syscall(SB)
+
+TEXT ·Syscall6(SB),NOSPLIT,$0-80
+ JMP syscall·Syscall6(SB)
+
+TEXT ·Syscall9(SB),NOSPLIT,$0-104
+ JMP syscall·Syscall9(SB)
+
+TEXT ·RawSyscall(SB),NOSPLIT,$0-56
+ JMP syscall·RawSyscall(SB)
+
+TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
+ JMP syscall·RawSyscall6(SB)
diff --git a/vendor/golang.org/x/sys/unix/asm_netbsd_arm.s b/vendor/golang.org/x/sys/unix/asm_netbsd_arm.s
new file mode 100644
index 0000000..e892857
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/asm_netbsd_arm.s
@@ -0,0 +1,29 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !gccgo
+
+#include "textflag.h"
+
+//
+// System call support for ARM, NetBSD
+//
+
+// Just jump to package syscall's implementation for all these functions.
+// The runtime may know about them.
+
+TEXT ·Syscall(SB),NOSPLIT,$0-28
+ B syscall·Syscall(SB)
+
+TEXT ·Syscall6(SB),NOSPLIT,$0-40
+ B syscall·Syscall6(SB)
+
+TEXT ·Syscall9(SB),NOSPLIT,$0-52
+ B syscall·Syscall9(SB)
+
+TEXT ·RawSyscall(SB),NOSPLIT,$0-28
+ B syscall·RawSyscall(SB)
+
+TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
+ B syscall·RawSyscall6(SB)
diff --git a/vendor/golang.org/x/sys/unix/asm_netbsd_arm64.s b/vendor/golang.org/x/sys/unix/asm_netbsd_arm64.s
new file mode 100644
index 0000000..6f98ba5
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/asm_netbsd_arm64.s
@@ -0,0 +1,29 @@
+// Copyright 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !gccgo
+
+#include "textflag.h"
+
+//
+// System call support for ARM64, NetBSD
+//
+
+// Just jump to package syscall's implementation for all these functions.
+// The runtime may know about them.
+
+TEXT ·Syscall(SB),NOSPLIT,$0-56
+ B syscall·Syscall(SB)
+
+TEXT ·Syscall6(SB),NOSPLIT,$0-80
+ B syscall·Syscall6(SB)
+
+TEXT ·Syscall9(SB),NOSPLIT,$0-104
+ B syscall·Syscall9(SB)
+
+TEXT ·RawSyscall(SB),NOSPLIT,$0-56
+ B syscall·RawSyscall(SB)
+
+TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
+ B syscall·RawSyscall6(SB)
diff --git a/vendor/golang.org/x/sys/unix/asm_openbsd_386.s b/vendor/golang.org/x/sys/unix/asm_openbsd_386.s
new file mode 100644
index 0000000..00576f3
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/asm_openbsd_386.s
@@ -0,0 +1,29 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !gccgo
+
+#include "textflag.h"
+
+//
+// System call support for 386, OpenBSD
+//
+
+// Just jump to package syscall's implementation for all these functions.
+// The runtime may know about them.
+
+TEXT ·Syscall(SB),NOSPLIT,$0-28
+ JMP syscall·Syscall(SB)
+
+TEXT ·Syscall6(SB),NOSPLIT,$0-40
+ JMP syscall·Syscall6(SB)
+
+TEXT ·Syscall9(SB),NOSPLIT,$0-52
+ JMP syscall·Syscall9(SB)
+
+TEXT ·RawSyscall(SB),NOSPLIT,$0-28
+ JMP syscall·RawSyscall(SB)
+
+TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
+ JMP syscall·RawSyscall6(SB)
diff --git a/vendor/golang.org/x/sys/unix/asm_openbsd_amd64.s b/vendor/golang.org/x/sys/unix/asm_openbsd_amd64.s
new file mode 100644
index 0000000..790ef77
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/asm_openbsd_amd64.s
@@ -0,0 +1,29 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !gccgo
+
+#include "textflag.h"
+
+//
+// System call support for AMD64, OpenBSD
+//
+
+// Just jump to package syscall's implementation for all these functions.
+// The runtime may know about them.
+
+TEXT ·Syscall(SB),NOSPLIT,$0-56
+ JMP syscall·Syscall(SB)
+
+TEXT ·Syscall6(SB),NOSPLIT,$0-80
+ JMP syscall·Syscall6(SB)
+
+TEXT ·Syscall9(SB),NOSPLIT,$0-104
+ JMP syscall·Syscall9(SB)
+
+TEXT ·RawSyscall(SB),NOSPLIT,$0-56
+ JMP syscall·RawSyscall(SB)
+
+TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
+ JMP syscall·RawSyscall6(SB)
diff --git a/vendor/golang.org/x/sys/unix/asm_openbsd_arm.s b/vendor/golang.org/x/sys/unix/asm_openbsd_arm.s
new file mode 100644
index 0000000..469bfa1
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/asm_openbsd_arm.s
@@ -0,0 +1,29 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !gccgo
+
+#include "textflag.h"
+
+//
+// System call support for ARM, OpenBSD
+//
+
+// Just jump to package syscall's implementation for all these functions.
+// The runtime may know about them.
+
+TEXT ·Syscall(SB),NOSPLIT,$0-28
+ B syscall·Syscall(SB)
+
+TEXT ·Syscall6(SB),NOSPLIT,$0-40
+ B syscall·Syscall6(SB)
+
+TEXT ·Syscall9(SB),NOSPLIT,$0-52
+ B syscall·Syscall9(SB)
+
+TEXT ·RawSyscall(SB),NOSPLIT,$0-28
+ B syscall·RawSyscall(SB)
+
+TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
+ B syscall·RawSyscall6(SB)
diff --git a/vendor/golang.org/x/sys/unix/asm_openbsd_arm64.s b/vendor/golang.org/x/sys/unix/asm_openbsd_arm64.s
new file mode 100644
index 0000000..0cedea3
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/asm_openbsd_arm64.s
@@ -0,0 +1,29 @@
+// Copyright 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !gccgo
+
+#include "textflag.h"
+
+//
+// System call support for arm64, OpenBSD
+//
+
+// Just jump to package syscall's implementation for all these functions.
+// The runtime may know about them.
+
+TEXT ·Syscall(SB),NOSPLIT,$0-56
+ JMP syscall·Syscall(SB)
+
+TEXT ·Syscall6(SB),NOSPLIT,$0-80
+ JMP syscall·Syscall6(SB)
+
+TEXT ·Syscall9(SB),NOSPLIT,$0-104
+ JMP syscall·Syscall9(SB)
+
+TEXT ·RawSyscall(SB),NOSPLIT,$0-56
+ JMP syscall·RawSyscall(SB)
+
+TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
+ JMP syscall·RawSyscall6(SB)
diff --git a/vendor/golang.org/x/sys/unix/asm_solaris_amd64.s b/vendor/golang.org/x/sys/unix/asm_solaris_amd64.s
new file mode 100644
index 0000000..ded8260
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/asm_solaris_amd64.s
@@ -0,0 +1,17 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !gccgo
+
+#include "textflag.h"
+
+//
+// System calls for amd64, Solaris are implemented in runtime/syscall_solaris.go
+//
+
+TEXT ·sysvicall6(SB),NOSPLIT,$0-88
+ JMP syscall·sysvicall6(SB)
+
+TEXT ·rawSysvicall6(SB),NOSPLIT,$0-88
+ JMP syscall·rawSysvicall6(SB)
diff --git a/vendor/golang.org/x/sys/unix/bluetooth_linux.go b/vendor/golang.org/x/sys/unix/bluetooth_linux.go
new file mode 100644
index 0000000..6e32296
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/bluetooth_linux.go
@@ -0,0 +1,35 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Bluetooth sockets and messages
+
+package unix
+
+// Bluetooth Protocols
+const (
+ BTPROTO_L2CAP = 0
+ BTPROTO_HCI = 1
+ BTPROTO_SCO = 2
+ BTPROTO_RFCOMM = 3
+ BTPROTO_BNEP = 4
+ BTPROTO_CMTP = 5
+ BTPROTO_HIDP = 6
+ BTPROTO_AVDTP = 7
+)
+
+const (
+ HCI_CHANNEL_RAW = 0
+ HCI_CHANNEL_USER = 1
+ HCI_CHANNEL_MONITOR = 2
+ HCI_CHANNEL_CONTROL = 3
+)
+
+// Socketoption Level
+const (
+ SOL_BLUETOOTH = 0x112
+ SOL_HCI = 0x0
+ SOL_L2CAP = 0x6
+ SOL_RFCOMM = 0x12
+ SOL_SCO = 0x11
+)
diff --git a/vendor/golang.org/x/sys/unix/cap_freebsd.go b/vendor/golang.org/x/sys/unix/cap_freebsd.go
new file mode 100644
index 0000000..df52048
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/cap_freebsd.go
@@ -0,0 +1,195 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build freebsd
+
+package unix
+
+import (
+ "errors"
+ "fmt"
+)
+
+// Go implementation of C mostly found in /usr/src/sys/kern/subr_capability.c
+
+const (
+ // This is the version of CapRights this package understands. See C implementation for parallels.
+ capRightsGoVersion = CAP_RIGHTS_VERSION_00
+ capArSizeMin = CAP_RIGHTS_VERSION_00 + 2
+ capArSizeMax = capRightsGoVersion + 2
+)
+
+var (
+ bit2idx = []int{
+ -1, 0, 1, -1, 2, -1, -1, -1, 3, -1, -1, -1, -1, -1, -1, -1,
+ 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ }
+)
+
+func capidxbit(right uint64) int {
+ return int((right >> 57) & 0x1f)
+}
+
+func rightToIndex(right uint64) (int, error) {
+ idx := capidxbit(right)
+ if idx < 0 || idx >= len(bit2idx) {
+ return -2, fmt.Errorf("index for right 0x%x out of range", right)
+ }
+ return bit2idx[idx], nil
+}
+
+func caprver(right uint64) int {
+ return int(right >> 62)
+}
+
+func capver(rights *CapRights) int {
+ return caprver(rights.Rights[0])
+}
+
+func caparsize(rights *CapRights) int {
+ return capver(rights) + 2
+}
+
+// CapRightsSet sets the permissions in setrights in rights.
+func CapRightsSet(rights *CapRights, setrights []uint64) error {
+ // This is essentially a copy of cap_rights_vset()
+ if capver(rights) != CAP_RIGHTS_VERSION_00 {
+ return fmt.Errorf("bad rights version %d", capver(rights))
+ }
+
+ n := caparsize(rights)
+ if n < capArSizeMin || n > capArSizeMax {
+ return errors.New("bad rights size")
+ }
+
+ for _, right := range setrights {
+ if caprver(right) != CAP_RIGHTS_VERSION_00 {
+ return errors.New("bad right version")
+ }
+ i, err := rightToIndex(right)
+ if err != nil {
+ return err
+ }
+ if i >= n {
+ return errors.New("index overflow")
+ }
+ if capidxbit(rights.Rights[i]) != capidxbit(right) {
+ return errors.New("index mismatch")
+ }
+ rights.Rights[i] |= right
+ if capidxbit(rights.Rights[i]) != capidxbit(right) {
+ return errors.New("index mismatch (after assign)")
+ }
+ }
+
+ return nil
+}
+
+// CapRightsClear clears the permissions in clearrights from rights.
+func CapRightsClear(rights *CapRights, clearrights []uint64) error {
+ // This is essentially a copy of cap_rights_vclear()
+ if capver(rights) != CAP_RIGHTS_VERSION_00 {
+ return fmt.Errorf("bad rights version %d", capver(rights))
+ }
+
+ n := caparsize(rights)
+ if n < capArSizeMin || n > capArSizeMax {
+ return errors.New("bad rights size")
+ }
+
+ for _, right := range clearrights {
+ if caprver(right) != CAP_RIGHTS_VERSION_00 {
+ return errors.New("bad right version")
+ }
+ i, err := rightToIndex(right)
+ if err != nil {
+ return err
+ }
+ if i >= n {
+ return errors.New("index overflow")
+ }
+ if capidxbit(rights.Rights[i]) != capidxbit(right) {
+ return errors.New("index mismatch")
+ }
+ rights.Rights[i] &= ^(right & 0x01FFFFFFFFFFFFFF)
+ if capidxbit(rights.Rights[i]) != capidxbit(right) {
+ return errors.New("index mismatch (after assign)")
+ }
+ }
+
+ return nil
+}
+
+// CapRightsIsSet checks whether all the permissions in setrights are present in rights.
+func CapRightsIsSet(rights *CapRights, setrights []uint64) (bool, error) {
+ // This is essentially a copy of cap_rights_is_vset()
+ if capver(rights) != CAP_RIGHTS_VERSION_00 {
+ return false, fmt.Errorf("bad rights version %d", capver(rights))
+ }
+
+ n := caparsize(rights)
+ if n < capArSizeMin || n > capArSizeMax {
+ return false, errors.New("bad rights size")
+ }
+
+ for _, right := range setrights {
+ if caprver(right) != CAP_RIGHTS_VERSION_00 {
+ return false, errors.New("bad right version")
+ }
+ i, err := rightToIndex(right)
+ if err != nil {
+ return false, err
+ }
+ if i >= n {
+ return false, errors.New("index overflow")
+ }
+ if capidxbit(rights.Rights[i]) != capidxbit(right) {
+ return false, errors.New("index mismatch")
+ }
+ if (rights.Rights[i] & right) != right {
+ return false, nil
+ }
+ }
+
+ return true, nil
+}
+
+func capright(idx uint64, bit uint64) uint64 {
+ return ((1 << (57 + idx)) | bit)
+}
+
+// CapRightsInit returns a pointer to an initialised CapRights structure filled with rights.
+// See man cap_rights_init(3) and rights(4).
+func CapRightsInit(rights []uint64) (*CapRights, error) {
+ var r CapRights
+ r.Rights[0] = (capRightsGoVersion << 62) | capright(0, 0)
+ r.Rights[1] = capright(1, 0)
+
+ err := CapRightsSet(&r, rights)
+ if err != nil {
+ return nil, err
+ }
+ return &r, nil
+}
+
+// CapRightsLimit reduces the operations permitted on fd to at most those contained in rights.
+// The capability rights on fd can never be increased by CapRightsLimit.
+// See man cap_rights_limit(2) and rights(4).
+func CapRightsLimit(fd uintptr, rights *CapRights) error {
+ return capRightsLimit(int(fd), rights)
+}
+
+// CapRightsGet returns a CapRights structure containing the operations permitted on fd.
+// See man cap_rights_get(3) and rights(4).
+func CapRightsGet(fd uintptr) (*CapRights, error) {
+ r, err := CapRightsInit(nil)
+ if err != nil {
+ return nil, err
+ }
+ err = capRightsGet(capRightsGoVersion, int(fd), r)
+ if err != nil {
+ return nil, err
+ }
+ return r, nil
+}
diff --git a/vendor/golang.org/x/sys/unix/constants.go b/vendor/golang.org/x/sys/unix/constants.go
new file mode 100644
index 0000000..3a6ac64
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/constants.go
@@ -0,0 +1,13 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
+
+package unix
+
+const (
+ R_OK = 0x4
+ W_OK = 0x2
+ X_OK = 0x1
+)
diff --git a/vendor/golang.org/x/sys/unix/dev_aix_ppc.go b/vendor/golang.org/x/sys/unix/dev_aix_ppc.go
new file mode 100644
index 0000000..5e5fb45
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/dev_aix_ppc.go
@@ -0,0 +1,27 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build aix
+// +build ppc
+
+// Functions to access/create device major and minor numbers matching the
+// encoding used by AIX.
+
+package unix
+
+// Major returns the major component of a Linux device number.
+func Major(dev uint64) uint32 {
+ return uint32((dev >> 16) & 0xffff)
+}
+
+// Minor returns the minor component of a Linux device number.
+func Minor(dev uint64) uint32 {
+ return uint32(dev & 0xffff)
+}
+
+// Mkdev returns a Linux device number generated from the given major and minor
+// components.
+func Mkdev(major, minor uint32) uint64 {
+ return uint64(((major) << 16) | (minor))
+}
diff --git a/vendor/golang.org/x/sys/unix/dev_aix_ppc64.go b/vendor/golang.org/x/sys/unix/dev_aix_ppc64.go
new file mode 100644
index 0000000..8b40124
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/dev_aix_ppc64.go
@@ -0,0 +1,29 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build aix
+// +build ppc64
+
+// Functions to access/create device major and minor numbers matching the
+// encoding used AIX.
+
+package unix
+
+// Major returns the major component of a Linux device number.
+func Major(dev uint64) uint32 {
+ return uint32((dev & 0x3fffffff00000000) >> 32)
+}
+
+// Minor returns the minor component of a Linux device number.
+func Minor(dev uint64) uint32 {
+ return uint32((dev & 0x00000000ffffffff) >> 0)
+}
+
+// Mkdev returns a Linux device number generated from the given major and minor
+// components.
+func Mkdev(major, minor uint32) uint64 {
+ var DEVNO64 uint64
+ DEVNO64 = 0x8000000000000000
+ return ((uint64(major) << 32) | (uint64(minor) & 0x00000000FFFFFFFF) | DEVNO64)
+}
diff --git a/vendor/golang.org/x/sys/unix/dev_darwin.go b/vendor/golang.org/x/sys/unix/dev_darwin.go
new file mode 100644
index 0000000..8d1dc0f
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/dev_darwin.go
@@ -0,0 +1,24 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Functions to access/create device major and minor numbers matching the
+// encoding used in Darwin's sys/types.h header.
+
+package unix
+
+// Major returns the major component of a Darwin device number.
+func Major(dev uint64) uint32 {
+ return uint32((dev >> 24) & 0xff)
+}
+
+// Minor returns the minor component of a Darwin device number.
+func Minor(dev uint64) uint32 {
+ return uint32(dev & 0xffffff)
+}
+
+// Mkdev returns a Darwin device number generated from the given major and minor
+// components.
+func Mkdev(major, minor uint32) uint64 {
+ return (uint64(major) << 24) | uint64(minor)
+}
diff --git a/vendor/golang.org/x/sys/unix/dev_dragonfly.go b/vendor/golang.org/x/sys/unix/dev_dragonfly.go
new file mode 100644
index 0000000..8502f20
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/dev_dragonfly.go
@@ -0,0 +1,30 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Functions to access/create device major and minor numbers matching the
+// encoding used in Dragonfly's sys/types.h header.
+//
+// The information below is extracted and adapted from sys/types.h:
+//
+// Minor gives a cookie instead of an index since in order to avoid changing the
+// meanings of bits 0-15 or wasting time and space shifting bits 16-31 for
+// devices that don't use them.
+
+package unix
+
+// Major returns the major component of a DragonFlyBSD device number.
+func Major(dev uint64) uint32 {
+ return uint32((dev >> 8) & 0xff)
+}
+
+// Minor returns the minor component of a DragonFlyBSD device number.
+func Minor(dev uint64) uint32 {
+ return uint32(dev & 0xffff00ff)
+}
+
+// Mkdev returns a DragonFlyBSD device number generated from the given major and
+// minor components.
+func Mkdev(major, minor uint32) uint64 {
+ return (uint64(major) << 8) | uint64(minor)
+}
diff --git a/vendor/golang.org/x/sys/unix/dev_freebsd.go b/vendor/golang.org/x/sys/unix/dev_freebsd.go
new file mode 100644
index 0000000..eba3b4b
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/dev_freebsd.go
@@ -0,0 +1,30 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Functions to access/create device major and minor numbers matching the
+// encoding used in FreeBSD's sys/types.h header.
+//
+// The information below is extracted and adapted from sys/types.h:
+//
+// Minor gives a cookie instead of an index since in order to avoid changing the
+// meanings of bits 0-15 or wasting time and space shifting bits 16-31 for
+// devices that don't use them.
+
+package unix
+
+// Major returns the major component of a FreeBSD device number.
+func Major(dev uint64) uint32 {
+ return uint32((dev >> 8) & 0xff)
+}
+
+// Minor returns the minor component of a FreeBSD device number.
+func Minor(dev uint64) uint32 {
+ return uint32(dev & 0xffff00ff)
+}
+
+// Mkdev returns a FreeBSD device number generated from the given major and
+// minor components.
+func Mkdev(major, minor uint32) uint64 {
+ return (uint64(major) << 8) | uint64(minor)
+}
diff --git a/vendor/golang.org/x/sys/unix/dev_linux.go b/vendor/golang.org/x/sys/unix/dev_linux.go
new file mode 100644
index 0000000..d165d6f
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/dev_linux.go
@@ -0,0 +1,42 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Functions to access/create device major and minor numbers matching the
+// encoding used by the Linux kernel and glibc.
+//
+// The information below is extracted and adapted from bits/sysmacros.h in the
+// glibc sources:
+//
+// dev_t in glibc is 64-bit, with 32-bit major and minor numbers. glibc's
+// default encoding is MMMM Mmmm mmmM MMmm, where M is a hex digit of the major
+// number and m is a hex digit of the minor number. This is backward compatible
+// with legacy systems where dev_t is 16 bits wide, encoded as MMmm. It is also
+// backward compatible with the Linux kernel, which for some architectures uses
+// 32-bit dev_t, encoded as mmmM MMmm.
+
+package unix
+
+// Major returns the major component of a Linux device number.
+func Major(dev uint64) uint32 {
+ major := uint32((dev & 0x00000000000fff00) >> 8)
+ major |= uint32((dev & 0xfffff00000000000) >> 32)
+ return major
+}
+
+// Minor returns the minor component of a Linux device number.
+func Minor(dev uint64) uint32 {
+ minor := uint32((dev & 0x00000000000000ff) >> 0)
+ minor |= uint32((dev & 0x00000ffffff00000) >> 12)
+ return minor
+}
+
+// Mkdev returns a Linux device number generated from the given major and minor
+// components.
+func Mkdev(major, minor uint32) uint64 {
+ dev := (uint64(major) & 0x00000fff) << 8
+ dev |= (uint64(major) & 0xfffff000) << 32
+ dev |= (uint64(minor) & 0x000000ff) << 0
+ dev |= (uint64(minor) & 0xffffff00) << 12
+ return dev
+}
diff --git a/vendor/golang.org/x/sys/unix/dev_netbsd.go b/vendor/golang.org/x/sys/unix/dev_netbsd.go
new file mode 100644
index 0000000..b4a203d
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/dev_netbsd.go
@@ -0,0 +1,29 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Functions to access/create device major and minor numbers matching the
+// encoding used in NetBSD's sys/types.h header.
+
+package unix
+
+// Major returns the major component of a NetBSD device number.
+func Major(dev uint64) uint32 {
+ return uint32((dev & 0x000fff00) >> 8)
+}
+
+// Minor returns the minor component of a NetBSD device number.
+func Minor(dev uint64) uint32 {
+ minor := uint32((dev & 0x000000ff) >> 0)
+ minor |= uint32((dev & 0xfff00000) >> 12)
+ return minor
+}
+
+// Mkdev returns a NetBSD device number generated from the given major and minor
+// components.
+func Mkdev(major, minor uint32) uint64 {
+ dev := (uint64(major) << 8) & 0x000fff00
+ dev |= (uint64(minor) << 12) & 0xfff00000
+ dev |= (uint64(minor) << 0) & 0x000000ff
+ return dev
+}
diff --git a/vendor/golang.org/x/sys/unix/dev_openbsd.go b/vendor/golang.org/x/sys/unix/dev_openbsd.go
new file mode 100644
index 0000000..f3430c4
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/dev_openbsd.go
@@ -0,0 +1,29 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Functions to access/create device major and minor numbers matching the
+// encoding used in OpenBSD's sys/types.h header.
+
+package unix
+
+// Major returns the major component of an OpenBSD device number.
+func Major(dev uint64) uint32 {
+ return uint32((dev & 0x0000ff00) >> 8)
+}
+
+// Minor returns the minor component of an OpenBSD device number.
+func Minor(dev uint64) uint32 {
+ minor := uint32((dev & 0x000000ff) >> 0)
+ minor |= uint32((dev & 0xffff0000) >> 8)
+ return minor
+}
+
+// Mkdev returns an OpenBSD device number generated from the given major and minor
+// components.
+func Mkdev(major, minor uint32) uint64 {
+ dev := (uint64(major) << 8) & 0x0000ff00
+ dev |= (uint64(minor) << 8) & 0xffff0000
+ dev |= (uint64(minor) << 0) & 0x000000ff
+ return dev
+}
diff --git a/vendor/golang.org/x/sys/unix/dirent.go b/vendor/golang.org/x/sys/unix/dirent.go
new file mode 100644
index 0000000..304016b
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/dirent.go
@@ -0,0 +1,102 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
+
+package unix
+
+import "unsafe"
+
+// readInt returns the size-bytes unsigned integer in native byte order at offset off.
+func readInt(b []byte, off, size uintptr) (u uint64, ok bool) {
+ if len(b) < int(off+size) {
+ return 0, false
+ }
+ if isBigEndian {
+ return readIntBE(b[off:], size), true
+ }
+ return readIntLE(b[off:], size), true
+}
+
+func readIntBE(b []byte, size uintptr) uint64 {
+ switch size {
+ case 1:
+ return uint64(b[0])
+ case 2:
+ _ = b[1] // bounds check hint to compiler; see golang.org/issue/14808
+ return uint64(b[1]) | uint64(b[0])<<8
+ case 4:
+ _ = b[3] // bounds check hint to compiler; see golang.org/issue/14808
+ return uint64(b[3]) | uint64(b[2])<<8 | uint64(b[1])<<16 | uint64(b[0])<<24
+ case 8:
+ _ = b[7] // bounds check hint to compiler; see golang.org/issue/14808
+ return uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 |
+ uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56
+ default:
+ panic("syscall: readInt with unsupported size")
+ }
+}
+
+func readIntLE(b []byte, size uintptr) uint64 {
+ switch size {
+ case 1:
+ return uint64(b[0])
+ case 2:
+ _ = b[1] // bounds check hint to compiler; see golang.org/issue/14808
+ return uint64(b[0]) | uint64(b[1])<<8
+ case 4:
+ _ = b[3] // bounds check hint to compiler; see golang.org/issue/14808
+ return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24
+ case 8:
+ _ = b[7] // bounds check hint to compiler; see golang.org/issue/14808
+ return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 |
+ uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56
+ default:
+ panic("syscall: readInt with unsupported size")
+ }
+}
+
+// ParseDirent parses up to max directory entries in buf,
+// appending the names to names. It returns the number of
+// bytes consumed from buf, the number of entries added
+// to names, and the new names slice.
+func ParseDirent(buf []byte, max int, names []string) (consumed int, count int, newnames []string) {
+ origlen := len(buf)
+ count = 0
+ for max != 0 && len(buf) > 0 {
+ reclen, ok := direntReclen(buf)
+ if !ok || reclen > uint64(len(buf)) {
+ return origlen, count, names
+ }
+ rec := buf[:reclen]
+ buf = buf[reclen:]
+ ino, ok := direntIno(rec)
+ if !ok {
+ break
+ }
+ if ino == 0 { // File absent in directory.
+ continue
+ }
+ const namoff = uint64(unsafe.Offsetof(Dirent{}.Name))
+ namlen, ok := direntNamlen(rec)
+ if !ok || namoff+namlen > uint64(len(rec)) {
+ break
+ }
+ name := rec[namoff : namoff+namlen]
+ for i, c := range name {
+ if c == 0 {
+ name = name[:i]
+ break
+ }
+ }
+ // Check for useless names before allocating a string.
+ if string(name) == "." || string(name) == ".." {
+ continue
+ }
+ max--
+ count++
+ names = append(names, string(name))
+ }
+ return origlen - len(buf), count, names
+}
diff --git a/vendor/golang.org/x/sys/unix/endian_big.go b/vendor/golang.org/x/sys/unix/endian_big.go
new file mode 100644
index 0000000..5e92690
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/endian_big.go
@@ -0,0 +1,9 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+//
+// +build ppc64 s390x mips mips64
+
+package unix
+
+const isBigEndian = true
diff --git a/vendor/golang.org/x/sys/unix/endian_little.go b/vendor/golang.org/x/sys/unix/endian_little.go
new file mode 100644
index 0000000..bcdb5d3
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/endian_little.go
@@ -0,0 +1,9 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+//
+// +build 386 amd64 amd64p32 arm arm64 ppc64le mipsle mips64le riscv64
+
+package unix
+
+const isBigEndian = false
diff --git a/vendor/golang.org/x/sys/unix/env_unix.go b/vendor/golang.org/x/sys/unix/env_unix.go
new file mode 100644
index 0000000..84178b0
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/env_unix.go
@@ -0,0 +1,31 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
+
+// Unix environment variables.
+
+package unix
+
+import "syscall"
+
+func Getenv(key string) (value string, found bool) {
+ return syscall.Getenv(key)
+}
+
+func Setenv(key, value string) error {
+ return syscall.Setenv(key, value)
+}
+
+func Clearenv() {
+ syscall.Clearenv()
+}
+
+func Environ() []string {
+ return syscall.Environ()
+}
+
+func Unsetenv(key string) error {
+ return syscall.Unsetenv(key)
+}
diff --git a/vendor/golang.org/x/sys/unix/errors_freebsd_386.go b/vendor/golang.org/x/sys/unix/errors_freebsd_386.go
new file mode 100644
index 0000000..c56bc8b
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/errors_freebsd_386.go
@@ -0,0 +1,227 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Constants that were deprecated or moved to enums in the FreeBSD headers. Keep
+// them here for backwards compatibility.
+
+package unix
+
+const (
+ IFF_SMART = 0x20
+ IFT_1822 = 0x2
+ IFT_A12MPPSWITCH = 0x82
+ IFT_AAL2 = 0xbb
+ IFT_AAL5 = 0x31
+ IFT_ADSL = 0x5e
+ IFT_AFLANE8023 = 0x3b
+ IFT_AFLANE8025 = 0x3c
+ IFT_ARAP = 0x58
+ IFT_ARCNET = 0x23
+ IFT_ARCNETPLUS = 0x24
+ IFT_ASYNC = 0x54
+ IFT_ATM = 0x25
+ IFT_ATMDXI = 0x69
+ IFT_ATMFUNI = 0x6a
+ IFT_ATMIMA = 0x6b
+ IFT_ATMLOGICAL = 0x50
+ IFT_ATMRADIO = 0xbd
+ IFT_ATMSUBINTERFACE = 0x86
+ IFT_ATMVCIENDPT = 0xc2
+ IFT_ATMVIRTUAL = 0x95
+ IFT_BGPPOLICYACCOUNTING = 0xa2
+ IFT_BSC = 0x53
+ IFT_CCTEMUL = 0x3d
+ IFT_CEPT = 0x13
+ IFT_CES = 0x85
+ IFT_CHANNEL = 0x46
+ IFT_CNR = 0x55
+ IFT_COFFEE = 0x84
+ IFT_COMPOSITELINK = 0x9b
+ IFT_DCN = 0x8d
+ IFT_DIGITALPOWERLINE = 0x8a
+ IFT_DIGITALWRAPPEROVERHEADCHANNEL = 0xba
+ IFT_DLSW = 0x4a
+ IFT_DOCSCABLEDOWNSTREAM = 0x80
+ IFT_DOCSCABLEMACLAYER = 0x7f
+ IFT_DOCSCABLEUPSTREAM = 0x81
+ IFT_DS0 = 0x51
+ IFT_DS0BUNDLE = 0x52
+ IFT_DS1FDL = 0xaa
+ IFT_DS3 = 0x1e
+ IFT_DTM = 0x8c
+ IFT_DVBASILN = 0xac
+ IFT_DVBASIOUT = 0xad
+ IFT_DVBRCCDOWNSTREAM = 0x93
+ IFT_DVBRCCMACLAYER = 0x92
+ IFT_DVBRCCUPSTREAM = 0x94
+ IFT_ENC = 0xf4
+ IFT_EON = 0x19
+ IFT_EPLRS = 0x57
+ IFT_ESCON = 0x49
+ IFT_ETHER = 0x6
+ IFT_FAITH = 0xf2
+ IFT_FAST = 0x7d
+ IFT_FASTETHER = 0x3e
+ IFT_FASTETHERFX = 0x45
+ IFT_FDDI = 0xf
+ IFT_FIBRECHANNEL = 0x38
+ IFT_FRAMERELAYINTERCONNECT = 0x3a
+ IFT_FRAMERELAYMPI = 0x5c
+ IFT_FRDLCIENDPT = 0xc1
+ IFT_FRELAY = 0x20
+ IFT_FRELAYDCE = 0x2c
+ IFT_FRF16MFRBUNDLE = 0xa3
+ IFT_FRFORWARD = 0x9e
+ IFT_G703AT2MB = 0x43
+ IFT_G703AT64K = 0x42
+ IFT_GIF = 0xf0
+ IFT_GIGABITETHERNET = 0x75
+ IFT_GR303IDT = 0xb2
+ IFT_GR303RDT = 0xb1
+ IFT_H323GATEKEEPER = 0xa4
+ IFT_H323PROXY = 0xa5
+ IFT_HDH1822 = 0x3
+ IFT_HDLC = 0x76
+ IFT_HDSL2 = 0xa8
+ IFT_HIPERLAN2 = 0xb7
+ IFT_HIPPI = 0x2f
+ IFT_HIPPIINTERFACE = 0x39
+ IFT_HOSTPAD = 0x5a
+ IFT_HSSI = 0x2e
+ IFT_HY = 0xe
+ IFT_IBM370PARCHAN = 0x48
+ IFT_IDSL = 0x9a
+ IFT_IEEE80211 = 0x47
+ IFT_IEEE80212 = 0x37
+ IFT_IEEE8023ADLAG = 0xa1
+ IFT_IFGSN = 0x91
+ IFT_IMT = 0xbe
+ IFT_INTERLEAVE = 0x7c
+ IFT_IP = 0x7e
+ IFT_IPFORWARD = 0x8e
+ IFT_IPOVERATM = 0x72
+ IFT_IPOVERCDLC = 0x6d
+ IFT_IPOVERCLAW = 0x6e
+ IFT_IPSWITCH = 0x4e
+ IFT_IPXIP = 0xf9
+ IFT_ISDN = 0x3f
+ IFT_ISDNBASIC = 0x14
+ IFT_ISDNPRIMARY = 0x15
+ IFT_ISDNS = 0x4b
+ IFT_ISDNU = 0x4c
+ IFT_ISO88022LLC = 0x29
+ IFT_ISO88023 = 0x7
+ IFT_ISO88024 = 0x8
+ IFT_ISO88025 = 0x9
+ IFT_ISO88025CRFPINT = 0x62
+ IFT_ISO88025DTR = 0x56
+ IFT_ISO88025FIBER = 0x73
+ IFT_ISO88026 = 0xa
+ IFT_ISUP = 0xb3
+ IFT_L3IPXVLAN = 0x89
+ IFT_LAPB = 0x10
+ IFT_LAPD = 0x4d
+ IFT_LAPF = 0x77
+ IFT_LOCALTALK = 0x2a
+ IFT_LOOP = 0x18
+ IFT_MEDIAMAILOVERIP = 0x8b
+ IFT_MFSIGLINK = 0xa7
+ IFT_MIOX25 = 0x26
+ IFT_MODEM = 0x30
+ IFT_MPC = 0x71
+ IFT_MPLS = 0xa6
+ IFT_MPLSTUNNEL = 0x96
+ IFT_MSDSL = 0x8f
+ IFT_MVL = 0xbf
+ IFT_MYRINET = 0x63
+ IFT_NFAS = 0xaf
+ IFT_NSIP = 0x1b
+ IFT_OPTICALCHANNEL = 0xc3
+ IFT_OPTICALTRANSPORT = 0xc4
+ IFT_OTHER = 0x1
+ IFT_P10 = 0xc
+ IFT_P80 = 0xd
+ IFT_PARA = 0x22
+ IFT_PFLOG = 0xf6
+ IFT_PFSYNC = 0xf7
+ IFT_PLC = 0xae
+ IFT_POS = 0xab
+ IFT_PPPMULTILINKBUNDLE = 0x6c
+ IFT_PROPBWAP2MP = 0xb8
+ IFT_PROPCNLS = 0x59
+ IFT_PROPDOCSWIRELESSDOWNSTREAM = 0xb5
+ IFT_PROPDOCSWIRELESSMACLAYER = 0xb4
+ IFT_PROPDOCSWIRELESSUPSTREAM = 0xb6
+ IFT_PROPMUX = 0x36
+ IFT_PROPWIRELESSP2P = 0x9d
+ IFT_PTPSERIAL = 0x16
+ IFT_PVC = 0xf1
+ IFT_QLLC = 0x44
+ IFT_RADIOMAC = 0xbc
+ IFT_RADSL = 0x5f
+ IFT_REACHDSL = 0xc0
+ IFT_RFC1483 = 0x9f
+ IFT_RS232 = 0x21
+ IFT_RSRB = 0x4f
+ IFT_SDLC = 0x11
+ IFT_SDSL = 0x60
+ IFT_SHDSL = 0xa9
+ IFT_SIP = 0x1f
+ IFT_SLIP = 0x1c
+ IFT_SMDSDXI = 0x2b
+ IFT_SMDSICIP = 0x34
+ IFT_SONET = 0x27
+ IFT_SONETOVERHEADCHANNEL = 0xb9
+ IFT_SONETPATH = 0x32
+ IFT_SONETVT = 0x33
+ IFT_SRP = 0x97
+ IFT_SS7SIGLINK = 0x9c
+ IFT_STACKTOSTACK = 0x6f
+ IFT_STARLAN = 0xb
+ IFT_STF = 0xd7
+ IFT_T1 = 0x12
+ IFT_TDLC = 0x74
+ IFT_TERMPAD = 0x5b
+ IFT_TR008 = 0xb0
+ IFT_TRANSPHDLC = 0x7b
+ IFT_TUNNEL = 0x83
+ IFT_ULTRA = 0x1d
+ IFT_USB = 0xa0
+ IFT_V11 = 0x40
+ IFT_V35 = 0x2d
+ IFT_V36 = 0x41
+ IFT_V37 = 0x78
+ IFT_VDSL = 0x61
+ IFT_VIRTUALIPADDRESS = 0x70
+ IFT_VOICEEM = 0x64
+ IFT_VOICEENCAP = 0x67
+ IFT_VOICEFXO = 0x65
+ IFT_VOICEFXS = 0x66
+ IFT_VOICEOVERATM = 0x98
+ IFT_VOICEOVERFRAMERELAY = 0x99
+ IFT_VOICEOVERIP = 0x68
+ IFT_X213 = 0x5d
+ IFT_X25 = 0x5
+ IFT_X25DDN = 0x4
+ IFT_X25HUNTGROUP = 0x7a
+ IFT_X25MLP = 0x79
+ IFT_X25PLE = 0x28
+ IFT_XETHER = 0x1a
+ IPPROTO_MAXID = 0x34
+ IPV6_FAITH = 0x1d
+ IP_FAITH = 0x16
+ MAP_NORESERVE = 0x40
+ MAP_RENAME = 0x20
+ NET_RT_MAXID = 0x6
+ RTF_PRCLONING = 0x10000
+ RTM_OLDADD = 0x9
+ RTM_OLDDEL = 0xa
+ SIOCADDRT = 0x8030720a
+ SIOCALIFADDR = 0x8118691b
+ SIOCDELRT = 0x8030720b
+ SIOCDLIFADDR = 0x8118691d
+ SIOCGLIFADDR = 0xc118691c
+ SIOCGLIFPHYADDR = 0xc118694b
+ SIOCSLIFPHYADDR = 0x8118694a
+)
diff --git a/vendor/golang.org/x/sys/unix/errors_freebsd_amd64.go b/vendor/golang.org/x/sys/unix/errors_freebsd_amd64.go
new file mode 100644
index 0000000..3e97711
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/errors_freebsd_amd64.go
@@ -0,0 +1,227 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Constants that were deprecated or moved to enums in the FreeBSD headers. Keep
+// them here for backwards compatibility.
+
+package unix
+
+const (
+ IFF_SMART = 0x20
+ IFT_1822 = 0x2
+ IFT_A12MPPSWITCH = 0x82
+ IFT_AAL2 = 0xbb
+ IFT_AAL5 = 0x31
+ IFT_ADSL = 0x5e
+ IFT_AFLANE8023 = 0x3b
+ IFT_AFLANE8025 = 0x3c
+ IFT_ARAP = 0x58
+ IFT_ARCNET = 0x23
+ IFT_ARCNETPLUS = 0x24
+ IFT_ASYNC = 0x54
+ IFT_ATM = 0x25
+ IFT_ATMDXI = 0x69
+ IFT_ATMFUNI = 0x6a
+ IFT_ATMIMA = 0x6b
+ IFT_ATMLOGICAL = 0x50
+ IFT_ATMRADIO = 0xbd
+ IFT_ATMSUBINTERFACE = 0x86
+ IFT_ATMVCIENDPT = 0xc2
+ IFT_ATMVIRTUAL = 0x95
+ IFT_BGPPOLICYACCOUNTING = 0xa2
+ IFT_BSC = 0x53
+ IFT_CCTEMUL = 0x3d
+ IFT_CEPT = 0x13
+ IFT_CES = 0x85
+ IFT_CHANNEL = 0x46
+ IFT_CNR = 0x55
+ IFT_COFFEE = 0x84
+ IFT_COMPOSITELINK = 0x9b
+ IFT_DCN = 0x8d
+ IFT_DIGITALPOWERLINE = 0x8a
+ IFT_DIGITALWRAPPEROVERHEADCHANNEL = 0xba
+ IFT_DLSW = 0x4a
+ IFT_DOCSCABLEDOWNSTREAM = 0x80
+ IFT_DOCSCABLEMACLAYER = 0x7f
+ IFT_DOCSCABLEUPSTREAM = 0x81
+ IFT_DS0 = 0x51
+ IFT_DS0BUNDLE = 0x52
+ IFT_DS1FDL = 0xaa
+ IFT_DS3 = 0x1e
+ IFT_DTM = 0x8c
+ IFT_DVBASILN = 0xac
+ IFT_DVBASIOUT = 0xad
+ IFT_DVBRCCDOWNSTREAM = 0x93
+ IFT_DVBRCCMACLAYER = 0x92
+ IFT_DVBRCCUPSTREAM = 0x94
+ IFT_ENC = 0xf4
+ IFT_EON = 0x19
+ IFT_EPLRS = 0x57
+ IFT_ESCON = 0x49
+ IFT_ETHER = 0x6
+ IFT_FAITH = 0xf2
+ IFT_FAST = 0x7d
+ IFT_FASTETHER = 0x3e
+ IFT_FASTETHERFX = 0x45
+ IFT_FDDI = 0xf
+ IFT_FIBRECHANNEL = 0x38
+ IFT_FRAMERELAYINTERCONNECT = 0x3a
+ IFT_FRAMERELAYMPI = 0x5c
+ IFT_FRDLCIENDPT = 0xc1
+ IFT_FRELAY = 0x20
+ IFT_FRELAYDCE = 0x2c
+ IFT_FRF16MFRBUNDLE = 0xa3
+ IFT_FRFORWARD = 0x9e
+ IFT_G703AT2MB = 0x43
+ IFT_G703AT64K = 0x42
+ IFT_GIF = 0xf0
+ IFT_GIGABITETHERNET = 0x75
+ IFT_GR303IDT = 0xb2
+ IFT_GR303RDT = 0xb1
+ IFT_H323GATEKEEPER = 0xa4
+ IFT_H323PROXY = 0xa5
+ IFT_HDH1822 = 0x3
+ IFT_HDLC = 0x76
+ IFT_HDSL2 = 0xa8
+ IFT_HIPERLAN2 = 0xb7
+ IFT_HIPPI = 0x2f
+ IFT_HIPPIINTERFACE = 0x39
+ IFT_HOSTPAD = 0x5a
+ IFT_HSSI = 0x2e
+ IFT_HY = 0xe
+ IFT_IBM370PARCHAN = 0x48
+ IFT_IDSL = 0x9a
+ IFT_IEEE80211 = 0x47
+ IFT_IEEE80212 = 0x37
+ IFT_IEEE8023ADLAG = 0xa1
+ IFT_IFGSN = 0x91
+ IFT_IMT = 0xbe
+ IFT_INTERLEAVE = 0x7c
+ IFT_IP = 0x7e
+ IFT_IPFORWARD = 0x8e
+ IFT_IPOVERATM = 0x72
+ IFT_IPOVERCDLC = 0x6d
+ IFT_IPOVERCLAW = 0x6e
+ IFT_IPSWITCH = 0x4e
+ IFT_IPXIP = 0xf9
+ IFT_ISDN = 0x3f
+ IFT_ISDNBASIC = 0x14
+ IFT_ISDNPRIMARY = 0x15
+ IFT_ISDNS = 0x4b
+ IFT_ISDNU = 0x4c
+ IFT_ISO88022LLC = 0x29
+ IFT_ISO88023 = 0x7
+ IFT_ISO88024 = 0x8
+ IFT_ISO88025 = 0x9
+ IFT_ISO88025CRFPINT = 0x62
+ IFT_ISO88025DTR = 0x56
+ IFT_ISO88025FIBER = 0x73
+ IFT_ISO88026 = 0xa
+ IFT_ISUP = 0xb3
+ IFT_L3IPXVLAN = 0x89
+ IFT_LAPB = 0x10
+ IFT_LAPD = 0x4d
+ IFT_LAPF = 0x77
+ IFT_LOCALTALK = 0x2a
+ IFT_LOOP = 0x18
+ IFT_MEDIAMAILOVERIP = 0x8b
+ IFT_MFSIGLINK = 0xa7
+ IFT_MIOX25 = 0x26
+ IFT_MODEM = 0x30
+ IFT_MPC = 0x71
+ IFT_MPLS = 0xa6
+ IFT_MPLSTUNNEL = 0x96
+ IFT_MSDSL = 0x8f
+ IFT_MVL = 0xbf
+ IFT_MYRINET = 0x63
+ IFT_NFAS = 0xaf
+ IFT_NSIP = 0x1b
+ IFT_OPTICALCHANNEL = 0xc3
+ IFT_OPTICALTRANSPORT = 0xc4
+ IFT_OTHER = 0x1
+ IFT_P10 = 0xc
+ IFT_P80 = 0xd
+ IFT_PARA = 0x22
+ IFT_PFLOG = 0xf6
+ IFT_PFSYNC = 0xf7
+ IFT_PLC = 0xae
+ IFT_POS = 0xab
+ IFT_PPPMULTILINKBUNDLE = 0x6c
+ IFT_PROPBWAP2MP = 0xb8
+ IFT_PROPCNLS = 0x59
+ IFT_PROPDOCSWIRELESSDOWNSTREAM = 0xb5
+ IFT_PROPDOCSWIRELESSMACLAYER = 0xb4
+ IFT_PROPDOCSWIRELESSUPSTREAM = 0xb6
+ IFT_PROPMUX = 0x36
+ IFT_PROPWIRELESSP2P = 0x9d
+ IFT_PTPSERIAL = 0x16
+ IFT_PVC = 0xf1
+ IFT_QLLC = 0x44
+ IFT_RADIOMAC = 0xbc
+ IFT_RADSL = 0x5f
+ IFT_REACHDSL = 0xc0
+ IFT_RFC1483 = 0x9f
+ IFT_RS232 = 0x21
+ IFT_RSRB = 0x4f
+ IFT_SDLC = 0x11
+ IFT_SDSL = 0x60
+ IFT_SHDSL = 0xa9
+ IFT_SIP = 0x1f
+ IFT_SLIP = 0x1c
+ IFT_SMDSDXI = 0x2b
+ IFT_SMDSICIP = 0x34
+ IFT_SONET = 0x27
+ IFT_SONETOVERHEADCHANNEL = 0xb9
+ IFT_SONETPATH = 0x32
+ IFT_SONETVT = 0x33
+ IFT_SRP = 0x97
+ IFT_SS7SIGLINK = 0x9c
+ IFT_STACKTOSTACK = 0x6f
+ IFT_STARLAN = 0xb
+ IFT_STF = 0xd7
+ IFT_T1 = 0x12
+ IFT_TDLC = 0x74
+ IFT_TERMPAD = 0x5b
+ IFT_TR008 = 0xb0
+ IFT_TRANSPHDLC = 0x7b
+ IFT_TUNNEL = 0x83
+ IFT_ULTRA = 0x1d
+ IFT_USB = 0xa0
+ IFT_V11 = 0x40
+ IFT_V35 = 0x2d
+ IFT_V36 = 0x41
+ IFT_V37 = 0x78
+ IFT_VDSL = 0x61
+ IFT_VIRTUALIPADDRESS = 0x70
+ IFT_VOICEEM = 0x64
+ IFT_VOICEENCAP = 0x67
+ IFT_VOICEFXO = 0x65
+ IFT_VOICEFXS = 0x66
+ IFT_VOICEOVERATM = 0x98
+ IFT_VOICEOVERFRAMERELAY = 0x99
+ IFT_VOICEOVERIP = 0x68
+ IFT_X213 = 0x5d
+ IFT_X25 = 0x5
+ IFT_X25DDN = 0x4
+ IFT_X25HUNTGROUP = 0x7a
+ IFT_X25MLP = 0x79
+ IFT_X25PLE = 0x28
+ IFT_XETHER = 0x1a
+ IPPROTO_MAXID = 0x34
+ IPV6_FAITH = 0x1d
+ IP_FAITH = 0x16
+ MAP_NORESERVE = 0x40
+ MAP_RENAME = 0x20
+ NET_RT_MAXID = 0x6
+ RTF_PRCLONING = 0x10000
+ RTM_OLDADD = 0x9
+ RTM_OLDDEL = 0xa
+ SIOCADDRT = 0x8040720a
+ SIOCALIFADDR = 0x8118691b
+ SIOCDELRT = 0x8040720b
+ SIOCDLIFADDR = 0x8118691d
+ SIOCGLIFADDR = 0xc118691c
+ SIOCGLIFPHYADDR = 0xc118694b
+ SIOCSLIFPHYADDR = 0x8118694a
+)
diff --git a/vendor/golang.org/x/sys/unix/errors_freebsd_arm.go b/vendor/golang.org/x/sys/unix/errors_freebsd_arm.go
new file mode 100644
index 0000000..856dca3
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/errors_freebsd_arm.go
@@ -0,0 +1,226 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package unix
+
+const (
+ IFT_1822 = 0x2
+ IFT_A12MPPSWITCH = 0x82
+ IFT_AAL2 = 0xbb
+ IFT_AAL5 = 0x31
+ IFT_ADSL = 0x5e
+ IFT_AFLANE8023 = 0x3b
+ IFT_AFLANE8025 = 0x3c
+ IFT_ARAP = 0x58
+ IFT_ARCNET = 0x23
+ IFT_ARCNETPLUS = 0x24
+ IFT_ASYNC = 0x54
+ IFT_ATM = 0x25
+ IFT_ATMDXI = 0x69
+ IFT_ATMFUNI = 0x6a
+ IFT_ATMIMA = 0x6b
+ IFT_ATMLOGICAL = 0x50
+ IFT_ATMRADIO = 0xbd
+ IFT_ATMSUBINTERFACE = 0x86
+ IFT_ATMVCIENDPT = 0xc2
+ IFT_ATMVIRTUAL = 0x95
+ IFT_BGPPOLICYACCOUNTING = 0xa2
+ IFT_BSC = 0x53
+ IFT_CCTEMUL = 0x3d
+ IFT_CEPT = 0x13
+ IFT_CES = 0x85
+ IFT_CHANNEL = 0x46
+ IFT_CNR = 0x55
+ IFT_COFFEE = 0x84
+ IFT_COMPOSITELINK = 0x9b
+ IFT_DCN = 0x8d
+ IFT_DIGITALPOWERLINE = 0x8a
+ IFT_DIGITALWRAPPEROVERHEADCHANNEL = 0xba
+ IFT_DLSW = 0x4a
+ IFT_DOCSCABLEDOWNSTREAM = 0x80
+ IFT_DOCSCABLEMACLAYER = 0x7f
+ IFT_DOCSCABLEUPSTREAM = 0x81
+ IFT_DS0 = 0x51
+ IFT_DS0BUNDLE = 0x52
+ IFT_DS1FDL = 0xaa
+ IFT_DS3 = 0x1e
+ IFT_DTM = 0x8c
+ IFT_DVBASILN = 0xac
+ IFT_DVBASIOUT = 0xad
+ IFT_DVBRCCDOWNSTREAM = 0x93
+ IFT_DVBRCCMACLAYER = 0x92
+ IFT_DVBRCCUPSTREAM = 0x94
+ IFT_ENC = 0xf4
+ IFT_EON = 0x19
+ IFT_EPLRS = 0x57
+ IFT_ESCON = 0x49
+ IFT_ETHER = 0x6
+ IFT_FAST = 0x7d
+ IFT_FASTETHER = 0x3e
+ IFT_FASTETHERFX = 0x45
+ IFT_FDDI = 0xf
+ IFT_FIBRECHANNEL = 0x38
+ IFT_FRAMERELAYINTERCONNECT = 0x3a
+ IFT_FRAMERELAYMPI = 0x5c
+ IFT_FRDLCIENDPT = 0xc1
+ IFT_FRELAY = 0x20
+ IFT_FRELAYDCE = 0x2c
+ IFT_FRF16MFRBUNDLE = 0xa3
+ IFT_FRFORWARD = 0x9e
+ IFT_G703AT2MB = 0x43
+ IFT_G703AT64K = 0x42
+ IFT_GIF = 0xf0
+ IFT_GIGABITETHERNET = 0x75
+ IFT_GR303IDT = 0xb2
+ IFT_GR303RDT = 0xb1
+ IFT_H323GATEKEEPER = 0xa4
+ IFT_H323PROXY = 0xa5
+ IFT_HDH1822 = 0x3
+ IFT_HDLC = 0x76
+ IFT_HDSL2 = 0xa8
+ IFT_HIPERLAN2 = 0xb7
+ IFT_HIPPI = 0x2f
+ IFT_HIPPIINTERFACE = 0x39
+ IFT_HOSTPAD = 0x5a
+ IFT_HSSI = 0x2e
+ IFT_HY = 0xe
+ IFT_IBM370PARCHAN = 0x48
+ IFT_IDSL = 0x9a
+ IFT_IEEE80211 = 0x47
+ IFT_IEEE80212 = 0x37
+ IFT_IEEE8023ADLAG = 0xa1
+ IFT_IFGSN = 0x91
+ IFT_IMT = 0xbe
+ IFT_INTERLEAVE = 0x7c
+ IFT_IP = 0x7e
+ IFT_IPFORWARD = 0x8e
+ IFT_IPOVERATM = 0x72
+ IFT_IPOVERCDLC = 0x6d
+ IFT_IPOVERCLAW = 0x6e
+ IFT_IPSWITCH = 0x4e
+ IFT_ISDN = 0x3f
+ IFT_ISDNBASIC = 0x14
+ IFT_ISDNPRIMARY = 0x15
+ IFT_ISDNS = 0x4b
+ IFT_ISDNU = 0x4c
+ IFT_ISO88022LLC = 0x29
+ IFT_ISO88023 = 0x7
+ IFT_ISO88024 = 0x8
+ IFT_ISO88025 = 0x9
+ IFT_ISO88025CRFPINT = 0x62
+ IFT_ISO88025DTR = 0x56
+ IFT_ISO88025FIBER = 0x73
+ IFT_ISO88026 = 0xa
+ IFT_ISUP = 0xb3
+ IFT_L3IPXVLAN = 0x89
+ IFT_LAPB = 0x10
+ IFT_LAPD = 0x4d
+ IFT_LAPF = 0x77
+ IFT_LOCALTALK = 0x2a
+ IFT_LOOP = 0x18
+ IFT_MEDIAMAILOVERIP = 0x8b
+ IFT_MFSIGLINK = 0xa7
+ IFT_MIOX25 = 0x26
+ IFT_MODEM = 0x30
+ IFT_MPC = 0x71
+ IFT_MPLS = 0xa6
+ IFT_MPLSTUNNEL = 0x96
+ IFT_MSDSL = 0x8f
+ IFT_MVL = 0xbf
+ IFT_MYRINET = 0x63
+ IFT_NFAS = 0xaf
+ IFT_NSIP = 0x1b
+ IFT_OPTICALCHANNEL = 0xc3
+ IFT_OPTICALTRANSPORT = 0xc4
+ IFT_OTHER = 0x1
+ IFT_P10 = 0xc
+ IFT_P80 = 0xd
+ IFT_PARA = 0x22
+ IFT_PFLOG = 0xf6
+ IFT_PFSYNC = 0xf7
+ IFT_PLC = 0xae
+ IFT_POS = 0xab
+ IFT_PPPMULTILINKBUNDLE = 0x6c
+ IFT_PROPBWAP2MP = 0xb8
+ IFT_PROPCNLS = 0x59
+ IFT_PROPDOCSWIRELESSDOWNSTREAM = 0xb5
+ IFT_PROPDOCSWIRELESSMACLAYER = 0xb4
+ IFT_PROPDOCSWIRELESSUPSTREAM = 0xb6
+ IFT_PROPMUX = 0x36
+ IFT_PROPWIRELESSP2P = 0x9d
+ IFT_PTPSERIAL = 0x16
+ IFT_PVC = 0xf1
+ IFT_QLLC = 0x44
+ IFT_RADIOMAC = 0xbc
+ IFT_RADSL = 0x5f
+ IFT_REACHDSL = 0xc0
+ IFT_RFC1483 = 0x9f
+ IFT_RS232 = 0x21
+ IFT_RSRB = 0x4f
+ IFT_SDLC = 0x11
+ IFT_SDSL = 0x60
+ IFT_SHDSL = 0xa9
+ IFT_SIP = 0x1f
+ IFT_SLIP = 0x1c
+ IFT_SMDSDXI = 0x2b
+ IFT_SMDSICIP = 0x34
+ IFT_SONET = 0x27
+ IFT_SONETOVERHEADCHANNEL = 0xb9
+ IFT_SONETPATH = 0x32
+ IFT_SONETVT = 0x33
+ IFT_SRP = 0x97
+ IFT_SS7SIGLINK = 0x9c
+ IFT_STACKTOSTACK = 0x6f
+ IFT_STARLAN = 0xb
+ IFT_STF = 0xd7
+ IFT_T1 = 0x12
+ IFT_TDLC = 0x74
+ IFT_TERMPAD = 0x5b
+ IFT_TR008 = 0xb0
+ IFT_TRANSPHDLC = 0x7b
+ IFT_TUNNEL = 0x83
+ IFT_ULTRA = 0x1d
+ IFT_USB = 0xa0
+ IFT_V11 = 0x40
+ IFT_V35 = 0x2d
+ IFT_V36 = 0x41
+ IFT_V37 = 0x78
+ IFT_VDSL = 0x61
+ IFT_VIRTUALIPADDRESS = 0x70
+ IFT_VOICEEM = 0x64
+ IFT_VOICEENCAP = 0x67
+ IFT_VOICEFXO = 0x65
+ IFT_VOICEFXS = 0x66
+ IFT_VOICEOVERATM = 0x98
+ IFT_VOICEOVERFRAMERELAY = 0x99
+ IFT_VOICEOVERIP = 0x68
+ IFT_X213 = 0x5d
+ IFT_X25 = 0x5
+ IFT_X25DDN = 0x4
+ IFT_X25HUNTGROUP = 0x7a
+ IFT_X25MLP = 0x79
+ IFT_X25PLE = 0x28
+ IFT_XETHER = 0x1a
+
+ // missing constants on FreeBSD-11.1-RELEASE, copied from old values in ztypes_freebsd_arm.go
+ IFF_SMART = 0x20
+ IFT_FAITH = 0xf2
+ IFT_IPXIP = 0xf9
+ IPPROTO_MAXID = 0x34
+ IPV6_FAITH = 0x1d
+ IP_FAITH = 0x16
+ MAP_NORESERVE = 0x40
+ MAP_RENAME = 0x20
+ NET_RT_MAXID = 0x6
+ RTF_PRCLONING = 0x10000
+ RTM_OLDADD = 0x9
+ RTM_OLDDEL = 0xa
+ SIOCADDRT = 0x8030720a
+ SIOCALIFADDR = 0x8118691b
+ SIOCDELRT = 0x8030720b
+ SIOCDLIFADDR = 0x8118691d
+ SIOCGLIFADDR = 0xc118691c
+ SIOCGLIFPHYADDR = 0xc118694b
+ SIOCSLIFPHYADDR = 0x8118694a
+)
diff --git a/vendor/golang.org/x/sys/unix/fcntl.go b/vendor/golang.org/x/sys/unix/fcntl.go
new file mode 100644
index 0000000..39c03f1
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/fcntl.go
@@ -0,0 +1,32 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build dragonfly freebsd linux netbsd openbsd
+
+package unix
+
+import "unsafe"
+
+// fcntl64Syscall is usually SYS_FCNTL, but is overridden on 32-bit Linux
+// systems by flock_linux_32bit.go to be SYS_FCNTL64.
+var fcntl64Syscall uintptr = SYS_FCNTL
+
+// FcntlInt performs a fcntl syscall on fd with the provided command and argument.
+func FcntlInt(fd uintptr, cmd, arg int) (int, error) {
+ valptr, _, errno := Syscall(fcntl64Syscall, fd, uintptr(cmd), uintptr(arg))
+ var err error
+ if errno != 0 {
+ err = errno
+ }
+ return int(valptr), err
+}
+
+// FcntlFlock performs a fcntl syscall for the F_GETLK, F_SETLK or F_SETLKW command.
+func FcntlFlock(fd uintptr, cmd int, lk *Flock_t) error {
+ _, _, errno := Syscall(fcntl64Syscall, fd, uintptr(cmd), uintptr(unsafe.Pointer(lk)))
+ if errno == 0 {
+ return nil
+ }
+ return errno
+}
diff --git a/vendor/golang.org/x/sys/unix/fcntl_darwin.go b/vendor/golang.org/x/sys/unix/fcntl_darwin.go
new file mode 100644
index 0000000..5868a4a
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/fcntl_darwin.go
@@ -0,0 +1,18 @@
+// Copyright 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package unix
+
+import "unsafe"
+
+// FcntlInt performs a fcntl syscall on fd with the provided command and argument.
+func FcntlInt(fd uintptr, cmd, arg int) (int, error) {
+ return fcntl(int(fd), cmd, arg)
+}
+
+// FcntlFlock performs a fcntl syscall for the F_GETLK, F_SETLK or F_SETLKW command.
+func FcntlFlock(fd uintptr, cmd int, lk *Flock_t) error {
+ _, err := fcntl(int(fd), cmd, int(uintptr(unsafe.Pointer(lk))))
+ return err
+}
diff --git a/vendor/golang.org/x/sys/unix/fcntl_linux_32bit.go b/vendor/golang.org/x/sys/unix/fcntl_linux_32bit.go
new file mode 100644
index 0000000..fc0e50e
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/fcntl_linux_32bit.go
@@ -0,0 +1,13 @@
+// +build linux,386 linux,arm linux,mips linux,mipsle
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package unix
+
+func init() {
+ // On 32-bit Linux systems, the fcntl syscall that matches Go's
+ // Flock_t type is SYS_FCNTL64, not SYS_FCNTL.
+ fcntl64Syscall = SYS_FCNTL64
+}
diff --git a/vendor/golang.org/x/sys/unix/gccgo.go b/vendor/golang.org/x/sys/unix/gccgo.go
new file mode 100644
index 0000000..cd6f5a6
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/gccgo.go
@@ -0,0 +1,62 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build gccgo
+// +build !aix
+
+package unix
+
+import "syscall"
+
+// We can't use the gc-syntax .s files for gccgo. On the plus side
+// much of the functionality can be written directly in Go.
+
+//extern gccgoRealSyscallNoError
+func realSyscallNoError(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r uintptr)
+
+//extern gccgoRealSyscall
+func realSyscall(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r, errno uintptr)
+
+func SyscallNoError(trap, a1, a2, a3 uintptr) (r1, r2 uintptr) {
+ syscall.Entersyscall()
+ r := realSyscallNoError(trap, a1, a2, a3, 0, 0, 0, 0, 0, 0)
+ syscall.Exitsyscall()
+ return r, 0
+}
+
+func Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno) {
+ syscall.Entersyscall()
+ r, errno := realSyscall(trap, a1, a2, a3, 0, 0, 0, 0, 0, 0)
+ syscall.Exitsyscall()
+ return r, 0, syscall.Errno(errno)
+}
+
+func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err syscall.Errno) {
+ syscall.Entersyscall()
+ r, errno := realSyscall(trap, a1, a2, a3, a4, a5, a6, 0, 0, 0)
+ syscall.Exitsyscall()
+ return r, 0, syscall.Errno(errno)
+}
+
+func Syscall9(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err syscall.Errno) {
+ syscall.Entersyscall()
+ r, errno := realSyscall(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9)
+ syscall.Exitsyscall()
+ return r, 0, syscall.Errno(errno)
+}
+
+func RawSyscallNoError(trap, a1, a2, a3 uintptr) (r1, r2 uintptr) {
+ r := realSyscallNoError(trap, a1, a2, a3, 0, 0, 0, 0, 0, 0)
+ return r, 0
+}
+
+func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno) {
+ r, errno := realSyscall(trap, a1, a2, a3, 0, 0, 0, 0, 0, 0)
+ return r, 0, syscall.Errno(errno)
+}
+
+func RawSyscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err syscall.Errno) {
+ r, errno := realSyscall(trap, a1, a2, a3, a4, a5, a6, 0, 0, 0)
+ return r, 0, syscall.Errno(errno)
+}
diff --git a/vendor/golang.org/x/sys/unix/gccgo_c.c b/vendor/golang.org/x/sys/unix/gccgo_c.c
new file mode 100644
index 0000000..c44730c
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/gccgo_c.c
@@ -0,0 +1,39 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build gccgo
+// +build !aix
+
+#include
+#include
+#include
+
+#define _STRINGIFY2_(x) #x
+#define _STRINGIFY_(x) _STRINGIFY2_(x)
+#define GOSYM_PREFIX _STRINGIFY_(__USER_LABEL_PREFIX__)
+
+// Call syscall from C code because the gccgo support for calling from
+// Go to C does not support varargs functions.
+
+struct ret {
+ uintptr_t r;
+ uintptr_t err;
+};
+
+struct ret
+gccgoRealSyscall(uintptr_t trap, uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4, uintptr_t a5, uintptr_t a6, uintptr_t a7, uintptr_t a8, uintptr_t a9)
+{
+ struct ret r;
+
+ errno = 0;
+ r.r = syscall(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+ r.err = errno;
+ return r;
+}
+
+uintptr_t
+gccgoRealSyscallNoError(uintptr_t trap, uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4, uintptr_t a5, uintptr_t a6, uintptr_t a7, uintptr_t a8, uintptr_t a9)
+{
+ return syscall(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+}
diff --git a/vendor/golang.org/x/sys/unix/gccgo_linux_amd64.go b/vendor/golang.org/x/sys/unix/gccgo_linux_amd64.go
new file mode 100644
index 0000000..251a977
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/gccgo_linux_amd64.go
@@ -0,0 +1,20 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build gccgo,linux,amd64
+
+package unix
+
+import "syscall"
+
+//extern gettimeofday
+func realGettimeofday(*Timeval, *byte) int32
+
+func gettimeofday(tv *Timeval) (err syscall.Errno) {
+ r := realGettimeofday(tv, nil)
+ if r < 0 {
+ return syscall.GetErrno()
+ }
+ return 0
+}
diff --git a/vendor/golang.org/x/sys/unix/ioctl.go b/vendor/golang.org/x/sys/unix/ioctl.go
new file mode 100644
index 0000000..f121a8d
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/ioctl.go
@@ -0,0 +1,30 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
+
+package unix
+
+import "runtime"
+
+// IoctlSetWinsize performs an ioctl on fd with a *Winsize argument.
+//
+// To change fd's window size, the req argument should be TIOCSWINSZ.
+func IoctlSetWinsize(fd int, req uint, value *Winsize) error {
+ // TODO: if we get the chance, remove the req parameter and
+ // hardcode TIOCSWINSZ.
+ err := ioctlSetWinsize(fd, req, value)
+ runtime.KeepAlive(value)
+ return err
+}
+
+// IoctlSetTermios performs an ioctl on fd with a *Termios.
+//
+// The req value will usually be TCSETA or TIOCSETA.
+func IoctlSetTermios(fd int, req uint, value *Termios) error {
+ // TODO: if we get the chance, remove the req parameter.
+ err := ioctlSetTermios(fd, req, value)
+ runtime.KeepAlive(value)
+ return err
+}
diff --git a/vendor/golang.org/x/sys/unix/mkall.sh b/vendor/golang.org/x/sys/unix/mkall.sh
new file mode 100644
index 0000000..5a22eca
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/mkall.sh
@@ -0,0 +1,227 @@
+#!/usr/bin/env bash
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+# This script runs or (given -n) prints suggested commands to generate files for
+# the Architecture/OS specified by the GOARCH and GOOS environment variables.
+# See README.md for more information about how the build system works.
+
+GOOSARCH="${GOOS}_${GOARCH}"
+
+# defaults
+mksyscall="go run mksyscall.go"
+mkerrors="./mkerrors.sh"
+zerrors="zerrors_$GOOSARCH.go"
+mksysctl=""
+zsysctl="zsysctl_$GOOSARCH.go"
+mksysnum=
+mktypes=
+mkasm=
+run="sh"
+cmd=""
+
+case "$1" in
+-syscalls)
+ for i in zsyscall*go
+ do
+ # Run the command line that appears in the first line
+ # of the generated file to regenerate it.
+ sed 1q $i | sed 's;^// ;;' | sh > _$i && gofmt < _$i > $i
+ rm _$i
+ done
+ exit 0
+ ;;
+-n)
+ run="cat"
+ cmd="echo"
+ shift
+esac
+
+case "$#" in
+0)
+ ;;
+*)
+ echo 'usage: mkall.sh [-n]' 1>&2
+ exit 2
+esac
+
+if [[ "$GOOS" = "linux" ]]; then
+ # Use the Docker-based build system
+ # Files generated through docker (use $cmd so you can Ctl-C the build or run)
+ $cmd docker build --tag generate:$GOOS $GOOS
+ $cmd docker run --interactive --tty --volume $(dirname "$(readlink -f "$0")"):/build generate:$GOOS
+ exit
+fi
+
+GOOSARCH_in=syscall_$GOOSARCH.go
+case "$GOOSARCH" in
+_* | *_ | _)
+ echo 'undefined $GOOS_$GOARCH:' "$GOOSARCH" 1>&2
+ exit 1
+ ;;
+aix_ppc)
+ mkerrors="$mkerrors -maix32"
+ mksyscall="go run mksyscall_aix_ppc.go -aix"
+ mktypes="GOARCH=$GOARCH go tool cgo -godefs"
+ ;;
+aix_ppc64)
+ mkerrors="$mkerrors -maix64"
+ mksyscall="go run mksyscall_aix_ppc64.go -aix"
+ mktypes="GOARCH=$GOARCH go tool cgo -godefs"
+ ;;
+darwin_386)
+ mkerrors="$mkerrors -m32"
+ mksyscall="go run mksyscall.go -l32"
+ mksysnum="go run mksysnum.go $(xcrun --show-sdk-path --sdk macosx)/usr/include/sys/syscall.h"
+ mktypes="GOARCH=$GOARCH go tool cgo -godefs"
+ mkasm="go run mkasm_darwin.go"
+ ;;
+darwin_amd64)
+ mkerrors="$mkerrors -m64"
+ mksysnum="go run mksysnum.go $(xcrun --show-sdk-path --sdk macosx)/usr/include/sys/syscall.h"
+ mktypes="GOARCH=$GOARCH go tool cgo -godefs"
+ mkasm="go run mkasm_darwin.go"
+ ;;
+darwin_arm)
+ mkerrors="$mkerrors"
+ mksyscall="go run mksyscall.go -l32"
+ mksysnum="go run mksysnum.go $(xcrun --show-sdk-path --sdk iphoneos)/usr/include/sys/syscall.h"
+ mktypes="GOARCH=$GOARCH go tool cgo -godefs"
+ mkasm="go run mkasm_darwin.go"
+ ;;
+darwin_arm64)
+ mkerrors="$mkerrors -m64"
+ mksysnum="go run mksysnum.go $(xcrun --show-sdk-path --sdk iphoneos)/usr/include/sys/syscall.h"
+ mktypes="GOARCH=$GOARCH go tool cgo -godefs"
+ mkasm="go run mkasm_darwin.go"
+ ;;
+dragonfly_amd64)
+ mkerrors="$mkerrors -m64"
+ mksyscall="go run mksyscall.go -dragonfly"
+ mksysnum="go run mksysnum.go 'https://gitweb.dragonflybsd.org/dragonfly.git/blob_plain/HEAD:/sys/kern/syscalls.master'"
+ mktypes="GOARCH=$GOARCH go tool cgo -godefs"
+ ;;
+freebsd_386)
+ mkerrors="$mkerrors -m32"
+ mksyscall="go run mksyscall.go -l32"
+ mksysnum="go run mksysnum.go 'https://svn.freebsd.org/base/stable/11/sys/kern/syscalls.master'"
+ mktypes="GOARCH=$GOARCH go tool cgo -godefs"
+ ;;
+freebsd_amd64)
+ mkerrors="$mkerrors -m64"
+ mksysnum="go run mksysnum.go 'https://svn.freebsd.org/base/stable/11/sys/kern/syscalls.master'"
+ mktypes="GOARCH=$GOARCH go tool cgo -godefs"
+ ;;
+freebsd_arm)
+ mkerrors="$mkerrors"
+ mksyscall="go run mksyscall.go -l32 -arm"
+ mksysnum="go run mksysnum.go 'https://svn.freebsd.org/base/stable/11/sys/kern/syscalls.master'"
+ # Let the type of C char be signed for making the bare syscall
+ # API consistent across platforms.
+ mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char"
+ ;;
+freebsd_arm64)
+ mkerrors="$mkerrors -m64"
+ mksysnum="go run mksysnum.go 'https://svn.freebsd.org/base/stable/11/sys/kern/syscalls.master'"
+ mktypes="GOARCH=$GOARCH go tool cgo -godefs"
+ ;;
+netbsd_386)
+ mkerrors="$mkerrors -m32"
+ mksyscall="go run mksyscall.go -l32 -netbsd"
+ mksysnum="go run mksysnum.go 'http://cvsweb.netbsd.org/bsdweb.cgi/~checkout~/src/sys/kern/syscalls.master'"
+ mktypes="GOARCH=$GOARCH go tool cgo -godefs"
+ ;;
+netbsd_amd64)
+ mkerrors="$mkerrors -m64"
+ mksyscall="go run mksyscall.go -netbsd"
+ mksysnum="go run mksysnum.go 'http://cvsweb.netbsd.org/bsdweb.cgi/~checkout~/src/sys/kern/syscalls.master'"
+ mktypes="GOARCH=$GOARCH go tool cgo -godefs"
+ ;;
+netbsd_arm)
+ mkerrors="$mkerrors"
+ mksyscall="go run mksyscall.go -l32 -netbsd -arm"
+ mksysnum="go run mksysnum.go 'http://cvsweb.netbsd.org/bsdweb.cgi/~checkout~/src/sys/kern/syscalls.master'"
+ # Let the type of C char be signed for making the bare syscall
+ # API consistent across platforms.
+ mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char"
+ ;;
+netbsd_arm64)
+ mkerrors="$mkerrors -m64"
+ mksyscall="go run mksyscall.go -netbsd"
+ mksysnum="go run mksysnum.go 'http://cvsweb.netbsd.org/bsdweb.cgi/~checkout~/src/sys/kern/syscalls.master'"
+ mktypes="GOARCH=$GOARCH go tool cgo -godefs"
+ ;;
+openbsd_386)
+ mkerrors="$mkerrors -m32"
+ mksyscall="go run mksyscall.go -l32 -openbsd"
+ mksysctl="go run mksysctl_openbsd.go"
+ mksysnum="go run mksysnum.go 'https://cvsweb.openbsd.org/cgi-bin/cvsweb/~checkout~/src/sys/kern/syscalls.master'"
+ mktypes="GOARCH=$GOARCH go tool cgo -godefs"
+ ;;
+openbsd_amd64)
+ mkerrors="$mkerrors -m64"
+ mksyscall="go run mksyscall.go -openbsd"
+ mksysctl="go run mksysctl_openbsd.go"
+ mksysnum="go run mksysnum.go 'https://cvsweb.openbsd.org/cgi-bin/cvsweb/~checkout~/src/sys/kern/syscalls.master'"
+ mktypes="GOARCH=$GOARCH go tool cgo -godefs"
+ ;;
+openbsd_arm)
+ mkerrors="$mkerrors"
+ mksyscall="go run mksyscall.go -l32 -openbsd -arm"
+ mksysctl="go run mksysctl_openbsd.go"
+ mksysnum="go run mksysnum.go 'https://cvsweb.openbsd.org/cgi-bin/cvsweb/~checkout~/src/sys/kern/syscalls.master'"
+ # Let the type of C char be signed for making the bare syscall
+ # API consistent across platforms.
+ mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char"
+ ;;
+openbsd_arm64)
+ mkerrors="$mkerrors -m64"
+ mksyscall="go run mksyscall.go -openbsd"
+ mksysctl="go run mksysctl_openbsd.go"
+ mksysnum="go run mksysnum.go 'https://cvsweb.openbsd.org/cgi-bin/cvsweb/~checkout~/src/sys/kern/syscalls.master'"
+ # Let the type of C char be signed for making the bare syscall
+ # API consistent across platforms.
+ mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char"
+ ;;
+solaris_amd64)
+ mksyscall="go run mksyscall_solaris.go"
+ mkerrors="$mkerrors -m64"
+ mksysnum=
+ mktypes="GOARCH=$GOARCH go tool cgo -godefs"
+ ;;
+*)
+ echo 'unrecognized $GOOS_$GOARCH: ' "$GOOSARCH" 1>&2
+ exit 1
+ ;;
+esac
+
+(
+ if [ -n "$mkerrors" ]; then echo "$mkerrors |gofmt >$zerrors"; fi
+ case "$GOOS" in
+ *)
+ syscall_goos="syscall_$GOOS.go"
+ case "$GOOS" in
+ darwin | dragonfly | freebsd | netbsd | openbsd)
+ syscall_goos="syscall_bsd.go $syscall_goos"
+ ;;
+ esac
+ if [ -n "$mksyscall" ]; then
+ if [ "$GOOSARCH" == "aix_ppc64" ]; then
+ # aix/ppc64 script generates files instead of writing to stdin.
+ echo "$mksyscall -tags $GOOS,$GOARCH $syscall_goos $GOOSARCH_in && gofmt -w zsyscall_$GOOSARCH.go && gofmt -w zsyscall_"$GOOSARCH"_gccgo.go && gofmt -w zsyscall_"$GOOSARCH"_gc.go " ;
+ elif [ "$GOOS" == "darwin" ]; then
+ # pre-1.12, direct syscalls
+ echo "$mksyscall -tags $GOOS,$GOARCH,!go1.12 $syscall_goos $GOOSARCH_in |gofmt >zsyscall_$GOOSARCH.1_11.go";
+ # 1.12 and later, syscalls via libSystem
+ echo "$mksyscall -tags $GOOS,$GOARCH,go1.12 $syscall_goos $GOOSARCH_in |gofmt >zsyscall_$GOOSARCH.go";
+ else
+ echo "$mksyscall -tags $GOOS,$GOARCH $syscall_goos $GOOSARCH_in |gofmt >zsyscall_$GOOSARCH.go";
+ fi
+ fi
+ esac
+ if [ -n "$mksysctl" ]; then echo "$mksysctl |gofmt >$zsysctl"; fi
+ if [ -n "$mksysnum" ]; then echo "$mksysnum |gofmt >zsysnum_$GOOSARCH.go"; fi
+ if [ -n "$mktypes" ]; then echo "$mktypes types_$GOOS.go | go run mkpost.go > ztypes_$GOOSARCH.go"; fi
+ if [ -n "$mkasm" ]; then echo "$mkasm $GOARCH"; fi
+) | $run
diff --git a/vendor/golang.org/x/sys/unix/mkerrors.sh b/vendor/golang.org/x/sys/unix/mkerrors.sh
new file mode 100644
index 0000000..14624b9
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/mkerrors.sh
@@ -0,0 +1,666 @@
+#!/usr/bin/env bash
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+# Generate Go code listing errors and other #defined constant
+# values (ENAMETOOLONG etc.), by asking the preprocessor
+# about the definitions.
+
+unset LANG
+export LC_ALL=C
+export LC_CTYPE=C
+
+if test -z "$GOARCH" -o -z "$GOOS"; then
+ echo 1>&2 "GOARCH or GOOS not defined in environment"
+ exit 1
+fi
+
+# Check that we are using the new build system if we should
+if [[ "$GOOS" = "linux" ]] && [[ "$GOLANG_SYS_BUILD" != "docker" ]]; then
+ echo 1>&2 "In the Docker based build system, mkerrors should not be called directly."
+ echo 1>&2 "See README.md"
+ exit 1
+fi
+
+if [[ "$GOOS" = "aix" ]]; then
+ CC=${CC:-gcc}
+else
+ CC=${CC:-cc}
+fi
+
+if [[ "$GOOS" = "solaris" ]]; then
+ # Assumes GNU versions of utilities in PATH.
+ export PATH=/usr/gnu/bin:$PATH
+fi
+
+uname=$(uname)
+
+includes_AIX='
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#define AF_LOCAL AF_UNIX
+'
+
+includes_Darwin='
+#define _DARWIN_C_SOURCE
+#define KERNEL
+#define _DARWIN_USE_64_BIT_INODE
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+'
+
+includes_DragonFly='
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+'
+
+includes_FreeBSD='
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#if __FreeBSD__ >= 10
+#define IFT_CARP 0xf8 // IFT_CARP is deprecated in FreeBSD 10
+#undef SIOCAIFADDR
+#define SIOCAIFADDR _IOW(105, 26, struct oifaliasreq) // ifaliasreq contains if_data
+#undef SIOCSIFPHYADDR
+#define SIOCSIFPHYADDR _IOW(105, 70, struct oifaliasreq) // ifaliasreq contains if_data
+#endif
+'
+
+includes_Linux='
+#define _LARGEFILE_SOURCE
+#define _LARGEFILE64_SOURCE
+#ifndef __LP64__
+#define _FILE_OFFSET_BITS 64
+#endif
+#define _GNU_SOURCE
+
+// is broken on powerpc64, as it fails to include definitions of
+// these structures. We just include them copied from