gcloud: use public DNS zones (#852)
This commit is contained in:
parent
f400ec5163
commit
ca7664d856
225 changed files with 47549 additions and 517 deletions
108
Gopkg.lock
generated
108
Gopkg.lock
generated
|
@ -232,9 +232,15 @@
|
||||||
version = "v1.8.0"
|
version = "v1.8.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:97df918963298c287643883209a2c3f642e6593379f97ab400c2a2e219ab647d"
|
digest = "1:63ccdfbd20f7ccd2399d0647a7d100b122f79c13bb83da9660b1598396fd9f62"
|
||||||
name = "github.com/golang/protobuf"
|
name = "github.com/golang/protobuf"
|
||||||
packages = ["proto"]
|
packages = [
|
||||||
|
"proto",
|
||||||
|
"ptypes",
|
||||||
|
"ptypes/any",
|
||||||
|
"ptypes/duration",
|
||||||
|
"ptypes/timestamp",
|
||||||
|
]
|
||||||
pruneopts = "NUT"
|
pruneopts = "NUT"
|
||||||
revision = "aa810b61a9c79d51363740d207bb46cf8e620ed5"
|
revision = "aa810b61a9c79d51363740d207bb46cf8e620ed5"
|
||||||
version = "v1.2.0"
|
version = "v1.2.0"
|
||||||
|
@ -273,6 +279,14 @@
|
||||||
pruneopts = "NUT"
|
pruneopts = "NUT"
|
||||||
revision = "a2b0ad6ce68c8302027db1a5f9dbb03b0c8ab072"
|
revision = "a2b0ad6ce68c8302027db1a5f9dbb03b0c8ab072"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
digest = "1:67474f760e9ac3799f740db2c489e6423a4cde45520673ec123ac831ad849cb8"
|
||||||
|
name = "github.com/hashicorp/golang-lru"
|
||||||
|
packages = ["simplelru"]
|
||||||
|
pruneopts = "NUT"
|
||||||
|
revision = "7087cb70de9f7a8bc0a10c375cb0d2280a8edf9c"
|
||||||
|
version = "v0.5.1"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
digest = "1:c45e4f1755487478216e06437e161d56299d963282ce109555091bc4c7a57343"
|
digest = "1:c45e4f1755487478216e06437e161d56299d963282ce109555091bc4c7a57343"
|
||||||
|
@ -512,6 +526,31 @@
|
||||||
revision = "cfb38830724cc34fedffe9a2a29fb54fa9169cd1"
|
revision = "cfb38830724cc34fedffe9a2a29fb54fa9169cd1"
|
||||||
version = "v1.20.0"
|
version = "v1.20.0"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
digest = "1:045bc0ab96bb83bdffd2606f019003da03d1c139d3cb8aad13596863e4dd37d6"
|
||||||
|
name = "go.opencensus.io"
|
||||||
|
packages = [
|
||||||
|
".",
|
||||||
|
"internal",
|
||||||
|
"internal/tagencoding",
|
||||||
|
"metric/metricdata",
|
||||||
|
"metric/metricproducer",
|
||||||
|
"plugin/ochttp",
|
||||||
|
"plugin/ochttp/propagation/b3",
|
||||||
|
"resource",
|
||||||
|
"stats",
|
||||||
|
"stats/internal",
|
||||||
|
"stats/view",
|
||||||
|
"tag",
|
||||||
|
"trace",
|
||||||
|
"trace/internal",
|
||||||
|
"trace/propagation",
|
||||||
|
"trace/tracestate",
|
||||||
|
]
|
||||||
|
pruneopts = "NUT"
|
||||||
|
revision = "8930459677fde1e11e3e1b50bbed1acc850b5665"
|
||||||
|
version = "v0.20.1"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
digest = "1:af471e1efb6318085c2c27ba0bcbf659feab5f7044388c0c0104f456831eb281"
|
digest = "1:af471e1efb6318085c2c27ba0bcbf659feab5f7044388c0c0104f456831eb281"
|
||||||
|
@ -530,18 +569,23 @@
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
digest = "1:14308e6b384fe18ce04d886e6a6d5d3fb3f532ec599c40cf00750e3519d845f1"
|
digest = "1:34f748d79542b732d2e4fab7cc0aad8500673e716e2a665cc72836942377fac9"
|
||||||
name = "golang.org/x/net"
|
name = "golang.org/x/net"
|
||||||
packages = [
|
packages = [
|
||||||
"bpf",
|
"bpf",
|
||||||
"context",
|
"context",
|
||||||
"context/ctxhttp",
|
"context/ctxhttp",
|
||||||
|
"http/httpguts",
|
||||||
|
"http2",
|
||||||
|
"http2/hpack",
|
||||||
"idna",
|
"idna",
|
||||||
"internal/iana",
|
"internal/iana",
|
||||||
"internal/socket",
|
"internal/socket",
|
||||||
|
"internal/timeseries",
|
||||||
"ipv4",
|
"ipv4",
|
||||||
"ipv6",
|
"ipv6",
|
||||||
"publicsuffix",
|
"publicsuffix",
|
||||||
|
"trace",
|
||||||
]
|
]
|
||||||
pruneopts = "NUT"
|
pruneopts = "NUT"
|
||||||
revision = "8a410e7b638dca158bf9e766925842f6651ff828"
|
revision = "8a410e7b638dca158bf9e766925842f6651ff828"
|
||||||
|
@ -605,16 +649,21 @@
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
digest = "1:90f61cd4297f7f4ce75f142744673ecdafd9023668cd24730f14033f265e394a"
|
digest = "1:887c07769ee52c81222ea1112b11a3947c703da529d1643d85c216b9537d87b8"
|
||||||
name = "google.golang.org/api"
|
name = "google.golang.org/api"
|
||||||
packages = [
|
packages = [
|
||||||
"dns/v1",
|
"dns/v1",
|
||||||
"gensupport",
|
"gensupport",
|
||||||
"googleapi",
|
"googleapi",
|
||||||
"googleapi/internal/uritemplates",
|
"googleapi/internal/uritemplates",
|
||||||
|
"googleapi/transport",
|
||||||
|
"internal",
|
||||||
|
"option",
|
||||||
|
"transport/http",
|
||||||
|
"transport/http/internal/propagation",
|
||||||
]
|
]
|
||||||
pruneopts = "NUT"
|
pruneopts = "NUT"
|
||||||
revision = "087779f1d2c96357d4c45bd04c4d10d7b5f22736"
|
revision = "0cbcb99a9ea0c8023c794b2693cbe1def82ed4d7"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:b5aeceb800276be69165a745328380c8a4b6f2edc7a6bac112e22c8596ed8a49"
|
digest = "1:b5aeceb800276be69165a745328380c8a4b6f2edc7a6bac112e22c8596ed8a49"
|
||||||
|
@ -635,6 +684,54 @@
|
||||||
revision = "b1f26356af11148e710935ed1ac8a7f5702c7612"
|
revision = "b1f26356af11148e710935ed1ac8a7f5702c7612"
|
||||||
version = "v1.1.0"
|
version = "v1.1.0"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
branch = "master"
|
||||||
|
digest = "1:c3076e7defee87de1236f1814beb588f40a75544c60121e6eb38b3b3721783e2"
|
||||||
|
name = "google.golang.org/genproto"
|
||||||
|
packages = ["googleapis/rpc/status"]
|
||||||
|
pruneopts = "NUT"
|
||||||
|
revision = "64821d5d210748c883cd2b809589555ae4654203"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
digest = "1:f9fe1989f8278a0976fadf27490720c7708c056a11ab7a7ad3d282ff26f28e9a"
|
||||||
|
name = "google.golang.org/grpc"
|
||||||
|
packages = [
|
||||||
|
".",
|
||||||
|
"balancer",
|
||||||
|
"balancer/base",
|
||||||
|
"balancer/roundrobin",
|
||||||
|
"binarylog/grpc_binarylog_v1",
|
||||||
|
"codes",
|
||||||
|
"connectivity",
|
||||||
|
"credentials",
|
||||||
|
"credentials/internal",
|
||||||
|
"encoding",
|
||||||
|
"encoding/proto",
|
||||||
|
"grpclog",
|
||||||
|
"internal",
|
||||||
|
"internal/backoff",
|
||||||
|
"internal/binarylog",
|
||||||
|
"internal/channelz",
|
||||||
|
"internal/envconfig",
|
||||||
|
"internal/grpcrand",
|
||||||
|
"internal/grpcsync",
|
||||||
|
"internal/syscall",
|
||||||
|
"internal/transport",
|
||||||
|
"keepalive",
|
||||||
|
"metadata",
|
||||||
|
"naming",
|
||||||
|
"peer",
|
||||||
|
"resolver",
|
||||||
|
"resolver/dns",
|
||||||
|
"resolver/passthrough",
|
||||||
|
"stats",
|
||||||
|
"status",
|
||||||
|
"tap",
|
||||||
|
]
|
||||||
|
pruneopts = "NUT"
|
||||||
|
revision = "3507fb8e1a5ad030303c106fef3a47c9fdad16ad"
|
||||||
|
version = "v1.19.1"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:74d9b0a7b4107b41e0ade759fac64502876f82d29fb23d77b3dd24b194ee3dd5"
|
digest = "1:74d9b0a7b4107b41e0ade759fac64502876f82d29fb23d77b3dd24b194ee3dd5"
|
||||||
name = "gopkg.in/ini.v1"
|
name = "gopkg.in/ini.v1"
|
||||||
|
@ -737,6 +834,7 @@
|
||||||
"golang.org/x/oauth2/google",
|
"golang.org/x/oauth2/google",
|
||||||
"google.golang.org/api/dns/v1",
|
"google.golang.org/api/dns/v1",
|
||||||
"google.golang.org/api/googleapi",
|
"google.golang.org/api/googleapi",
|
||||||
|
"google.golang.org/api/option",
|
||||||
"gopkg.in/ns1/ns1-go.v2/rest",
|
"gopkg.in/ns1/ns1-go.v2/rest",
|
||||||
"gopkg.in/ns1/ns1-go.v2/rest/model/dns",
|
"gopkg.in/ns1/ns1-go.v2/rest/model/dns",
|
||||||
"gopkg.in/square/go-jose.v2",
|
"gopkg.in/square/go-jose.v2",
|
||||||
|
|
|
@ -18,6 +18,7 @@ import (
|
||||||
"golang.org/x/oauth2/google"
|
"golang.org/x/oauth2/google"
|
||||||
"google.golang.org/api/dns/v1"
|
"google.golang.org/api/dns/v1"
|
||||||
"google.golang.org/api/googleapi"
|
"google.golang.org/api/googleapi"
|
||||||
|
"google.golang.org/api/option"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -139,8 +140,11 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
|
||||||
if config == nil {
|
if config == nil {
|
||||||
return nil, errors.New("googlecloud: the configuration of the DNS provider is nil")
|
return nil, errors.New("googlecloud: the configuration of the DNS provider is nil")
|
||||||
}
|
}
|
||||||
|
if config.HTTPClient == nil {
|
||||||
|
return nil, fmt.Errorf("googlecloud: unable to create Google Cloud DNS service: client is nil")
|
||||||
|
}
|
||||||
|
|
||||||
svc, err := dns.New(config.HTTPClient)
|
svc, err := dns.NewService(context.Background(), option.WithHTTPClient(config.HTTPClient))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("googlecloud: unable to create Google Cloud DNS service: %v", err)
|
return nil, fmt.Errorf("googlecloud: unable to create Google Cloud DNS service: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -306,7 +310,13 @@ func (d *DNSProvider) getHostedZone(domain string) (string, error) {
|
||||||
return "", fmt.Errorf("no matching domain found for domain %s", authZone)
|
return "", fmt.Errorf("no matching domain found for domain %s", authZone)
|
||||||
}
|
}
|
||||||
|
|
||||||
return zones.ManagedZones[0].Name, nil
|
for _, z := range zones.ManagedZones {
|
||||||
|
if z.Visibility == "public" {
|
||||||
|
return z.Name, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return "", fmt.Errorf("no public zone found for domain %s", authZone)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DNSProvider) findTxtRecords(zone, fqdn string) ([]*dns.ResourceRecordSet, error) {
|
func (d *DNSProvider) findTxtRecords(zone, fqdn string) ([]*dns.ResourceRecordSet, error) {
|
||||||
|
|
|
@ -139,7 +139,7 @@ func TestPresentNoExistingRR(t *testing.T) {
|
||||||
|
|
||||||
mzlrs := &dns.ManagedZonesListResponse{
|
mzlrs := &dns.ManagedZonesListResponse{
|
||||||
ManagedZones: []*dns.ManagedZone{
|
ManagedZones: []*dns.ManagedZone{
|
||||||
{Name: "test"},
|
{Name: "test", Visibility: "public"},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -219,7 +219,7 @@ func TestPresentWithExistingRR(t *testing.T) {
|
||||||
|
|
||||||
mzlrs := &dns.ManagedZonesListResponse{
|
mzlrs := &dns.ManagedZonesListResponse{
|
||||||
ManagedZones: []*dns.ManagedZone{
|
ManagedZones: []*dns.ManagedZone{
|
||||||
{Name: "test"},
|
{Name: "test", Visibility: "public"},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -319,7 +319,7 @@ func TestPresentSkipExistingRR(t *testing.T) {
|
||||||
|
|
||||||
mzlrs := &dns.ManagedZonesListResponse{
|
mzlrs := &dns.ManagedZonesListResponse{
|
||||||
ManagedZones: []*dns.ManagedZone{
|
ManagedZones: []*dns.ManagedZone{
|
||||||
{Name: "test"},
|
{Name: "test", Visibility: "public"},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
141
vendor/github.com/golang/protobuf/ptypes/any.go
generated
vendored
Normal file
141
vendor/github.com/golang/protobuf/ptypes/any.go
generated
vendored
Normal file
|
@ -0,0 +1,141 @@
|
||||||
|
// Go support for Protocol Buffers - Google's data interchange format
|
||||||
|
//
|
||||||
|
// Copyright 2016 The Go Authors. All rights reserved.
|
||||||
|
// https://github.com/golang/protobuf
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
package ptypes
|
||||||
|
|
||||||
|
// This file implements functions to marshal proto.Message to/from
|
||||||
|
// google.protobuf.Any message.
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/golang/protobuf/proto"
|
||||||
|
"github.com/golang/protobuf/ptypes/any"
|
||||||
|
)
|
||||||
|
|
||||||
|
const googleApis = "type.googleapis.com/"
|
||||||
|
|
||||||
|
// AnyMessageName returns the name of the message contained in a google.protobuf.Any message.
|
||||||
|
//
|
||||||
|
// Note that regular type assertions should be done using the Is
|
||||||
|
// function. AnyMessageName is provided for less common use cases like filtering a
|
||||||
|
// sequence of Any messages based on a set of allowed message type names.
|
||||||
|
func AnyMessageName(any *any.Any) (string, error) {
|
||||||
|
if any == nil {
|
||||||
|
return "", fmt.Errorf("message is nil")
|
||||||
|
}
|
||||||
|
slash := strings.LastIndex(any.TypeUrl, "/")
|
||||||
|
if slash < 0 {
|
||||||
|
return "", fmt.Errorf("message type url %q is invalid", any.TypeUrl)
|
||||||
|
}
|
||||||
|
return any.TypeUrl[slash+1:], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalAny takes the protocol buffer and encodes it into google.protobuf.Any.
|
||||||
|
func MarshalAny(pb proto.Message) (*any.Any, error) {
|
||||||
|
value, err := proto.Marshal(pb)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &any.Any{TypeUrl: googleApis + proto.MessageName(pb), Value: value}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DynamicAny is a value that can be passed to UnmarshalAny to automatically
|
||||||
|
// allocate a proto.Message for the type specified in a google.protobuf.Any
|
||||||
|
// message. The allocated message is stored in the embedded proto.Message.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// var x ptypes.DynamicAny
|
||||||
|
// if err := ptypes.UnmarshalAny(a, &x); err != nil { ... }
|
||||||
|
// fmt.Printf("unmarshaled message: %v", x.Message)
|
||||||
|
type DynamicAny struct {
|
||||||
|
proto.Message
|
||||||
|
}
|
||||||
|
|
||||||
|
// Empty returns a new proto.Message of the type specified in a
|
||||||
|
// google.protobuf.Any message. It returns an error if corresponding message
|
||||||
|
// type isn't linked in.
|
||||||
|
func Empty(any *any.Any) (proto.Message, error) {
|
||||||
|
aname, err := AnyMessageName(any)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
t := proto.MessageType(aname)
|
||||||
|
if t == nil {
|
||||||
|
return nil, fmt.Errorf("any: message type %q isn't linked in", aname)
|
||||||
|
}
|
||||||
|
return reflect.New(t.Elem()).Interface().(proto.Message), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalAny parses the protocol buffer representation in a google.protobuf.Any
|
||||||
|
// message and places the decoded result in pb. It returns an error if type of
|
||||||
|
// contents of Any message does not match type of pb message.
|
||||||
|
//
|
||||||
|
// pb can be a proto.Message, or a *DynamicAny.
|
||||||
|
func UnmarshalAny(any *any.Any, pb proto.Message) error {
|
||||||
|
if d, ok := pb.(*DynamicAny); ok {
|
||||||
|
if d.Message == nil {
|
||||||
|
var err error
|
||||||
|
d.Message, err = Empty(any)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return UnmarshalAny(any, d.Message)
|
||||||
|
}
|
||||||
|
|
||||||
|
aname, err := AnyMessageName(any)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
mname := proto.MessageName(pb)
|
||||||
|
if aname != mname {
|
||||||
|
return fmt.Errorf("mismatched message type: got %q want %q", aname, mname)
|
||||||
|
}
|
||||||
|
return proto.Unmarshal(any.Value, pb)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Is returns true if any value contains a given message type.
|
||||||
|
func Is(any *any.Any, pb proto.Message) bool {
|
||||||
|
// The following is equivalent to AnyMessageName(any) == proto.MessageName(pb),
|
||||||
|
// but it avoids scanning TypeUrl for the slash.
|
||||||
|
if any == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
name := proto.MessageName(pb)
|
||||||
|
prefix := len(any.TypeUrl) - len(name)
|
||||||
|
return prefix >= 1 && any.TypeUrl[prefix-1] == '/' && any.TypeUrl[prefix:] == name
|
||||||
|
}
|
191
vendor/github.com/golang/protobuf/ptypes/any/any.pb.go
generated
vendored
Normal file
191
vendor/github.com/golang/protobuf/ptypes/any/any.pb.go
generated
vendored
Normal file
|
@ -0,0 +1,191 @@
|
||||||
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
|
// source: google/protobuf/any.proto
|
||||||
|
|
||||||
|
package any // import "github.com/golang/protobuf/ptypes/any"
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
// `Any` contains an arbitrary serialized protocol buffer message along with a
|
||||||
|
// URL that describes the type of the serialized message.
|
||||||
|
//
|
||||||
|
// Protobuf library provides support to pack/unpack Any values in the form
|
||||||
|
// of utility functions or additional generated methods of the Any type.
|
||||||
|
//
|
||||||
|
// Example 1: Pack and unpack a message in C++.
|
||||||
|
//
|
||||||
|
// Foo foo = ...;
|
||||||
|
// Any any;
|
||||||
|
// any.PackFrom(foo);
|
||||||
|
// ...
|
||||||
|
// if (any.UnpackTo(&foo)) {
|
||||||
|
// ...
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// Example 2: Pack and unpack a message in Java.
|
||||||
|
//
|
||||||
|
// Foo foo = ...;
|
||||||
|
// Any any = Any.pack(foo);
|
||||||
|
// ...
|
||||||
|
// if (any.is(Foo.class)) {
|
||||||
|
// foo = any.unpack(Foo.class);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// Example 3: Pack and unpack a message in Python.
|
||||||
|
//
|
||||||
|
// foo = Foo(...)
|
||||||
|
// any = Any()
|
||||||
|
// any.Pack(foo)
|
||||||
|
// ...
|
||||||
|
// if any.Is(Foo.DESCRIPTOR):
|
||||||
|
// any.Unpack(foo)
|
||||||
|
// ...
|
||||||
|
//
|
||||||
|
// Example 4: Pack and unpack a message in Go
|
||||||
|
//
|
||||||
|
// foo := &pb.Foo{...}
|
||||||
|
// any, err := ptypes.MarshalAny(foo)
|
||||||
|
// ...
|
||||||
|
// foo := &pb.Foo{}
|
||||||
|
// if err := ptypes.UnmarshalAny(any, foo); err != nil {
|
||||||
|
// ...
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// The pack methods provided by protobuf library will by default use
|
||||||
|
// 'type.googleapis.com/full.type.name' as the type URL and the unpack
|
||||||
|
// methods only use the fully qualified type name after the last '/'
|
||||||
|
// in the type URL, for example "foo.bar.com/x/y.z" will yield type
|
||||||
|
// name "y.z".
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// JSON
|
||||||
|
// ====
|
||||||
|
// The JSON representation of an `Any` value uses the regular
|
||||||
|
// representation of the deserialized, embedded message, with an
|
||||||
|
// additional field `@type` which contains the type URL. Example:
|
||||||
|
//
|
||||||
|
// package google.profile;
|
||||||
|
// message Person {
|
||||||
|
// string first_name = 1;
|
||||||
|
// string last_name = 2;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// {
|
||||||
|
// "@type": "type.googleapis.com/google.profile.Person",
|
||||||
|
// "firstName": <string>,
|
||||||
|
// "lastName": <string>
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// If the embedded message type is well-known and has a custom JSON
|
||||||
|
// representation, that representation will be embedded adding a field
|
||||||
|
// `value` which holds the custom JSON in addition to the `@type`
|
||||||
|
// field. Example (for message [google.protobuf.Duration][]):
|
||||||
|
//
|
||||||
|
// {
|
||||||
|
// "@type": "type.googleapis.com/google.protobuf.Duration",
|
||||||
|
// "value": "1.212s"
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
type Any struct {
|
||||||
|
// A URL/resource name whose content describes the type of the
|
||||||
|
// serialized protocol buffer message.
|
||||||
|
//
|
||||||
|
// For URLs which use the scheme `http`, `https`, or no scheme, the
|
||||||
|
// following restrictions and interpretations apply:
|
||||||
|
//
|
||||||
|
// * If no scheme is provided, `https` is assumed.
|
||||||
|
// * The last segment of the URL's path must represent the fully
|
||||||
|
// qualified name of the type (as in `path/google.protobuf.Duration`).
|
||||||
|
// The name should be in a canonical form (e.g., leading "." is
|
||||||
|
// not accepted).
|
||||||
|
// * An HTTP GET on the URL must yield a [google.protobuf.Type][]
|
||||||
|
// value in binary format, or produce an error.
|
||||||
|
// * Applications are allowed to cache lookup results based on the
|
||||||
|
// URL, or have them precompiled into a binary to avoid any
|
||||||
|
// lookup. Therefore, binary compatibility needs to be preserved
|
||||||
|
// on changes to types. (Use versioned type names to manage
|
||||||
|
// breaking changes.)
|
||||||
|
//
|
||||||
|
// Schemes other than `http`, `https` (or the empty scheme) might be
|
||||||
|
// used with implementation specific semantics.
|
||||||
|
//
|
||||||
|
TypeUrl string `protobuf:"bytes,1,opt,name=type_url,json=typeUrl,proto3" json:"type_url,omitempty"`
|
||||||
|
// Must be a valid serialized protocol buffer of the above specified type.
|
||||||
|
Value []byte `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"`
|
||||||
|
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||||
|
XXX_unrecognized []byte `json:"-"`
|
||||||
|
XXX_sizecache int32 `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Any) Reset() { *m = Any{} }
|
||||||
|
func (m *Any) String() string { return proto.CompactTextString(m) }
|
||||||
|
func (*Any) ProtoMessage() {}
|
||||||
|
func (*Any) Descriptor() ([]byte, []int) {
|
||||||
|
return fileDescriptor_any_744b9ca530f228db, []int{0}
|
||||||
|
}
|
||||||
|
func (*Any) XXX_WellKnownType() string { return "Any" }
|
||||||
|
func (m *Any) XXX_Unmarshal(b []byte) error {
|
||||||
|
return xxx_messageInfo_Any.Unmarshal(m, b)
|
||||||
|
}
|
||||||
|
func (m *Any) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||||
|
return xxx_messageInfo_Any.Marshal(b, m, deterministic)
|
||||||
|
}
|
||||||
|
func (dst *Any) XXX_Merge(src proto.Message) {
|
||||||
|
xxx_messageInfo_Any.Merge(dst, src)
|
||||||
|
}
|
||||||
|
func (m *Any) XXX_Size() int {
|
||||||
|
return xxx_messageInfo_Any.Size(m)
|
||||||
|
}
|
||||||
|
func (m *Any) XXX_DiscardUnknown() {
|
||||||
|
xxx_messageInfo_Any.DiscardUnknown(m)
|
||||||
|
}
|
||||||
|
|
||||||
|
var xxx_messageInfo_Any proto.InternalMessageInfo
|
||||||
|
|
||||||
|
func (m *Any) GetTypeUrl() string {
|
||||||
|
if m != nil {
|
||||||
|
return m.TypeUrl
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Any) GetValue() []byte {
|
||||||
|
if m != nil {
|
||||||
|
return m.Value
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
proto.RegisterType((*Any)(nil), "google.protobuf.Any")
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() { proto.RegisterFile("google/protobuf/any.proto", fileDescriptor_any_744b9ca530f228db) }
|
||||||
|
|
||||||
|
var fileDescriptor_any_744b9ca530f228db = []byte{
|
||||||
|
// 185 bytes of a gzipped FileDescriptorProto
|
||||||
|
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0x4c, 0xcf, 0xcf, 0x4f,
|
||||||
|
0xcf, 0x49, 0xd5, 0x2f, 0x28, 0xca, 0x2f, 0xc9, 0x4f, 0x2a, 0x4d, 0xd3, 0x4f, 0xcc, 0xab, 0xd4,
|
||||||
|
0x03, 0x73, 0x84, 0xf8, 0x21, 0x52, 0x7a, 0x30, 0x29, 0x25, 0x33, 0x2e, 0x66, 0xc7, 0xbc, 0x4a,
|
||||||
|
0x21, 0x49, 0x2e, 0x8e, 0x92, 0xca, 0x82, 0xd4, 0xf8, 0xd2, 0xa2, 0x1c, 0x09, 0x46, 0x05, 0x46,
|
||||||
|
0x0d, 0xce, 0x20, 0x76, 0x10, 0x3f, 0xb4, 0x28, 0x47, 0x48, 0x84, 0x8b, 0xb5, 0x2c, 0x31, 0xa7,
|
||||||
|
0x34, 0x55, 0x82, 0x49, 0x81, 0x51, 0x83, 0x27, 0x08, 0xc2, 0x71, 0xca, 0xe7, 0x12, 0x4e, 0xce,
|
||||||
|
0xcf, 0xd5, 0x43, 0x33, 0xce, 0x89, 0xc3, 0x31, 0xaf, 0x32, 0x00, 0xc4, 0x09, 0x60, 0x8c, 0x52,
|
||||||
|
0x4d, 0xcf, 0x2c, 0xc9, 0x28, 0x4d, 0xd2, 0x4b, 0xce, 0xcf, 0xd5, 0x4f, 0xcf, 0xcf, 0x49, 0xcc,
|
||||||
|
0x4b, 0x47, 0xb8, 0xa8, 0x00, 0x64, 0x7a, 0x31, 0xc8, 0x61, 0x8b, 0x98, 0x98, 0xdd, 0x03, 0x9c,
|
||||||
|
0x56, 0x31, 0xc9, 0xb9, 0x43, 0x8c, 0x0a, 0x80, 0x2a, 0xd1, 0x0b, 0x4f, 0xcd, 0xc9, 0xf1, 0xce,
|
||||||
|
0xcb, 0x2f, 0xcf, 0x0b, 0x01, 0x29, 0x4d, 0x62, 0x03, 0xeb, 0x35, 0x06, 0x04, 0x00, 0x00, 0xff,
|
||||||
|
0xff, 0x13, 0xf8, 0xe8, 0x42, 0xdd, 0x00, 0x00, 0x00,
|
||||||
|
}
|
35
vendor/github.com/golang/protobuf/ptypes/doc.go
generated
vendored
Normal file
35
vendor/github.com/golang/protobuf/ptypes/doc.go
generated
vendored
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
// Go support for Protocol Buffers - Google's data interchange format
|
||||||
|
//
|
||||||
|
// Copyright 2016 The Go Authors. All rights reserved.
|
||||||
|
// https://github.com/golang/protobuf
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
/*
|
||||||
|
Package ptypes contains code for interacting with well-known types.
|
||||||
|
*/
|
||||||
|
package ptypes
|
102
vendor/github.com/golang/protobuf/ptypes/duration.go
generated
vendored
Normal file
102
vendor/github.com/golang/protobuf/ptypes/duration.go
generated
vendored
Normal file
|
@ -0,0 +1,102 @@
|
||||||
|
// Go support for Protocol Buffers - Google's data interchange format
|
||||||
|
//
|
||||||
|
// Copyright 2016 The Go Authors. All rights reserved.
|
||||||
|
// https://github.com/golang/protobuf
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
package ptypes
|
||||||
|
|
||||||
|
// This file implements conversions between google.protobuf.Duration
|
||||||
|
// and time.Duration.
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
durpb "github.com/golang/protobuf/ptypes/duration"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Range of a durpb.Duration in seconds, as specified in
|
||||||
|
// google/protobuf/duration.proto. This is about 10,000 years in seconds.
|
||||||
|
maxSeconds = int64(10000 * 365.25 * 24 * 60 * 60)
|
||||||
|
minSeconds = -maxSeconds
|
||||||
|
)
|
||||||
|
|
||||||
|
// validateDuration determines whether the durpb.Duration is valid according to the
|
||||||
|
// definition in google/protobuf/duration.proto. A valid durpb.Duration
|
||||||
|
// may still be too large to fit into a time.Duration (the range of durpb.Duration
|
||||||
|
// is about 10,000 years, and the range of time.Duration is about 290).
|
||||||
|
func validateDuration(d *durpb.Duration) error {
|
||||||
|
if d == nil {
|
||||||
|
return errors.New("duration: nil Duration")
|
||||||
|
}
|
||||||
|
if d.Seconds < minSeconds || d.Seconds > maxSeconds {
|
||||||
|
return fmt.Errorf("duration: %v: seconds out of range", d)
|
||||||
|
}
|
||||||
|
if d.Nanos <= -1e9 || d.Nanos >= 1e9 {
|
||||||
|
return fmt.Errorf("duration: %v: nanos out of range", d)
|
||||||
|
}
|
||||||
|
// Seconds and Nanos must have the same sign, unless d.Nanos is zero.
|
||||||
|
if (d.Seconds < 0 && d.Nanos > 0) || (d.Seconds > 0 && d.Nanos < 0) {
|
||||||
|
return fmt.Errorf("duration: %v: seconds and nanos have different signs", d)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Duration converts a durpb.Duration to a time.Duration. Duration
|
||||||
|
// returns an error if the durpb.Duration is invalid or is too large to be
|
||||||
|
// represented in a time.Duration.
|
||||||
|
func Duration(p *durpb.Duration) (time.Duration, error) {
|
||||||
|
if err := validateDuration(p); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
d := time.Duration(p.Seconds) * time.Second
|
||||||
|
if int64(d/time.Second) != p.Seconds {
|
||||||
|
return 0, fmt.Errorf("duration: %v is out of range for time.Duration", p)
|
||||||
|
}
|
||||||
|
if p.Nanos != 0 {
|
||||||
|
d += time.Duration(p.Nanos)
|
||||||
|
if (d < 0) != (p.Nanos < 0) {
|
||||||
|
return 0, fmt.Errorf("duration: %v is out of range for time.Duration", p)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return d, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DurationProto converts a time.Duration to a durpb.Duration.
|
||||||
|
func DurationProto(d time.Duration) *durpb.Duration {
|
||||||
|
nanos := d.Nanoseconds()
|
||||||
|
secs := nanos / 1e9
|
||||||
|
nanos -= secs * 1e9
|
||||||
|
return &durpb.Duration{
|
||||||
|
Seconds: secs,
|
||||||
|
Nanos: int32(nanos),
|
||||||
|
}
|
||||||
|
}
|
159
vendor/github.com/golang/protobuf/ptypes/duration/duration.pb.go
generated
vendored
Normal file
159
vendor/github.com/golang/protobuf/ptypes/duration/duration.pb.go
generated
vendored
Normal file
|
@ -0,0 +1,159 @@
|
||||||
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
|
// source: google/protobuf/duration.proto
|
||||||
|
|
||||||
|
package duration // import "github.com/golang/protobuf/ptypes/duration"
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
// A Duration represents a signed, fixed-length span of time represented
|
||||||
|
// as a count of seconds and fractions of seconds at nanosecond
|
||||||
|
// resolution. It is independent of any calendar and concepts like "day"
|
||||||
|
// or "month". It is related to Timestamp in that the difference between
|
||||||
|
// two Timestamp values is a Duration and it can be added or subtracted
|
||||||
|
// from a Timestamp. Range is approximately +-10,000 years.
|
||||||
|
//
|
||||||
|
// # Examples
|
||||||
|
//
|
||||||
|
// Example 1: Compute Duration from two Timestamps in pseudo code.
|
||||||
|
//
|
||||||
|
// Timestamp start = ...;
|
||||||
|
// Timestamp end = ...;
|
||||||
|
// Duration duration = ...;
|
||||||
|
//
|
||||||
|
// duration.seconds = end.seconds - start.seconds;
|
||||||
|
// duration.nanos = end.nanos - start.nanos;
|
||||||
|
//
|
||||||
|
// if (duration.seconds < 0 && duration.nanos > 0) {
|
||||||
|
// duration.seconds += 1;
|
||||||
|
// duration.nanos -= 1000000000;
|
||||||
|
// } else if (durations.seconds > 0 && duration.nanos < 0) {
|
||||||
|
// duration.seconds -= 1;
|
||||||
|
// duration.nanos += 1000000000;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// Example 2: Compute Timestamp from Timestamp + Duration in pseudo code.
|
||||||
|
//
|
||||||
|
// Timestamp start = ...;
|
||||||
|
// Duration duration = ...;
|
||||||
|
// Timestamp end = ...;
|
||||||
|
//
|
||||||
|
// end.seconds = start.seconds + duration.seconds;
|
||||||
|
// end.nanos = start.nanos + duration.nanos;
|
||||||
|
//
|
||||||
|
// if (end.nanos < 0) {
|
||||||
|
// end.seconds -= 1;
|
||||||
|
// end.nanos += 1000000000;
|
||||||
|
// } else if (end.nanos >= 1000000000) {
|
||||||
|
// end.seconds += 1;
|
||||||
|
// end.nanos -= 1000000000;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// Example 3: Compute Duration from datetime.timedelta in Python.
|
||||||
|
//
|
||||||
|
// td = datetime.timedelta(days=3, minutes=10)
|
||||||
|
// duration = Duration()
|
||||||
|
// duration.FromTimedelta(td)
|
||||||
|
//
|
||||||
|
// # JSON Mapping
|
||||||
|
//
|
||||||
|
// In JSON format, the Duration type is encoded as a string rather than an
|
||||||
|
// object, where the string ends in the suffix "s" (indicating seconds) and
|
||||||
|
// is preceded by the number of seconds, with nanoseconds expressed as
|
||||||
|
// fractional seconds. For example, 3 seconds with 0 nanoseconds should be
|
||||||
|
// encoded in JSON format as "3s", while 3 seconds and 1 nanosecond should
|
||||||
|
// be expressed in JSON format as "3.000000001s", and 3 seconds and 1
|
||||||
|
// microsecond should be expressed in JSON format as "3.000001s".
|
||||||
|
//
|
||||||
|
//
|
||||||
|
type Duration struct {
|
||||||
|
// Signed seconds of the span of time. Must be from -315,576,000,000
|
||||||
|
// to +315,576,000,000 inclusive. Note: these bounds are computed from:
|
||||||
|
// 60 sec/min * 60 min/hr * 24 hr/day * 365.25 days/year * 10000 years
|
||||||
|
Seconds int64 `protobuf:"varint,1,opt,name=seconds,proto3" json:"seconds,omitempty"`
|
||||||
|
// Signed fractions of a second at nanosecond resolution of the span
|
||||||
|
// of time. Durations less than one second are represented with a 0
|
||||||
|
// `seconds` field and a positive or negative `nanos` field. For durations
|
||||||
|
// of one second or more, a non-zero value for the `nanos` field must be
|
||||||
|
// of the same sign as the `seconds` field. Must be from -999,999,999
|
||||||
|
// to +999,999,999 inclusive.
|
||||||
|
Nanos int32 `protobuf:"varint,2,opt,name=nanos,proto3" json:"nanos,omitempty"`
|
||||||
|
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||||
|
XXX_unrecognized []byte `json:"-"`
|
||||||
|
XXX_sizecache int32 `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Duration) Reset() { *m = Duration{} }
|
||||||
|
func (m *Duration) String() string { return proto.CompactTextString(m) }
|
||||||
|
func (*Duration) ProtoMessage() {}
|
||||||
|
func (*Duration) Descriptor() ([]byte, []int) {
|
||||||
|
return fileDescriptor_duration_e7d612259e3f0613, []int{0}
|
||||||
|
}
|
||||||
|
func (*Duration) XXX_WellKnownType() string { return "Duration" }
|
||||||
|
func (m *Duration) XXX_Unmarshal(b []byte) error {
|
||||||
|
return xxx_messageInfo_Duration.Unmarshal(m, b)
|
||||||
|
}
|
||||||
|
func (m *Duration) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||||
|
return xxx_messageInfo_Duration.Marshal(b, m, deterministic)
|
||||||
|
}
|
||||||
|
func (dst *Duration) XXX_Merge(src proto.Message) {
|
||||||
|
xxx_messageInfo_Duration.Merge(dst, src)
|
||||||
|
}
|
||||||
|
func (m *Duration) XXX_Size() int {
|
||||||
|
return xxx_messageInfo_Duration.Size(m)
|
||||||
|
}
|
||||||
|
func (m *Duration) XXX_DiscardUnknown() {
|
||||||
|
xxx_messageInfo_Duration.DiscardUnknown(m)
|
||||||
|
}
|
||||||
|
|
||||||
|
var xxx_messageInfo_Duration proto.InternalMessageInfo
|
||||||
|
|
||||||
|
func (m *Duration) GetSeconds() int64 {
|
||||||
|
if m != nil {
|
||||||
|
return m.Seconds
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Duration) GetNanos() int32 {
|
||||||
|
if m != nil {
|
||||||
|
return m.Nanos
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
proto.RegisterType((*Duration)(nil), "google.protobuf.Duration")
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
proto.RegisterFile("google/protobuf/duration.proto", fileDescriptor_duration_e7d612259e3f0613)
|
||||||
|
}
|
||||||
|
|
||||||
|
var fileDescriptor_duration_e7d612259e3f0613 = []byte{
|
||||||
|
// 190 bytes of a gzipped FileDescriptorProto
|
||||||
|
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0x4b, 0xcf, 0xcf, 0x4f,
|
||||||
|
0xcf, 0x49, 0xd5, 0x2f, 0x28, 0xca, 0x2f, 0xc9, 0x4f, 0x2a, 0x4d, 0xd3, 0x4f, 0x29, 0x2d, 0x4a,
|
||||||
|
0x2c, 0xc9, 0xcc, 0xcf, 0xd3, 0x03, 0x8b, 0x08, 0xf1, 0x43, 0xe4, 0xf5, 0x60, 0xf2, 0x4a, 0x56,
|
||||||
|
0x5c, 0x1c, 0x2e, 0x50, 0x25, 0x42, 0x12, 0x5c, 0xec, 0xc5, 0xa9, 0xc9, 0xf9, 0x79, 0x29, 0xc5,
|
||||||
|
0x12, 0x8c, 0x0a, 0x8c, 0x1a, 0xcc, 0x41, 0x30, 0xae, 0x90, 0x08, 0x17, 0x6b, 0x5e, 0x62, 0x5e,
|
||||||
|
0x7e, 0xb1, 0x04, 0x93, 0x02, 0xa3, 0x06, 0x6b, 0x10, 0x84, 0xe3, 0x54, 0xc3, 0x25, 0x9c, 0x9c,
|
||||||
|
0x9f, 0xab, 0x87, 0x66, 0xa4, 0x13, 0x2f, 0xcc, 0xc0, 0x00, 0x90, 0x48, 0x00, 0x63, 0x94, 0x56,
|
||||||
|
0x7a, 0x66, 0x49, 0x46, 0x69, 0x92, 0x5e, 0x72, 0x7e, 0xae, 0x7e, 0x7a, 0x7e, 0x4e, 0x62, 0x5e,
|
||||||
|
0x3a, 0xc2, 0x7d, 0x05, 0x25, 0x95, 0x05, 0xa9, 0xc5, 0x70, 0x67, 0xfe, 0x60, 0x64, 0x5c, 0xc4,
|
||||||
|
0xc4, 0xec, 0x1e, 0xe0, 0xb4, 0x8a, 0x49, 0xce, 0x1d, 0x62, 0x6e, 0x00, 0x54, 0xa9, 0x5e, 0x78,
|
||||||
|
0x6a, 0x4e, 0x8e, 0x77, 0x5e, 0x7e, 0x79, 0x5e, 0x08, 0x48, 0x4b, 0x12, 0x1b, 0xd8, 0x0c, 0x63,
|
||||||
|
0x40, 0x00, 0x00, 0x00, 0xff, 0xff, 0xdc, 0x84, 0x30, 0xff, 0xf3, 0x00, 0x00, 0x00,
|
||||||
|
}
|
134
vendor/github.com/golang/protobuf/ptypes/timestamp.go
generated
vendored
Normal file
134
vendor/github.com/golang/protobuf/ptypes/timestamp.go
generated
vendored
Normal file
|
@ -0,0 +1,134 @@
|
||||||
|
// Go support for Protocol Buffers - Google's data interchange format
|
||||||
|
//
|
||||||
|
// Copyright 2016 The Go Authors. All rights reserved.
|
||||||
|
// https://github.com/golang/protobuf
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
package ptypes
|
||||||
|
|
||||||
|
// This file implements operations on google.protobuf.Timestamp.
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
tspb "github.com/golang/protobuf/ptypes/timestamp"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Seconds field of the earliest valid Timestamp.
|
||||||
|
// This is time.Date(1, 1, 1, 0, 0, 0, 0, time.UTC).Unix().
|
||||||
|
minValidSeconds = -62135596800
|
||||||
|
// Seconds field just after the latest valid Timestamp.
|
||||||
|
// This is time.Date(10000, 1, 1, 0, 0, 0, 0, time.UTC).Unix().
|
||||||
|
maxValidSeconds = 253402300800
|
||||||
|
)
|
||||||
|
|
||||||
|
// validateTimestamp determines whether a Timestamp is valid.
|
||||||
|
// A valid timestamp represents a time in the range
|
||||||
|
// [0001-01-01, 10000-01-01) and has a Nanos field
|
||||||
|
// in the range [0, 1e9).
|
||||||
|
//
|
||||||
|
// If the Timestamp is valid, validateTimestamp returns nil.
|
||||||
|
// Otherwise, it returns an error that describes
|
||||||
|
// the problem.
|
||||||
|
//
|
||||||
|
// Every valid Timestamp can be represented by a time.Time, but the converse is not true.
|
||||||
|
func validateTimestamp(ts *tspb.Timestamp) error {
|
||||||
|
if ts == nil {
|
||||||
|
return errors.New("timestamp: nil Timestamp")
|
||||||
|
}
|
||||||
|
if ts.Seconds < minValidSeconds {
|
||||||
|
return fmt.Errorf("timestamp: %v before 0001-01-01", ts)
|
||||||
|
}
|
||||||
|
if ts.Seconds >= maxValidSeconds {
|
||||||
|
return fmt.Errorf("timestamp: %v after 10000-01-01", ts)
|
||||||
|
}
|
||||||
|
if ts.Nanos < 0 || ts.Nanos >= 1e9 {
|
||||||
|
return fmt.Errorf("timestamp: %v: nanos not in range [0, 1e9)", ts)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Timestamp converts a google.protobuf.Timestamp proto to a time.Time.
|
||||||
|
// It returns an error if the argument is invalid.
|
||||||
|
//
|
||||||
|
// Unlike most Go functions, if Timestamp returns an error, the first return value
|
||||||
|
// is not the zero time.Time. Instead, it is the value obtained from the
|
||||||
|
// time.Unix function when passed the contents of the Timestamp, in the UTC
|
||||||
|
// locale. This may or may not be a meaningful time; many invalid Timestamps
|
||||||
|
// do map to valid time.Times.
|
||||||
|
//
|
||||||
|
// A nil Timestamp returns an error. The first return value in that case is
|
||||||
|
// undefined.
|
||||||
|
func Timestamp(ts *tspb.Timestamp) (time.Time, error) {
|
||||||
|
// Don't return the zero value on error, because corresponds to a valid
|
||||||
|
// timestamp. Instead return whatever time.Unix gives us.
|
||||||
|
var t time.Time
|
||||||
|
if ts == nil {
|
||||||
|
t = time.Unix(0, 0).UTC() // treat nil like the empty Timestamp
|
||||||
|
} else {
|
||||||
|
t = time.Unix(ts.Seconds, int64(ts.Nanos)).UTC()
|
||||||
|
}
|
||||||
|
return t, validateTimestamp(ts)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TimestampNow returns a google.protobuf.Timestamp for the current time.
|
||||||
|
func TimestampNow() *tspb.Timestamp {
|
||||||
|
ts, err := TimestampProto(time.Now())
|
||||||
|
if err != nil {
|
||||||
|
panic("ptypes: time.Now() out of Timestamp range")
|
||||||
|
}
|
||||||
|
return ts
|
||||||
|
}
|
||||||
|
|
||||||
|
// TimestampProto converts the time.Time to a google.protobuf.Timestamp proto.
|
||||||
|
// It returns an error if the resulting Timestamp is invalid.
|
||||||
|
func TimestampProto(t time.Time) (*tspb.Timestamp, error) {
|
||||||
|
seconds := t.Unix()
|
||||||
|
nanos := int32(t.Sub(time.Unix(seconds, 0)))
|
||||||
|
ts := &tspb.Timestamp{
|
||||||
|
Seconds: seconds,
|
||||||
|
Nanos: nanos,
|
||||||
|
}
|
||||||
|
if err := validateTimestamp(ts); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return ts, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// TimestampString returns the RFC 3339 string for valid Timestamps. For invalid
|
||||||
|
// Timestamps, it returns an error message in parentheses.
|
||||||
|
func TimestampString(ts *tspb.Timestamp) string {
|
||||||
|
t, err := Timestamp(ts)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Sprintf("(%v)", err)
|
||||||
|
}
|
||||||
|
return t.Format(time.RFC3339Nano)
|
||||||
|
}
|
175
vendor/github.com/golang/protobuf/ptypes/timestamp/timestamp.pb.go
generated
vendored
Normal file
175
vendor/github.com/golang/protobuf/ptypes/timestamp/timestamp.pb.go
generated
vendored
Normal file
|
@ -0,0 +1,175 @@
|
||||||
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
|
// source: google/protobuf/timestamp.proto
|
||||||
|
|
||||||
|
package timestamp // import "github.com/golang/protobuf/ptypes/timestamp"
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
// A Timestamp represents a point in time independent of any time zone
|
||||||
|
// or calendar, represented as seconds and fractions of seconds at
|
||||||
|
// nanosecond resolution in UTC Epoch time. It is encoded using the
|
||||||
|
// Proleptic Gregorian Calendar which extends the Gregorian calendar
|
||||||
|
// backwards to year one. It is encoded assuming all minutes are 60
|
||||||
|
// seconds long, i.e. leap seconds are "smeared" so that no leap second
|
||||||
|
// table is needed for interpretation. Range is from
|
||||||
|
// 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z.
|
||||||
|
// By restricting to that range, we ensure that we can convert to
|
||||||
|
// and from RFC 3339 date strings.
|
||||||
|
// See [https://www.ietf.org/rfc/rfc3339.txt](https://www.ietf.org/rfc/rfc3339.txt).
|
||||||
|
//
|
||||||
|
// # Examples
|
||||||
|
//
|
||||||
|
// Example 1: Compute Timestamp from POSIX `time()`.
|
||||||
|
//
|
||||||
|
// Timestamp timestamp;
|
||||||
|
// timestamp.set_seconds(time(NULL));
|
||||||
|
// timestamp.set_nanos(0);
|
||||||
|
//
|
||||||
|
// Example 2: Compute Timestamp from POSIX `gettimeofday()`.
|
||||||
|
//
|
||||||
|
// struct timeval tv;
|
||||||
|
// gettimeofday(&tv, NULL);
|
||||||
|
//
|
||||||
|
// Timestamp timestamp;
|
||||||
|
// timestamp.set_seconds(tv.tv_sec);
|
||||||
|
// timestamp.set_nanos(tv.tv_usec * 1000);
|
||||||
|
//
|
||||||
|
// Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`.
|
||||||
|
//
|
||||||
|
// FILETIME ft;
|
||||||
|
// GetSystemTimeAsFileTime(&ft);
|
||||||
|
// UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime;
|
||||||
|
//
|
||||||
|
// // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z
|
||||||
|
// // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z.
|
||||||
|
// Timestamp timestamp;
|
||||||
|
// timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL));
|
||||||
|
// timestamp.set_nanos((INT32) ((ticks % 10000000) * 100));
|
||||||
|
//
|
||||||
|
// Example 4: Compute Timestamp from Java `System.currentTimeMillis()`.
|
||||||
|
//
|
||||||
|
// long millis = System.currentTimeMillis();
|
||||||
|
//
|
||||||
|
// Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000)
|
||||||
|
// .setNanos((int) ((millis % 1000) * 1000000)).build();
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Example 5: Compute Timestamp from current time in Python.
|
||||||
|
//
|
||||||
|
// timestamp = Timestamp()
|
||||||
|
// timestamp.GetCurrentTime()
|
||||||
|
//
|
||||||
|
// # JSON Mapping
|
||||||
|
//
|
||||||
|
// In JSON format, the Timestamp type is encoded as a string in the
|
||||||
|
// [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the
|
||||||
|
// format is "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z"
|
||||||
|
// where {year} is always expressed using four digits while {month}, {day},
|
||||||
|
// {hour}, {min}, and {sec} are zero-padded to two digits each. The fractional
|
||||||
|
// seconds, which can go up to 9 digits (i.e. up to 1 nanosecond resolution),
|
||||||
|
// are optional. The "Z" suffix indicates the timezone ("UTC"); the timezone
|
||||||
|
// is required, though only UTC (as indicated by "Z") is presently supported.
|
||||||
|
//
|
||||||
|
// For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past
|
||||||
|
// 01:30 UTC on January 15, 2017.
|
||||||
|
//
|
||||||
|
// In JavaScript, one can convert a Date object to this format using the
|
||||||
|
// standard [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString]
|
||||||
|
// method. In Python, a standard `datetime.datetime` object can be converted
|
||||||
|
// to this format using [`strftime`](https://docs.python.org/2/library/time.html#time.strftime)
|
||||||
|
// with the time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one
|
||||||
|
// can use the Joda Time's [`ISODateTimeFormat.dateTime()`](
|
||||||
|
// http://www.joda.org/joda-time/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime--)
|
||||||
|
// to obtain a formatter capable of generating timestamps in this format.
|
||||||
|
//
|
||||||
|
//
|
||||||
|
type Timestamp struct {
|
||||||
|
// Represents seconds of UTC time since Unix epoch
|
||||||
|
// 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to
|
||||||
|
// 9999-12-31T23:59:59Z inclusive.
|
||||||
|
Seconds int64 `protobuf:"varint,1,opt,name=seconds,proto3" json:"seconds,omitempty"`
|
||||||
|
// Non-negative fractions of a second at nanosecond resolution. Negative
|
||||||
|
// second values with fractions must still have non-negative nanos values
|
||||||
|
// that count forward in time. Must be from 0 to 999,999,999
|
||||||
|
// inclusive.
|
||||||
|
Nanos int32 `protobuf:"varint,2,opt,name=nanos,proto3" json:"nanos,omitempty"`
|
||||||
|
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||||
|
XXX_unrecognized []byte `json:"-"`
|
||||||
|
XXX_sizecache int32 `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Timestamp) Reset() { *m = Timestamp{} }
|
||||||
|
func (m *Timestamp) String() string { return proto.CompactTextString(m) }
|
||||||
|
func (*Timestamp) ProtoMessage() {}
|
||||||
|
func (*Timestamp) Descriptor() ([]byte, []int) {
|
||||||
|
return fileDescriptor_timestamp_b826e8e5fba671a8, []int{0}
|
||||||
|
}
|
||||||
|
func (*Timestamp) XXX_WellKnownType() string { return "Timestamp" }
|
||||||
|
func (m *Timestamp) XXX_Unmarshal(b []byte) error {
|
||||||
|
return xxx_messageInfo_Timestamp.Unmarshal(m, b)
|
||||||
|
}
|
||||||
|
func (m *Timestamp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||||
|
return xxx_messageInfo_Timestamp.Marshal(b, m, deterministic)
|
||||||
|
}
|
||||||
|
func (dst *Timestamp) XXX_Merge(src proto.Message) {
|
||||||
|
xxx_messageInfo_Timestamp.Merge(dst, src)
|
||||||
|
}
|
||||||
|
func (m *Timestamp) XXX_Size() int {
|
||||||
|
return xxx_messageInfo_Timestamp.Size(m)
|
||||||
|
}
|
||||||
|
func (m *Timestamp) XXX_DiscardUnknown() {
|
||||||
|
xxx_messageInfo_Timestamp.DiscardUnknown(m)
|
||||||
|
}
|
||||||
|
|
||||||
|
var xxx_messageInfo_Timestamp proto.InternalMessageInfo
|
||||||
|
|
||||||
|
func (m *Timestamp) GetSeconds() int64 {
|
||||||
|
if m != nil {
|
||||||
|
return m.Seconds
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Timestamp) GetNanos() int32 {
|
||||||
|
if m != nil {
|
||||||
|
return m.Nanos
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
proto.RegisterType((*Timestamp)(nil), "google.protobuf.Timestamp")
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
proto.RegisterFile("google/protobuf/timestamp.proto", fileDescriptor_timestamp_b826e8e5fba671a8)
|
||||||
|
}
|
||||||
|
|
||||||
|
var fileDescriptor_timestamp_b826e8e5fba671a8 = []byte{
|
||||||
|
// 191 bytes of a gzipped FileDescriptorProto
|
||||||
|
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0x4f, 0xcf, 0xcf, 0x4f,
|
||||||
|
0xcf, 0x49, 0xd5, 0x2f, 0x28, 0xca, 0x2f, 0xc9, 0x4f, 0x2a, 0x4d, 0xd3, 0x2f, 0xc9, 0xcc, 0x4d,
|
||||||
|
0x2d, 0x2e, 0x49, 0xcc, 0x2d, 0xd0, 0x03, 0x0b, 0x09, 0xf1, 0x43, 0x14, 0xe8, 0xc1, 0x14, 0x28,
|
||||||
|
0x59, 0x73, 0x71, 0x86, 0xc0, 0xd4, 0x08, 0x49, 0x70, 0xb1, 0x17, 0xa7, 0x26, 0xe7, 0xe7, 0xa5,
|
||||||
|
0x14, 0x4b, 0x30, 0x2a, 0x30, 0x6a, 0x30, 0x07, 0xc1, 0xb8, 0x42, 0x22, 0x5c, 0xac, 0x79, 0x89,
|
||||||
|
0x79, 0xf9, 0xc5, 0x12, 0x4c, 0x0a, 0x8c, 0x1a, 0xac, 0x41, 0x10, 0x8e, 0x53, 0x1d, 0x97, 0x70,
|
||||||
|
0x72, 0x7e, 0xae, 0x1e, 0x9a, 0x99, 0x4e, 0x7c, 0x70, 0x13, 0x03, 0x40, 0x42, 0x01, 0x8c, 0x51,
|
||||||
|
0xda, 0xe9, 0x99, 0x25, 0x19, 0xa5, 0x49, 0x7a, 0xc9, 0xf9, 0xb9, 0xfa, 0xe9, 0xf9, 0x39, 0x89,
|
||||||
|
0x79, 0xe9, 0x08, 0x27, 0x16, 0x94, 0x54, 0x16, 0xa4, 0x16, 0x23, 0x5c, 0xfa, 0x83, 0x91, 0x71,
|
||||||
|
0x11, 0x13, 0xb3, 0x7b, 0x80, 0xd3, 0x2a, 0x26, 0x39, 0x77, 0x88, 0xc9, 0x01, 0x50, 0xb5, 0x7a,
|
||||||
|
0xe1, 0xa9, 0x39, 0x39, 0xde, 0x79, 0xf9, 0xe5, 0x79, 0x21, 0x20, 0x3d, 0x49, 0x6c, 0x60, 0x43,
|
||||||
|
0x8c, 0x01, 0x01, 0x00, 0x00, 0xff, 0xff, 0xbc, 0x77, 0x4a, 0x07, 0xf7, 0x00, 0x00, 0x00,
|
||||||
|
}
|
362
vendor/github.com/hashicorp/golang-lru/LICENSE
generated
vendored
Normal file
362
vendor/github.com/hashicorp/golang-lru/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,362 @@
|
||||||
|
Mozilla Public License, version 2.0
|
||||||
|
|
||||||
|
1. Definitions
|
||||||
|
|
||||||
|
1.1. "Contributor"
|
||||||
|
|
||||||
|
means each individual or legal entity that creates, contributes to the
|
||||||
|
creation of, or owns Covered Software.
|
||||||
|
|
||||||
|
1.2. "Contributor Version"
|
||||||
|
|
||||||
|
means the combination of the Contributions of others (if any) used by a
|
||||||
|
Contributor and that particular Contributor's Contribution.
|
||||||
|
|
||||||
|
1.3. "Contribution"
|
||||||
|
|
||||||
|
means Covered Software of a particular Contributor.
|
||||||
|
|
||||||
|
1.4. "Covered Software"
|
||||||
|
|
||||||
|
means Source Code Form to which the initial Contributor has attached the
|
||||||
|
notice in Exhibit A, the Executable Form of such Source Code Form, and
|
||||||
|
Modifications of such Source Code Form, in each case including portions
|
||||||
|
thereof.
|
||||||
|
|
||||||
|
1.5. "Incompatible With Secondary Licenses"
|
||||||
|
means
|
||||||
|
|
||||||
|
a. that the initial Contributor has attached the notice described in
|
||||||
|
Exhibit B to the Covered Software; or
|
||||||
|
|
||||||
|
b. that the Covered Software was made available under the terms of
|
||||||
|
version 1.1 or earlier of the License, but not also under the terms of
|
||||||
|
a Secondary License.
|
||||||
|
|
||||||
|
1.6. "Executable Form"
|
||||||
|
|
||||||
|
means any form of the work other than Source Code Form.
|
||||||
|
|
||||||
|
1.7. "Larger Work"
|
||||||
|
|
||||||
|
means a work that combines Covered Software with other material, in a
|
||||||
|
separate file or files, that is not Covered Software.
|
||||||
|
|
||||||
|
1.8. "License"
|
||||||
|
|
||||||
|
means this document.
|
||||||
|
|
||||||
|
1.9. "Licensable"
|
||||||
|
|
||||||
|
means having the right to grant, to the maximum extent possible, whether
|
||||||
|
at the time of the initial grant or subsequently, any and all of the
|
||||||
|
rights conveyed by this License.
|
||||||
|
|
||||||
|
1.10. "Modifications"
|
||||||
|
|
||||||
|
means any of the following:
|
||||||
|
|
||||||
|
a. any file in Source Code Form that results from an addition to,
|
||||||
|
deletion from, or modification of the contents of Covered Software; or
|
||||||
|
|
||||||
|
b. any new file in Source Code Form that contains any Covered Software.
|
||||||
|
|
||||||
|
1.11. "Patent Claims" of a Contributor
|
||||||
|
|
||||||
|
means any patent claim(s), including without limitation, method,
|
||||||
|
process, and apparatus claims, in any patent Licensable by such
|
||||||
|
Contributor that would be infringed, but for the grant of the License,
|
||||||
|
by the making, using, selling, offering for sale, having made, import,
|
||||||
|
or transfer of either its Contributions or its Contributor Version.
|
||||||
|
|
||||||
|
1.12. "Secondary License"
|
||||||
|
|
||||||
|
means either the GNU General Public License, Version 2.0, the GNU Lesser
|
||||||
|
General Public License, Version 2.1, the GNU Affero General Public
|
||||||
|
License, Version 3.0, or any later versions of those licenses.
|
||||||
|
|
||||||
|
1.13. "Source Code Form"
|
||||||
|
|
||||||
|
means the form of the work preferred for making modifications.
|
||||||
|
|
||||||
|
1.14. "You" (or "Your")
|
||||||
|
|
||||||
|
means an individual or a legal entity exercising rights under this
|
||||||
|
License. For legal entities, "You" includes any entity that controls, is
|
||||||
|
controlled by, or is under common control with You. For purposes of this
|
||||||
|
definition, "control" means (a) the power, direct or indirect, to cause
|
||||||
|
the direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (b) ownership of more than fifty percent (50%) of the
|
||||||
|
outstanding shares or beneficial ownership of such entity.
|
||||||
|
|
||||||
|
|
||||||
|
2. License Grants and Conditions
|
||||||
|
|
||||||
|
2.1. Grants
|
||||||
|
|
||||||
|
Each Contributor hereby grants You a world-wide, royalty-free,
|
||||||
|
non-exclusive license:
|
||||||
|
|
||||||
|
a. under intellectual property rights (other than patent or trademark)
|
||||||
|
Licensable by such Contributor to use, reproduce, make available,
|
||||||
|
modify, display, perform, distribute, and otherwise exploit its
|
||||||
|
Contributions, either on an unmodified basis, with Modifications, or
|
||||||
|
as part of a Larger Work; and
|
||||||
|
|
||||||
|
b. under Patent Claims of such Contributor to make, use, sell, offer for
|
||||||
|
sale, have made, import, and otherwise transfer either its
|
||||||
|
Contributions or its Contributor Version.
|
||||||
|
|
||||||
|
2.2. Effective Date
|
||||||
|
|
||||||
|
The licenses granted in Section 2.1 with respect to any Contribution
|
||||||
|
become effective for each Contribution on the date the Contributor first
|
||||||
|
distributes such Contribution.
|
||||||
|
|
||||||
|
2.3. Limitations on Grant Scope
|
||||||
|
|
||||||
|
The licenses granted in this Section 2 are the only rights granted under
|
||||||
|
this License. No additional rights or licenses will be implied from the
|
||||||
|
distribution or licensing of Covered Software under this License.
|
||||||
|
Notwithstanding Section 2.1(b) above, no patent license is granted by a
|
||||||
|
Contributor:
|
||||||
|
|
||||||
|
a. for any code that a Contributor has removed from Covered Software; or
|
||||||
|
|
||||||
|
b. for infringements caused by: (i) Your and any other third party's
|
||||||
|
modifications of Covered Software, or (ii) the combination of its
|
||||||
|
Contributions with other software (except as part of its Contributor
|
||||||
|
Version); or
|
||||||
|
|
||||||
|
c. under Patent Claims infringed by Covered Software in the absence of
|
||||||
|
its Contributions.
|
||||||
|
|
||||||
|
This License does not grant any rights in the trademarks, service marks,
|
||||||
|
or logos of any Contributor (except as may be necessary to comply with
|
||||||
|
the notice requirements in Section 3.4).
|
||||||
|
|
||||||
|
2.4. Subsequent Licenses
|
||||||
|
|
||||||
|
No Contributor makes additional grants as a result of Your choice to
|
||||||
|
distribute the Covered Software under a subsequent version of this
|
||||||
|
License (see Section 10.2) or under the terms of a Secondary License (if
|
||||||
|
permitted under the terms of Section 3.3).
|
||||||
|
|
||||||
|
2.5. Representation
|
||||||
|
|
||||||
|
Each Contributor represents that the Contributor believes its
|
||||||
|
Contributions are its original creation(s) or it has sufficient rights to
|
||||||
|
grant the rights to its Contributions conveyed by this License.
|
||||||
|
|
||||||
|
2.6. Fair Use
|
||||||
|
|
||||||
|
This License is not intended to limit any rights You have under
|
||||||
|
applicable copyright doctrines of fair use, fair dealing, or other
|
||||||
|
equivalents.
|
||||||
|
|
||||||
|
2.7. Conditions
|
||||||
|
|
||||||
|
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in
|
||||||
|
Section 2.1.
|
||||||
|
|
||||||
|
|
||||||
|
3. Responsibilities
|
||||||
|
|
||||||
|
3.1. Distribution of Source Form
|
||||||
|
|
||||||
|
All distribution of Covered Software in Source Code Form, including any
|
||||||
|
Modifications that You create or to which You contribute, must be under
|
||||||
|
the terms of this License. You must inform recipients that the Source
|
||||||
|
Code Form of the Covered Software is governed by the terms of this
|
||||||
|
License, and how they can obtain a copy of this License. You may not
|
||||||
|
attempt to alter or restrict the recipients' rights in the Source Code
|
||||||
|
Form.
|
||||||
|
|
||||||
|
3.2. Distribution of Executable Form
|
||||||
|
|
||||||
|
If You distribute Covered Software in Executable Form then:
|
||||||
|
|
||||||
|
a. such Covered Software must also be made available in Source Code Form,
|
||||||
|
as described in Section 3.1, and You must inform recipients of the
|
||||||
|
Executable Form how they can obtain a copy of such Source Code Form by
|
||||||
|
reasonable means in a timely manner, at a charge no more than the cost
|
||||||
|
of distribution to the recipient; and
|
||||||
|
|
||||||
|
b. You may distribute such Executable Form under the terms of this
|
||||||
|
License, or sublicense it under different terms, provided that the
|
||||||
|
license for the Executable Form does not attempt to limit or alter the
|
||||||
|
recipients' rights in the Source Code Form under this License.
|
||||||
|
|
||||||
|
3.3. Distribution of a Larger Work
|
||||||
|
|
||||||
|
You may create and distribute a Larger Work under terms of Your choice,
|
||||||
|
provided that You also comply with the requirements of this License for
|
||||||
|
the Covered Software. If the Larger Work is a combination of Covered
|
||||||
|
Software with a work governed by one or more Secondary Licenses, and the
|
||||||
|
Covered Software is not Incompatible With Secondary Licenses, this
|
||||||
|
License permits You to additionally distribute such Covered Software
|
||||||
|
under the terms of such Secondary License(s), so that the recipient of
|
||||||
|
the Larger Work may, at their option, further distribute the Covered
|
||||||
|
Software under the terms of either this License or such Secondary
|
||||||
|
License(s).
|
||||||
|
|
||||||
|
3.4. Notices
|
||||||
|
|
||||||
|
You may not remove or alter the substance of any license notices
|
||||||
|
(including copyright notices, patent notices, disclaimers of warranty, or
|
||||||
|
limitations of liability) contained within the Source Code Form of the
|
||||||
|
Covered Software, except that You may alter any license notices to the
|
||||||
|
extent required to remedy known factual inaccuracies.
|
||||||
|
|
||||||
|
3.5. Application of Additional Terms
|
||||||
|
|
||||||
|
You may choose to offer, and to charge a fee for, warranty, support,
|
||||||
|
indemnity or liability obligations to one or more recipients of Covered
|
||||||
|
Software. However, You may do so only on Your own behalf, and not on
|
||||||
|
behalf of any Contributor. You must make it absolutely clear that any
|
||||||
|
such warranty, support, indemnity, or liability obligation is offered by
|
||||||
|
You alone, and You hereby agree to indemnify every Contributor for any
|
||||||
|
liability incurred by such Contributor as a result of warranty, support,
|
||||||
|
indemnity or liability terms You offer. You may include additional
|
||||||
|
disclaimers of warranty and limitations of liability specific to any
|
||||||
|
jurisdiction.
|
||||||
|
|
||||||
|
4. Inability to Comply Due to Statute or Regulation
|
||||||
|
|
||||||
|
If it is impossible for You to comply with any of the terms of this License
|
||||||
|
with respect to some or all of the Covered Software due to statute,
|
||||||
|
judicial order, or regulation then You must: (a) comply with the terms of
|
||||||
|
this License to the maximum extent possible; and (b) describe the
|
||||||
|
limitations and the code they affect. Such description must be placed in a
|
||||||
|
text file included with all distributions of the Covered Software under
|
||||||
|
this License. Except to the extent prohibited by statute or regulation,
|
||||||
|
such description must be sufficiently detailed for a recipient of ordinary
|
||||||
|
skill to be able to understand it.
|
||||||
|
|
||||||
|
5. Termination
|
||||||
|
|
||||||
|
5.1. The rights granted under this License will terminate automatically if You
|
||||||
|
fail to comply with any of its terms. However, if You become compliant,
|
||||||
|
then the rights granted under this License from a particular Contributor
|
||||||
|
are reinstated (a) provisionally, unless and until such Contributor
|
||||||
|
explicitly and finally terminates Your grants, and (b) on an ongoing
|
||||||
|
basis, if such Contributor fails to notify You of the non-compliance by
|
||||||
|
some reasonable means prior to 60 days after You have come back into
|
||||||
|
compliance. Moreover, Your grants from a particular Contributor are
|
||||||
|
reinstated on an ongoing basis if such Contributor notifies You of the
|
||||||
|
non-compliance by some reasonable means, this is the first time You have
|
||||||
|
received notice of non-compliance with this License from such
|
||||||
|
Contributor, and You become compliant prior to 30 days after Your receipt
|
||||||
|
of the notice.
|
||||||
|
|
||||||
|
5.2. If You initiate litigation against any entity by asserting a patent
|
||||||
|
infringement claim (excluding declaratory judgment actions,
|
||||||
|
counter-claims, and cross-claims) alleging that a Contributor Version
|
||||||
|
directly or indirectly infringes any patent, then the rights granted to
|
||||||
|
You by any and all Contributors for the Covered Software under Section
|
||||||
|
2.1 of this License shall terminate.
|
||||||
|
|
||||||
|
5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user
|
||||||
|
license agreements (excluding distributors and resellers) which have been
|
||||||
|
validly granted by You or Your distributors under this License prior to
|
||||||
|
termination shall survive termination.
|
||||||
|
|
||||||
|
6. Disclaimer of Warranty
|
||||||
|
|
||||||
|
Covered Software is provided under this License on an "as is" basis,
|
||||||
|
without warranty of any kind, either expressed, implied, or statutory,
|
||||||
|
including, without limitation, warranties that the Covered Software is free
|
||||||
|
of defects, merchantable, fit for a particular purpose or non-infringing.
|
||||||
|
The entire risk as to the quality and performance of the Covered Software
|
||||||
|
is with You. Should any Covered Software prove defective in any respect,
|
||||||
|
You (not any Contributor) assume the cost of any necessary servicing,
|
||||||
|
repair, or correction. This disclaimer of warranty constitutes an essential
|
||||||
|
part of this License. No use of any Covered Software is authorized under
|
||||||
|
this License except under this disclaimer.
|
||||||
|
|
||||||
|
7. Limitation of Liability
|
||||||
|
|
||||||
|
Under no circumstances and under no legal theory, whether tort (including
|
||||||
|
negligence), contract, or otherwise, shall any Contributor, or anyone who
|
||||||
|
distributes Covered Software as permitted above, be liable to You for any
|
||||||
|
direct, indirect, special, incidental, or consequential damages of any
|
||||||
|
character including, without limitation, damages for lost profits, loss of
|
||||||
|
goodwill, work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses, even if such party shall have been
|
||||||
|
informed of the possibility of such damages. This limitation of liability
|
||||||
|
shall not apply to liability for death or personal injury resulting from
|
||||||
|
such party's negligence to the extent applicable law prohibits such
|
||||||
|
limitation. Some jurisdictions do not allow the exclusion or limitation of
|
||||||
|
incidental or consequential damages, so this exclusion and limitation may
|
||||||
|
not apply to You.
|
||||||
|
|
||||||
|
8. Litigation
|
||||||
|
|
||||||
|
Any litigation relating to this License may be brought only in the courts
|
||||||
|
of a jurisdiction where the defendant maintains its principal place of
|
||||||
|
business and such litigation shall be governed by laws of that
|
||||||
|
jurisdiction, without reference to its conflict-of-law provisions. Nothing
|
||||||
|
in this Section shall prevent a party's ability to bring cross-claims or
|
||||||
|
counter-claims.
|
||||||
|
|
||||||
|
9. Miscellaneous
|
||||||
|
|
||||||
|
This License represents the complete agreement concerning the subject
|
||||||
|
matter hereof. If any provision of this License is held to be
|
||||||
|
unenforceable, such provision shall be reformed only to the extent
|
||||||
|
necessary to make it enforceable. Any law or regulation which provides that
|
||||||
|
the language of a contract shall be construed against the drafter shall not
|
||||||
|
be used to construe this License against a Contributor.
|
||||||
|
|
||||||
|
|
||||||
|
10. Versions of the License
|
||||||
|
|
||||||
|
10.1. New Versions
|
||||||
|
|
||||||
|
Mozilla Foundation is the license steward. Except as provided in Section
|
||||||
|
10.3, no one other than the license steward has the right to modify or
|
||||||
|
publish new versions of this License. Each version will be given a
|
||||||
|
distinguishing version number.
|
||||||
|
|
||||||
|
10.2. Effect of New Versions
|
||||||
|
|
||||||
|
You may distribute the Covered Software under the terms of the version
|
||||||
|
of the License under which You originally received the Covered Software,
|
||||||
|
or under the terms of any subsequent version published by the license
|
||||||
|
steward.
|
||||||
|
|
||||||
|
10.3. Modified Versions
|
||||||
|
|
||||||
|
If you create software not governed by this License, and you want to
|
||||||
|
create a new license for such software, you may create and use a
|
||||||
|
modified version of this License if you rename the license and remove
|
||||||
|
any references to the name of the license steward (except to note that
|
||||||
|
such modified license differs from this License).
|
||||||
|
|
||||||
|
10.4. Distributing Source Code Form that is Incompatible With Secondary
|
||||||
|
Licenses If You choose to distribute Source Code Form that is
|
||||||
|
Incompatible With Secondary Licenses under the terms of this version of
|
||||||
|
the License, the notice described in Exhibit B of this License must be
|
||||||
|
attached.
|
||||||
|
|
||||||
|
Exhibit A - Source Code Form License Notice
|
||||||
|
|
||||||
|
This Source Code Form is subject to the
|
||||||
|
terms of the Mozilla Public License, v.
|
||||||
|
2.0. If a copy of the MPL was not
|
||||||
|
distributed with this file, You can
|
||||||
|
obtain one at
|
||||||
|
http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
If it is not possible or desirable to put the notice in a particular file,
|
||||||
|
then You may include the notice in a location (such as a LICENSE file in a
|
||||||
|
relevant directory) where a recipient would be likely to look for such a
|
||||||
|
notice.
|
||||||
|
|
||||||
|
You may add additional accurate notices of copyright ownership.
|
||||||
|
|
||||||
|
Exhibit B - "Incompatible With Secondary Licenses" Notice
|
||||||
|
|
||||||
|
This Source Code Form is "Incompatible
|
||||||
|
With Secondary Licenses", as defined by
|
||||||
|
the Mozilla Public License, v. 2.0.
|
161
vendor/github.com/hashicorp/golang-lru/simplelru/lru.go
generated
vendored
Normal file
161
vendor/github.com/hashicorp/golang-lru/simplelru/lru.go
generated
vendored
Normal file
|
@ -0,0 +1,161 @@
|
||||||
|
package simplelru
|
||||||
|
|
||||||
|
import (
|
||||||
|
"container/list"
|
||||||
|
"errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
// EvictCallback is used to get a callback when a cache entry is evicted
|
||||||
|
type EvictCallback func(key interface{}, value interface{})
|
||||||
|
|
||||||
|
// LRU implements a non-thread safe fixed size LRU cache
|
||||||
|
type LRU struct {
|
||||||
|
size int
|
||||||
|
evictList *list.List
|
||||||
|
items map[interface{}]*list.Element
|
||||||
|
onEvict EvictCallback
|
||||||
|
}
|
||||||
|
|
||||||
|
// entry is used to hold a value in the evictList
|
||||||
|
type entry struct {
|
||||||
|
key interface{}
|
||||||
|
value interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewLRU constructs an LRU of the given size
|
||||||
|
func NewLRU(size int, onEvict EvictCallback) (*LRU, error) {
|
||||||
|
if size <= 0 {
|
||||||
|
return nil, errors.New("Must provide a positive size")
|
||||||
|
}
|
||||||
|
c := &LRU{
|
||||||
|
size: size,
|
||||||
|
evictList: list.New(),
|
||||||
|
items: make(map[interface{}]*list.Element),
|
||||||
|
onEvict: onEvict,
|
||||||
|
}
|
||||||
|
return c, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Purge is used to completely clear the cache.
|
||||||
|
func (c *LRU) Purge() {
|
||||||
|
for k, v := range c.items {
|
||||||
|
if c.onEvict != nil {
|
||||||
|
c.onEvict(k, v.Value.(*entry).value)
|
||||||
|
}
|
||||||
|
delete(c.items, k)
|
||||||
|
}
|
||||||
|
c.evictList.Init()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add adds a value to the cache. Returns true if an eviction occurred.
|
||||||
|
func (c *LRU) Add(key, value interface{}) (evicted bool) {
|
||||||
|
// Check for existing item
|
||||||
|
if ent, ok := c.items[key]; ok {
|
||||||
|
c.evictList.MoveToFront(ent)
|
||||||
|
ent.Value.(*entry).value = value
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add new item
|
||||||
|
ent := &entry{key, value}
|
||||||
|
entry := c.evictList.PushFront(ent)
|
||||||
|
c.items[key] = entry
|
||||||
|
|
||||||
|
evict := c.evictList.Len() > c.size
|
||||||
|
// Verify size not exceeded
|
||||||
|
if evict {
|
||||||
|
c.removeOldest()
|
||||||
|
}
|
||||||
|
return evict
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get looks up a key's value from the cache.
|
||||||
|
func (c *LRU) Get(key interface{}) (value interface{}, ok bool) {
|
||||||
|
if ent, ok := c.items[key]; ok {
|
||||||
|
c.evictList.MoveToFront(ent)
|
||||||
|
return ent.Value.(*entry).value, true
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Contains checks if a key is in the cache, without updating the recent-ness
|
||||||
|
// or deleting it for being stale.
|
||||||
|
func (c *LRU) Contains(key interface{}) (ok bool) {
|
||||||
|
_, ok = c.items[key]
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// Peek returns the key value (or undefined if not found) without updating
|
||||||
|
// the "recently used"-ness of the key.
|
||||||
|
func (c *LRU) Peek(key interface{}) (value interface{}, ok bool) {
|
||||||
|
var ent *list.Element
|
||||||
|
if ent, ok = c.items[key]; ok {
|
||||||
|
return ent.Value.(*entry).value, true
|
||||||
|
}
|
||||||
|
return nil, ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove removes the provided key from the cache, returning if the
|
||||||
|
// key was contained.
|
||||||
|
func (c *LRU) Remove(key interface{}) (present bool) {
|
||||||
|
if ent, ok := c.items[key]; ok {
|
||||||
|
c.removeElement(ent)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoveOldest removes the oldest item from the cache.
|
||||||
|
func (c *LRU) RemoveOldest() (key interface{}, value interface{}, ok bool) {
|
||||||
|
ent := c.evictList.Back()
|
||||||
|
if ent != nil {
|
||||||
|
c.removeElement(ent)
|
||||||
|
kv := ent.Value.(*entry)
|
||||||
|
return kv.key, kv.value, true
|
||||||
|
}
|
||||||
|
return nil, nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetOldest returns the oldest entry
|
||||||
|
func (c *LRU) GetOldest() (key interface{}, value interface{}, ok bool) {
|
||||||
|
ent := c.evictList.Back()
|
||||||
|
if ent != nil {
|
||||||
|
kv := ent.Value.(*entry)
|
||||||
|
return kv.key, kv.value, true
|
||||||
|
}
|
||||||
|
return nil, nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Keys returns a slice of the keys in the cache, from oldest to newest.
|
||||||
|
func (c *LRU) Keys() []interface{} {
|
||||||
|
keys := make([]interface{}, len(c.items))
|
||||||
|
i := 0
|
||||||
|
for ent := c.evictList.Back(); ent != nil; ent = ent.Prev() {
|
||||||
|
keys[i] = ent.Value.(*entry).key
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
return keys
|
||||||
|
}
|
||||||
|
|
||||||
|
// Len returns the number of items in the cache.
|
||||||
|
func (c *LRU) Len() int {
|
||||||
|
return c.evictList.Len()
|
||||||
|
}
|
||||||
|
|
||||||
|
// removeOldest removes the oldest item from the cache.
|
||||||
|
func (c *LRU) removeOldest() {
|
||||||
|
ent := c.evictList.Back()
|
||||||
|
if ent != nil {
|
||||||
|
c.removeElement(ent)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// removeElement is used to remove a given list element from the cache
|
||||||
|
func (c *LRU) removeElement(e *list.Element) {
|
||||||
|
c.evictList.Remove(e)
|
||||||
|
kv := e.Value.(*entry)
|
||||||
|
delete(c.items, kv.key)
|
||||||
|
if c.onEvict != nil {
|
||||||
|
c.onEvict(kv.key, kv.value)
|
||||||
|
}
|
||||||
|
}
|
36
vendor/github.com/hashicorp/golang-lru/simplelru/lru_interface.go
generated
vendored
Normal file
36
vendor/github.com/hashicorp/golang-lru/simplelru/lru_interface.go
generated
vendored
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
package simplelru
|
||||||
|
|
||||||
|
// LRUCache is the interface for simple LRU cache.
|
||||||
|
type LRUCache interface {
|
||||||
|
// Adds a value to the cache, returns true if an eviction occurred and
|
||||||
|
// updates the "recently used"-ness of the key.
|
||||||
|
Add(key, value interface{}) bool
|
||||||
|
|
||||||
|
// Returns key's value from the cache and
|
||||||
|
// updates the "recently used"-ness of the key. #value, isFound
|
||||||
|
Get(key interface{}) (value interface{}, ok bool)
|
||||||
|
|
||||||
|
// Check if a key exsists in cache without updating the recent-ness.
|
||||||
|
Contains(key interface{}) (ok bool)
|
||||||
|
|
||||||
|
// Returns key's value without updating the "recently used"-ness of the key.
|
||||||
|
Peek(key interface{}) (value interface{}, ok bool)
|
||||||
|
|
||||||
|
// Removes a key from the cache.
|
||||||
|
Remove(key interface{}) bool
|
||||||
|
|
||||||
|
// Removes the oldest entry from cache.
|
||||||
|
RemoveOldest() (interface{}, interface{}, bool)
|
||||||
|
|
||||||
|
// Returns the oldest entry from the cache. #key, value, isFound
|
||||||
|
GetOldest() (interface{}, interface{}, bool)
|
||||||
|
|
||||||
|
// Returns a slice of the keys in the cache, from oldest to newest.
|
||||||
|
Keys() []interface{}
|
||||||
|
|
||||||
|
// Returns the number of items in the cache.
|
||||||
|
Len() int
|
||||||
|
|
||||||
|
// Clear all cache entries
|
||||||
|
Purge()
|
||||||
|
}
|
1
vendor/go.opencensus.io/AUTHORS
generated
vendored
Normal file
1
vendor/go.opencensus.io/AUTHORS
generated
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Google Inc.
|
202
vendor/go.opencensus.io/LICENSE
generated
vendored
Normal file
202
vendor/go.opencensus.io/LICENSE
generated
vendored
Normal file
|
@ -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.
|
37
vendor/go.opencensus.io/internal/internal.go
generated
vendored
Normal file
37
vendor/go.opencensus.io/internal/internal.go
generated
vendored
Normal file
|
@ -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.Now().Sub(start))
|
||||||
|
}
|
50
vendor/go.opencensus.io/internal/sanitize.go
generated
vendored
Normal file
50
vendor/go.opencensus.io/internal/sanitize.go
generated
vendored
Normal file
|
@ -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 '_'
|
||||||
|
}
|
75
vendor/go.opencensus.io/internal/tagencoding/tagencoding.go
generated
vendored
Normal file
75
vendor/go.opencensus.io/internal/tagencoding/tagencoding.go
generated
vendored
Normal file
|
@ -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]
|
||||||
|
}
|
53
vendor/go.opencensus.io/internal/traceinternals.go
generated
vendored
Normal file
53
vendor/go.opencensus.io/internal/traceinternals.go
generated
vendored
Normal file
|
@ -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
|
||||||
|
}
|
19
vendor/go.opencensus.io/metric/metricdata/doc.go
generated
vendored
Normal file
19
vendor/go.opencensus.io/metric/metricdata/doc.go
generated
vendored
Normal file
|
@ -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"
|
33
vendor/go.opencensus.io/metric/metricdata/exemplar.go
generated
vendored
Normal file
33
vendor/go.opencensus.io/metric/metricdata/exemplar.go
generated
vendored
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
// 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"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 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{}
|
28
vendor/go.opencensus.io/metric/metricdata/label.go
generated
vendored
Normal file
28
vendor/go.opencensus.io/metric/metricdata/label.go
generated
vendored
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
// 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
|
||||||
|
|
||||||
|
// 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}
|
||||||
|
}
|
46
vendor/go.opencensus.io/metric/metricdata/metric.go
generated
vendored
Normal file
46
vendor/go.opencensus.io/metric/metricdata/metric.go
generated
vendored
Normal file
|
@ -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 []string // 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
|
||||||
|
}
|
193
vendor/go.opencensus.io/metric/metricdata/point.go
generated
vendored
Normal file
193
vendor/go.opencensus.io/metric/metricdata/point.go
generated
vendored
Normal file
|
@ -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
|
||||||
|
)
|
16
vendor/go.opencensus.io/metric/metricdata/type_string.go
generated
vendored
Normal file
16
vendor/go.opencensus.io/metric/metricdata/type_string.go
generated
vendored
Normal file
|
@ -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]]
|
||||||
|
}
|
27
vendor/go.opencensus.io/metric/metricdata/unit.go
generated
vendored
Normal file
27
vendor/go.opencensus.io/metric/metricdata/unit.go
generated
vendored
Normal file
|
@ -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"
|
||||||
|
)
|
78
vendor/go.opencensus.io/metric/metricproducer/manager.go
generated
vendored
Normal file
78
vendor/go.opencensus.io/metric/metricproducer/manager.go
generated
vendored
Normal file
|
@ -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
|
||||||
|
}
|
28
vendor/go.opencensus.io/metric/metricproducer/producer.go
generated
vendored
Normal file
28
vendor/go.opencensus.io/metric/metricproducer/producer.go
generated
vendored
Normal file
|
@ -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
|
||||||
|
}
|
21
vendor/go.opencensus.io/opencensus.go
generated
vendored
Normal file
21
vendor/go.opencensus.io/opencensus.go
generated
vendored
Normal file
|
@ -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.21.0"
|
||||||
|
}
|
117
vendor/go.opencensus.io/plugin/ochttp/client.go
generated
vendored
Normal file
117
vendor/go.opencensus.io/plugin/ochttp/client.go
generated
vendored
Normal file
|
@ -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 ochttp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptrace"
|
||||||
|
|
||||||
|
"go.opencensus.io/trace"
|
||||||
|
"go.opencensus.io/trace/propagation"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Transport is an http.RoundTripper that instruments all outgoing requests with
|
||||||
|
// OpenCensus stats and tracing.
|
||||||
|
//
|
||||||
|
// The zero value is intended to be a useful default, but for
|
||||||
|
// now it's recommended that you explicitly set Propagation, since the default
|
||||||
|
// for this may change.
|
||||||
|
type Transport struct {
|
||||||
|
// Base may be set to wrap another http.RoundTripper that does the actual
|
||||||
|
// requests. By default http.DefaultTransport is used.
|
||||||
|
//
|
||||||
|
// If base HTTP roundtripper implements CancelRequest,
|
||||||
|
// the returned round tripper will be cancelable.
|
||||||
|
Base http.RoundTripper
|
||||||
|
|
||||||
|
// Propagation defines how traces are propagated. If unspecified, a default
|
||||||
|
// (currently B3 format) will be used.
|
||||||
|
Propagation propagation.HTTPFormat
|
||||||
|
|
||||||
|
// StartOptions are applied to the span started by this Transport around each
|
||||||
|
// request.
|
||||||
|
//
|
||||||
|
// StartOptions.SpanKind will always be set to trace.SpanKindClient
|
||||||
|
// for spans started by this transport.
|
||||||
|
StartOptions trace.StartOptions
|
||||||
|
|
||||||
|
// GetStartOptions allows to set start options per request. If set,
|
||||||
|
// StartOptions is going to be ignored.
|
||||||
|
GetStartOptions func(*http.Request) trace.StartOptions
|
||||||
|
|
||||||
|
// NameFromRequest holds the function to use for generating the span name
|
||||||
|
// from the information found in the outgoing HTTP Request. By default the
|
||||||
|
// name equals the URL Path.
|
||||||
|
FormatSpanName func(*http.Request) string
|
||||||
|
|
||||||
|
// NewClientTrace may be set to a function allowing the current *trace.Span
|
||||||
|
// to be annotated with HTTP request event information emitted by the
|
||||||
|
// httptrace package.
|
||||||
|
NewClientTrace func(*http.Request, *trace.Span) *httptrace.ClientTrace
|
||||||
|
|
||||||
|
// TODO: Implement tag propagation for HTTP.
|
||||||
|
}
|
||||||
|
|
||||||
|
// RoundTrip implements http.RoundTripper, delegating to Base and recording stats and traces for the request.
|
||||||
|
func (t *Transport) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||||
|
rt := t.base()
|
||||||
|
if isHealthEndpoint(req.URL.Path) {
|
||||||
|
return rt.RoundTrip(req)
|
||||||
|
}
|
||||||
|
// TODO: remove excessive nesting of http.RoundTrippers here.
|
||||||
|
format := t.Propagation
|
||||||
|
if format == nil {
|
||||||
|
format = defaultFormat
|
||||||
|
}
|
||||||
|
spanNameFormatter := t.FormatSpanName
|
||||||
|
if spanNameFormatter == nil {
|
||||||
|
spanNameFormatter = spanNameFromURL
|
||||||
|
}
|
||||||
|
|
||||||
|
startOpts := t.StartOptions
|
||||||
|
if t.GetStartOptions != nil {
|
||||||
|
startOpts = t.GetStartOptions(req)
|
||||||
|
}
|
||||||
|
|
||||||
|
rt = &traceTransport{
|
||||||
|
base: rt,
|
||||||
|
format: format,
|
||||||
|
startOptions: trace.StartOptions{
|
||||||
|
Sampler: startOpts.Sampler,
|
||||||
|
SpanKind: trace.SpanKindClient,
|
||||||
|
},
|
||||||
|
formatSpanName: spanNameFormatter,
|
||||||
|
newClientTrace: t.NewClientTrace,
|
||||||
|
}
|
||||||
|
rt = statsTransport{base: rt}
|
||||||
|
return rt.RoundTrip(req)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Transport) base() http.RoundTripper {
|
||||||
|
if t.Base != nil {
|
||||||
|
return t.Base
|
||||||
|
}
|
||||||
|
return http.DefaultTransport
|
||||||
|
}
|
||||||
|
|
||||||
|
// CancelRequest cancels an in-flight request by closing its connection.
|
||||||
|
func (t *Transport) CancelRequest(req *http.Request) {
|
||||||
|
type canceler interface {
|
||||||
|
CancelRequest(*http.Request)
|
||||||
|
}
|
||||||
|
if cr, ok := t.base().(canceler); ok {
|
||||||
|
cr.CancelRequest(req)
|
||||||
|
}
|
||||||
|
}
|
143
vendor/go.opencensus.io/plugin/ochttp/client_stats.go
generated
vendored
Normal file
143
vendor/go.opencensus.io/plugin/ochttp/client_stats.go
generated
vendored
Normal file
|
@ -0,0 +1,143 @@
|
||||||
|
// 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 ochttp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"go.opencensus.io/stats"
|
||||||
|
"go.opencensus.io/tag"
|
||||||
|
)
|
||||||
|
|
||||||
|
// statsTransport is an http.RoundTripper that collects stats for the outgoing requests.
|
||||||
|
type statsTransport struct {
|
||||||
|
base http.RoundTripper
|
||||||
|
}
|
||||||
|
|
||||||
|
// RoundTrip implements http.RoundTripper, delegating to Base and recording stats for the request.
|
||||||
|
func (t statsTransport) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||||
|
ctx, _ := tag.New(req.Context(),
|
||||||
|
tag.Upsert(KeyClientHost, req.Host),
|
||||||
|
tag.Upsert(Host, req.Host),
|
||||||
|
tag.Upsert(KeyClientPath, req.URL.Path),
|
||||||
|
tag.Upsert(Path, req.URL.Path),
|
||||||
|
tag.Upsert(KeyClientMethod, req.Method),
|
||||||
|
tag.Upsert(Method, req.Method))
|
||||||
|
req = req.WithContext(ctx)
|
||||||
|
track := &tracker{
|
||||||
|
start: time.Now(),
|
||||||
|
ctx: ctx,
|
||||||
|
}
|
||||||
|
if req.Body == nil {
|
||||||
|
// TODO: Handle cases where ContentLength is not set.
|
||||||
|
track.reqSize = -1
|
||||||
|
} else if req.ContentLength > 0 {
|
||||||
|
track.reqSize = req.ContentLength
|
||||||
|
}
|
||||||
|
stats.Record(ctx, ClientRequestCount.M(1))
|
||||||
|
|
||||||
|
// Perform request.
|
||||||
|
resp, err := t.base.RoundTrip(req)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
track.statusCode = http.StatusInternalServerError
|
||||||
|
track.end()
|
||||||
|
} else {
|
||||||
|
track.statusCode = resp.StatusCode
|
||||||
|
if req.Method != "HEAD" {
|
||||||
|
track.respContentLength = resp.ContentLength
|
||||||
|
}
|
||||||
|
if resp.Body == nil {
|
||||||
|
track.end()
|
||||||
|
} else {
|
||||||
|
track.body = resp.Body
|
||||||
|
resp.Body = wrappedBody(track, resp.Body)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// CancelRequest cancels an in-flight request by closing its connection.
|
||||||
|
func (t statsTransport) CancelRequest(req *http.Request) {
|
||||||
|
type canceler interface {
|
||||||
|
CancelRequest(*http.Request)
|
||||||
|
}
|
||||||
|
if cr, ok := t.base.(canceler); ok {
|
||||||
|
cr.CancelRequest(req)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type tracker struct {
|
||||||
|
ctx context.Context
|
||||||
|
respSize int64
|
||||||
|
respContentLength int64
|
||||||
|
reqSize int64
|
||||||
|
start time.Time
|
||||||
|
body io.ReadCloser
|
||||||
|
statusCode int
|
||||||
|
endOnce sync.Once
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ io.ReadCloser = (*tracker)(nil)
|
||||||
|
|
||||||
|
func (t *tracker) end() {
|
||||||
|
t.endOnce.Do(func() {
|
||||||
|
latencyMs := float64(time.Since(t.start)) / float64(time.Millisecond)
|
||||||
|
respSize := t.respSize
|
||||||
|
if t.respSize == 0 && t.respContentLength > 0 {
|
||||||
|
respSize = t.respContentLength
|
||||||
|
}
|
||||||
|
m := []stats.Measurement{
|
||||||
|
ClientSentBytes.M(t.reqSize),
|
||||||
|
ClientReceivedBytes.M(respSize),
|
||||||
|
ClientRoundtripLatency.M(latencyMs),
|
||||||
|
ClientLatency.M(latencyMs),
|
||||||
|
ClientResponseBytes.M(t.respSize),
|
||||||
|
}
|
||||||
|
if t.reqSize >= 0 {
|
||||||
|
m = append(m, ClientRequestBytes.M(t.reqSize))
|
||||||
|
}
|
||||||
|
|
||||||
|
stats.RecordWithTags(t.ctx, []tag.Mutator{
|
||||||
|
tag.Upsert(StatusCode, strconv.Itoa(t.statusCode)),
|
||||||
|
tag.Upsert(KeyClientStatus, strconv.Itoa(t.statusCode)),
|
||||||
|
}, m...)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tracker) Read(b []byte) (int, error) {
|
||||||
|
n, err := t.body.Read(b)
|
||||||
|
t.respSize += int64(n)
|
||||||
|
switch err {
|
||||||
|
case nil:
|
||||||
|
return n, nil
|
||||||
|
case io.EOF:
|
||||||
|
t.end()
|
||||||
|
}
|
||||||
|
return n, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tracker) Close() error {
|
||||||
|
// Invoking endSpan on Close will help catch the cases
|
||||||
|
// in which a read returned a non-nil error, we set the
|
||||||
|
// span status but didn't end the span.
|
||||||
|
t.end()
|
||||||
|
return t.body.Close()
|
||||||
|
}
|
19
vendor/go.opencensus.io/plugin/ochttp/doc.go
generated
vendored
Normal file
19
vendor/go.opencensus.io/plugin/ochttp/doc.go
generated
vendored
Normal file
|
@ -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 ochttp provides OpenCensus instrumentation for net/http package.
|
||||||
|
//
|
||||||
|
// For server instrumentation, see Handler. For client-side instrumentation,
|
||||||
|
// see Transport.
|
||||||
|
package ochttp // import "go.opencensus.io/plugin/ochttp"
|
123
vendor/go.opencensus.io/plugin/ochttp/propagation/b3/b3.go
generated
vendored
Normal file
123
vendor/go.opencensus.io/plugin/ochttp/propagation/b3/b3.go
generated
vendored
Normal file
|
@ -0,0 +1,123 @@
|
||||||
|
// 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 b3 contains a propagation.HTTPFormat implementation
|
||||||
|
// for B3 propagation. See https://github.com/openzipkin/b3-propagation
|
||||||
|
// for more details.
|
||||||
|
package b3 // import "go.opencensus.io/plugin/ochttp/propagation/b3"
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/hex"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"go.opencensus.io/trace"
|
||||||
|
"go.opencensus.io/trace/propagation"
|
||||||
|
)
|
||||||
|
|
||||||
|
// B3 headers that OpenCensus understands.
|
||||||
|
const (
|
||||||
|
TraceIDHeader = "X-B3-TraceId"
|
||||||
|
SpanIDHeader = "X-B3-SpanId"
|
||||||
|
SampledHeader = "X-B3-Sampled"
|
||||||
|
)
|
||||||
|
|
||||||
|
// HTTPFormat implements propagation.HTTPFormat to propagate
|
||||||
|
// traces in HTTP headers in B3 propagation format.
|
||||||
|
// HTTPFormat skips the X-B3-ParentId and X-B3-Flags headers
|
||||||
|
// because there are additional fields not represented in the
|
||||||
|
// OpenCensus span context. Spans created from the incoming
|
||||||
|
// header will be the direct children of the client-side span.
|
||||||
|
// Similarly, receiver of the outgoing spans should use client-side
|
||||||
|
// span created by OpenCensus as the parent.
|
||||||
|
type HTTPFormat struct{}
|
||||||
|
|
||||||
|
var _ propagation.HTTPFormat = (*HTTPFormat)(nil)
|
||||||
|
|
||||||
|
// SpanContextFromRequest extracts a B3 span context from incoming requests.
|
||||||
|
func (f *HTTPFormat) SpanContextFromRequest(req *http.Request) (sc trace.SpanContext, ok bool) {
|
||||||
|
tid, ok := ParseTraceID(req.Header.Get(TraceIDHeader))
|
||||||
|
if !ok {
|
||||||
|
return trace.SpanContext{}, false
|
||||||
|
}
|
||||||
|
sid, ok := ParseSpanID(req.Header.Get(SpanIDHeader))
|
||||||
|
if !ok {
|
||||||
|
return trace.SpanContext{}, false
|
||||||
|
}
|
||||||
|
sampled, _ := ParseSampled(req.Header.Get(SampledHeader))
|
||||||
|
return trace.SpanContext{
|
||||||
|
TraceID: tid,
|
||||||
|
SpanID: sid,
|
||||||
|
TraceOptions: sampled,
|
||||||
|
}, true
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseTraceID parses the value of the X-B3-TraceId header.
|
||||||
|
func ParseTraceID(tid string) (trace.TraceID, bool) {
|
||||||
|
if tid == "" {
|
||||||
|
return trace.TraceID{}, false
|
||||||
|
}
|
||||||
|
b, err := hex.DecodeString(tid)
|
||||||
|
if err != nil {
|
||||||
|
return trace.TraceID{}, false
|
||||||
|
}
|
||||||
|
var traceID trace.TraceID
|
||||||
|
if len(b) <= 8 {
|
||||||
|
// The lower 64-bits.
|
||||||
|
start := 8 + (8 - len(b))
|
||||||
|
copy(traceID[start:], b)
|
||||||
|
} else {
|
||||||
|
start := 16 - len(b)
|
||||||
|
copy(traceID[start:], b)
|
||||||
|
}
|
||||||
|
|
||||||
|
return traceID, true
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseSpanID parses the value of the X-B3-SpanId or X-B3-ParentSpanId headers.
|
||||||
|
func ParseSpanID(sid string) (spanID trace.SpanID, ok bool) {
|
||||||
|
if sid == "" {
|
||||||
|
return trace.SpanID{}, false
|
||||||
|
}
|
||||||
|
b, err := hex.DecodeString(sid)
|
||||||
|
if err != nil {
|
||||||
|
return trace.SpanID{}, false
|
||||||
|
}
|
||||||
|
start := 8 - len(b)
|
||||||
|
copy(spanID[start:], b)
|
||||||
|
return spanID, true
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseSampled parses the value of the X-B3-Sampled header.
|
||||||
|
func ParseSampled(sampled string) (trace.TraceOptions, bool) {
|
||||||
|
switch sampled {
|
||||||
|
case "true", "1":
|
||||||
|
return trace.TraceOptions(1), true
|
||||||
|
default:
|
||||||
|
return trace.TraceOptions(0), false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SpanContextToRequest modifies the given request to include B3 headers.
|
||||||
|
func (f *HTTPFormat) SpanContextToRequest(sc trace.SpanContext, req *http.Request) {
|
||||||
|
req.Header.Set(TraceIDHeader, hex.EncodeToString(sc.TraceID[:]))
|
||||||
|
req.Header.Set(SpanIDHeader, hex.EncodeToString(sc.SpanID[:]))
|
||||||
|
|
||||||
|
var sampled string
|
||||||
|
if sc.IsSampled() {
|
||||||
|
sampled = "1"
|
||||||
|
} else {
|
||||||
|
sampled = "0"
|
||||||
|
}
|
||||||
|
req.Header.Set(SampledHeader, sampled)
|
||||||
|
}
|
61
vendor/go.opencensus.io/plugin/ochttp/route.go
generated
vendored
Normal file
61
vendor/go.opencensus.io/plugin/ochttp/route.go
generated
vendored
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
// 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 ochttp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"go.opencensus.io/tag"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SetRoute sets the http_server_route tag to the given value.
|
||||||
|
// It's useful when an HTTP framework does not support the http.Handler interface
|
||||||
|
// and using WithRouteTag is not an option, but provides a way to hook into the request flow.
|
||||||
|
func SetRoute(ctx context.Context, route string) {
|
||||||
|
if a, ok := ctx.Value(addedTagsKey{}).(*addedTags); ok {
|
||||||
|
a.t = append(a.t, tag.Upsert(KeyServerRoute, route))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithRouteTag returns an http.Handler that records stats with the
|
||||||
|
// http_server_route tag set to the given value.
|
||||||
|
func WithRouteTag(handler http.Handler, route string) http.Handler {
|
||||||
|
return taggedHandlerFunc(func(w http.ResponseWriter, r *http.Request) []tag.Mutator {
|
||||||
|
addRoute := []tag.Mutator{tag.Upsert(KeyServerRoute, route)}
|
||||||
|
ctx, _ := tag.New(r.Context(), addRoute...)
|
||||||
|
r = r.WithContext(ctx)
|
||||||
|
handler.ServeHTTP(w, r)
|
||||||
|
return addRoute
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// taggedHandlerFunc is a http.Handler that returns tags describing the
|
||||||
|
// processing of the request. These tags will be recorded along with the
|
||||||
|
// measures in this package at the end of the request.
|
||||||
|
type taggedHandlerFunc func(w http.ResponseWriter, r *http.Request) []tag.Mutator
|
||||||
|
|
||||||
|
func (h taggedHandlerFunc) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
|
tags := h(w, r)
|
||||||
|
if a, ok := r.Context().Value(addedTagsKey{}).(*addedTags); ok {
|
||||||
|
a.t = append(a.t, tags...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type addedTagsKey struct{}
|
||||||
|
|
||||||
|
type addedTags struct {
|
||||||
|
t []tag.Mutator
|
||||||
|
}
|
440
vendor/go.opencensus.io/plugin/ochttp/server.go
generated
vendored
Normal file
440
vendor/go.opencensus.io/plugin/ochttp/server.go
generated
vendored
Normal file
|
@ -0,0 +1,440 @@
|
||||||
|
// 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 ochttp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"go.opencensus.io/stats"
|
||||||
|
"go.opencensus.io/tag"
|
||||||
|
"go.opencensus.io/trace"
|
||||||
|
"go.opencensus.io/trace/propagation"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Handler is an http.Handler wrapper to instrument your HTTP server with
|
||||||
|
// OpenCensus. It supports both stats and tracing.
|
||||||
|
//
|
||||||
|
// Tracing
|
||||||
|
//
|
||||||
|
// This handler is aware of the incoming request's span, reading it from request
|
||||||
|
// headers as configured using the Propagation field.
|
||||||
|
// The extracted span can be accessed from the incoming request's
|
||||||
|
// context.
|
||||||
|
//
|
||||||
|
// span := trace.FromContext(r.Context())
|
||||||
|
//
|
||||||
|
// The server span will be automatically ended at the end of ServeHTTP.
|
||||||
|
type Handler struct {
|
||||||
|
// Propagation defines how traces are propagated. If unspecified,
|
||||||
|
// B3 propagation will be used.
|
||||||
|
Propagation propagation.HTTPFormat
|
||||||
|
|
||||||
|
// Handler is the handler used to handle the incoming request.
|
||||||
|
Handler http.Handler
|
||||||
|
|
||||||
|
// StartOptions are applied to the span started by this Handler around each
|
||||||
|
// request.
|
||||||
|
//
|
||||||
|
// StartOptions.SpanKind will always be set to trace.SpanKindServer
|
||||||
|
// for spans started by this transport.
|
||||||
|
StartOptions trace.StartOptions
|
||||||
|
|
||||||
|
// GetStartOptions allows to set start options per request. If set,
|
||||||
|
// StartOptions is going to be ignored.
|
||||||
|
GetStartOptions func(*http.Request) trace.StartOptions
|
||||||
|
|
||||||
|
// IsPublicEndpoint should be set to true for publicly accessible HTTP(S)
|
||||||
|
// servers. If true, any trace metadata set on the incoming request will
|
||||||
|
// be added as a linked trace instead of being added as a parent of the
|
||||||
|
// current trace.
|
||||||
|
IsPublicEndpoint bool
|
||||||
|
|
||||||
|
// FormatSpanName holds the function to use for generating the span name
|
||||||
|
// from the information found in the incoming HTTP Request. By default the
|
||||||
|
// name equals the URL Path.
|
||||||
|
FormatSpanName func(*http.Request) string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
|
var tags addedTags
|
||||||
|
r, traceEnd := h.startTrace(w, r)
|
||||||
|
defer traceEnd()
|
||||||
|
w, statsEnd := h.startStats(w, r)
|
||||||
|
defer statsEnd(&tags)
|
||||||
|
handler := h.Handler
|
||||||
|
if handler == nil {
|
||||||
|
handler = http.DefaultServeMux
|
||||||
|
}
|
||||||
|
r = r.WithContext(context.WithValue(r.Context(), addedTagsKey{}, &tags))
|
||||||
|
handler.ServeHTTP(w, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handler) startTrace(w http.ResponseWriter, r *http.Request) (*http.Request, func()) {
|
||||||
|
if isHealthEndpoint(r.URL.Path) {
|
||||||
|
return r, func() {}
|
||||||
|
}
|
||||||
|
var name string
|
||||||
|
if h.FormatSpanName == nil {
|
||||||
|
name = spanNameFromURL(r)
|
||||||
|
} else {
|
||||||
|
name = h.FormatSpanName(r)
|
||||||
|
}
|
||||||
|
ctx := r.Context()
|
||||||
|
|
||||||
|
startOpts := h.StartOptions
|
||||||
|
if h.GetStartOptions != nil {
|
||||||
|
startOpts = h.GetStartOptions(r)
|
||||||
|
}
|
||||||
|
|
||||||
|
var span *trace.Span
|
||||||
|
sc, ok := h.extractSpanContext(r)
|
||||||
|
if ok && !h.IsPublicEndpoint {
|
||||||
|
ctx, span = trace.StartSpanWithRemoteParent(ctx, name, sc,
|
||||||
|
trace.WithSampler(startOpts.Sampler),
|
||||||
|
trace.WithSpanKind(trace.SpanKindServer))
|
||||||
|
} else {
|
||||||
|
ctx, span = trace.StartSpan(ctx, name,
|
||||||
|
trace.WithSampler(startOpts.Sampler),
|
||||||
|
trace.WithSpanKind(trace.SpanKindServer),
|
||||||
|
)
|
||||||
|
if ok {
|
||||||
|
span.AddLink(trace.Link{
|
||||||
|
TraceID: sc.TraceID,
|
||||||
|
SpanID: sc.SpanID,
|
||||||
|
Type: trace.LinkTypeParent,
|
||||||
|
Attributes: nil,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
span.AddAttributes(requestAttrs(r)...)
|
||||||
|
return r.WithContext(ctx), span.End
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handler) extractSpanContext(r *http.Request) (trace.SpanContext, bool) {
|
||||||
|
if h.Propagation == nil {
|
||||||
|
return defaultFormat.SpanContextFromRequest(r)
|
||||||
|
}
|
||||||
|
return h.Propagation.SpanContextFromRequest(r)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handler) startStats(w http.ResponseWriter, r *http.Request) (http.ResponseWriter, func(tags *addedTags)) {
|
||||||
|
ctx, _ := tag.New(r.Context(),
|
||||||
|
tag.Upsert(Host, r.Host),
|
||||||
|
tag.Upsert(Path, r.URL.Path),
|
||||||
|
tag.Upsert(Method, r.Method))
|
||||||
|
track := &trackingResponseWriter{
|
||||||
|
start: time.Now(),
|
||||||
|
ctx: ctx,
|
||||||
|
writer: w,
|
||||||
|
}
|
||||||
|
if r.Body == nil {
|
||||||
|
// TODO: Handle cases where ContentLength is not set.
|
||||||
|
track.reqSize = -1
|
||||||
|
} else if r.ContentLength > 0 {
|
||||||
|
track.reqSize = r.ContentLength
|
||||||
|
}
|
||||||
|
stats.Record(ctx, ServerRequestCount.M(1))
|
||||||
|
return track.wrappedResponseWriter(), track.end
|
||||||
|
}
|
||||||
|
|
||||||
|
type trackingResponseWriter struct {
|
||||||
|
ctx context.Context
|
||||||
|
reqSize int64
|
||||||
|
respSize int64
|
||||||
|
start time.Time
|
||||||
|
statusCode int
|
||||||
|
statusLine string
|
||||||
|
endOnce sync.Once
|
||||||
|
writer http.ResponseWriter
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compile time assertion for ResponseWriter interface
|
||||||
|
var _ http.ResponseWriter = (*trackingResponseWriter)(nil)
|
||||||
|
|
||||||
|
var logTagsErrorOnce sync.Once
|
||||||
|
|
||||||
|
func (t *trackingResponseWriter) end(tags *addedTags) {
|
||||||
|
t.endOnce.Do(func() {
|
||||||
|
if t.statusCode == 0 {
|
||||||
|
t.statusCode = 200
|
||||||
|
}
|
||||||
|
|
||||||
|
span := trace.FromContext(t.ctx)
|
||||||
|
span.SetStatus(TraceStatus(t.statusCode, t.statusLine))
|
||||||
|
span.AddAttributes(trace.Int64Attribute(StatusCodeAttribute, int64(t.statusCode)))
|
||||||
|
|
||||||
|
m := []stats.Measurement{
|
||||||
|
ServerLatency.M(float64(time.Since(t.start)) / float64(time.Millisecond)),
|
||||||
|
ServerResponseBytes.M(t.respSize),
|
||||||
|
}
|
||||||
|
if t.reqSize >= 0 {
|
||||||
|
m = append(m, ServerRequestBytes.M(t.reqSize))
|
||||||
|
}
|
||||||
|
allTags := make([]tag.Mutator, len(tags.t)+1)
|
||||||
|
allTags[0] = tag.Upsert(StatusCode, strconv.Itoa(t.statusCode))
|
||||||
|
copy(allTags[1:], tags.t)
|
||||||
|
stats.RecordWithTags(t.ctx, allTags, m...)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *trackingResponseWriter) Header() http.Header {
|
||||||
|
return t.writer.Header()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *trackingResponseWriter) Write(data []byte) (int, error) {
|
||||||
|
n, err := t.writer.Write(data)
|
||||||
|
t.respSize += int64(n)
|
||||||
|
return n, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *trackingResponseWriter) WriteHeader(statusCode int) {
|
||||||
|
t.writer.WriteHeader(statusCode)
|
||||||
|
t.statusCode = statusCode
|
||||||
|
t.statusLine = http.StatusText(t.statusCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
// wrappedResponseWriter returns a wrapped version of the original
|
||||||
|
// ResponseWriter and only implements the same combination of additional
|
||||||
|
// interfaces as the original.
|
||||||
|
// This implementation is based on https://github.com/felixge/httpsnoop.
|
||||||
|
func (t *trackingResponseWriter) wrappedResponseWriter() http.ResponseWriter {
|
||||||
|
var (
|
||||||
|
hj, i0 = t.writer.(http.Hijacker)
|
||||||
|
cn, i1 = t.writer.(http.CloseNotifier)
|
||||||
|
pu, i2 = t.writer.(http.Pusher)
|
||||||
|
fl, i3 = t.writer.(http.Flusher)
|
||||||
|
rf, i4 = t.writer.(io.ReaderFrom)
|
||||||
|
)
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case !i0 && !i1 && !i2 && !i3 && !i4:
|
||||||
|
return struct {
|
||||||
|
http.ResponseWriter
|
||||||
|
}{t}
|
||||||
|
case !i0 && !i1 && !i2 && !i3 && i4:
|
||||||
|
return struct {
|
||||||
|
http.ResponseWriter
|
||||||
|
io.ReaderFrom
|
||||||
|
}{t, rf}
|
||||||
|
case !i0 && !i1 && !i2 && i3 && !i4:
|
||||||
|
return struct {
|
||||||
|
http.ResponseWriter
|
||||||
|
http.Flusher
|
||||||
|
}{t, fl}
|
||||||
|
case !i0 && !i1 && !i2 && i3 && i4:
|
||||||
|
return struct {
|
||||||
|
http.ResponseWriter
|
||||||
|
http.Flusher
|
||||||
|
io.ReaderFrom
|
||||||
|
}{t, fl, rf}
|
||||||
|
case !i0 && !i1 && i2 && !i3 && !i4:
|
||||||
|
return struct {
|
||||||
|
http.ResponseWriter
|
||||||
|
http.Pusher
|
||||||
|
}{t, pu}
|
||||||
|
case !i0 && !i1 && i2 && !i3 && i4:
|
||||||
|
return struct {
|
||||||
|
http.ResponseWriter
|
||||||
|
http.Pusher
|
||||||
|
io.ReaderFrom
|
||||||
|
}{t, pu, rf}
|
||||||
|
case !i0 && !i1 && i2 && i3 && !i4:
|
||||||
|
return struct {
|
||||||
|
http.ResponseWriter
|
||||||
|
http.Pusher
|
||||||
|
http.Flusher
|
||||||
|
}{t, pu, fl}
|
||||||
|
case !i0 && !i1 && i2 && i3 && i4:
|
||||||
|
return struct {
|
||||||
|
http.ResponseWriter
|
||||||
|
http.Pusher
|
||||||
|
http.Flusher
|
||||||
|
io.ReaderFrom
|
||||||
|
}{t, pu, fl, rf}
|
||||||
|
case !i0 && i1 && !i2 && !i3 && !i4:
|
||||||
|
return struct {
|
||||||
|
http.ResponseWriter
|
||||||
|
http.CloseNotifier
|
||||||
|
}{t, cn}
|
||||||
|
case !i0 && i1 && !i2 && !i3 && i4:
|
||||||
|
return struct {
|
||||||
|
http.ResponseWriter
|
||||||
|
http.CloseNotifier
|
||||||
|
io.ReaderFrom
|
||||||
|
}{t, cn, rf}
|
||||||
|
case !i0 && i1 && !i2 && i3 && !i4:
|
||||||
|
return struct {
|
||||||
|
http.ResponseWriter
|
||||||
|
http.CloseNotifier
|
||||||
|
http.Flusher
|
||||||
|
}{t, cn, fl}
|
||||||
|
case !i0 && i1 && !i2 && i3 && i4:
|
||||||
|
return struct {
|
||||||
|
http.ResponseWriter
|
||||||
|
http.CloseNotifier
|
||||||
|
http.Flusher
|
||||||
|
io.ReaderFrom
|
||||||
|
}{t, cn, fl, rf}
|
||||||
|
case !i0 && i1 && i2 && !i3 && !i4:
|
||||||
|
return struct {
|
||||||
|
http.ResponseWriter
|
||||||
|
http.CloseNotifier
|
||||||
|
http.Pusher
|
||||||
|
}{t, cn, pu}
|
||||||
|
case !i0 && i1 && i2 && !i3 && i4:
|
||||||
|
return struct {
|
||||||
|
http.ResponseWriter
|
||||||
|
http.CloseNotifier
|
||||||
|
http.Pusher
|
||||||
|
io.ReaderFrom
|
||||||
|
}{t, cn, pu, rf}
|
||||||
|
case !i0 && i1 && i2 && i3 && !i4:
|
||||||
|
return struct {
|
||||||
|
http.ResponseWriter
|
||||||
|
http.CloseNotifier
|
||||||
|
http.Pusher
|
||||||
|
http.Flusher
|
||||||
|
}{t, cn, pu, fl}
|
||||||
|
case !i0 && i1 && i2 && i3 && i4:
|
||||||
|
return struct {
|
||||||
|
http.ResponseWriter
|
||||||
|
http.CloseNotifier
|
||||||
|
http.Pusher
|
||||||
|
http.Flusher
|
||||||
|
io.ReaderFrom
|
||||||
|
}{t, cn, pu, fl, rf}
|
||||||
|
case i0 && !i1 && !i2 && !i3 && !i4:
|
||||||
|
return struct {
|
||||||
|
http.ResponseWriter
|
||||||
|
http.Hijacker
|
||||||
|
}{t, hj}
|
||||||
|
case i0 && !i1 && !i2 && !i3 && i4:
|
||||||
|
return struct {
|
||||||
|
http.ResponseWriter
|
||||||
|
http.Hijacker
|
||||||
|
io.ReaderFrom
|
||||||
|
}{t, hj, rf}
|
||||||
|
case i0 && !i1 && !i2 && i3 && !i4:
|
||||||
|
return struct {
|
||||||
|
http.ResponseWriter
|
||||||
|
http.Hijacker
|
||||||
|
http.Flusher
|
||||||
|
}{t, hj, fl}
|
||||||
|
case i0 && !i1 && !i2 && i3 && i4:
|
||||||
|
return struct {
|
||||||
|
http.ResponseWriter
|
||||||
|
http.Hijacker
|
||||||
|
http.Flusher
|
||||||
|
io.ReaderFrom
|
||||||
|
}{t, hj, fl, rf}
|
||||||
|
case i0 && !i1 && i2 && !i3 && !i4:
|
||||||
|
return struct {
|
||||||
|
http.ResponseWriter
|
||||||
|
http.Hijacker
|
||||||
|
http.Pusher
|
||||||
|
}{t, hj, pu}
|
||||||
|
case i0 && !i1 && i2 && !i3 && i4:
|
||||||
|
return struct {
|
||||||
|
http.ResponseWriter
|
||||||
|
http.Hijacker
|
||||||
|
http.Pusher
|
||||||
|
io.ReaderFrom
|
||||||
|
}{t, hj, pu, rf}
|
||||||
|
case i0 && !i1 && i2 && i3 && !i4:
|
||||||
|
return struct {
|
||||||
|
http.ResponseWriter
|
||||||
|
http.Hijacker
|
||||||
|
http.Pusher
|
||||||
|
http.Flusher
|
||||||
|
}{t, hj, pu, fl}
|
||||||
|
case i0 && !i1 && i2 && i3 && i4:
|
||||||
|
return struct {
|
||||||
|
http.ResponseWriter
|
||||||
|
http.Hijacker
|
||||||
|
http.Pusher
|
||||||
|
http.Flusher
|
||||||
|
io.ReaderFrom
|
||||||
|
}{t, hj, pu, fl, rf}
|
||||||
|
case i0 && i1 && !i2 && !i3 && !i4:
|
||||||
|
return struct {
|
||||||
|
http.ResponseWriter
|
||||||
|
http.Hijacker
|
||||||
|
http.CloseNotifier
|
||||||
|
}{t, hj, cn}
|
||||||
|
case i0 && i1 && !i2 && !i3 && i4:
|
||||||
|
return struct {
|
||||||
|
http.ResponseWriter
|
||||||
|
http.Hijacker
|
||||||
|
http.CloseNotifier
|
||||||
|
io.ReaderFrom
|
||||||
|
}{t, hj, cn, rf}
|
||||||
|
case i0 && i1 && !i2 && i3 && !i4:
|
||||||
|
return struct {
|
||||||
|
http.ResponseWriter
|
||||||
|
http.Hijacker
|
||||||
|
http.CloseNotifier
|
||||||
|
http.Flusher
|
||||||
|
}{t, hj, cn, fl}
|
||||||
|
case i0 && i1 && !i2 && i3 && i4:
|
||||||
|
return struct {
|
||||||
|
http.ResponseWriter
|
||||||
|
http.Hijacker
|
||||||
|
http.CloseNotifier
|
||||||
|
http.Flusher
|
||||||
|
io.ReaderFrom
|
||||||
|
}{t, hj, cn, fl, rf}
|
||||||
|
case i0 && i1 && i2 && !i3 && !i4:
|
||||||
|
return struct {
|
||||||
|
http.ResponseWriter
|
||||||
|
http.Hijacker
|
||||||
|
http.CloseNotifier
|
||||||
|
http.Pusher
|
||||||
|
}{t, hj, cn, pu}
|
||||||
|
case i0 && i1 && i2 && !i3 && i4:
|
||||||
|
return struct {
|
||||||
|
http.ResponseWriter
|
||||||
|
http.Hijacker
|
||||||
|
http.CloseNotifier
|
||||||
|
http.Pusher
|
||||||
|
io.ReaderFrom
|
||||||
|
}{t, hj, cn, pu, rf}
|
||||||
|
case i0 && i1 && i2 && i3 && !i4:
|
||||||
|
return struct {
|
||||||
|
http.ResponseWriter
|
||||||
|
http.Hijacker
|
||||||
|
http.CloseNotifier
|
||||||
|
http.Pusher
|
||||||
|
http.Flusher
|
||||||
|
}{t, hj, cn, pu, fl}
|
||||||
|
case i0 && i1 && i2 && i3 && i4:
|
||||||
|
return struct {
|
||||||
|
http.ResponseWriter
|
||||||
|
http.Hijacker
|
||||||
|
http.CloseNotifier
|
||||||
|
http.Pusher
|
||||||
|
http.Flusher
|
||||||
|
io.ReaderFrom
|
||||||
|
}{t, hj, cn, pu, fl, rf}
|
||||||
|
default:
|
||||||
|
return struct {
|
||||||
|
http.ResponseWriter
|
||||||
|
}{t}
|
||||||
|
}
|
||||||
|
}
|
169
vendor/go.opencensus.io/plugin/ochttp/span_annotating_client_trace.go
generated
vendored
Normal file
169
vendor/go.opencensus.io/plugin/ochttp/span_annotating_client_trace.go
generated
vendored
Normal file
|
@ -0,0 +1,169 @@
|
||||||
|
// 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 ochttp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/tls"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptrace"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"go.opencensus.io/trace"
|
||||||
|
)
|
||||||
|
|
||||||
|
type spanAnnotator struct {
|
||||||
|
sp *trace.Span
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Remove NewSpanAnnotator at the next release.
|
||||||
|
|
||||||
|
// NewSpanAnnotator returns a httptrace.ClientTrace which annotates
|
||||||
|
// all emitted httptrace events on the provided Span.
|
||||||
|
// Deprecated: Use NewSpanAnnotatingClientTrace instead
|
||||||
|
func NewSpanAnnotator(r *http.Request, s *trace.Span) *httptrace.ClientTrace {
|
||||||
|
return NewSpanAnnotatingClientTrace(r, s)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewSpanAnnotatingClientTrace returns a httptrace.ClientTrace which annotates
|
||||||
|
// all emitted httptrace events on the provided Span.
|
||||||
|
func NewSpanAnnotatingClientTrace(_ *http.Request, s *trace.Span) *httptrace.ClientTrace {
|
||||||
|
sa := spanAnnotator{sp: s}
|
||||||
|
|
||||||
|
return &httptrace.ClientTrace{
|
||||||
|
GetConn: sa.getConn,
|
||||||
|
GotConn: sa.gotConn,
|
||||||
|
PutIdleConn: sa.putIdleConn,
|
||||||
|
GotFirstResponseByte: sa.gotFirstResponseByte,
|
||||||
|
Got100Continue: sa.got100Continue,
|
||||||
|
DNSStart: sa.dnsStart,
|
||||||
|
DNSDone: sa.dnsDone,
|
||||||
|
ConnectStart: sa.connectStart,
|
||||||
|
ConnectDone: sa.connectDone,
|
||||||
|
TLSHandshakeStart: sa.tlsHandshakeStart,
|
||||||
|
TLSHandshakeDone: sa.tlsHandshakeDone,
|
||||||
|
WroteHeaders: sa.wroteHeaders,
|
||||||
|
Wait100Continue: sa.wait100Continue,
|
||||||
|
WroteRequest: sa.wroteRequest,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s spanAnnotator) getConn(hostPort string) {
|
||||||
|
attrs := []trace.Attribute{
|
||||||
|
trace.StringAttribute("httptrace.get_connection.host_port", hostPort),
|
||||||
|
}
|
||||||
|
s.sp.Annotate(attrs, "GetConn")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s spanAnnotator) gotConn(info httptrace.GotConnInfo) {
|
||||||
|
attrs := []trace.Attribute{
|
||||||
|
trace.BoolAttribute("httptrace.got_connection.reused", info.Reused),
|
||||||
|
trace.BoolAttribute("httptrace.got_connection.was_idle", info.WasIdle),
|
||||||
|
}
|
||||||
|
if info.WasIdle {
|
||||||
|
attrs = append(attrs,
|
||||||
|
trace.StringAttribute("httptrace.got_connection.idle_time", info.IdleTime.String()))
|
||||||
|
}
|
||||||
|
s.sp.Annotate(attrs, "GotConn")
|
||||||
|
}
|
||||||
|
|
||||||
|
// PutIdleConn implements a httptrace.ClientTrace hook
|
||||||
|
func (s spanAnnotator) putIdleConn(err error) {
|
||||||
|
var attrs []trace.Attribute
|
||||||
|
if err != nil {
|
||||||
|
attrs = append(attrs,
|
||||||
|
trace.StringAttribute("httptrace.put_idle_connection.error", err.Error()))
|
||||||
|
}
|
||||||
|
s.sp.Annotate(attrs, "PutIdleConn")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s spanAnnotator) gotFirstResponseByte() {
|
||||||
|
s.sp.Annotate(nil, "GotFirstResponseByte")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s spanAnnotator) got100Continue() {
|
||||||
|
s.sp.Annotate(nil, "Got100Continue")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s spanAnnotator) dnsStart(info httptrace.DNSStartInfo) {
|
||||||
|
attrs := []trace.Attribute{
|
||||||
|
trace.StringAttribute("httptrace.dns_start.host", info.Host),
|
||||||
|
}
|
||||||
|
s.sp.Annotate(attrs, "DNSStart")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s spanAnnotator) dnsDone(info httptrace.DNSDoneInfo) {
|
||||||
|
var addrs []string
|
||||||
|
for _, addr := range info.Addrs {
|
||||||
|
addrs = append(addrs, addr.String())
|
||||||
|
}
|
||||||
|
attrs := []trace.Attribute{
|
||||||
|
trace.StringAttribute("httptrace.dns_done.addrs", strings.Join(addrs, " , ")),
|
||||||
|
}
|
||||||
|
if info.Err != nil {
|
||||||
|
attrs = append(attrs,
|
||||||
|
trace.StringAttribute("httptrace.dns_done.error", info.Err.Error()))
|
||||||
|
}
|
||||||
|
s.sp.Annotate(attrs, "DNSDone")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s spanAnnotator) connectStart(network, addr string) {
|
||||||
|
attrs := []trace.Attribute{
|
||||||
|
trace.StringAttribute("httptrace.connect_start.network", network),
|
||||||
|
trace.StringAttribute("httptrace.connect_start.addr", addr),
|
||||||
|
}
|
||||||
|
s.sp.Annotate(attrs, "ConnectStart")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s spanAnnotator) connectDone(network, addr string, err error) {
|
||||||
|
attrs := []trace.Attribute{
|
||||||
|
trace.StringAttribute("httptrace.connect_done.network", network),
|
||||||
|
trace.StringAttribute("httptrace.connect_done.addr", addr),
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
attrs = append(attrs,
|
||||||
|
trace.StringAttribute("httptrace.connect_done.error", err.Error()))
|
||||||
|
}
|
||||||
|
s.sp.Annotate(attrs, "ConnectDone")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s spanAnnotator) tlsHandshakeStart() {
|
||||||
|
s.sp.Annotate(nil, "TLSHandshakeStart")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s spanAnnotator) tlsHandshakeDone(_ tls.ConnectionState, err error) {
|
||||||
|
var attrs []trace.Attribute
|
||||||
|
if err != nil {
|
||||||
|
attrs = append(attrs,
|
||||||
|
trace.StringAttribute("httptrace.tls_handshake_done.error", err.Error()))
|
||||||
|
}
|
||||||
|
s.sp.Annotate(attrs, "TLSHandshakeDone")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s spanAnnotator) wroteHeaders() {
|
||||||
|
s.sp.Annotate(nil, "WroteHeaders")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s spanAnnotator) wait100Continue() {
|
||||||
|
s.sp.Annotate(nil, "Wait100Continue")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s spanAnnotator) wroteRequest(info httptrace.WroteRequestInfo) {
|
||||||
|
var attrs []trace.Attribute
|
||||||
|
if info.Err != nil {
|
||||||
|
attrs = append(attrs,
|
||||||
|
trace.StringAttribute("httptrace.wrote_request.error", info.Err.Error()))
|
||||||
|
}
|
||||||
|
s.sp.Annotate(attrs, "WroteRequest")
|
||||||
|
}
|
292
vendor/go.opencensus.io/plugin/ochttp/stats.go
generated
vendored
Normal file
292
vendor/go.opencensus.io/plugin/ochttp/stats.go
generated
vendored
Normal file
|
@ -0,0 +1,292 @@
|
||||||
|
// 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 ochttp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"go.opencensus.io/stats"
|
||||||
|
"go.opencensus.io/stats/view"
|
||||||
|
"go.opencensus.io/tag"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Deprecated: client HTTP measures.
|
||||||
|
var (
|
||||||
|
// Deprecated: Use a Count aggregation over one of the other client measures to achieve the same effect.
|
||||||
|
ClientRequestCount = stats.Int64(
|
||||||
|
"opencensus.io/http/client/request_count",
|
||||||
|
"Number of HTTP requests started",
|
||||||
|
stats.UnitDimensionless)
|
||||||
|
// Deprecated: Use ClientSentBytes.
|
||||||
|
ClientRequestBytes = stats.Int64(
|
||||||
|
"opencensus.io/http/client/request_bytes",
|
||||||
|
"HTTP request body size if set as ContentLength (uncompressed)",
|
||||||
|
stats.UnitBytes)
|
||||||
|
// Deprecated: Use ClientReceivedBytes.
|
||||||
|
ClientResponseBytes = stats.Int64(
|
||||||
|
"opencensus.io/http/client/response_bytes",
|
||||||
|
"HTTP response body size (uncompressed)",
|
||||||
|
stats.UnitBytes)
|
||||||
|
// Deprecated: Use ClientRoundtripLatency.
|
||||||
|
ClientLatency = stats.Float64(
|
||||||
|
"opencensus.io/http/client/latency",
|
||||||
|
"End-to-end latency",
|
||||||
|
stats.UnitMilliseconds)
|
||||||
|
)
|
||||||
|
|
||||||
|
// The following client HTTP measures are supported for use in custom views.
|
||||||
|
var (
|
||||||
|
ClientSentBytes = stats.Int64(
|
||||||
|
"opencensus.io/http/client/sent_bytes",
|
||||||
|
"Total bytes sent in request body (not including headers)",
|
||||||
|
stats.UnitBytes,
|
||||||
|
)
|
||||||
|
ClientReceivedBytes = stats.Int64(
|
||||||
|
"opencensus.io/http/client/received_bytes",
|
||||||
|
"Total bytes received in response bodies (not including headers but including error responses with bodies)",
|
||||||
|
stats.UnitBytes,
|
||||||
|
)
|
||||||
|
ClientRoundtripLatency = stats.Float64(
|
||||||
|
"opencensus.io/http/client/roundtrip_latency",
|
||||||
|
"Time between first byte of request headers sent to last byte of response received, or terminal error",
|
||||||
|
stats.UnitMilliseconds,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
// The following server HTTP measures are supported for use in custom views:
|
||||||
|
var (
|
||||||
|
ServerRequestCount = stats.Int64(
|
||||||
|
"opencensus.io/http/server/request_count",
|
||||||
|
"Number of HTTP requests started",
|
||||||
|
stats.UnitDimensionless)
|
||||||
|
ServerRequestBytes = stats.Int64(
|
||||||
|
"opencensus.io/http/server/request_bytes",
|
||||||
|
"HTTP request body size if set as ContentLength (uncompressed)",
|
||||||
|
stats.UnitBytes)
|
||||||
|
ServerResponseBytes = stats.Int64(
|
||||||
|
"opencensus.io/http/server/response_bytes",
|
||||||
|
"HTTP response body size (uncompressed)",
|
||||||
|
stats.UnitBytes)
|
||||||
|
ServerLatency = stats.Float64(
|
||||||
|
"opencensus.io/http/server/latency",
|
||||||
|
"End-to-end latency",
|
||||||
|
stats.UnitMilliseconds)
|
||||||
|
)
|
||||||
|
|
||||||
|
// The following tags are applied to stats recorded by this package. Host, Path
|
||||||
|
// and Method are applied to all measures. StatusCode is not applied to
|
||||||
|
// ClientRequestCount or ServerRequestCount, since it is recorded before the status is known.
|
||||||
|
var (
|
||||||
|
// Host is the value of the HTTP Host header.
|
||||||
|
//
|
||||||
|
// The value of this tag can be controlled by the HTTP client, so you need
|
||||||
|
// to watch out for potentially generating high-cardinality labels in your
|
||||||
|
// metrics backend if you use this tag in views.
|
||||||
|
Host, _ = tag.NewKey("http.host")
|
||||||
|
|
||||||
|
// StatusCode is the numeric HTTP response status code,
|
||||||
|
// or "error" if a transport error occurred and no status code was read.
|
||||||
|
StatusCode, _ = tag.NewKey("http.status")
|
||||||
|
|
||||||
|
// Path is the URL path (not including query string) in the request.
|
||||||
|
//
|
||||||
|
// The value of this tag can be controlled by the HTTP client, so you need
|
||||||
|
// to watch out for potentially generating high-cardinality labels in your
|
||||||
|
// metrics backend if you use this tag in views.
|
||||||
|
Path, _ = tag.NewKey("http.path")
|
||||||
|
|
||||||
|
// Method is the HTTP method of the request, capitalized (GET, POST, etc.).
|
||||||
|
Method, _ = tag.NewKey("http.method")
|
||||||
|
|
||||||
|
// KeyServerRoute is a low cardinality string representing the logical
|
||||||
|
// handler of the request. This is usually the pattern registered on the a
|
||||||
|
// ServeMux (or similar string).
|
||||||
|
KeyServerRoute, _ = tag.NewKey("http_server_route")
|
||||||
|
)
|
||||||
|
|
||||||
|
// Client tag keys.
|
||||||
|
var (
|
||||||
|
// KeyClientMethod is the HTTP method, capitalized (i.e. GET, POST, PUT, DELETE, etc.).
|
||||||
|
KeyClientMethod, _ = tag.NewKey("http_client_method")
|
||||||
|
// KeyClientPath is the URL path (not including query string).
|
||||||
|
KeyClientPath, _ = tag.NewKey("http_client_path")
|
||||||
|
// KeyClientStatus is the HTTP status code as an integer (e.g. 200, 404, 500.), or "error" if no response status line was received.
|
||||||
|
KeyClientStatus, _ = tag.NewKey("http_client_status")
|
||||||
|
// KeyClientHost is the value of the request Host header.
|
||||||
|
KeyClientHost, _ = tag.NewKey("http_client_host")
|
||||||
|
)
|
||||||
|
|
||||||
|
// Default distributions used by views in this package.
|
||||||
|
var (
|
||||||
|
DefaultSizeDistribution = view.Distribution(1024, 2048, 4096, 16384, 65536, 262144, 1048576, 4194304, 16777216, 67108864, 268435456, 1073741824, 4294967296)
|
||||||
|
DefaultLatencyDistribution = view.Distribution(1, 2, 3, 4, 5, 6, 8, 10, 13, 16, 20, 25, 30, 40, 50, 65, 80, 100, 130, 160, 200, 250, 300, 400, 500, 650, 800, 1000, 2000, 5000, 10000, 20000, 50000, 100000)
|
||||||
|
)
|
||||||
|
|
||||||
|
// Package ochttp provides some convenience views for client measures.
|
||||||
|
// You still need to register these views for data to actually be collected.
|
||||||
|
var (
|
||||||
|
ClientSentBytesDistribution = &view.View{
|
||||||
|
Name: "opencensus.io/http/client/sent_bytes",
|
||||||
|
Measure: ClientSentBytes,
|
||||||
|
Aggregation: DefaultSizeDistribution,
|
||||||
|
Description: "Total bytes sent in request body (not including headers), by HTTP method and response status",
|
||||||
|
TagKeys: []tag.Key{KeyClientMethod, KeyClientStatus},
|
||||||
|
}
|
||||||
|
|
||||||
|
ClientReceivedBytesDistribution = &view.View{
|
||||||
|
Name: "opencensus.io/http/client/received_bytes",
|
||||||
|
Measure: ClientReceivedBytes,
|
||||||
|
Aggregation: DefaultSizeDistribution,
|
||||||
|
Description: "Total bytes received in response bodies (not including headers but including error responses with bodies), by HTTP method and response status",
|
||||||
|
TagKeys: []tag.Key{KeyClientMethod, KeyClientStatus},
|
||||||
|
}
|
||||||
|
|
||||||
|
ClientRoundtripLatencyDistribution = &view.View{
|
||||||
|
Name: "opencensus.io/http/client/roundtrip_latency",
|
||||||
|
Measure: ClientRoundtripLatency,
|
||||||
|
Aggregation: DefaultLatencyDistribution,
|
||||||
|
Description: "End-to-end latency, by HTTP method and response status",
|
||||||
|
TagKeys: []tag.Key{KeyClientMethod, KeyClientStatus},
|
||||||
|
}
|
||||||
|
|
||||||
|
ClientCompletedCount = &view.View{
|
||||||
|
Name: "opencensus.io/http/client/completed_count",
|
||||||
|
Measure: ClientRoundtripLatency,
|
||||||
|
Aggregation: view.Count(),
|
||||||
|
Description: "Count of completed requests, by HTTP method and response status",
|
||||||
|
TagKeys: []tag.Key{KeyClientMethod, KeyClientStatus},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// Deprecated: Old client Views.
|
||||||
|
var (
|
||||||
|
// Deprecated: No direct replacement, but see ClientCompletedCount.
|
||||||
|
ClientRequestCountView = &view.View{
|
||||||
|
Name: "opencensus.io/http/client/request_count",
|
||||||
|
Description: "Count of HTTP requests started",
|
||||||
|
Measure: ClientRequestCount,
|
||||||
|
Aggregation: view.Count(),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use ClientSentBytesDistribution.
|
||||||
|
ClientRequestBytesView = &view.View{
|
||||||
|
Name: "opencensus.io/http/client/request_bytes",
|
||||||
|
Description: "Size distribution of HTTP request body",
|
||||||
|
Measure: ClientSentBytes,
|
||||||
|
Aggregation: DefaultSizeDistribution,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use ClientReceivedBytesDistribution instead.
|
||||||
|
ClientResponseBytesView = &view.View{
|
||||||
|
Name: "opencensus.io/http/client/response_bytes",
|
||||||
|
Description: "Size distribution of HTTP response body",
|
||||||
|
Measure: ClientReceivedBytes,
|
||||||
|
Aggregation: DefaultSizeDistribution,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use ClientRoundtripLatencyDistribution instead.
|
||||||
|
ClientLatencyView = &view.View{
|
||||||
|
Name: "opencensus.io/http/client/latency",
|
||||||
|
Description: "Latency distribution of HTTP requests",
|
||||||
|
Measure: ClientRoundtripLatency,
|
||||||
|
Aggregation: DefaultLatencyDistribution,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use ClientCompletedCount instead.
|
||||||
|
ClientRequestCountByMethod = &view.View{
|
||||||
|
Name: "opencensus.io/http/client/request_count_by_method",
|
||||||
|
Description: "Client request count by HTTP method",
|
||||||
|
TagKeys: []tag.Key{Method},
|
||||||
|
Measure: ClientSentBytes,
|
||||||
|
Aggregation: view.Count(),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use ClientCompletedCount instead.
|
||||||
|
ClientResponseCountByStatusCode = &view.View{
|
||||||
|
Name: "opencensus.io/http/client/response_count_by_status_code",
|
||||||
|
Description: "Client response count by status code",
|
||||||
|
TagKeys: []tag.Key{StatusCode},
|
||||||
|
Measure: ClientRoundtripLatency,
|
||||||
|
Aggregation: view.Count(),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// Package ochttp provides some convenience views for server measures.
|
||||||
|
// You still need to register these views for data to actually be collected.
|
||||||
|
var (
|
||||||
|
ServerRequestCountView = &view.View{
|
||||||
|
Name: "opencensus.io/http/server/request_count",
|
||||||
|
Description: "Count of HTTP requests started",
|
||||||
|
Measure: ServerRequestCount,
|
||||||
|
Aggregation: view.Count(),
|
||||||
|
}
|
||||||
|
|
||||||
|
ServerRequestBytesView = &view.View{
|
||||||
|
Name: "opencensus.io/http/server/request_bytes",
|
||||||
|
Description: "Size distribution of HTTP request body",
|
||||||
|
Measure: ServerRequestBytes,
|
||||||
|
Aggregation: DefaultSizeDistribution,
|
||||||
|
}
|
||||||
|
|
||||||
|
ServerResponseBytesView = &view.View{
|
||||||
|
Name: "opencensus.io/http/server/response_bytes",
|
||||||
|
Description: "Size distribution of HTTP response body",
|
||||||
|
Measure: ServerResponseBytes,
|
||||||
|
Aggregation: DefaultSizeDistribution,
|
||||||
|
}
|
||||||
|
|
||||||
|
ServerLatencyView = &view.View{
|
||||||
|
Name: "opencensus.io/http/server/latency",
|
||||||
|
Description: "Latency distribution of HTTP requests",
|
||||||
|
Measure: ServerLatency,
|
||||||
|
Aggregation: DefaultLatencyDistribution,
|
||||||
|
}
|
||||||
|
|
||||||
|
ServerRequestCountByMethod = &view.View{
|
||||||
|
Name: "opencensus.io/http/server/request_count_by_method",
|
||||||
|
Description: "Server request count by HTTP method",
|
||||||
|
TagKeys: []tag.Key{Method},
|
||||||
|
Measure: ServerRequestCount,
|
||||||
|
Aggregation: view.Count(),
|
||||||
|
}
|
||||||
|
|
||||||
|
ServerResponseCountByStatusCode = &view.View{
|
||||||
|
Name: "opencensus.io/http/server/response_count_by_status_code",
|
||||||
|
Description: "Server response count by status code",
|
||||||
|
TagKeys: []tag.Key{StatusCode},
|
||||||
|
Measure: ServerLatency,
|
||||||
|
Aggregation: view.Count(),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// DefaultClientViews are the default client views provided by this package.
|
||||||
|
// Deprecated: No replacement. Register the views you would like individually.
|
||||||
|
var DefaultClientViews = []*view.View{
|
||||||
|
ClientRequestCountView,
|
||||||
|
ClientRequestBytesView,
|
||||||
|
ClientResponseBytesView,
|
||||||
|
ClientLatencyView,
|
||||||
|
ClientRequestCountByMethod,
|
||||||
|
ClientResponseCountByStatusCode,
|
||||||
|
}
|
||||||
|
|
||||||
|
// DefaultServerViews are the default server views provided by this package.
|
||||||
|
// Deprecated: No replacement. Register the views you would like individually.
|
||||||
|
var DefaultServerViews = []*view.View{
|
||||||
|
ServerRequestCountView,
|
||||||
|
ServerRequestBytesView,
|
||||||
|
ServerResponseBytesView,
|
||||||
|
ServerLatencyView,
|
||||||
|
ServerRequestCountByMethod,
|
||||||
|
ServerResponseCountByStatusCode,
|
||||||
|
}
|
239
vendor/go.opencensus.io/plugin/ochttp/trace.go
generated
vendored
Normal file
239
vendor/go.opencensus.io/plugin/ochttp/trace.go
generated
vendored
Normal file
|
@ -0,0 +1,239 @@
|
||||||
|
// 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 ochttp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptrace"
|
||||||
|
|
||||||
|
"go.opencensus.io/plugin/ochttp/propagation/b3"
|
||||||
|
"go.opencensus.io/trace"
|
||||||
|
"go.opencensus.io/trace/propagation"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TODO(jbd): Add godoc examples.
|
||||||
|
|
||||||
|
var defaultFormat propagation.HTTPFormat = &b3.HTTPFormat{}
|
||||||
|
|
||||||
|
// Attributes recorded on the span for the requests.
|
||||||
|
// Only trace exporters will need them.
|
||||||
|
const (
|
||||||
|
HostAttribute = "http.host"
|
||||||
|
MethodAttribute = "http.method"
|
||||||
|
PathAttribute = "http.path"
|
||||||
|
URLAttribute = "http.url"
|
||||||
|
UserAgentAttribute = "http.user_agent"
|
||||||
|
StatusCodeAttribute = "http.status_code"
|
||||||
|
)
|
||||||
|
|
||||||
|
type traceTransport struct {
|
||||||
|
base http.RoundTripper
|
||||||
|
startOptions trace.StartOptions
|
||||||
|
format propagation.HTTPFormat
|
||||||
|
formatSpanName func(*http.Request) string
|
||||||
|
newClientTrace func(*http.Request, *trace.Span) *httptrace.ClientTrace
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(jbd): Add message events for request and response size.
|
||||||
|
|
||||||
|
// RoundTrip creates a trace.Span and inserts it into the outgoing request's headers.
|
||||||
|
// The created span can follow a parent span, if a parent is presented in
|
||||||
|
// the request's context.
|
||||||
|
func (t *traceTransport) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||||
|
name := t.formatSpanName(req)
|
||||||
|
// TODO(jbd): Discuss whether we want to prefix
|
||||||
|
// outgoing requests with Sent.
|
||||||
|
ctx, span := trace.StartSpan(req.Context(), name,
|
||||||
|
trace.WithSampler(t.startOptions.Sampler),
|
||||||
|
trace.WithSpanKind(trace.SpanKindClient))
|
||||||
|
|
||||||
|
if t.newClientTrace != nil {
|
||||||
|
req = req.WithContext(httptrace.WithClientTrace(ctx, t.newClientTrace(req, span)))
|
||||||
|
} else {
|
||||||
|
req = req.WithContext(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
if t.format != nil {
|
||||||
|
// SpanContextToRequest will modify its Request argument, which is
|
||||||
|
// contrary to the contract for http.RoundTripper, so we need to
|
||||||
|
// pass it a copy of the Request.
|
||||||
|
// However, the Request struct itself was already copied by
|
||||||
|
// the WithContext calls above and so we just need to copy the header.
|
||||||
|
header := make(http.Header)
|
||||||
|
for k, v := range req.Header {
|
||||||
|
header[k] = v
|
||||||
|
}
|
||||||
|
req.Header = header
|
||||||
|
t.format.SpanContextToRequest(span.SpanContext(), req)
|
||||||
|
}
|
||||||
|
|
||||||
|
span.AddAttributes(requestAttrs(req)...)
|
||||||
|
resp, err := t.base.RoundTrip(req)
|
||||||
|
if err != nil {
|
||||||
|
span.SetStatus(trace.Status{Code: trace.StatusCodeUnknown, Message: err.Error()})
|
||||||
|
span.End()
|
||||||
|
return resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
span.AddAttributes(responseAttrs(resp)...)
|
||||||
|
span.SetStatus(TraceStatus(resp.StatusCode, resp.Status))
|
||||||
|
|
||||||
|
// span.End() will be invoked after
|
||||||
|
// a read from resp.Body returns io.EOF or when
|
||||||
|
// resp.Body.Close() is invoked.
|
||||||
|
bt := &bodyTracker{rc: resp.Body, span: span}
|
||||||
|
resp.Body = wrappedBody(bt, resp.Body)
|
||||||
|
return resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// bodyTracker wraps a response.Body and invokes
|
||||||
|
// trace.EndSpan on encountering io.EOF on reading
|
||||||
|
// the body of the original response.
|
||||||
|
type bodyTracker struct {
|
||||||
|
rc io.ReadCloser
|
||||||
|
span *trace.Span
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ io.ReadCloser = (*bodyTracker)(nil)
|
||||||
|
|
||||||
|
func (bt *bodyTracker) Read(b []byte) (int, error) {
|
||||||
|
n, err := bt.rc.Read(b)
|
||||||
|
|
||||||
|
switch err {
|
||||||
|
case nil:
|
||||||
|
return n, nil
|
||||||
|
case io.EOF:
|
||||||
|
bt.span.End()
|
||||||
|
default:
|
||||||
|
// For all other errors, set the span status
|
||||||
|
bt.span.SetStatus(trace.Status{
|
||||||
|
// Code 2 is the error code for Internal server error.
|
||||||
|
Code: 2,
|
||||||
|
Message: err.Error(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return n, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bt *bodyTracker) Close() error {
|
||||||
|
// Invoking endSpan on Close will help catch the cases
|
||||||
|
// in which a read returned a non-nil error, we set the
|
||||||
|
// span status but didn't end the span.
|
||||||
|
bt.span.End()
|
||||||
|
return bt.rc.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
// CancelRequest cancels an in-flight request by closing its connection.
|
||||||
|
func (t *traceTransport) CancelRequest(req *http.Request) {
|
||||||
|
type canceler interface {
|
||||||
|
CancelRequest(*http.Request)
|
||||||
|
}
|
||||||
|
if cr, ok := t.base.(canceler); ok {
|
||||||
|
cr.CancelRequest(req)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func spanNameFromURL(req *http.Request) string {
|
||||||
|
return req.URL.Path
|
||||||
|
}
|
||||||
|
|
||||||
|
func requestAttrs(r *http.Request) []trace.Attribute {
|
||||||
|
userAgent := r.UserAgent()
|
||||||
|
|
||||||
|
attrs := make([]trace.Attribute, 0, 5)
|
||||||
|
attrs = append(attrs,
|
||||||
|
trace.StringAttribute(PathAttribute, r.URL.Path),
|
||||||
|
trace.StringAttribute(URLAttribute, r.URL.String()),
|
||||||
|
trace.StringAttribute(HostAttribute, r.Host),
|
||||||
|
trace.StringAttribute(MethodAttribute, r.Method),
|
||||||
|
)
|
||||||
|
|
||||||
|
if userAgent != "" {
|
||||||
|
attrs = append(attrs, trace.StringAttribute(UserAgentAttribute, userAgent))
|
||||||
|
}
|
||||||
|
|
||||||
|
return attrs
|
||||||
|
}
|
||||||
|
|
||||||
|
func responseAttrs(resp *http.Response) []trace.Attribute {
|
||||||
|
return []trace.Attribute{
|
||||||
|
trace.Int64Attribute(StatusCodeAttribute, int64(resp.StatusCode)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TraceStatus is a utility to convert the HTTP status code to a trace.Status that
|
||||||
|
// represents the outcome as closely as possible.
|
||||||
|
func TraceStatus(httpStatusCode int, statusLine string) trace.Status {
|
||||||
|
var code int32
|
||||||
|
if httpStatusCode < 200 || httpStatusCode >= 400 {
|
||||||
|
code = trace.StatusCodeUnknown
|
||||||
|
}
|
||||||
|
switch httpStatusCode {
|
||||||
|
case 499:
|
||||||
|
code = trace.StatusCodeCancelled
|
||||||
|
case http.StatusBadRequest:
|
||||||
|
code = trace.StatusCodeInvalidArgument
|
||||||
|
case http.StatusGatewayTimeout:
|
||||||
|
code = trace.StatusCodeDeadlineExceeded
|
||||||
|
case http.StatusNotFound:
|
||||||
|
code = trace.StatusCodeNotFound
|
||||||
|
case http.StatusForbidden:
|
||||||
|
code = trace.StatusCodePermissionDenied
|
||||||
|
case http.StatusUnauthorized: // 401 is actually unauthenticated.
|
||||||
|
code = trace.StatusCodeUnauthenticated
|
||||||
|
case http.StatusTooManyRequests:
|
||||||
|
code = trace.StatusCodeResourceExhausted
|
||||||
|
case http.StatusNotImplemented:
|
||||||
|
code = trace.StatusCodeUnimplemented
|
||||||
|
case http.StatusServiceUnavailable:
|
||||||
|
code = trace.StatusCodeUnavailable
|
||||||
|
case http.StatusOK:
|
||||||
|
code = trace.StatusCodeOK
|
||||||
|
}
|
||||||
|
return trace.Status{Code: code, Message: codeToStr[code]}
|
||||||
|
}
|
||||||
|
|
||||||
|
var codeToStr = map[int32]string{
|
||||||
|
trace.StatusCodeOK: `OK`,
|
||||||
|
trace.StatusCodeCancelled: `CANCELLED`,
|
||||||
|
trace.StatusCodeUnknown: `UNKNOWN`,
|
||||||
|
trace.StatusCodeInvalidArgument: `INVALID_ARGUMENT`,
|
||||||
|
trace.StatusCodeDeadlineExceeded: `DEADLINE_EXCEEDED`,
|
||||||
|
trace.StatusCodeNotFound: `NOT_FOUND`,
|
||||||
|
trace.StatusCodeAlreadyExists: `ALREADY_EXISTS`,
|
||||||
|
trace.StatusCodePermissionDenied: `PERMISSION_DENIED`,
|
||||||
|
trace.StatusCodeResourceExhausted: `RESOURCE_EXHAUSTED`,
|
||||||
|
trace.StatusCodeFailedPrecondition: `FAILED_PRECONDITION`,
|
||||||
|
trace.StatusCodeAborted: `ABORTED`,
|
||||||
|
trace.StatusCodeOutOfRange: `OUT_OF_RANGE`,
|
||||||
|
trace.StatusCodeUnimplemented: `UNIMPLEMENTED`,
|
||||||
|
trace.StatusCodeInternal: `INTERNAL`,
|
||||||
|
trace.StatusCodeUnavailable: `UNAVAILABLE`,
|
||||||
|
trace.StatusCodeDataLoss: `DATA_LOSS`,
|
||||||
|
trace.StatusCodeUnauthenticated: `UNAUTHENTICATED`,
|
||||||
|
}
|
||||||
|
|
||||||
|
func isHealthEndpoint(path string) bool {
|
||||||
|
// Health checking is pretty frequent and
|
||||||
|
// traces collected for health endpoints
|
||||||
|
// can be extremely noisy and expensive.
|
||||||
|
// Disable canonical health checking endpoints
|
||||||
|
// like /healthz and /_ah/health for now.
|
||||||
|
if path == "/healthz" || path == "/_ah/health" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
44
vendor/go.opencensus.io/plugin/ochttp/wrapped_body.go
generated
vendored
Normal file
44
vendor/go.opencensus.io/plugin/ochttp/wrapped_body.go
generated
vendored
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
// 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 ochttp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
// wrappedBody returns a wrapped version of the original
|
||||||
|
// Body and only implements the same combination of additional
|
||||||
|
// interfaces as the original.
|
||||||
|
func wrappedBody(wrapper io.ReadCloser, body io.ReadCloser) io.ReadCloser {
|
||||||
|
var (
|
||||||
|
wr, i0 = body.(io.Writer)
|
||||||
|
)
|
||||||
|
switch {
|
||||||
|
case !i0:
|
||||||
|
return struct {
|
||||||
|
io.ReadCloser
|
||||||
|
}{wrapper}
|
||||||
|
|
||||||
|
case i0:
|
||||||
|
return struct {
|
||||||
|
io.ReadCloser
|
||||||
|
io.Writer
|
||||||
|
}{wrapper, wr}
|
||||||
|
default:
|
||||||
|
return struct {
|
||||||
|
io.ReadCloser
|
||||||
|
}{wrapper}
|
||||||
|
}
|
||||||
|
}
|
164
vendor/go.opencensus.io/resource/resource.go
generated
vendored
Normal file
164
vendor/go.opencensus.io/resource/resource.go
generated
vendored
Normal file
|
@ -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 `<key1>="<value1>",<key2>="<value2>",...` 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
|
||||||
|
}
|
69
vendor/go.opencensus.io/stats/doc.go
generated
vendored
Normal file
69
vendor/go.opencensus.io/stats/doc.go
generated
vendored
Normal file
|
@ -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"
|
25
vendor/go.opencensus.io/stats/internal/record.go
generated
vendored
Normal file
25
vendor/go.opencensus.io/stats/internal/record.go
generated
vendored
Normal file
|
@ -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)
|
109
vendor/go.opencensus.io/stats/measure.go
generated
vendored
Normal file
109
vendor/go.opencensus.io/stats/measure.go
generated
vendored
Normal file
|
@ -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
|
||||||
|
}
|
55
vendor/go.opencensus.io/stats/measure_float64.go
generated
vendored
Normal file
55
vendor/go.opencensus.io/stats/measure_float64.go
generated
vendored
Normal file
|
@ -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
|
||||||
|
}
|
55
vendor/go.opencensus.io/stats/measure_int64.go
generated
vendored
Normal file
55
vendor/go.opencensus.io/stats/measure_int64.go
generated
vendored
Normal file
|
@ -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
|
||||||
|
}
|
69
vendor/go.opencensus.io/stats/record.go
generated
vendored
Normal file
69
vendor/go.opencensus.io/stats/record.go
generated
vendored
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
// 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/stats/internal"
|
||||||
|
"go.opencensus.io/tag"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
internal.SubscriptionReporter = func(measure string) {
|
||||||
|
mu.Lock()
|
||||||
|
measures[measure].subscribe()
|
||||||
|
mu.Unlock()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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) {
|
||||||
|
recorder := internal.DefaultRecorder
|
||||||
|
if recorder == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if len(ms) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
record := false
|
||||||
|
for _, m := range ms {
|
||||||
|
if m.desc.subscribed() {
|
||||||
|
record = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !record {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// TODO(songy23): fix attachments.
|
||||||
|
recorder(tag.FromContext(ctx), ms, map[string]interface{}{})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 {
|
||||||
|
ctx, err := tag.New(ctx, mutators...)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
Record(ctx, ms...)
|
||||||
|
return nil
|
||||||
|
}
|
25
vendor/go.opencensus.io/stats/units.go
generated
vendored
Normal file
25
vendor/go.opencensus.io/stats/units.go
generated
vendored
Normal file
|
@ -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 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"
|
||||||
|
)
|
120
vendor/go.opencensus.io/stats/view/aggregation.go
generated
vendored
Normal file
120
vendor/go.opencensus.io/stats/view/aggregation.go
generated
vendored
Normal file
|
@ -0,0 +1,120 @@
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
// An 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 {
|
||||||
|
return &Aggregation{
|
||||||
|
Type: AggTypeDistribution,
|
||||||
|
Buckets: bounds,
|
||||||
|
newData: func() AggregationData {
|
||||||
|
return newDistributionData(bounds)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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{}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
293
vendor/go.opencensus.io/stats/view/aggregation_data.go
generated
vendored
Normal file
293
vendor/go.opencensus.io/stats/view/aggregation_data.go
generated
vendored
Normal file
|
@ -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(bounds []float64) *DistributionData {
|
||||||
|
bucketCount := len(bounds) + 1
|
||||||
|
return &DistributionData{
|
||||||
|
CountPerBucket: make([]int64, bucketCount),
|
||||||
|
ExemplarsPerBucket: make([]*metricdata.Exemplar, bucketCount),
|
||||||
|
bounds: bounds,
|
||||||
|
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")
|
||||||
|
}
|
||||||
|
}
|
86
vendor/go.opencensus.io/stats/view/collector.go
generated
vendored
Normal file
86
vendor/go.opencensus.io/stats/view/collector.go
generated
vendored
Normal file
|
@ -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
|
||||||
|
}
|
47
vendor/go.opencensus.io/stats/view/doc.go
generated
vendored
Normal file
47
vendor/go.opencensus.io/stats/view/doc.go
generated
vendored
Normal file
|
@ -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 registerd 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.
|
58
vendor/go.opencensus.io/stats/view/export.go
generated
vendored
Normal file
58
vendor/go.opencensus.io/stats/view/export.go
generated
vendored
Normal file
|
@ -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)
|
||||||
|
}
|
221
vendor/go.opencensus.io/stats/view/view.go
generated
vendored
Normal file
221
vendor/go.opencensus.io/stats/view/view.go
generated
vendored
Normal file
|
@ -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 to be 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 tp 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 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
|
||||||
|
}
|
131
vendor/go.opencensus.io/stats/view/view_to_metric.go
generated
vendored
Normal file
131
vendor/go.opencensus.io/stats/view/view_to_metric.go
generated
vendored
Normal file
|
@ -0,0 +1,131 @@
|
||||||
|
// 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 getLableKeys(v *View) []string {
|
||||||
|
labelKeys := []string{}
|
||||||
|
for _, k := range v.TagKeys {
|
||||||
|
labelKeys = append(labelKeys, k.Name())
|
||||||
|
}
|
||||||
|
return labelKeys
|
||||||
|
}
|
||||||
|
|
||||||
|
func viewToMetricDescriptor(v *View) *metricdata.Descriptor {
|
||||||
|
return &metricdata.Descriptor{
|
||||||
|
Name: v.Name,
|
||||||
|
Description: v.Description,
|
||||||
|
Unit: getUnit(v.Measure.Unit()),
|
||||||
|
Type: getType(v),
|
||||||
|
LabelKeys: getLableKeys(v),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func toLabelValues(row *Row) []metricdata.LabelValue {
|
||||||
|
labelValues := []metricdata.LabelValue{}
|
||||||
|
for _, tag := range row.Tags {
|
||||||
|
labelValues = append(labelValues, metricdata.NewLabelValue(tag.Value))
|
||||||
|
}
|
||||||
|
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),
|
||||||
|
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
|
||||||
|
}
|
279
vendor/go.opencensus.io/stats/view/worker.go
generated
vendored
Normal file
279
vendor/go.opencensus.io/stats/view/worker.go
generated
vendored
Normal file
|
@ -0,0 +1,279 @@
|
||||||
|
// 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) {
|
||||||
|
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
|
||||||
|
}
|
182
vendor/go.opencensus.io/stats/view/worker_commands.go
generated
vendored
Normal file
182
vendor/go.opencensus.io/stats/view/worker_commands.go
generated
vendored
Normal file
|
@ -0,0 +1,182 @@
|
||||||
|
// 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) {
|
||||||
|
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) {
|
||||||
|
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
|
||||||
|
}
|
43
vendor/go.opencensus.io/tag/context.go
generated
vendored
Normal file
43
vendor/go.opencensus.io/tag/context.go
generated
vendored
Normal file
|
@ -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{}
|
26
vendor/go.opencensus.io/tag/doc.go
generated
vendored
Normal file
26
vendor/go.opencensus.io/tag/doc.go
generated
vendored
Normal file
|
@ -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"
|
35
vendor/go.opencensus.io/tag/key.go
generated
vendored
Normal file
35
vendor/go.opencensus.io/tag/key.go
generated
vendored
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
// 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 consequently 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
|
||||||
|
}
|
||||||
|
|
||||||
|
// Name returns the name of the key.
|
||||||
|
func (k Key) Name() string {
|
||||||
|
return k.name
|
||||||
|
}
|
197
vendor/go.opencensus.io/tag/map.go
generated
vendored
Normal file
197
vendor/go.opencensus.io/tag/map.go
generated
vendored
Normal file
|
@ -0,0 +1,197 @@
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
|
||||||
|
// Map is a map of tags. Use New to create a context containing
|
||||||
|
// a new Map.
|
||||||
|
type Map struct {
|
||||||
|
m map[Key]string
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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, 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) {
|
||||||
|
if _, ok := m.m[k]; ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
m.m[k] = v
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Map) update(k Key, v string) {
|
||||||
|
if _, ok := m.m[k]; ok {
|
||||||
|
m.m[k] = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Map) upsert(k Key, v string) {
|
||||||
|
m.m[k] = v
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Map) delete(k Key) {
|
||||||
|
delete(m.m, k)
|
||||||
|
}
|
||||||
|
|
||||||
|
func newMap() *Map {
|
||||||
|
return &Map{m: make(map[Key]string)}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
func Insert(k Key, v string) Mutator {
|
||||||
|
return &mutator{
|
||||||
|
fn: func(m *Map) (*Map, error) {
|
||||||
|
if !checkValue(v) {
|
||||||
|
return nil, errInvalidValue
|
||||||
|
}
|
||||||
|
m.insert(k, v)
|
||||||
|
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.
|
||||||
|
func Update(k Key, v string) Mutator {
|
||||||
|
return &mutator{
|
||||||
|
fn: func(m *Map) (*Map, error) {
|
||||||
|
if !checkValue(v) {
|
||||||
|
return nil, errInvalidValue
|
||||||
|
}
|
||||||
|
m.update(k, v)
|
||||||
|
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.
|
||||||
|
func Upsert(k Key, v string) Mutator {
|
||||||
|
return &mutator{
|
||||||
|
fn: func(m *Map) (*Map, error) {
|
||||||
|
if !checkValue(v) {
|
||||||
|
return nil, errInvalidValue
|
||||||
|
}
|
||||||
|
m.upsert(k, v)
|
||||||
|
return m, nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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) {
|
||||||
|
return ctx, fmt.Errorf("key:%q value:%q: %v", k.Name(), v, errInvalidValue)
|
||||||
|
}
|
||||||
|
m.insert(k, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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)
|
||||||
|
}
|
237
vendor/go.opencensus.io/tag/map_codec.go
generated
vendored
Normal file
237
vendor/go.opencensus.io/tag/map_codec.go
generated
vendored
Normal file
|
@ -0,0 +1,237 @@
|
||||||
|
// 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(byte(tagsVersionID))
|
||||||
|
for k, v := range m.m {
|
||||||
|
eg.writeByte(byte(keyTypeString))
|
||||||
|
eg.writeStringWithVarintLen(k.name)
|
||||||
|
eg.writeBytesWithVarintLen([]byte(v))
|
||||||
|
}
|
||||||
|
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)) 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)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
31
vendor/go.opencensus.io/tag/profile_19.go
generated
vendored
Normal file
31
vendor/go.opencensus.io/tag/profile_19.go
generated
vendored
Normal file
|
@ -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)
|
||||||
|
}
|
||||||
|
pprof.Do(ctx, pprof.Labels(keyvals...), f)
|
||||||
|
}
|
23
vendor/go.opencensus.io/tag/profile_not19.go
generated
vendored
Normal file
23
vendor/go.opencensus.io/tag/profile_not19.go
generated
vendored
Normal file
|
@ -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)
|
||||||
|
}
|
56
vendor/go.opencensus.io/tag/validate.go
generated
vendored
Normal file
56
vendor/go.opencensus.io/tag/validate.go
generated
vendored
Normal file
|
@ -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)
|
||||||
|
}
|
119
vendor/go.opencensus.io/trace/basetypes.go
generated
vendored
Normal file
119
vendor/go.opencensus.io/trace/basetypes.go
generated
vendored
Normal file
|
@ -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
|
||||||
|
}
|
86
vendor/go.opencensus.io/trace/config.go
generated
vendored
Normal file
86
vendor/go.opencensus.io/trace/config.go
generated
vendored
Normal file
|
@ -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)
|
||||||
|
}
|
53
vendor/go.opencensus.io/trace/doc.go
generated
vendored
Normal file
53
vendor/go.opencensus.io/trace/doc.go
generated
vendored
Normal file
|
@ -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"
|
38
vendor/go.opencensus.io/trace/evictedqueue.go
generated
vendored
Normal file
38
vendor/go.opencensus.io/trace/evictedqueue.go
generated
vendored
Normal file
|
@ -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)
|
||||||
|
}
|
97
vendor/go.opencensus.io/trace/export.go
generated
vendored
Normal file
97
vendor/go.opencensus.io/trace/export.go
generated
vendored
Normal file
|
@ -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
|
||||||
|
}
|
22
vendor/go.opencensus.io/trace/internal/internal.go
generated
vendored
Normal file
22
vendor/go.opencensus.io/trace/internal/internal.go
generated
vendored
Normal file
|
@ -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
|
||||||
|
}
|
37
vendor/go.opencensus.io/trace/lrumap.go
generated
vendored
Normal file
37
vendor/go.opencensus.io/trace/lrumap.go
generated
vendored
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
// 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/hashicorp/golang-lru/simplelru"
|
||||||
|
)
|
||||||
|
|
||||||
|
type lruMap struct {
|
||||||
|
simpleLruMap *simplelru.LRU
|
||||||
|
droppedCount int
|
||||||
|
}
|
||||||
|
|
||||||
|
func newLruMap(size int) *lruMap {
|
||||||
|
lm := &lruMap{}
|
||||||
|
lm.simpleLruMap, _ = simplelru.NewLRU(size, nil)
|
||||||
|
return lm
|
||||||
|
}
|
||||||
|
|
||||||
|
func (lm *lruMap) add(key, value interface{}) {
|
||||||
|
evicted := lm.simpleLruMap.Add(key, value)
|
||||||
|
if evicted {
|
||||||
|
lm.droppedCount++
|
||||||
|
}
|
||||||
|
}
|
108
vendor/go.opencensus.io/trace/propagation/propagation.go
generated
vendored
Normal file
108
vendor/go.opencensus.io/trace/propagation/propagation.go
generated
vendored
Normal file
|
@ -0,0 +1,108 @@
|
||||||
|
// 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 propagation implements the binary trace context format.
|
||||||
|
package propagation // import "go.opencensus.io/trace/propagation"
|
||||||
|
|
||||||
|
// TODO: link to external spec document.
|
||||||
|
|
||||||
|
// BinaryFormat format:
|
||||||
|
//
|
||||||
|
// Binary value: <version_id><version_format>
|
||||||
|
// version_id: 1 byte representing the version id.
|
||||||
|
//
|
||||||
|
// For version_id = 0:
|
||||||
|
//
|
||||||
|
// version_format: <field><field>
|
||||||
|
// field_format: <field_id><field_format>
|
||||||
|
//
|
||||||
|
// Fields:
|
||||||
|
//
|
||||||
|
// TraceId: (field_id = 0, len = 16, default = "0000000000000000") - 16-byte array representing the trace_id.
|
||||||
|
// SpanId: (field_id = 1, len = 8, default = "00000000") - 8-byte array representing the span_id.
|
||||||
|
// TraceOptions: (field_id = 2, len = 1, default = "0") - 1-byte array representing the trace_options.
|
||||||
|
//
|
||||||
|
// Fields MUST be encoded using the field id order (smaller to higher).
|
||||||
|
//
|
||||||
|
// Valid value example:
|
||||||
|
//
|
||||||
|
// {0, 0, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 1, 97,
|
||||||
|
// 98, 99, 100, 101, 102, 103, 104, 2, 1}
|
||||||
|
//
|
||||||
|
// version_id = 0;
|
||||||
|
// trace_id = {64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79}
|
||||||
|
// span_id = {97, 98, 99, 100, 101, 102, 103, 104};
|
||||||
|
// trace_options = {1};
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"go.opencensus.io/trace"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Binary returns the binary format representation of a SpanContext.
|
||||||
|
//
|
||||||
|
// If sc is the zero value, Binary returns nil.
|
||||||
|
func Binary(sc trace.SpanContext) []byte {
|
||||||
|
if sc == (trace.SpanContext{}) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
var b [29]byte
|
||||||
|
copy(b[2:18], sc.TraceID[:])
|
||||||
|
b[18] = 1
|
||||||
|
copy(b[19:27], sc.SpanID[:])
|
||||||
|
b[27] = 2
|
||||||
|
b[28] = uint8(sc.TraceOptions)
|
||||||
|
return b[:]
|
||||||
|
}
|
||||||
|
|
||||||
|
// FromBinary returns the SpanContext represented by b.
|
||||||
|
//
|
||||||
|
// If b has an unsupported version ID or contains no TraceID, FromBinary
|
||||||
|
// returns with ok==false.
|
||||||
|
func FromBinary(b []byte) (sc trace.SpanContext, ok bool) {
|
||||||
|
if len(b) == 0 || b[0] != 0 {
|
||||||
|
return trace.SpanContext{}, false
|
||||||
|
}
|
||||||
|
b = b[1:]
|
||||||
|
if len(b) >= 17 && b[0] == 0 {
|
||||||
|
copy(sc.TraceID[:], b[1:17])
|
||||||
|
b = b[17:]
|
||||||
|
} else {
|
||||||
|
return trace.SpanContext{}, false
|
||||||
|
}
|
||||||
|
if len(b) >= 9 && b[0] == 1 {
|
||||||
|
copy(sc.SpanID[:], b[1:9])
|
||||||
|
b = b[9:]
|
||||||
|
}
|
||||||
|
if len(b) >= 2 && b[0] == 2 {
|
||||||
|
sc.TraceOptions = trace.TraceOptions(b[1])
|
||||||
|
}
|
||||||
|
return sc, true
|
||||||
|
}
|
||||||
|
|
||||||
|
// HTTPFormat implementations propagate span contexts
|
||||||
|
// in HTTP requests.
|
||||||
|
//
|
||||||
|
// SpanContextFromRequest extracts a span context from incoming
|
||||||
|
// requests.
|
||||||
|
//
|
||||||
|
// SpanContextToRequest modifies the given request to include the given
|
||||||
|
// span context.
|
||||||
|
type HTTPFormat interface {
|
||||||
|
SpanContextFromRequest(req *http.Request) (sc trace.SpanContext, ok bool)
|
||||||
|
SpanContextToRequest(sc trace.SpanContext, req *http.Request)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(jbd): Find a more representative but short name for HTTPFormat.
|
75
vendor/go.opencensus.io/trace/sampling.go
generated
vendored
Normal file
75
vendor/go.opencensus.io/trace/sampling.go
generated
vendored
Normal file
|
@ -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}
|
||||||
|
}
|
||||||
|
}
|
130
vendor/go.opencensus.io/trace/spanbucket.go
generated
vendored
Normal file
130
vendor/go.opencensus.io/trace/spanbucket.go
generated
vendored
Normal file
|
@ -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]
|
||||||
|
}
|
306
vendor/go.opencensus.io/trace/spanstore.go
generated
vendored
Normal file
306
vendor/go.opencensus.io/trace/spanstore.go
generated
vendored
Normal file
|
@ -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()
|
||||||
|
}
|
37
vendor/go.opencensus.io/trace/status_codes.go
generated
vendored
Normal file
37
vendor/go.opencensus.io/trace/status_codes.go
generated
vendored
Normal file
|
@ -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
|
||||||
|
)
|
598
vendor/go.opencensus.io/trace/trace.go
generated
vendored
Normal file
598
vendor/go.opencensus.io/trace/trace.go
generated
vendored
Normal file
|
@ -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.simpleLruMap.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.simpleLruMap.Keys() {
|
||||||
|
value, ok := s.lruAttributes.simpleLruMap.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 "<nil>"
|
||||||
|
}
|
||||||
|
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
|
||||||
|
}
|
32
vendor/go.opencensus.io/trace/trace_go11.go
generated
vendored
Normal file
32
vendor/go.opencensus.io/trace/trace_go11.go
generated
vendored
Normal file
|
@ -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
|
||||||
|
}
|
25
vendor/go.opencensus.io/trace/trace_nongo11.go
generated
vendored
Normal file
25
vendor/go.opencensus.io/trace/trace_nongo11.go
generated
vendored
Normal file
|
@ -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() {}
|
||||||
|
}
|
147
vendor/go.opencensus.io/trace/tracestate/tracestate.go
generated
vendored
Normal file
147
vendor/go.opencensus.io/trace/tracestate/tracestate.go
generated
vendored
Normal file
|
@ -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
|
||||||
|
}
|
50
vendor/golang.org/x/net/http/httpguts/guts.go
generated
vendored
Normal file
50
vendor/golang.org/x/net/http/httpguts/guts.go
generated
vendored
Normal file
|
@ -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,
|
||||||
|
}
|
346
vendor/golang.org/x/net/http/httpguts/httplex.go
generated
vendored
Normal file
346
vendor/golang.org/x/net/http/httpguts/httplex.go
generated
vendored
Normal file
|
@ -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 = <any US-ASCII control character
|
||||||
|
// (octets 0 - 31) and DEL (127)>
|
||||||
|
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 = <the OCTETs making up the field-value
|
||||||
|
// and consisting of either *TEXT or combinations
|
||||||
|
// of token, separators, and quoted-string>
|
||||||
|
//
|
||||||
|
// http://www.w3.org/Protocols/rfc2616/rfc2616-sec2.html#sec2.2 :
|
||||||
|
//
|
||||||
|
// TEXT = <any OCTET except CTLs,
|
||||||
|
// but including LWS>
|
||||||
|
// LWS = [CRLF] 1*( SP | HT )
|
||||||
|
// CTL = <any US-ASCII control character
|
||||||
|
// (octets 0 - 31) and DEL (127)>
|
||||||
|
//
|
||||||
|
// 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
|
||||||
|
}
|
641
vendor/golang.org/x/net/http2/ciphers.go
generated
vendored
Normal file
641
vendor/golang.org/x/net/http2/ciphers.go
generated
vendored
Normal file
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
282
vendor/golang.org/x/net/http2/client_conn_pool.go
generated
vendored
Normal file
282
vendor/golang.org/x/net/http2/client_conn_pool.go
generated
vendored
Normal file
|
@ -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)
|
||||||
|
}
|
82
vendor/golang.org/x/net/http2/configure_transport.go
generated
vendored
Normal file
82
vendor/golang.org/x/net/http2/configure_transport.go
generated
vendored
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
// 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 go1.6
|
||||||
|
|
||||||
|
package http2
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/tls"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
func configureTransport(t1 *http.Transport) (*Transport, error) {
|
||||||
|
connPool := new(clientConnPool)
|
||||||
|
t2 := &Transport{
|
||||||
|
ConnPool: noDialClientConnPool{connPool},
|
||||||
|
t1: t1,
|
||||||
|
}
|
||||||
|
connPool.t = t2
|
||||||
|
if err := registerHTTPSProtocol(t1, noDialH2RoundTripper{t2}); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if t1.TLSClientConfig == nil {
|
||||||
|
t1.TLSClientConfig = new(tls.Config)
|
||||||
|
}
|
||||||
|
if !strSliceContains(t1.TLSClientConfig.NextProtos, "h2") {
|
||||||
|
t1.TLSClientConfig.NextProtos = append([]string{"h2"}, t1.TLSClientConfig.NextProtos...)
|
||||||
|
}
|
||||||
|
if !strSliceContains(t1.TLSClientConfig.NextProtos, "http/1.1") {
|
||||||
|
t1.TLSClientConfig.NextProtos = append(t1.TLSClientConfig.NextProtos, "http/1.1")
|
||||||
|
}
|
||||||
|
upgradeFn := func(authority string, c *tls.Conn) http.RoundTripper {
|
||||||
|
addr := authorityAddr("https", authority)
|
||||||
|
if used, err := connPool.addConnIfNeeded(addr, t2, c); err != nil {
|
||||||
|
go c.Close()
|
||||||
|
return erringRoundTripper{err}
|
||||||
|
} else if !used {
|
||||||
|
// Turns out we don't need this c.
|
||||||
|
// For example, two goroutines made requests to the same host
|
||||||
|
// at the same time, both kicking off TCP dials. (since protocol
|
||||||
|
// was unknown)
|
||||||
|
go c.Close()
|
||||||
|
}
|
||||||
|
return t2
|
||||||
|
}
|
||||||
|
if m := t1.TLSNextProto; len(m) == 0 {
|
||||||
|
t1.TLSNextProto = map[string]func(string, *tls.Conn) http.RoundTripper{
|
||||||
|
"h2": upgradeFn,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
m["h2"] = upgradeFn
|
||||||
|
}
|
||||||
|
return t2, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// registerHTTPSProtocol calls Transport.RegisterProtocol but
|
||||||
|
// converting panics into errors.
|
||||||
|
func registerHTTPSProtocol(t *http.Transport, rt noDialH2RoundTripper) (err error) {
|
||||||
|
defer func() {
|
||||||
|
if e := recover(); e != nil {
|
||||||
|
err = fmt.Errorf("%v", e)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
t.RegisterProtocol("https", rt)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// noDialH2RoundTripper is a RoundTripper which only tries to complete the request
|
||||||
|
// if there's already has a cached connection to the host.
|
||||||
|
// (The field is exported so it can be accessed via reflect from net/http; tested
|
||||||
|
// by TestNoDialH2RoundTripperType)
|
||||||
|
type noDialH2RoundTripper struct{ *Transport }
|
||||||
|
|
||||||
|
func (rt noDialH2RoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||||
|
res, err := rt.Transport.RoundTrip(req)
|
||||||
|
if isNoCachedConnError(err) {
|
||||||
|
return nil, http.ErrSkipAltProtocol
|
||||||
|
}
|
||||||
|
return res, err
|
||||||
|
}
|
146
vendor/golang.org/x/net/http2/databuffer.go
generated
vendored
Normal file
146
vendor/golang.org/x/net/http2/databuffer.go
generated
vendored
Normal file
|
@ -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
|
||||||
|
}
|
133
vendor/golang.org/x/net/http2/errors.go
generated
vendored
Normal file
133
vendor/golang.org/x/net/http2/errors.go
generated
vendored
Normal file
|
@ -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")
|
||||||
|
)
|
50
vendor/golang.org/x/net/http2/flow.go
generated
vendored
Normal file
50
vendor/golang.org/x/net/http2/flow.go
generated
vendored
Normal file
|
@ -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
|
||||||
|
}
|
1614
vendor/golang.org/x/net/http2/frame.go
generated
vendored
Normal file
1614
vendor/golang.org/x/net/http2/frame.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
26
vendor/golang.org/x/net/http2/go111.go
generated
vendored
Normal file
26
vendor/golang.org/x/net/http2/go111.go
generated
vendored
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
// 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/textproto"
|
||||||
|
|
||||||
|
func traceHasWroteHeaderField(trace *clientTrace) bool {
|
||||||
|
return trace != nil && trace.WroteHeaderField != nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func traceWroteHeaderField(trace *clientTrace, k, v string) {
|
||||||
|
if trace != nil && trace.WroteHeaderField != nil {
|
||||||
|
trace.WroteHeaderField(k, []string{v})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func traceGot1xxResponseFunc(trace *clientTrace) func(int, textproto.MIMEHeader) error {
|
||||||
|
if trace != nil {
|
||||||
|
return trace.Got1xxResponse
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
16
vendor/golang.org/x/net/http2/go16.go
generated
vendored
Normal file
16
vendor/golang.org/x/net/http2/go16.go
generated
vendored
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
// 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 go1.6
|
||||||
|
|
||||||
|
package http2
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func transportExpectContinueTimeout(t1 *http.Transport) time.Duration {
|
||||||
|
return t1.ExpectContinueTimeout
|
||||||
|
}
|
121
vendor/golang.org/x/net/http2/go17.go
generated
vendored
Normal file
121
vendor/golang.org/x/net/http2/go17.go
generated
vendored
Normal file
|
@ -0,0 +1,121 @@
|
||||||
|
// 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 go1.7
|
||||||
|
|
||||||
|
package http2
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptrace"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type contextContext interface {
|
||||||
|
context.Context
|
||||||
|
}
|
||||||
|
|
||||||
|
var errCanceled = context.Canceled
|
||||||
|
|
||||||
|
func serverConnBaseContext(c net.Conn, opts *ServeConnOpts) (ctx contextContext, cancel func()) {
|
||||||
|
ctx, cancel = context.WithCancel(context.Background())
|
||||||
|
ctx = context.WithValue(ctx, http.LocalAddrContextKey, c.LocalAddr())
|
||||||
|
if hs := opts.baseConfig(); hs != nil {
|
||||||
|
ctx = context.WithValue(ctx, http.ServerContextKey, hs)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func contextWithCancel(ctx contextContext) (_ contextContext, cancel func()) {
|
||||||
|
return context.WithCancel(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func requestWithContext(req *http.Request, ctx contextContext) *http.Request {
|
||||||
|
return req.WithContext(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
type clientTrace httptrace.ClientTrace
|
||||||
|
|
||||||
|
func reqContext(r *http.Request) context.Context { return r.Context() }
|
||||||
|
|
||||||
|
func (t *Transport) idleConnTimeout() time.Duration {
|
||||||
|
if t.t1 != nil {
|
||||||
|
return t.t1.IdleConnTimeout
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func setResponseUncompressed(res *http.Response) { res.Uncompressed = true }
|
||||||
|
|
||||||
|
func traceGetConn(req *http.Request, hostPort string) {
|
||||||
|
trace := httptrace.ContextClientTrace(req.Context())
|
||||||
|
if trace == nil || trace.GetConn == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
trace.GetConn(hostPort)
|
||||||
|
}
|
||||||
|
|
||||||
|
func traceGotConn(req *http.Request, cc *ClientConn) {
|
||||||
|
trace := httptrace.ContextClientTrace(req.Context())
|
||||||
|
if trace == nil || trace.GotConn == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ci := httptrace.GotConnInfo{Conn: cc.tconn}
|
||||||
|
cc.mu.Lock()
|
||||||
|
ci.Reused = cc.nextStreamID > 1
|
||||||
|
ci.WasIdle = len(cc.streams) == 0 && ci.Reused
|
||||||
|
if ci.WasIdle && !cc.lastActive.IsZero() {
|
||||||
|
ci.IdleTime = time.Now().Sub(cc.lastActive)
|
||||||
|
}
|
||||||
|
cc.mu.Unlock()
|
||||||
|
|
||||||
|
trace.GotConn(ci)
|
||||||
|
}
|
||||||
|
|
||||||
|
func traceWroteHeaders(trace *clientTrace) {
|
||||||
|
if trace != nil && trace.WroteHeaders != nil {
|
||||||
|
trace.WroteHeaders()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func traceGot100Continue(trace *clientTrace) {
|
||||||
|
if trace != nil && trace.Got100Continue != nil {
|
||||||
|
trace.Got100Continue()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func traceWait100Continue(trace *clientTrace) {
|
||||||
|
if trace != nil && trace.Wait100Continue != nil {
|
||||||
|
trace.Wait100Continue()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func traceWroteRequest(trace *clientTrace, err error) {
|
||||||
|
if trace != nil && trace.WroteRequest != nil {
|
||||||
|
trace.WroteRequest(httptrace.WroteRequestInfo{Err: err})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func traceFirstResponseByte(trace *clientTrace) {
|
||||||
|
if trace != nil && trace.GotFirstResponseByte != nil {
|
||||||
|
trace.GotFirstResponseByte()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func requestTrace(req *http.Request) *clientTrace {
|
||||||
|
trace := httptrace.ContextClientTrace(req.Context())
|
||||||
|
return (*clientTrace)(trace)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ping sends a PING frame to the server and waits for the ack.
|
||||||
|
func (cc *ClientConn) Ping(ctx context.Context) error {
|
||||||
|
return cc.ping(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shutdown gracefully closes the client connection, waiting for running streams to complete.
|
||||||
|
func (cc *ClientConn) Shutdown(ctx context.Context) error {
|
||||||
|
return cc.shutdown(ctx)
|
||||||
|
}
|
36
vendor/golang.org/x/net/http2/go17_not18.go
generated
vendored
Normal file
36
vendor/golang.org/x/net/http2/go17_not18.go
generated
vendored
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
// 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 go1.7,!go1.8
|
||||||
|
|
||||||
|
package http2
|
||||||
|
|
||||||
|
import "crypto/tls"
|
||||||
|
|
||||||
|
// temporary copy of Go 1.7's private tls.Config.clone:
|
||||||
|
func cloneTLSConfig(c *tls.Config) *tls.Config {
|
||||||
|
return &tls.Config{
|
||||||
|
Rand: c.Rand,
|
||||||
|
Time: c.Time,
|
||||||
|
Certificates: c.Certificates,
|
||||||
|
NameToCertificate: c.NameToCertificate,
|
||||||
|
GetCertificate: c.GetCertificate,
|
||||||
|
RootCAs: c.RootCAs,
|
||||||
|
NextProtos: c.NextProtos,
|
||||||
|
ServerName: c.ServerName,
|
||||||
|
ClientAuth: c.ClientAuth,
|
||||||
|
ClientCAs: c.ClientCAs,
|
||||||
|
InsecureSkipVerify: c.InsecureSkipVerify,
|
||||||
|
CipherSuites: c.CipherSuites,
|
||||||
|
PreferServerCipherSuites: c.PreferServerCipherSuites,
|
||||||
|
SessionTicketsDisabled: c.SessionTicketsDisabled,
|
||||||
|
SessionTicketKey: c.SessionTicketKey,
|
||||||
|
ClientSessionCache: c.ClientSessionCache,
|
||||||
|
MinVersion: c.MinVersion,
|
||||||
|
MaxVersion: c.MaxVersion,
|
||||||
|
CurvePreferences: c.CurvePreferences,
|
||||||
|
DynamicRecordSizingDisabled: c.DynamicRecordSizingDisabled,
|
||||||
|
Renegotiation: c.Renegotiation,
|
||||||
|
}
|
||||||
|
}
|
56
vendor/golang.org/x/net/http2/go18.go
generated
vendored
Normal file
56
vendor/golang.org/x/net/http2/go18.go
generated
vendored
Normal file
|
@ -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 go1.8
|
||||||
|
|
||||||
|
package http2
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/tls"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
func cloneTLSConfig(c *tls.Config) *tls.Config {
|
||||||
|
c2 := c.Clone()
|
||||||
|
c2.GetClientCertificate = c.GetClientCertificate // golang.org/issue/19264
|
||||||
|
return c2
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ http.Pusher = (*responseWriter)(nil)
|
||||||
|
|
||||||
|
// Push implements http.Pusher.
|
||||||
|
func (w *responseWriter) Push(target string, opts *http.PushOptions) error {
|
||||||
|
internalOpts := pushOptions{}
|
||||||
|
if opts != nil {
|
||||||
|
internalOpts.Method = opts.Method
|
||||||
|
internalOpts.Header = opts.Header
|
||||||
|
}
|
||||||
|
return w.push(target, internalOpts)
|
||||||
|
}
|
||||||
|
|
||||||
|
func configureServer18(h1 *http.Server, h2 *Server) error {
|
||||||
|
if h2.IdleTimeout == 0 {
|
||||||
|
if h1.IdleTimeout != 0 {
|
||||||
|
h2.IdleTimeout = h1.IdleTimeout
|
||||||
|
} else {
|
||||||
|
h2.IdleTimeout = h1.ReadTimeout
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func shouldLogPanic(panicValue interface{}) bool {
|
||||||
|
return panicValue != nil && panicValue != http.ErrAbortHandler
|
||||||
|
}
|
||||||
|
|
||||||
|
func reqGetBody(req *http.Request) func() (io.ReadCloser, error) {
|
||||||
|
return req.GetBody
|
||||||
|
}
|
||||||
|
|
||||||
|
func reqBodyIsNoBody(body io.ReadCloser) bool {
|
||||||
|
return body == http.NoBody
|
||||||
|
}
|
||||||
|
|
||||||
|
func go18httpNoBody() io.ReadCloser { return http.NoBody } // for tests only
|
16
vendor/golang.org/x/net/http2/go19.go
generated
vendored
Normal file
16
vendor/golang.org/x/net/http2/go19.go
generated
vendored
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
// 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 go1.9
|
||||||
|
|
||||||
|
package http2
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
func configureServer19(s *http.Server, conf *Server) error {
|
||||||
|
s.RegisterOnShutdown(conf.state.startGracefulShutdown)
|
||||||
|
return nil
|
||||||
|
}
|
170
vendor/golang.org/x/net/http2/gotrack.go
generated
vendored
Normal file
170
vendor/golang.org/x/net/http2/gotrack.go
generated
vendored
Normal file
|
@ -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<<uint(bitSize) - 1
|
||||||
|
|
||||||
|
for i := 0; i < len(s); i++ {
|
||||||
|
var v byte
|
||||||
|
d := s[i]
|
||||||
|
switch {
|
||||||
|
case '0' <= d && d <= '9':
|
||||||
|
v = d - '0'
|
||||||
|
case 'a' <= d && d <= 'z':
|
||||||
|
v = d - 'a' + 10
|
||||||
|
case 'A' <= d && d <= 'Z':
|
||||||
|
v = d - 'A' + 10
|
||||||
|
default:
|
||||||
|
n = 0
|
||||||
|
err = strconv.ErrSyntax
|
||||||
|
goto Error
|
||||||
|
}
|
||||||
|
if int(v) >= 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
|
||||||
|
}
|
88
vendor/golang.org/x/net/http2/headermap.go
generated
vendored
Normal file
88
vendor/golang.org/x/net/http2/headermap.go
generated
vendored
Normal file
|
@ -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)
|
||||||
|
}
|
240
vendor/golang.org/x/net/http2/hpack/encode.go
generated
vendored
Normal file
240
vendor/golang.org/x/net/http2/hpack/encode.go
generated
vendored
Normal file
|
@ -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, "Inremental 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
|
||||||
|
}
|
496
vendor/golang.org/x/net/http2/hpack/hpack.go
generated
vendored
Normal file
496
vendor/golang.org/x/net/http2/hpack/hpack.go
generated
vendored
Normal file
|
@ -0,0 +1,496 @@
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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,
|
||||||
|
}
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Decoder) Close() error {
|
||||||
|
if d.saveBuf.Len() > 0 {
|
||||||
|
d.saveBuf.Reset()
|
||||||
|
return DecodingError{errors.New("truncated headers")}
|
||||||
|
}
|
||||||
|
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
|
||||||
|
}
|
||||||
|
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.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<<uint64(n))-1 {
|
||||||
|
return i, p[1:], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
origP := p
|
||||||
|
p = p[1:]
|
||||||
|
var m uint64
|
||||||
|
for len(p) > 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
|
||||||
|
}
|
222
vendor/golang.org/x/net/http2/hpack/huffman.go
generated
vendored
Normal file
222
vendor/golang.org/x/net/http2/hpack/huffman.go
generated
vendored
Normal file
|
@ -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<<cbits - 1); cur&mask != mask {
|
||||||
|
// Trailing bits must be a prefix of EOS per RFC 7541 section 5.2.
|
||||||
|
return ErrInvalidHuffman
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type node struct {
|
||||||
|
// children is non-nil for internal nodes
|
||||||
|
children *[256]*node
|
||||||
|
|
||||||
|
// The following are only valid if children is nil:
|
||||||
|
codeLen uint8 // number of bits that led to the output of sym
|
||||||
|
sym byte // output symbol
|
||||||
|
}
|
||||||
|
|
||||||
|
func newInternalNode() *node {
|
||||||
|
return &node{children: new([256]*node)}
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
buildRootOnce sync.Once
|
||||||
|
lazyRootHuffmanNode *node
|
||||||
|
)
|
||||||
|
|
||||||
|
func getRootHuffmanNode() *node {
|
||||||
|
buildRootOnce.Do(buildRootHuffmanNode)
|
||||||
|
return lazyRootHuffmanNode
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildRootHuffmanNode() {
|
||||||
|
if len(huffmanCodes) != 256 {
|
||||||
|
panic("unexpected size")
|
||||||
|
}
|
||||||
|
lazyRootHuffmanNode = newInternalNode()
|
||||||
|
for i, code := range huffmanCodes {
|
||||||
|
addDecoderNode(byte(i), code, huffmanCodeLen[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func addDecoderNode(sym byte, code uint32, codeLen uint8) {
|
||||||
|
cur := lazyRootHuffmanNode
|
||||||
|
for codeLen > 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<<shift)), int(1<<shift)
|
||||||
|
for i := start; i < start+end; i++ {
|
||||||
|
cur.children[i] = &node{sym: sym, codeLen: codeLen}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// AppendHuffmanString appends s, as encoded in Huffman codes, to dst
|
||||||
|
// and returns the extended buffer.
|
||||||
|
func AppendHuffmanString(dst []byte, s string) []byte {
|
||||||
|
rembits := uint8(8)
|
||||||
|
|
||||||
|
for i := 0; i < len(s); i++ {
|
||||||
|
if rembits == 8 {
|
||||||
|
dst = append(dst, 0)
|
||||||
|
}
|
||||||
|
dst, rembits = appendByteToHuffmanCode(dst, rembits, s[i])
|
||||||
|
}
|
||||||
|
|
||||||
|
if rembits < 8 {
|
||||||
|
// special EOS symbol
|
||||||
|
code := uint32(0x3fffffff)
|
||||||
|
nbits := uint8(30)
|
||||||
|
|
||||||
|
t := 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
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue