Instana tracer implementation
This commit is contained in:
parent
c2c6aee18a
commit
aef24dd74b
43 changed files with 4502 additions and 2 deletions
28
Gopkg.lock
generated
28
Gopkg.lock
generated
|
@ -1022,6 +1022,14 @@
|
||||||
revision = "2d474a3089bcfce6b472779be9470a1f0ef3d5e4"
|
revision = "2d474a3089bcfce6b472779be9470a1f0ef3d5e4"
|
||||||
version = "v1.3.7"
|
version = "v1.3.7"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
digest = "1:78efd72f12ed0244e5fbe82bd0ecdbaf3e21402ee9176525ef1138a2fc0d3b17"
|
||||||
|
name = "github.com/instana/go-sensor"
|
||||||
|
packages = ["."]
|
||||||
|
pruneopts = "NUT"
|
||||||
|
revision = "493edb42228321483dd4d59ade71ca93fa89d66b"
|
||||||
|
version = "1.4.12"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:ac6d01547ec4f7f673311b4663909269bfb8249952de3279799289467837c3cc"
|
digest = "1:ac6d01547ec4f7f673311b4663909269bfb8249952de3279799289467837c3cc"
|
||||||
name = "github.com/jmespath/go-jmespath"
|
name = "github.com/jmespath/go-jmespath"
|
||||||
|
@ -1111,6 +1119,14 @@
|
||||||
revision = "d0d31d8ca62fa3f7e4526ca0ce95de81e4ed001e"
|
revision = "d0d31d8ca62fa3f7e4526ca0ce95de81e4ed001e"
|
||||||
version = "v0.5.1"
|
version = "v0.5.1"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
digest = "1:8520e78cbe9878f6bf0cfdcfaed5761cd575b3568c260a1c891ac1f5c5c6a726"
|
||||||
|
name = "github.com/looplab/fsm"
|
||||||
|
packages = ["."]
|
||||||
|
pruneopts = "NUT"
|
||||||
|
revision = "84b5307469f859464403f80919467950a79de1b1"
|
||||||
|
version = "v0.1.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:196b0d7580e898df15a7cc5371cbfe2b8e22904f5c6c883ed5db0130e551c8fb"
|
digest = "1:196b0d7580e898df15a7cc5371cbfe2b8e22904f5c6c883ed5db0130e551c8fb"
|
||||||
name = "github.com/mailgun/minheap"
|
name = "github.com/mailgun/minheap"
|
||||||
|
@ -1327,6 +1343,17 @@
|
||||||
pruneopts = "NUT"
|
pruneopts = "NUT"
|
||||||
revision = "a52f2342449246d5bcc273e65cbdcfa5f7d6c63c"
|
revision = "a52f2342449246d5bcc273e65cbdcfa5f7d6c63c"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
digest = "1:cc405544fecfb5a8e0c409127ef67ce3b91d11143a00121e5b822e4f8eabe7d2"
|
||||||
|
name = "github.com/opentracing/basictracer-go"
|
||||||
|
packages = [
|
||||||
|
".",
|
||||||
|
"wire",
|
||||||
|
]
|
||||||
|
pruneopts = "NUT"
|
||||||
|
revision = "1b32af207119a14b1b231d451df3ed04a72efebf"
|
||||||
|
version = "v1.0.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:7da29c22bcc5c2ffb308324377dc00b5084650348c2799e573ed226d8cc9faf0"
|
digest = "1:7da29c22bcc5c2ffb308324377dc00b5084650348c2799e573ed226d8cc9faf0"
|
||||||
name = "github.com/opentracing/opentracing-go"
|
name = "github.com/opentracing/opentracing-go"
|
||||||
|
@ -2326,6 +2353,7 @@
|
||||||
"github.com/hashicorp/consul/api",
|
"github.com/hashicorp/consul/api",
|
||||||
"github.com/hashicorp/go-version",
|
"github.com/hashicorp/go-version",
|
||||||
"github.com/influxdata/influxdb/client/v2",
|
"github.com/influxdata/influxdb/client/v2",
|
||||||
|
"github.com/instana/go-sensor",
|
||||||
"github.com/libkermit/compose/check",
|
"github.com/libkermit/compose/check",
|
||||||
"github.com/libkermit/docker",
|
"github.com/libkermit/docker",
|
||||||
"github.com/libkermit/docker-check",
|
"github.com/libkermit/docker-check",
|
||||||
|
|
|
@ -255,3 +255,7 @@
|
||||||
[[constraint]]
|
[[constraint]]
|
||||||
name = "gopkg.in/DataDog/dd-trace-go.v1"
|
name = "gopkg.in/DataDog/dd-trace-go.v1"
|
||||||
version = "1.7.0"
|
version = "1.7.0"
|
||||||
|
|
||||||
|
[[constraint]]
|
||||||
|
name = "github.com/instana/go-sensor"
|
||||||
|
version = "1.4.12"
|
||||||
|
|
|
@ -24,6 +24,7 @@ import (
|
||||||
"github.com/containous/traefik/provider/marathon"
|
"github.com/containous/traefik/provider/marathon"
|
||||||
"github.com/containous/traefik/provider/rest"
|
"github.com/containous/traefik/provider/rest"
|
||||||
"github.com/containous/traefik/tracing/datadog"
|
"github.com/containous/traefik/tracing/datadog"
|
||||||
|
"github.com/containous/traefik/tracing/instana"
|
||||||
"github.com/containous/traefik/tracing/jaeger"
|
"github.com/containous/traefik/tracing/jaeger"
|
||||||
"github.com/containous/traefik/tracing/zipkin"
|
"github.com/containous/traefik/tracing/zipkin"
|
||||||
"github.com/containous/traefik/types"
|
"github.com/containous/traefik/types"
|
||||||
|
@ -114,6 +115,11 @@ func NewTraefikDefaultPointersConfiguration() *TraefikConfiguration {
|
||||||
Debug: false,
|
Debug: false,
|
||||||
PrioritySampling: false,
|
PrioritySampling: false,
|
||||||
},
|
},
|
||||||
|
Instana: &instana.Config{
|
||||||
|
LocalAgentHost: "localhost",
|
||||||
|
LocalAgentPort: 42699,
|
||||||
|
LogLevel: "info",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
// default ApiConfiguration
|
// default ApiConfiguration
|
||||||
|
|
|
@ -27,6 +27,7 @@ import (
|
||||||
"github.com/containous/traefik/provider/rest"
|
"github.com/containous/traefik/provider/rest"
|
||||||
"github.com/containous/traefik/tls"
|
"github.com/containous/traefik/tls"
|
||||||
"github.com/containous/traefik/tracing/datadog"
|
"github.com/containous/traefik/tracing/datadog"
|
||||||
|
"github.com/containous/traefik/tracing/instana"
|
||||||
"github.com/containous/traefik/tracing/jaeger"
|
"github.com/containous/traefik/tracing/jaeger"
|
||||||
"github.com/containous/traefik/tracing/zipkin"
|
"github.com/containous/traefik/tracing/zipkin"
|
||||||
"github.com/containous/traefik/types"
|
"github.com/containous/traefik/types"
|
||||||
|
@ -117,12 +118,13 @@ type LifeCycle struct {
|
||||||
|
|
||||||
// Tracing holds the tracing configuration.
|
// Tracing holds the tracing configuration.
|
||||||
type Tracing struct {
|
type Tracing struct {
|
||||||
Backend string `description:"Selects the tracking backend ('jaeger','zipkin', 'datadog')." export:"true"`
|
Backend string `description:"Selects the tracking backend ('jaeger','zipkin','datadog','instana')." export:"true"`
|
||||||
ServiceName string `description:"Set the name for this service" export:"true"`
|
ServiceName string `description:"Set the name for this service" export:"true"`
|
||||||
SpanNameLimit int `description:"Set the maximum character limit for Span names (default 0 = no limit)" export:"true"`
|
SpanNameLimit int `description:"Set the maximum character limit for Span names (default 0 = no limit)" export:"true"`
|
||||||
Jaeger *jaeger.Config `description:"Settings for jaeger"`
|
Jaeger *jaeger.Config `description:"Settings for jaeger"`
|
||||||
Zipkin *zipkin.Config `description:"Settings for zipkin"`
|
Zipkin *zipkin.Config `description:"Settings for zipkin"`
|
||||||
DataDog *datadog.Config `description:"Settings for DataDog"`
|
DataDog *datadog.Config `description:"Settings for DataDog"`
|
||||||
|
Instana *instana.Config `description:"Settings for Instana"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Providers contains providers configuration
|
// Providers contains providers configuration
|
||||||
|
@ -244,6 +246,10 @@ func (c *Configuration) initTracing() {
|
||||||
log.Warn("DataDog configuration will be ignored")
|
log.Warn("DataDog configuration will be ignored")
|
||||||
c.Tracing.DataDog = nil
|
c.Tracing.DataDog = nil
|
||||||
}
|
}
|
||||||
|
if c.Tracing.Instana != nil {
|
||||||
|
log.Warn("Instana configuration will be ignored")
|
||||||
|
c.Tracing.Instana = nil
|
||||||
|
}
|
||||||
case zipkin.Name:
|
case zipkin.Name:
|
||||||
if c.Tracing.Zipkin == nil {
|
if c.Tracing.Zipkin == nil {
|
||||||
c.Tracing.Zipkin = &zipkin.Config{
|
c.Tracing.Zipkin = &zipkin.Config{
|
||||||
|
@ -262,6 +268,10 @@ func (c *Configuration) initTracing() {
|
||||||
log.Warn("DataDog configuration will be ignored")
|
log.Warn("DataDog configuration will be ignored")
|
||||||
c.Tracing.DataDog = nil
|
c.Tracing.DataDog = nil
|
||||||
}
|
}
|
||||||
|
if c.Tracing.Instana != nil {
|
||||||
|
log.Warn("Instana configuration will be ignored")
|
||||||
|
c.Tracing.Instana = nil
|
||||||
|
}
|
||||||
case datadog.Name:
|
case datadog.Name:
|
||||||
if c.Tracing.DataDog == nil {
|
if c.Tracing.DataDog == nil {
|
||||||
c.Tracing.DataDog = &datadog.Config{
|
c.Tracing.DataDog = &datadog.Config{
|
||||||
|
@ -278,6 +288,30 @@ func (c *Configuration) initTracing() {
|
||||||
log.Warn("Jaeger configuration will be ignored")
|
log.Warn("Jaeger configuration will be ignored")
|
||||||
c.Tracing.Jaeger = nil
|
c.Tracing.Jaeger = nil
|
||||||
}
|
}
|
||||||
|
if c.Tracing.Instana != nil {
|
||||||
|
log.Warn("Instana configuration will be ignored")
|
||||||
|
c.Tracing.Instana = nil
|
||||||
|
}
|
||||||
|
case instana.Name:
|
||||||
|
if c.Tracing.Instana == nil {
|
||||||
|
c.Tracing.Instana = &instana.Config{
|
||||||
|
LocalAgentHost: "localhost",
|
||||||
|
LocalAgentPort: 42699,
|
||||||
|
LogLevel: "info",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if c.Tracing.Zipkin != nil {
|
||||||
|
log.Warn("Zipkin configuration will be ignored")
|
||||||
|
c.Tracing.Zipkin = nil
|
||||||
|
}
|
||||||
|
if c.Tracing.Jaeger != nil {
|
||||||
|
log.Warn("Jaeger configuration will be ignored")
|
||||||
|
c.Tracing.Jaeger = nil
|
||||||
|
}
|
||||||
|
if c.Tracing.DataDog != nil {
|
||||||
|
log.Warn("DataDog configuration will be ignored")
|
||||||
|
c.Tracing.DataDog = nil
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
log.Warnf("Unknown tracer %q", c.Tracing.Backend)
|
log.Warnf("Unknown tracer %q", c.Tracing.Backend)
|
||||||
return
|
return
|
||||||
|
|
|
@ -4,7 +4,7 @@ The tracing system allows developers to visualize call flows in their infrastruc
|
||||||
|
|
||||||
We use [OpenTracing](http://opentracing.io). It is an open standard designed for distributed tracing.
|
We use [OpenTracing](http://opentracing.io). It is an open standard designed for distributed tracing.
|
||||||
|
|
||||||
Traefik supports three tracing backends: Jaeger, Zipkin and DataDog.
|
Traefik supports four tracing backends: Jaeger, Zipkin, DataDog, and Instana.
|
||||||
|
|
||||||
## Jaeger
|
## Jaeger
|
||||||
|
|
||||||
|
@ -188,3 +188,41 @@ Traefik supports three tracing backends: Jaeger, Zipkin and DataDog.
|
||||||
#
|
#
|
||||||
prioritySampling = false
|
prioritySampling = false
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Instana
|
||||||
|
|
||||||
|
```toml
|
||||||
|
# Tracing definition
|
||||||
|
[tracing]
|
||||||
|
# Backend name used to send tracing data
|
||||||
|
#
|
||||||
|
# Default: "jaeger"
|
||||||
|
#
|
||||||
|
backend = "instana"
|
||||||
|
# Service name used in Instana backend
|
||||||
|
#
|
||||||
|
# Default: "traefik"
|
||||||
|
#
|
||||||
|
serviceName = "traefik"
|
||||||
|
[tracing.instana]
|
||||||
|
# Local Agent Host instructs reporter to send spans to instana-agent at this address
|
||||||
|
#
|
||||||
|
# Default: "127.0.0.1"
|
||||||
|
#
|
||||||
|
localAgentHost = "127.0.0.1"
|
||||||
|
# Local Agent port instructs reporter to send spans to the instana-agent at this port
|
||||||
|
#
|
||||||
|
# Default: 42699
|
||||||
|
#
|
||||||
|
localAgentPort = 42699
|
||||||
|
# Set Instana tracer log level
|
||||||
|
#
|
||||||
|
# Default: info
|
||||||
|
# Valid values for logLevel field are:
|
||||||
|
# - error
|
||||||
|
# - warn
|
||||||
|
# - debug
|
||||||
|
# - info
|
||||||
|
#
|
||||||
|
logLevel = "info"
|
||||||
|
```
|
|
@ -21,6 +21,7 @@ import (
|
||||||
"github.com/containous/traefik/server/middleware"
|
"github.com/containous/traefik/server/middleware"
|
||||||
"github.com/containous/traefik/tracing"
|
"github.com/containous/traefik/tracing"
|
||||||
"github.com/containous/traefik/tracing/datadog"
|
"github.com/containous/traefik/tracing/datadog"
|
||||||
|
"github.com/containous/traefik/tracing/instana"
|
||||||
"github.com/containous/traefik/tracing/jaeger"
|
"github.com/containous/traefik/tracing/jaeger"
|
||||||
"github.com/containous/traefik/tracing/zipkin"
|
"github.com/containous/traefik/tracing/zipkin"
|
||||||
"github.com/containous/traefik/types"
|
"github.com/containous/traefik/types"
|
||||||
|
@ -60,6 +61,8 @@ func setupTracing(conf *static.Tracing) tracing.TrackingBackend {
|
||||||
return conf.Zipkin
|
return conf.Zipkin
|
||||||
case datadog.Name:
|
case datadog.Name:
|
||||||
return conf.DataDog
|
return conf.DataDog
|
||||||
|
case instana.Name:
|
||||||
|
return conf.Instana
|
||||||
default:
|
default:
|
||||||
log.WithoutContext().Warnf("Could not initialize tracing: unknown tracer %q", conf.Backend)
|
log.WithoutContext().Warnf("Could not initialize tracing: unknown tracer %q", conf.Backend)
|
||||||
return nil
|
return nil
|
||||||
|
|
49
tracing/instana/instana.go
Normal file
49
tracing/instana/instana.go
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
package instana
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
|
||||||
|
"github.com/containous/traefik/log"
|
||||||
|
"github.com/instana/go-sensor"
|
||||||
|
"github.com/opentracing/opentracing-go"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Name sets the name of this tracer
|
||||||
|
const Name = "instana"
|
||||||
|
|
||||||
|
// Config provides configuration settings for a instana tracer
|
||||||
|
type Config struct {
|
||||||
|
LocalAgentHost string `description:"Set instana-agent's host that the reporter will used." export:"false"`
|
||||||
|
LocalAgentPort int `description:"Set instana-agent's port that the reporter will used." export:"false"`
|
||||||
|
LogLevel string `description:"Set instana-agent's log level. ('error','warn','info','debug')" export:"false"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup sets up the tracer
|
||||||
|
func (c *Config) Setup(serviceName string) (opentracing.Tracer, io.Closer, error) {
|
||||||
|
// set default logLevel
|
||||||
|
logLevel := instana.Info
|
||||||
|
|
||||||
|
// check/set logLevel overrides
|
||||||
|
switch c.LogLevel {
|
||||||
|
case "error":
|
||||||
|
logLevel = instana.Error
|
||||||
|
case "warn":
|
||||||
|
logLevel = instana.Warn
|
||||||
|
case "debug":
|
||||||
|
logLevel = instana.Debug
|
||||||
|
}
|
||||||
|
|
||||||
|
tracer := instana.NewTracerWithOptions(&instana.Options{
|
||||||
|
Service: serviceName,
|
||||||
|
LogLevel: logLevel,
|
||||||
|
AgentPort: c.LocalAgentPort,
|
||||||
|
AgentHost: c.LocalAgentHost,
|
||||||
|
})
|
||||||
|
|
||||||
|
// Without this, child spans are getting the NOOP tracer
|
||||||
|
opentracing.SetGlobalTracer(tracer)
|
||||||
|
|
||||||
|
log.WithoutContext().Debug("Instana tracer configured")
|
||||||
|
|
||||||
|
return tracer, nil, nil
|
||||||
|
}
|
21
vendor/github.com/instana/go-sensor/LICENSE.md
generated
vendored
Normal file
21
vendor/github.com/instana/go-sensor/LICENSE.md
generated
vendored
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2016 Instana
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
183
vendor/github.com/instana/go-sensor/agent.go
generated
vendored
Normal file
183
vendor/github.com/instana/go-sensor/agent.go
generated
vendored
Normal file
|
@ -0,0 +1,183 @@
|
||||||
|
package instana
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
agentDiscoveryURL = "/com.instana.plugin.golang.discovery"
|
||||||
|
agentTracesURL = "/com.instana.plugin.golang/traces."
|
||||||
|
agentDataURL = "/com.instana.plugin.golang."
|
||||||
|
agentEventURL = "/com.instana.plugin.generic.event"
|
||||||
|
agentDefaultHost = "localhost"
|
||||||
|
agentDefaultPort = 42699
|
||||||
|
agentHeader = "Instana Agent"
|
||||||
|
)
|
||||||
|
|
||||||
|
type agentResponse struct {
|
||||||
|
Pid uint32 `json:"pid"`
|
||||||
|
HostID string `json:"agentUuid"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type discoveryS struct {
|
||||||
|
PID int `json:"pid"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Args []string `json:"args"`
|
||||||
|
Fd string `json:"fd"`
|
||||||
|
Inode string `json:"inode"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type fromS struct {
|
||||||
|
PID string `json:"e"`
|
||||||
|
HostID string `json:"h"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type agentS struct {
|
||||||
|
sensor *sensorS
|
||||||
|
fsm *fsmS
|
||||||
|
from *fromS
|
||||||
|
host string
|
||||||
|
client *http.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *agentS) init() {
|
||||||
|
r.client = &http.Client{Timeout: 5 * time.Second}
|
||||||
|
r.fsm = r.initFsm()
|
||||||
|
r.setFrom(&fromS{})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *agentS) makeURL(prefix string) string {
|
||||||
|
return r.makeHostURL(r.host, prefix)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *agentS) makeHostURL(host string, prefix string) string {
|
||||||
|
envPort := os.Getenv("INSTANA_AGENT_PORT")
|
||||||
|
port := agentDefaultPort
|
||||||
|
if r.sensor.options.AgentPort > 0 {
|
||||||
|
return r.makeFullURL(host, r.sensor.options.AgentPort, prefix)
|
||||||
|
}
|
||||||
|
if envPort == "" {
|
||||||
|
return r.makeFullURL(host, port, prefix)
|
||||||
|
}
|
||||||
|
port, err := strconv.Atoi(envPort)
|
||||||
|
if err != nil {
|
||||||
|
return r.makeFullURL(host, agentDefaultPort, prefix)
|
||||||
|
}
|
||||||
|
return r.makeFullURL(host, port, prefix)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *agentS) makeFullURL(host string, port int, prefix string) string {
|
||||||
|
var buffer bytes.Buffer
|
||||||
|
|
||||||
|
buffer.WriteString("http://")
|
||||||
|
buffer.WriteString(host)
|
||||||
|
buffer.WriteString(":")
|
||||||
|
buffer.WriteString(strconv.Itoa(port))
|
||||||
|
buffer.WriteString(prefix)
|
||||||
|
if prefix[len(prefix)-1:] == "." && r.from.PID != "" {
|
||||||
|
buffer.WriteString(r.from.PID)
|
||||||
|
}
|
||||||
|
|
||||||
|
return buffer.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *agentS) head(url string) (string, error) {
|
||||||
|
return r.request(url, "HEAD", nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *agentS) request(url string, method string, data interface{}) (string, error) {
|
||||||
|
return r.fullRequestResponse(url, method, data, nil, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *agentS) requestResponse(url string, method string, data interface{}, ret interface{}) (string, error) {
|
||||||
|
return r.fullRequestResponse(url, method, data, ret, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *agentS) requestHeader(url string, method string, header string) (string, error) {
|
||||||
|
return r.fullRequestResponse(url, method, nil, nil, header)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *agentS) fullRequestResponse(url string, method string, data interface{}, body interface{}, header string) (string, error) {
|
||||||
|
var j []byte
|
||||||
|
var ret string
|
||||||
|
var err error
|
||||||
|
var resp *http.Response
|
||||||
|
var req *http.Request
|
||||||
|
if data != nil {
|
||||||
|
j, err = json.Marshal(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err == nil {
|
||||||
|
if j != nil {
|
||||||
|
req, err = http.NewRequest(method, url, bytes.NewBuffer(j))
|
||||||
|
} else {
|
||||||
|
req, err = http.NewRequest(method, url, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err == nil {
|
||||||
|
req.Header.Set("Content-Type", "application/json")
|
||||||
|
resp, err = r.client.Do(req)
|
||||||
|
if err == nil {
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
|
||||||
|
err = errors.New(resp.Status)
|
||||||
|
} else {
|
||||||
|
|
||||||
|
log.debug("agent response:", url, resp.Status)
|
||||||
|
|
||||||
|
if body != nil {
|
||||||
|
var b []byte
|
||||||
|
b, err = ioutil.ReadAll(resp.Body)
|
||||||
|
json.Unmarshal(b, body)
|
||||||
|
}
|
||||||
|
|
||||||
|
if header != "" {
|
||||||
|
ret = resp.Header.Get(header)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
// Ignore errors while in announced stated (before ready) as
|
||||||
|
// this is the time where the entity is registering in the Instana
|
||||||
|
// backend and it will return 404 until it's done.
|
||||||
|
if !r.sensor.agent.fsm.fsm.Is("announced") {
|
||||||
|
log.info(err, url)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *agentS) setFrom(from *fromS) {
|
||||||
|
r.from = from
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *agentS) setHost(host string) {
|
||||||
|
r.host = host
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *agentS) reset() {
|
||||||
|
r.fsm.reset()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *sensorS) initAgent() *agentS {
|
||||||
|
|
||||||
|
log.debug("initializing agent")
|
||||||
|
|
||||||
|
ret := new(agentS)
|
||||||
|
ret.sensor = r
|
||||||
|
ret.init()
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
42
vendor/github.com/instana/go-sensor/context.go
generated
vendored
Normal file
42
vendor/github.com/instana/go-sensor/context.go
generated
vendored
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
package instana
|
||||||
|
|
||||||
|
// SpanContext holds the basic Span metadata.
|
||||||
|
type SpanContext struct {
|
||||||
|
// A probabilistically unique identifier for a [multi-span] trace.
|
||||||
|
TraceID int64
|
||||||
|
|
||||||
|
// A probabilistically unique identifier for a span.
|
||||||
|
SpanID int64
|
||||||
|
|
||||||
|
// Whether the trace is sampled.
|
||||||
|
Sampled bool
|
||||||
|
|
||||||
|
// The span's associated baggage.
|
||||||
|
Baggage map[string]string // initialized on first use
|
||||||
|
}
|
||||||
|
|
||||||
|
// ForeachBaggageItem belongs to the opentracing.SpanContext interface
|
||||||
|
func (c SpanContext) ForeachBaggageItem(handler func(k, v string) bool) {
|
||||||
|
for k, v := range c.Baggage {
|
||||||
|
if !handler(k, v) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithBaggageItem returns an entirely new SpanContext with the
|
||||||
|
// given key:value baggage pair set.
|
||||||
|
func (c SpanContext) WithBaggageItem(key, val string) SpanContext {
|
||||||
|
var newBaggage map[string]string
|
||||||
|
if c.Baggage == nil {
|
||||||
|
newBaggage = map[string]string{key: val}
|
||||||
|
} else {
|
||||||
|
newBaggage = make(map[string]string, len(c.Baggage)+1)
|
||||||
|
for k, v := range c.Baggage {
|
||||||
|
newBaggage[k] = v
|
||||||
|
}
|
||||||
|
newBaggage[key] = val
|
||||||
|
}
|
||||||
|
// Use positional parameters so the compiler will help catch new fields.
|
||||||
|
return SpanContext{c.TraceID, c.SpanID, c.Sampled, newBaggage}
|
||||||
|
}
|
37
vendor/github.com/instana/go-sensor/eum.go
generated
vendored
Normal file
37
vendor/github.com/instana/go-sensor/eum.go
generated
vendored
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
package instana
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"io/ioutil"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
const eumTemplate string = "eum.js"
|
||||||
|
|
||||||
|
// EumSnippet generates javascript code to initialize JavaScript agent
|
||||||
|
func EumSnippet(apiKey string, traceID string, meta map[string]string) string {
|
||||||
|
|
||||||
|
if len(apiKey) == 0 || len(traceID) == 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
b, err := ioutil.ReadFile(eumTemplate)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
var snippet = string(b)
|
||||||
|
var metaBuffer bytes.Buffer
|
||||||
|
|
||||||
|
snippet = strings.Replace(snippet, "$apiKey", apiKey, -1)
|
||||||
|
snippet = strings.Replace(snippet, "$traceId", traceID, -1)
|
||||||
|
|
||||||
|
for key, value := range meta {
|
||||||
|
metaBuffer.WriteString(" ineum('meta', '" + key + "', '" + value + "');\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
snippet = strings.Replace(snippet, "$meta", metaBuffer.String(), -1)
|
||||||
|
|
||||||
|
return snippet
|
||||||
|
}
|
78
vendor/github.com/instana/go-sensor/event.go
generated
vendored
Normal file
78
vendor/github.com/instana/go-sensor/event.go
generated
vendored
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
package instana
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// EventData is the construct serialized for the host agent
|
||||||
|
type EventData struct {
|
||||||
|
Title string `json:"title"`
|
||||||
|
Text string `json:"text"`
|
||||||
|
// Duration in milliseconds
|
||||||
|
Duration int `json:"duration"`
|
||||||
|
// Severity with value of -1, 5, 10 : see type severity
|
||||||
|
Severity int `json:"severity"`
|
||||||
|
Plugin string `json:"plugin,omitempty"`
|
||||||
|
ID string `json:"id,omitempty"`
|
||||||
|
Host string `json:"host"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type severity int
|
||||||
|
|
||||||
|
//Severity values for events sent to the instana agent
|
||||||
|
const (
|
||||||
|
SeverityChange severity = -1
|
||||||
|
SeverityWarning severity = 5
|
||||||
|
SeverityCritical severity = 10
|
||||||
|
)
|
||||||
|
|
||||||
|
// Defaults for the Event API
|
||||||
|
const (
|
||||||
|
ServicePlugin = "com.instana.forge.connection.http.logical.LogicalWebApp"
|
||||||
|
ServiceHost = ""
|
||||||
|
)
|
||||||
|
|
||||||
|
// SendDefaultServiceEvent sends a default event which already contains the service and host
|
||||||
|
func SendDefaultServiceEvent(title string, text string, sev severity, duration time.Duration) {
|
||||||
|
if sensor == nil {
|
||||||
|
// Since no sensor was initialized, there is no default service (as
|
||||||
|
// configured on the sensor) so we send blank.
|
||||||
|
SendServiceEvent("", title, text, sev, duration)
|
||||||
|
} else {
|
||||||
|
SendServiceEvent(sensor.serviceName, title, text, sev, duration)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SendServiceEvent send an event on a specific service
|
||||||
|
func SendServiceEvent(service string, title string, text string, sev severity, duration time.Duration) {
|
||||||
|
sendEvent(&EventData{
|
||||||
|
Title: title,
|
||||||
|
Text: text,
|
||||||
|
Severity: int(sev),
|
||||||
|
Plugin: ServicePlugin,
|
||||||
|
ID: service,
|
||||||
|
Host: ServiceHost,
|
||||||
|
Duration: int(duration / time.Millisecond),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// SendHostEvent send an event on the current host
|
||||||
|
func SendHostEvent(title string, text string, sev severity, duration time.Duration) {
|
||||||
|
sendEvent(&EventData{
|
||||||
|
Title: title,
|
||||||
|
Text: text,
|
||||||
|
Duration: int(duration / time.Millisecond),
|
||||||
|
Severity: int(sev),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func sendEvent(event *EventData) {
|
||||||
|
if sensor == nil {
|
||||||
|
// If the sensor hasn't initialized we do so here so that we properly
|
||||||
|
// discover where the host agent may be as it varies between a
|
||||||
|
// normal host, docker, kubernetes etc..
|
||||||
|
InitSensor(&Options{})
|
||||||
|
}
|
||||||
|
//we do fire & forget here, because the whole pid dance isn't necessary to send events
|
||||||
|
go sensor.agent.request(sensor.agent.makeURL(agentEventURL), "POST", event)
|
||||||
|
}
|
242
vendor/github.com/instana/go-sensor/fsm.go
generated
vendored
Normal file
242
vendor/github.com/instana/go-sensor/fsm.go
generated
vendored
Normal file
|
@ -0,0 +1,242 @@
|
||||||
|
package instana
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
f "github.com/looplab/fsm"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
eInit = "init"
|
||||||
|
eLookup = "lookup"
|
||||||
|
eAnnounce = "announce"
|
||||||
|
eTest = "test"
|
||||||
|
|
||||||
|
retryPeriod = 30 * 1000
|
||||||
|
maximumRetries = 2
|
||||||
|
)
|
||||||
|
|
||||||
|
type fsmS struct {
|
||||||
|
agent *agentS
|
||||||
|
fsm *f.FSM
|
||||||
|
timer *time.Timer
|
||||||
|
retries int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *fsmS) init() {
|
||||||
|
|
||||||
|
log.warn("Stan is on the scene. Starting Instana instrumentation.")
|
||||||
|
log.debug("initializing fsm")
|
||||||
|
|
||||||
|
r.fsm = f.NewFSM(
|
||||||
|
"none",
|
||||||
|
f.Events{
|
||||||
|
{Name: eInit, Src: []string{"none", "unannounced", "announced", "ready"}, Dst: "init"},
|
||||||
|
{Name: eLookup, Src: []string{"init"}, Dst: "unannounced"},
|
||||||
|
{Name: eAnnounce, Src: []string{"unannounced"}, Dst: "announced"},
|
||||||
|
{Name: eTest, Src: []string{"announced"}, Dst: "ready"}},
|
||||||
|
f.Callbacks{
|
||||||
|
"init": r.lookupAgentHost,
|
||||||
|
"enter_unannounced": r.announceSensor,
|
||||||
|
"enter_announced": r.testAgent})
|
||||||
|
|
||||||
|
r.retries = maximumRetries
|
||||||
|
r.fsm.Event(eInit)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *fsmS) scheduleRetry(e *f.Event, cb func(e *f.Event)) {
|
||||||
|
r.timer = time.NewTimer(retryPeriod * time.Millisecond)
|
||||||
|
go func() {
|
||||||
|
<-r.timer.C
|
||||||
|
cb(e)
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *fsmS) lookupAgentHost(e *f.Event) {
|
||||||
|
cb := func(b bool, host string) {
|
||||||
|
if b {
|
||||||
|
r.lookupSuccess(host)
|
||||||
|
} else {
|
||||||
|
gateway := r.getDefaultGateway()
|
||||||
|
if gateway != "" {
|
||||||
|
go r.checkHost(gateway, func(b bool, host string) {
|
||||||
|
if b {
|
||||||
|
r.lookupSuccess(host)
|
||||||
|
} else {
|
||||||
|
log.error("Cannot connect to the agent through localhost or default gateway. Scheduling retry.")
|
||||||
|
r.scheduleRetry(e, r.lookupAgentHost)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
log.error("Default gateway not available. Scheduling retry")
|
||||||
|
r.scheduleRetry(e, r.lookupAgentHost)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
hostNames := []string{
|
||||||
|
r.agent.sensor.options.AgentHost,
|
||||||
|
os.Getenv("INSTANA_AGENT_HOST"),
|
||||||
|
agentDefaultHost,
|
||||||
|
}
|
||||||
|
for _, name := range hostNames {
|
||||||
|
if name != "" {
|
||||||
|
go r.checkHost(name, cb)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *fsmS) getDefaultGateway() string {
|
||||||
|
out, _ := exec.Command("/bin/sh", "-c", "/sbin/ip route | awk '/default/' | cut -d ' ' -f 3 | tr -d '\n'").Output()
|
||||||
|
|
||||||
|
log.debug("checking default gateway", string(out[:]))
|
||||||
|
|
||||||
|
return string(out[:])
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *fsmS) checkHost(host string, cb func(b bool, host string)) {
|
||||||
|
log.debug("checking host", host)
|
||||||
|
|
||||||
|
header, err := r.agent.requestHeader(r.agent.makeHostURL(host, "/"), "GET", "Server")
|
||||||
|
|
||||||
|
cb(err == nil && header == agentHeader, host)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *fsmS) lookupSuccess(host string) {
|
||||||
|
log.debug("agent lookup success", host)
|
||||||
|
|
||||||
|
r.agent.setHost(host)
|
||||||
|
r.retries = maximumRetries
|
||||||
|
r.fsm.Event(eLookup)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *fsmS) announceSensor(e *f.Event) {
|
||||||
|
cb := func(b bool, from *fromS) {
|
||||||
|
if b {
|
||||||
|
log.info("Host agent available. We're in business. Announced pid:", from.PID)
|
||||||
|
r.agent.setFrom(from)
|
||||||
|
r.retries = maximumRetries
|
||||||
|
r.fsm.Event(eAnnounce)
|
||||||
|
} else {
|
||||||
|
log.error("Cannot announce sensor. Scheduling retry.")
|
||||||
|
r.retries--
|
||||||
|
if r.retries > 0 {
|
||||||
|
r.scheduleRetry(e, r.announceSensor)
|
||||||
|
} else {
|
||||||
|
r.fsm.Event(eInit)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log.debug("announcing sensor to the agent")
|
||||||
|
|
||||||
|
go func(cb func(b bool, from *fromS)) {
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
log.debug("Announce recovered:", r)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
pid := 0
|
||||||
|
schedFile := fmt.Sprintf("/proc/%d/sched", os.Getpid())
|
||||||
|
if _, err := os.Stat(schedFile); err == nil {
|
||||||
|
sf, err := os.Open(schedFile)
|
||||||
|
defer sf.Close()
|
||||||
|
if err == nil {
|
||||||
|
fscanner := bufio.NewScanner(sf)
|
||||||
|
fscanner.Scan()
|
||||||
|
primaLinea := fscanner.Text()
|
||||||
|
|
||||||
|
r := regexp.MustCompile("\\((\\d+),")
|
||||||
|
match := r.FindStringSubmatch(primaLinea)
|
||||||
|
i, err := strconv.Atoi(match[1])
|
||||||
|
if err == nil {
|
||||||
|
pid = i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if pid == 0 {
|
||||||
|
pid = os.Getpid()
|
||||||
|
}
|
||||||
|
|
||||||
|
d := &discoveryS{PID: pid}
|
||||||
|
d.Name, d.Args = getCommandLine()
|
||||||
|
|
||||||
|
if _, err := os.Stat("/proc"); err == nil {
|
||||||
|
if addr, err := net.ResolveTCPAddr("tcp", r.agent.host+":42699"); err == nil {
|
||||||
|
if tcpConn, err := net.DialTCP("tcp", nil, addr); err == nil {
|
||||||
|
defer tcpConn.Close()
|
||||||
|
|
||||||
|
f, err := tcpConn.File()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.error(err)
|
||||||
|
} else {
|
||||||
|
d.Fd = fmt.Sprintf("%v", f.Fd())
|
||||||
|
|
||||||
|
link := fmt.Sprintf("/proc/%d/fd/%d", os.Getpid(), f.Fd())
|
||||||
|
if _, err := os.Stat(link); err == nil {
|
||||||
|
d.Inode, _ = os.Readlink(link)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret := &agentResponse{}
|
||||||
|
_, err := r.agent.requestResponse(r.agent.makeURL(agentDiscoveryURL), "PUT", d, ret)
|
||||||
|
cb(err == nil,
|
||||||
|
&fromS{
|
||||||
|
PID: strconv.Itoa(int(ret.Pid)),
|
||||||
|
HostID: ret.HostID})
|
||||||
|
}(cb)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *fsmS) testAgent(e *f.Event) {
|
||||||
|
cb := func(b bool) {
|
||||||
|
if b {
|
||||||
|
r.retries = maximumRetries
|
||||||
|
r.fsm.Event(eTest)
|
||||||
|
} else {
|
||||||
|
log.debug("Agent is not yet ready. Scheduling retry.")
|
||||||
|
r.retries--
|
||||||
|
if r.retries > 0 {
|
||||||
|
r.scheduleRetry(e, r.testAgent)
|
||||||
|
} else {
|
||||||
|
r.fsm.Event(eInit)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log.debug("testing communication with the agent")
|
||||||
|
|
||||||
|
go func(cb func(b bool)) {
|
||||||
|
_, err := r.agent.head(r.agent.makeURL(agentDataURL))
|
||||||
|
cb(err == nil)
|
||||||
|
}(cb)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *fsmS) reset() {
|
||||||
|
r.retries = maximumRetries
|
||||||
|
r.fsm.Event(eInit)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *agentS) initFsm() *fsmS {
|
||||||
|
ret := new(fsmS)
|
||||||
|
ret.agent = r
|
||||||
|
ret.init()
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *agentS) canSend() bool {
|
||||||
|
return r.fsm.fsm.Current() == "ready"
|
||||||
|
}
|
38
vendor/github.com/instana/go-sensor/json_span.go
generated
vendored
Normal file
38
vendor/github.com/instana/go-sensor/json_span.go
generated
vendored
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
package instana
|
||||||
|
|
||||||
|
import (
|
||||||
|
ot "github.com/opentracing/opentracing-go"
|
||||||
|
)
|
||||||
|
|
||||||
|
type jsonSpan struct {
|
||||||
|
TraceID int64 `json:"t"`
|
||||||
|
ParentID *int64 `json:"p,omitempty"`
|
||||||
|
SpanID int64 `json:"s"`
|
||||||
|
Timestamp uint64 `json:"ts"`
|
||||||
|
Duration uint64 `json:"d"`
|
||||||
|
Name string `json:"n"`
|
||||||
|
From *fromS `json:"f"`
|
||||||
|
Error bool `json:"error"`
|
||||||
|
Ec int `json:"ec,omitempty"`
|
||||||
|
Lang string `json:"ta,omitempty"`
|
||||||
|
Data *jsonData `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type jsonData struct {
|
||||||
|
Service string `json:"service,omitempty"`
|
||||||
|
SDK *jsonSDKData `json:"sdk"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type jsonCustomData struct {
|
||||||
|
Tags ot.Tags `json:"tags,omitempty"`
|
||||||
|
Logs map[uint64]map[string]interface{} `json:"logs,omitempty"`
|
||||||
|
Baggage map[string]string `json:"baggage,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type jsonSDKData struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Type string `json:"type,omitempty"`
|
||||||
|
Arguments string `json:"arguments,omitempty"`
|
||||||
|
Return string `json:"return,omitempty"`
|
||||||
|
Custom *jsonCustomData `json:"custom,omitempty"`
|
||||||
|
}
|
52
vendor/github.com/instana/go-sensor/log.go
generated
vendored
Normal file
52
vendor/github.com/instana/go-sensor/log.go
generated
vendored
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
package instana
|
||||||
|
|
||||||
|
import (
|
||||||
|
l "log"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Valid log levels
|
||||||
|
const (
|
||||||
|
Error = 0
|
||||||
|
Warn = 1
|
||||||
|
Info = 2
|
||||||
|
Debug = 3
|
||||||
|
)
|
||||||
|
|
||||||
|
type logS struct {
|
||||||
|
sensor *sensorS
|
||||||
|
}
|
||||||
|
|
||||||
|
var log *logS
|
||||||
|
|
||||||
|
func (r *logS) makeV(prefix string, v ...interface{}) []interface{} {
|
||||||
|
return append([]interface{}{prefix}, v...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *logS) debug(v ...interface{}) {
|
||||||
|
if r.sensor.options.LogLevel >= Debug {
|
||||||
|
l.Println(r.makeV("DEBUG: instana:", v...)...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *logS) info(v ...interface{}) {
|
||||||
|
if r.sensor.options.LogLevel >= Info {
|
||||||
|
l.Println(r.makeV("INFO: instana:", v...)...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *logS) warn(v ...interface{}) {
|
||||||
|
if r.sensor.options.LogLevel >= Warn {
|
||||||
|
l.Println(r.makeV("WARN: instana:", v...)...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *logS) error(v ...interface{}) {
|
||||||
|
if r.sensor.options.LogLevel >= Error {
|
||||||
|
l.Println(r.makeV("ERROR: instana:", v...)...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *sensorS) initLog() {
|
||||||
|
log = new(logS)
|
||||||
|
log.sensor = r
|
||||||
|
}
|
157
vendor/github.com/instana/go-sensor/meter.go
generated
vendored
Normal file
157
vendor/github.com/instana/go-sensor/meter.go
generated
vendored
Normal file
|
@ -0,0 +1,157 @@
|
||||||
|
package instana
|
||||||
|
|
||||||
|
import (
|
||||||
|
"runtime"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// SnapshotPeriod is the amount of time in seconds between snapshot reports.
|
||||||
|
SnapshotPeriod = 600
|
||||||
|
)
|
||||||
|
|
||||||
|
// SnapshotS struct to hold snapshot data.
|
||||||
|
type SnapshotS struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Version string `json:"version"`
|
||||||
|
Root string `json:"goroot"`
|
||||||
|
MaxProcs int `json:"maxprocs"`
|
||||||
|
Compiler string `json:"compiler"`
|
||||||
|
NumCPU int `json:"cpu"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// MemoryS struct to hold snapshot data.
|
||||||
|
type MemoryS struct {
|
||||||
|
Alloc uint64 `json:"alloc"`
|
||||||
|
TotalAlloc uint64 `json:"total_alloc"`
|
||||||
|
Sys uint64 `json:"sys"`
|
||||||
|
Lookups uint64 `json:"lookups"`
|
||||||
|
Mallocs uint64 `json:"mallocs"`
|
||||||
|
Frees uint64 `json:"frees"`
|
||||||
|
HeapAlloc uint64 `json:"heap_alloc"`
|
||||||
|
HeapSys uint64 `json:"heap_sys"`
|
||||||
|
HeapIdle uint64 `json:"heap_idle"`
|
||||||
|
HeapInuse uint64 `json:"heap_in_use"`
|
||||||
|
HeapReleased uint64 `json:"heap_released"`
|
||||||
|
HeapObjects uint64 `json:"heap_objects"`
|
||||||
|
PauseTotalNs uint64 `json:"pause_total_ns"`
|
||||||
|
PauseNs uint64 `json:"pause_ns"`
|
||||||
|
NumGC uint32 `json:"num_gc"`
|
||||||
|
GCCPUFraction float64 `json:"gc_cpu_fraction"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// MetricsS struct to hold snapshot data.
|
||||||
|
type MetricsS struct {
|
||||||
|
CgoCall int64 `json:"cgo_call"`
|
||||||
|
Goroutine int `json:"goroutine"`
|
||||||
|
Memory *MemoryS `json:"memory"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// EntityData struct to hold snapshot data.
|
||||||
|
type EntityData struct {
|
||||||
|
PID int `json:"pid"`
|
||||||
|
Snapshot *SnapshotS `json:"snapshot,omitempty"`
|
||||||
|
Metrics *MetricsS `json:"metrics"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type meterS struct {
|
||||||
|
sensor *sensorS
|
||||||
|
numGC uint32
|
||||||
|
ticker *time.Ticker
|
||||||
|
snapshotCountdown int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *meterS) init() {
|
||||||
|
r.ticker = time.NewTicker(1 * time.Second)
|
||||||
|
go func() {
|
||||||
|
r.snapshotCountdown = 1
|
||||||
|
for range r.ticker.C {
|
||||||
|
if r.sensor.agent.canSend() {
|
||||||
|
r.snapshotCountdown--
|
||||||
|
var s *SnapshotS
|
||||||
|
if r.snapshotCountdown == 0 {
|
||||||
|
r.snapshotCountdown = SnapshotPeriod
|
||||||
|
s = r.collectSnapshot()
|
||||||
|
log.debug("collected snapshot")
|
||||||
|
} else {
|
||||||
|
s = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
pid, _ := strconv.Atoi(r.sensor.agent.from.PID)
|
||||||
|
d := &EntityData{
|
||||||
|
PID: pid,
|
||||||
|
Snapshot: s,
|
||||||
|
Metrics: r.collectMetrics()}
|
||||||
|
|
||||||
|
go r.send(d)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *meterS) send(d *EntityData) {
|
||||||
|
_, err := r.sensor.agent.request(r.sensor.agent.makeURL(agentDataURL), "POST", d)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
r.sensor.agent.reset()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *meterS) collectMemoryMetrics() *MemoryS {
|
||||||
|
var memStats runtime.MemStats
|
||||||
|
runtime.ReadMemStats(&memStats)
|
||||||
|
ret := &MemoryS{
|
||||||
|
Alloc: memStats.Alloc,
|
||||||
|
TotalAlloc: memStats.TotalAlloc,
|
||||||
|
Sys: memStats.Sys,
|
||||||
|
Lookups: memStats.Lookups,
|
||||||
|
Mallocs: memStats.Mallocs,
|
||||||
|
Frees: memStats.Frees,
|
||||||
|
HeapAlloc: memStats.HeapAlloc,
|
||||||
|
HeapSys: memStats.HeapSys,
|
||||||
|
HeapIdle: memStats.HeapIdle,
|
||||||
|
HeapInuse: memStats.HeapInuse,
|
||||||
|
HeapReleased: memStats.HeapReleased,
|
||||||
|
HeapObjects: memStats.HeapObjects,
|
||||||
|
PauseTotalNs: memStats.PauseTotalNs,
|
||||||
|
NumGC: memStats.NumGC,
|
||||||
|
GCCPUFraction: memStats.GCCPUFraction}
|
||||||
|
|
||||||
|
if r.numGC < memStats.NumGC {
|
||||||
|
ret.PauseNs = memStats.PauseNs[(memStats.NumGC+255)%256]
|
||||||
|
r.numGC = memStats.NumGC
|
||||||
|
} else {
|
||||||
|
ret.PauseNs = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *meterS) collectMetrics() *MetricsS {
|
||||||
|
return &MetricsS{
|
||||||
|
CgoCall: runtime.NumCgoCall(),
|
||||||
|
Goroutine: runtime.NumGoroutine(),
|
||||||
|
Memory: r.collectMemoryMetrics()}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *meterS) collectSnapshot() *SnapshotS {
|
||||||
|
return &SnapshotS{
|
||||||
|
Name: r.sensor.serviceName,
|
||||||
|
Version: runtime.Version(),
|
||||||
|
Root: runtime.GOROOT(),
|
||||||
|
MaxProcs: runtime.GOMAXPROCS(0),
|
||||||
|
Compiler: runtime.Compiler,
|
||||||
|
NumCPU: runtime.NumCPU()}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *sensorS) initMeter() *meterS {
|
||||||
|
|
||||||
|
log.debug("initializing meter")
|
||||||
|
|
||||||
|
ret := new(meterS)
|
||||||
|
ret.sensor = r
|
||||||
|
ret.init()
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
12
vendor/github.com/instana/go-sensor/options.go
generated
vendored
Normal file
12
vendor/github.com/instana/go-sensor/options.go
generated
vendored
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
package instana
|
||||||
|
|
||||||
|
// Options allows the user to configure the to-be-initialized
|
||||||
|
// sensor
|
||||||
|
type Options struct {
|
||||||
|
Service string
|
||||||
|
AgentHost string
|
||||||
|
AgentPort int
|
||||||
|
MaxBufferedSpans int
|
||||||
|
ForceTransmissionStartingAt int
|
||||||
|
LogLevel int
|
||||||
|
}
|
165
vendor/github.com/instana/go-sensor/propagation.go
generated
vendored
Normal file
165
vendor/github.com/instana/go-sensor/propagation.go
generated
vendored
Normal file
|
@ -0,0 +1,165 @@
|
||||||
|
package instana
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
ot "github.com/opentracing/opentracing-go"
|
||||||
|
)
|
||||||
|
|
||||||
|
type textMapPropagator struct {
|
||||||
|
tracer *tracerS
|
||||||
|
}
|
||||||
|
|
||||||
|
// Instana header constants
|
||||||
|
const (
|
||||||
|
// FieldT Trace ID header
|
||||||
|
FieldT = "x-instana-t"
|
||||||
|
// FieldS Span ID header
|
||||||
|
FieldS = "x-instana-s"
|
||||||
|
// FieldL Level header
|
||||||
|
FieldL = "x-instana-l"
|
||||||
|
// FieldB OT Baggage header
|
||||||
|
FieldB = "x-instana-b-"
|
||||||
|
fieldCount = 2
|
||||||
|
)
|
||||||
|
|
||||||
|
func (r *textMapPropagator) inject(spanContext ot.SpanContext, opaqueCarrier interface{}) error {
|
||||||
|
sc, ok := spanContext.(SpanContext)
|
||||||
|
if !ok {
|
||||||
|
return ot.ErrInvalidSpanContext
|
||||||
|
}
|
||||||
|
|
||||||
|
roCarrier, ok := opaqueCarrier.(ot.TextMapReader)
|
||||||
|
if !ok {
|
||||||
|
return ot.ErrInvalidCarrier
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle pre-existing case-sensitive keys
|
||||||
|
var (
|
||||||
|
exstfieldT = FieldT
|
||||||
|
exstfieldS = FieldS
|
||||||
|
exstfieldL = FieldL
|
||||||
|
exstfieldB = FieldB
|
||||||
|
)
|
||||||
|
|
||||||
|
roCarrier.ForeachKey(func(k, v string) error {
|
||||||
|
switch strings.ToLower(k) {
|
||||||
|
case FieldT:
|
||||||
|
exstfieldT = k
|
||||||
|
case FieldS:
|
||||||
|
exstfieldS = k
|
||||||
|
case FieldL:
|
||||||
|
exstfieldL = k
|
||||||
|
default:
|
||||||
|
if strings.HasPrefix(strings.ToLower(k), FieldB) {
|
||||||
|
exstfieldB = string([]rune(k)[0:len(FieldB)])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
carrier, ok := opaqueCarrier.(ot.TextMapWriter)
|
||||||
|
if !ok {
|
||||||
|
return ot.ErrInvalidCarrier
|
||||||
|
}
|
||||||
|
|
||||||
|
hhcarrier, ok := opaqueCarrier.(ot.HTTPHeadersCarrier)
|
||||||
|
if ok {
|
||||||
|
// If http.Headers has pre-existing keys, calling Set() like we do
|
||||||
|
// below will just append to those existing values and break context
|
||||||
|
// propagation. So defend against that case, we delete any pre-existing
|
||||||
|
// keys entirely first.
|
||||||
|
y := http.Header(hhcarrier)
|
||||||
|
y.Del(exstfieldT)
|
||||||
|
y.Del(exstfieldS)
|
||||||
|
y.Del(exstfieldL)
|
||||||
|
|
||||||
|
for key := range y {
|
||||||
|
if strings.HasPrefix(strings.ToLower(key), FieldB) {
|
||||||
|
y.Del(key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if instanaTID, err := ID2Header(sc.TraceID); err == nil {
|
||||||
|
carrier.Set(exstfieldT, instanaTID)
|
||||||
|
} else {
|
||||||
|
log.debug(err)
|
||||||
|
}
|
||||||
|
if instanaSID, err := ID2Header(sc.SpanID); err == nil {
|
||||||
|
carrier.Set(exstfieldS, instanaSID)
|
||||||
|
} else {
|
||||||
|
log.debug(err)
|
||||||
|
}
|
||||||
|
carrier.Set(exstfieldL, strconv.Itoa(1))
|
||||||
|
|
||||||
|
for k, v := range sc.Baggage {
|
||||||
|
carrier.Set(exstfieldB+k, v)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *textMapPropagator) extract(opaqueCarrier interface{}) (ot.SpanContext, error) {
|
||||||
|
carrier, ok := opaqueCarrier.(ot.TextMapReader)
|
||||||
|
if !ok {
|
||||||
|
return nil, ot.ErrInvalidCarrier
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldCount := 0
|
||||||
|
var traceID, spanID int64
|
||||||
|
var err error
|
||||||
|
baggage := make(map[string]string)
|
||||||
|
err = carrier.ForeachKey(func(k, v string) error {
|
||||||
|
switch strings.ToLower(k) {
|
||||||
|
case FieldT:
|
||||||
|
fieldCount++
|
||||||
|
traceID, err = Header2ID(v)
|
||||||
|
if err != nil {
|
||||||
|
return ot.ErrSpanContextCorrupted
|
||||||
|
}
|
||||||
|
case FieldS:
|
||||||
|
fieldCount++
|
||||||
|
spanID, err = Header2ID(v)
|
||||||
|
if err != nil {
|
||||||
|
return ot.ErrSpanContextCorrupted
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
lk := strings.ToLower(k)
|
||||||
|
|
||||||
|
if strings.HasPrefix(lk, FieldB) {
|
||||||
|
baggage[strings.TrimPrefix(lk, FieldB)] = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
return r.finishExtract(err, fieldCount, traceID, spanID, baggage)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *textMapPropagator) finishExtract(err error,
|
||||||
|
fieldCount int,
|
||||||
|
traceID int64,
|
||||||
|
spanID int64,
|
||||||
|
baggage map[string]string) (ot.SpanContext, error) {
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if fieldCount < 2 {
|
||||||
|
if fieldCount == 0 {
|
||||||
|
return nil, ot.ErrSpanContextNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, ot.ErrSpanContextCorrupted
|
||||||
|
}
|
||||||
|
|
||||||
|
return SpanContext{
|
||||||
|
TraceID: traceID,
|
||||||
|
SpanID: spanID,
|
||||||
|
Sampled: false,
|
||||||
|
Baggage: baggage,
|
||||||
|
}, nil
|
||||||
|
}
|
175
vendor/github.com/instana/go-sensor/recorder.go
generated
vendored
Normal file
175
vendor/github.com/instana/go-sensor/recorder.go
generated
vendored
Normal file
|
@ -0,0 +1,175 @@
|
||||||
|
package instana
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// A SpanRecorder handles all of the `RawSpan` data generated via an
|
||||||
|
// associated `Tracer` (see `NewStandardTracer`) instance. It also names
|
||||||
|
// the containing process and provides access to a straightforward tag map.
|
||||||
|
type SpanRecorder interface {
|
||||||
|
// Implementations must determine whether and where to store `span`.
|
||||||
|
RecordSpan(span *spanS)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recorder accepts spans, processes and queues them
|
||||||
|
// for delivery to the backend.
|
||||||
|
type Recorder struct {
|
||||||
|
sync.RWMutex
|
||||||
|
spans []jsonSpan
|
||||||
|
testMode bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewRecorder Establish a Recorder span recorder
|
||||||
|
func NewRecorder() *Recorder {
|
||||||
|
r := new(Recorder)
|
||||||
|
r.init()
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewTestRecorder Establish a new span recorder used for testing
|
||||||
|
func NewTestRecorder() *Recorder {
|
||||||
|
r := new(Recorder)
|
||||||
|
r.testMode = true
|
||||||
|
r.init()
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Recorder) init() {
|
||||||
|
r.clearQueuedSpans()
|
||||||
|
|
||||||
|
if r.testMode {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ticker := time.NewTicker(1 * time.Second)
|
||||||
|
go func() {
|
||||||
|
for range ticker.C {
|
||||||
|
if sensor.agent.canSend() {
|
||||||
|
r.send()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
// RecordSpan accepts spans to be recorded and and added to the span queue
|
||||||
|
// for eventual reporting to the host agent.
|
||||||
|
func (r *Recorder) RecordSpan(span *spanS) {
|
||||||
|
// If we're not announced and not in test mode then just
|
||||||
|
// return
|
||||||
|
if !r.testMode && !sensor.agent.canSend() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var data = &jsonData{}
|
||||||
|
kind := span.getSpanKind()
|
||||||
|
|
||||||
|
data.SDK = &jsonSDKData{
|
||||||
|
Name: span.Operation,
|
||||||
|
Type: kind,
|
||||||
|
Custom: &jsonCustomData{Tags: span.Tags, Logs: span.collectLogs()}}
|
||||||
|
|
||||||
|
baggage := make(map[string]string)
|
||||||
|
span.context.ForeachBaggageItem(func(k string, v string) bool {
|
||||||
|
baggage[k] = v
|
||||||
|
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
|
||||||
|
if len(baggage) > 0 {
|
||||||
|
data.SDK.Custom.Baggage = baggage
|
||||||
|
}
|
||||||
|
|
||||||
|
data.Service = sensor.serviceName
|
||||||
|
|
||||||
|
var parentID *int64
|
||||||
|
if span.ParentSpanID == 0 {
|
||||||
|
parentID = nil
|
||||||
|
} else {
|
||||||
|
parentID = &span.ParentSpanID
|
||||||
|
}
|
||||||
|
|
||||||
|
r.Lock()
|
||||||
|
defer r.Unlock()
|
||||||
|
|
||||||
|
if len(r.spans) == sensor.options.MaxBufferedSpans {
|
||||||
|
r.spans = r.spans[1:]
|
||||||
|
}
|
||||||
|
|
||||||
|
r.spans = append(r.spans, jsonSpan{
|
||||||
|
TraceID: span.context.TraceID,
|
||||||
|
ParentID: parentID,
|
||||||
|
SpanID: span.context.SpanID,
|
||||||
|
Timestamp: uint64(span.Start.UnixNano()) / uint64(time.Millisecond),
|
||||||
|
Duration: uint64(span.Duration) / uint64(time.Millisecond),
|
||||||
|
Name: "sdk",
|
||||||
|
Error: span.Error,
|
||||||
|
Ec: span.Ec,
|
||||||
|
Lang: "go",
|
||||||
|
From: sensor.agent.from,
|
||||||
|
Data: data})
|
||||||
|
|
||||||
|
if r.testMode || !sensor.agent.canSend() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(r.spans) >= sensor.options.ForceTransmissionStartingAt {
|
||||||
|
log.debug("Forcing spans to agent. Count:", len(r.spans))
|
||||||
|
go r.send()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// QueuedSpansCount returns the number of queued spans
|
||||||
|
// Used only in tests currently.
|
||||||
|
func (r *Recorder) QueuedSpansCount() int {
|
||||||
|
r.RLock()
|
||||||
|
defer r.RUnlock()
|
||||||
|
return len(r.spans)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetQueuedSpans returns a copy of the queued spans and clears the queue.
|
||||||
|
func (r *Recorder) GetQueuedSpans() []jsonSpan {
|
||||||
|
r.Lock()
|
||||||
|
defer r.Unlock()
|
||||||
|
|
||||||
|
// Copy queued spans
|
||||||
|
queuedSpans := make([]jsonSpan, len(r.spans))
|
||||||
|
copy(queuedSpans, r.spans)
|
||||||
|
|
||||||
|
// and clear out the source
|
||||||
|
r.clearQueuedSpans()
|
||||||
|
return queuedSpans
|
||||||
|
}
|
||||||
|
|
||||||
|
// clearQueuedSpans brings the span queue to empty/0/nada
|
||||||
|
// This function doesn't take the Lock so make sure to have
|
||||||
|
// the write lock before calling.
|
||||||
|
// This is meant to be called from GetQueuedSpans which handles
|
||||||
|
// locking.
|
||||||
|
func (r *Recorder) clearQueuedSpans() {
|
||||||
|
var mbs int
|
||||||
|
|
||||||
|
if len(r.spans) > 0 {
|
||||||
|
if sensor != nil {
|
||||||
|
mbs = sensor.options.MaxBufferedSpans
|
||||||
|
} else {
|
||||||
|
mbs = DefaultMaxBufferedSpans
|
||||||
|
}
|
||||||
|
r.spans = make([]jsonSpan, 0, mbs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retrieve the queued spans and post them to the host agent asynchronously.
|
||||||
|
func (r *Recorder) send() {
|
||||||
|
spansToSend := r.GetQueuedSpans()
|
||||||
|
if len(spansToSend) > 0 {
|
||||||
|
go func() {
|
||||||
|
_, err := sensor.agent.request(sensor.agent.makeURL(agentTracesURL), "POST", spansToSend)
|
||||||
|
if err != nil {
|
||||||
|
log.debug("Posting traces failed in send(): ", err)
|
||||||
|
sensor.agent.reset()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
}
|
76
vendor/github.com/instana/go-sensor/sensor.go
generated
vendored
Normal file
76
vendor/github.com/instana/go-sensor/sensor.go
generated
vendored
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
package instana
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
DefaultMaxBufferedSpans = 1000
|
||||||
|
DefaultForceSpanSendAt = 500
|
||||||
|
)
|
||||||
|
|
||||||
|
type sensorS struct {
|
||||||
|
meter *meterS
|
||||||
|
agent *agentS
|
||||||
|
options *Options
|
||||||
|
serviceName string
|
||||||
|
}
|
||||||
|
|
||||||
|
var sensor *sensorS
|
||||||
|
|
||||||
|
func (r *sensorS) init(options *Options) {
|
||||||
|
//sensor can be initialized explicit or implicit through OpenTracing global init
|
||||||
|
if r.meter == nil {
|
||||||
|
r.setOptions(options)
|
||||||
|
r.configureServiceName()
|
||||||
|
r.agent = r.initAgent()
|
||||||
|
r.meter = r.initMeter()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *sensorS) setOptions(options *Options) {
|
||||||
|
r.options = options
|
||||||
|
if r.options == nil {
|
||||||
|
r.options = &Options{}
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.options.MaxBufferedSpans == 0 {
|
||||||
|
r.options.MaxBufferedSpans = DefaultMaxBufferedSpans
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.options.ForceTransmissionStartingAt == 0 {
|
||||||
|
r.options.ForceTransmissionStartingAt = DefaultForceSpanSendAt
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *sensorS) getOptions() *Options {
|
||||||
|
return r.options
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *sensorS) configureServiceName() {
|
||||||
|
if r.options != nil {
|
||||||
|
r.serviceName = r.options.Service
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.serviceName == "" {
|
||||||
|
r.serviceName = filepath.Base(os.Args[0])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// InitSensor Intializes the sensor (without tracing) to begin collecting
|
||||||
|
// and reporting metrics.
|
||||||
|
func InitSensor(options *Options) {
|
||||||
|
if sensor == nil {
|
||||||
|
sensor = new(sensorS)
|
||||||
|
// If this environment variable is set, then override log level
|
||||||
|
_, ok := os.LookupEnv("INSTANA_DEV")
|
||||||
|
if ok {
|
||||||
|
options.LogLevel = Debug
|
||||||
|
}
|
||||||
|
|
||||||
|
sensor.initLog()
|
||||||
|
sensor.init(options)
|
||||||
|
log.debug("initialized sensor")
|
||||||
|
}
|
||||||
|
}
|
253
vendor/github.com/instana/go-sensor/span.go
generated
vendored
Normal file
253
vendor/github.com/instana/go-sensor/span.go
generated
vendored
Normal file
|
@ -0,0 +1,253 @@
|
||||||
|
package instana
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
ot "github.com/opentracing/opentracing-go"
|
||||||
|
"github.com/opentracing/opentracing-go/ext"
|
||||||
|
otlog "github.com/opentracing/opentracing-go/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
type spanS struct {
|
||||||
|
tracer *tracerS
|
||||||
|
sync.Mutex
|
||||||
|
|
||||||
|
context SpanContext
|
||||||
|
ParentSpanID int64
|
||||||
|
Operation string
|
||||||
|
Start time.Time
|
||||||
|
Duration time.Duration
|
||||||
|
Tags ot.Tags
|
||||||
|
Logs []ot.LogRecord
|
||||||
|
Error bool
|
||||||
|
Ec int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *spanS) BaggageItem(key string) string {
|
||||||
|
r.Lock()
|
||||||
|
defer r.Unlock()
|
||||||
|
|
||||||
|
return r.context.Baggage[key]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *spanS) SetBaggageItem(key, val string) ot.Span {
|
||||||
|
if r.trim() {
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
r.Lock()
|
||||||
|
defer r.Unlock()
|
||||||
|
r.context = r.context.WithBaggageItem(key, val)
|
||||||
|
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *spanS) Context() ot.SpanContext {
|
||||||
|
return r.context
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *spanS) Finish() {
|
||||||
|
r.FinishWithOptions(ot.FinishOptions{})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *spanS) FinishWithOptions(opts ot.FinishOptions) {
|
||||||
|
finishTime := opts.FinishTime
|
||||||
|
if finishTime.IsZero() {
|
||||||
|
finishTime = time.Now()
|
||||||
|
}
|
||||||
|
|
||||||
|
duration := finishTime.Sub(r.Start)
|
||||||
|
r.Lock()
|
||||||
|
defer r.Unlock()
|
||||||
|
for _, lr := range opts.LogRecords {
|
||||||
|
r.appendLog(lr)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, ld := range opts.BulkLogData {
|
||||||
|
r.appendLog(ld.ToLogRecord())
|
||||||
|
}
|
||||||
|
|
||||||
|
r.Duration = duration
|
||||||
|
r.tracer.options.Recorder.RecordSpan(r)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *spanS) appendLog(lr ot.LogRecord) {
|
||||||
|
maxLogs := r.tracer.options.MaxLogsPerSpan
|
||||||
|
if maxLogs == 0 || len(r.Logs) < maxLogs {
|
||||||
|
r.Logs = append(r.Logs, lr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *spanS) Log(ld ot.LogData) {
|
||||||
|
r.Lock()
|
||||||
|
defer r.Unlock()
|
||||||
|
if r.trim() || r.tracer.options.DropAllLogs {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if ld.Timestamp.IsZero() {
|
||||||
|
ld.Timestamp = time.Now()
|
||||||
|
}
|
||||||
|
|
||||||
|
r.appendLog(ld.ToLogRecord())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *spanS) trim() bool {
|
||||||
|
return !r.context.Sampled && r.tracer.options.TrimUnsampledSpans
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *spanS) LogEvent(event string) {
|
||||||
|
r.Log(ot.LogData{
|
||||||
|
Event: event})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *spanS) LogEventWithPayload(event string, payload interface{}) {
|
||||||
|
r.Log(ot.LogData{
|
||||||
|
Event: event,
|
||||||
|
Payload: payload})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *spanS) LogFields(fields ...otlog.Field) {
|
||||||
|
|
||||||
|
for _, v := range fields {
|
||||||
|
// If this tag indicates an error, increase the error count
|
||||||
|
if v.Key() == "error" {
|
||||||
|
r.Error = true
|
||||||
|
r.Ec++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lr := ot.LogRecord{
|
||||||
|
Fields: fields,
|
||||||
|
}
|
||||||
|
|
||||||
|
r.Lock()
|
||||||
|
defer r.Unlock()
|
||||||
|
if r.trim() || r.tracer.options.DropAllLogs {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if lr.Timestamp.IsZero() {
|
||||||
|
lr.Timestamp = time.Now()
|
||||||
|
}
|
||||||
|
|
||||||
|
r.appendLog(lr)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *spanS) LogKV(keyValues ...interface{}) {
|
||||||
|
fields, err := otlog.InterleavedKVToFields(keyValues...)
|
||||||
|
if err != nil {
|
||||||
|
r.LogFields(otlog.Error(err), otlog.String("function", "LogKV"))
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
r.LogFields(fields...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *spanS) SetOperationName(operationName string) ot.Span {
|
||||||
|
r.Lock()
|
||||||
|
defer r.Unlock()
|
||||||
|
r.Operation = operationName
|
||||||
|
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *spanS) SetTag(key string, value interface{}) ot.Span {
|
||||||
|
r.Lock()
|
||||||
|
defer r.Unlock()
|
||||||
|
if r.trim() {
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.Tags == nil {
|
||||||
|
r.Tags = ot.Tags{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If this tag indicates an error, increase the error count
|
||||||
|
if key == "error" {
|
||||||
|
r.Error = true
|
||||||
|
r.Ec++
|
||||||
|
}
|
||||||
|
|
||||||
|
r.Tags[key] = value
|
||||||
|
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *spanS) Tracer() ot.Tracer {
|
||||||
|
return r.tracer
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *spanS) getTag(tag string) interface{} {
|
||||||
|
var x, ok = r.Tags[tag]
|
||||||
|
if !ok {
|
||||||
|
x = ""
|
||||||
|
}
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *spanS) getIntTag(tag string) int {
|
||||||
|
d := r.Tags[tag]
|
||||||
|
if d == nil {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
x, ok := d.(int)
|
||||||
|
if !ok {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *spanS) getStringTag(tag string) string {
|
||||||
|
d := r.Tags[tag]
|
||||||
|
if d == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return fmt.Sprint(d)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *spanS) getHostName() string {
|
||||||
|
hostTag := r.getStringTag(string(ext.PeerHostname))
|
||||||
|
if hostTag != "" {
|
||||||
|
return hostTag
|
||||||
|
}
|
||||||
|
|
||||||
|
h, err := os.Hostname()
|
||||||
|
if err != nil {
|
||||||
|
h = "localhost"
|
||||||
|
}
|
||||||
|
return h
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *spanS) getSpanKind() string {
|
||||||
|
kind := r.getStringTag(string(ext.SpanKind))
|
||||||
|
|
||||||
|
switch kind {
|
||||||
|
case string(ext.SpanKindRPCServerEnum), "consumer", "entry":
|
||||||
|
return "entry"
|
||||||
|
case string(ext.SpanKindRPCClientEnum), "producer", "exit":
|
||||||
|
return "exit"
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *spanS) collectLogs() map[uint64]map[string]interface{} {
|
||||||
|
logs := make(map[uint64]map[string]interface{})
|
||||||
|
for _, l := range r.Logs {
|
||||||
|
if _, ok := logs[uint64(l.Timestamp.UnixNano())/uint64(time.Millisecond)]; !ok {
|
||||||
|
logs[uint64(l.Timestamp.UnixNano())/uint64(time.Millisecond)] = make(map[string]interface{})
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, f := range l.Fields {
|
||||||
|
logs[uint64(l.Timestamp.UnixNano())/uint64(time.Millisecond)][f.Key()] = f.Value()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return logs
|
||||||
|
}
|
119
vendor/github.com/instana/go-sensor/tracer.go
generated
vendored
Normal file
119
vendor/github.com/instana/go-sensor/tracer.go
generated
vendored
Normal file
|
@ -0,0 +1,119 @@
|
||||||
|
package instana
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
ot "github.com/opentracing/opentracing-go"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// MaxLogsPerSpan The maximum number of logs allowed on a span.
|
||||||
|
MaxLogsPerSpan = 2
|
||||||
|
)
|
||||||
|
|
||||||
|
type tracerS struct {
|
||||||
|
options TracerOptions
|
||||||
|
textPropagator *textMapPropagator
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *tracerS) Inject(sc ot.SpanContext, format interface{}, carrier interface{}) error {
|
||||||
|
switch format {
|
||||||
|
case ot.TextMap, ot.HTTPHeaders:
|
||||||
|
return r.textPropagator.inject(sc, carrier)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ot.ErrUnsupportedFormat
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *tracerS) Extract(format interface{}, carrier interface{}) (ot.SpanContext, error) {
|
||||||
|
switch format {
|
||||||
|
case ot.TextMap, ot.HTTPHeaders:
|
||||||
|
return r.textPropagator.extract(carrier)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, ot.ErrUnsupportedFormat
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *tracerS) StartSpan(operationName string, opts ...ot.StartSpanOption) ot.Span {
|
||||||
|
sso := ot.StartSpanOptions{}
|
||||||
|
for _, o := range opts {
|
||||||
|
o.Apply(&sso)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r.StartSpanWithOptions(operationName, sso)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *tracerS) StartSpanWithOptions(operationName string, opts ot.StartSpanOptions) ot.Span {
|
||||||
|
startTime := opts.StartTime
|
||||||
|
if startTime.IsZero() {
|
||||||
|
startTime = time.Now()
|
||||||
|
}
|
||||||
|
|
||||||
|
tags := opts.Tags
|
||||||
|
span := &spanS{}
|
||||||
|
Loop:
|
||||||
|
for _, ref := range opts.References {
|
||||||
|
switch ref.Type {
|
||||||
|
case ot.ChildOfRef, ot.FollowsFromRef:
|
||||||
|
refCtx := ref.ReferencedContext.(SpanContext)
|
||||||
|
span.context.TraceID = refCtx.TraceID
|
||||||
|
span.context.SpanID = randomID()
|
||||||
|
span.context.Sampled = refCtx.Sampled
|
||||||
|
span.ParentSpanID = refCtx.SpanID
|
||||||
|
if l := len(refCtx.Baggage); l > 0 {
|
||||||
|
span.context.Baggage = make(map[string]string, l)
|
||||||
|
for k, v := range refCtx.Baggage {
|
||||||
|
span.context.Baggage[k] = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break Loop
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if span.context.TraceID == 0 {
|
||||||
|
span.context.SpanID = randomID()
|
||||||
|
span.context.TraceID = span.context.SpanID
|
||||||
|
span.context.Sampled = r.options.ShouldSample(span.context.TraceID)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r.startSpanInternal(span, operationName, startTime, tags)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *tracerS) startSpanInternal(span *spanS, operationName string, startTime time.Time, tags ot.Tags) ot.Span {
|
||||||
|
span.tracer = r
|
||||||
|
span.Operation = operationName
|
||||||
|
span.Start = startTime
|
||||||
|
span.Duration = -1
|
||||||
|
span.Tags = tags
|
||||||
|
|
||||||
|
return span
|
||||||
|
}
|
||||||
|
|
||||||
|
func shouldSample(traceID int64) bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewTracer Get a new Tracer with the default options applied.
|
||||||
|
func NewTracer() ot.Tracer {
|
||||||
|
return NewTracerWithOptions(&Options{})
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewTracerWithOptions Get a new Tracer with the specified options.
|
||||||
|
func NewTracerWithOptions(options *Options) ot.Tracer {
|
||||||
|
InitSensor(options)
|
||||||
|
|
||||||
|
return NewTracerWithEverything(options, NewRecorder())
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewTracerWithEverything Get a new Tracer with the works.
|
||||||
|
func NewTracerWithEverything(options *Options, recorder SpanRecorder) ot.Tracer {
|
||||||
|
InitSensor(options)
|
||||||
|
ret := &tracerS{options: TracerOptions{
|
||||||
|
Recorder: recorder,
|
||||||
|
ShouldSample: shouldSample,
|
||||||
|
MaxLogsPerSpan: MaxLogsPerSpan}}
|
||||||
|
ret.textPropagator = &textMapPropagator{ret}
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
91
vendor/github.com/instana/go-sensor/tracer_options.go
generated
vendored
Normal file
91
vendor/github.com/instana/go-sensor/tracer_options.go
generated
vendored
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
package instana
|
||||||
|
|
||||||
|
import (
|
||||||
|
bt "github.com/opentracing/basictracer-go"
|
||||||
|
opentracing "github.com/opentracing/opentracing-go"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Tracer extends the opentracing.Tracer interface
|
||||||
|
type Tracer interface {
|
||||||
|
opentracing.Tracer
|
||||||
|
|
||||||
|
// Options gets the Options used in New() or NewWithOptions().
|
||||||
|
Options() TracerOptions
|
||||||
|
}
|
||||||
|
|
||||||
|
// TracerOptions allows creating a customized Tracer via NewWithOptions. The object
|
||||||
|
// must not be updated when there is an active tracer using it.
|
||||||
|
type TracerOptions struct {
|
||||||
|
// ShouldSample is a function which is called when creating a new Span and
|
||||||
|
// determines whether that Span is sampled. The randomized TraceID is supplied
|
||||||
|
// to allow deterministic sampling decisions to be made across different nodes.
|
||||||
|
// For example,
|
||||||
|
//
|
||||||
|
// func(traceID uint64) { return traceID % 64 == 0 }
|
||||||
|
//
|
||||||
|
// samples every 64th trace on average.
|
||||||
|
ShouldSample func(traceID int64) bool
|
||||||
|
// TrimUnsampledSpans turns potentially expensive operations on unsampled
|
||||||
|
// Spans into no-ops. More precisely, tags and log events are silently
|
||||||
|
// discarded. If NewSpanEventListener is set, the callbacks will still fire.
|
||||||
|
TrimUnsampledSpans bool
|
||||||
|
// Recorder receives Spans which have been finished.
|
||||||
|
Recorder SpanRecorder
|
||||||
|
// NewSpanEventListener can be used to enhance the tracer by effectively
|
||||||
|
// attaching external code to trace events. See NetTraceIntegrator for a
|
||||||
|
// practical example, and event.go for the list of possible events.
|
||||||
|
NewSpanEventListener func() func(bt.SpanEvent)
|
||||||
|
// DropAllLogs turns log events on all Spans into no-ops.
|
||||||
|
// If NewSpanEventListener is set, the callbacks will still fire.
|
||||||
|
DropAllLogs bool
|
||||||
|
// MaxLogsPerSpan limits the number of Logs in a span (if set to a nonzero
|
||||||
|
// value). If a span has more logs than this value, logs are dropped as
|
||||||
|
// necessary (and replaced with a log describing how many were dropped).
|
||||||
|
//
|
||||||
|
// About half of the MaxLogPerSpan logs kept are the oldest logs, and about
|
||||||
|
// half are the newest logs.
|
||||||
|
//
|
||||||
|
// If NewSpanEventListener is set, the callbacks will still fire for all log
|
||||||
|
// events. This value is ignored if DropAllLogs is true.
|
||||||
|
MaxLogsPerSpan int
|
||||||
|
// DebugAssertSingleGoroutine internally records the ID of the goroutine
|
||||||
|
// creating each Span and verifies that no operation is carried out on
|
||||||
|
// it on a different goroutine.
|
||||||
|
// Provided strictly for development purposes.
|
||||||
|
// Passing Spans between goroutine without proper synchronization often
|
||||||
|
// results in use-after-Finish() errors. For a simple example, consider the
|
||||||
|
// following pseudocode:
|
||||||
|
//
|
||||||
|
// func (s *Server) Handle(req http.Request) error {
|
||||||
|
// sp := s.StartSpan("server")
|
||||||
|
// defer sp.Finish()
|
||||||
|
// wait := s.queueProcessing(opentracing.ContextWithSpan(context.Background(), sp), req)
|
||||||
|
// select {
|
||||||
|
// case resp := <-wait:
|
||||||
|
// return resp.Error
|
||||||
|
// case <-time.After(10*time.Second):
|
||||||
|
// sp.LogEvent("timed out waiting for processing")
|
||||||
|
// return ErrTimedOut
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// This looks reasonable at first, but a request which spends more than ten
|
||||||
|
// seconds in the queue is abandoned by the main goroutine and its trace
|
||||||
|
// finished, leading to use-after-finish when the request is finally
|
||||||
|
// processed. Note also that even joining on to a finished Span via
|
||||||
|
// StartSpanWithOptions constitutes an illegal operation.
|
||||||
|
//
|
||||||
|
// Code bases which do not require (or decide they do not want) Spans to
|
||||||
|
// be passed across goroutine boundaries can run with this flag enabled in
|
||||||
|
// tests to increase their chances of spotting wrong-doers.
|
||||||
|
DebugAssertSingleGoroutine bool
|
||||||
|
// DebugAssertUseAfterFinish is provided strictly for development purposes.
|
||||||
|
// When set, it attempts to exacerbate issues emanating from use of Spans
|
||||||
|
// after calling Finish by running additional assertions.
|
||||||
|
DebugAssertUseAfterFinish bool
|
||||||
|
// EnableSpanPool enables the use of a pool, so that the tracer reuses spans
|
||||||
|
// after Finish has been called on it. Adds a slight performance gain as it
|
||||||
|
// reduces allocations. However, if you have any use-after-finish race
|
||||||
|
// conditions the code may panic.
|
||||||
|
EnableSpanPool bool
|
||||||
|
}
|
99
vendor/github.com/instana/go-sensor/util.go
generated
vendored
Normal file
99
vendor/github.com/instana/go-sensor/util.go
generated
vendored
Normal file
|
@ -0,0 +1,99 @@
|
||||||
|
package instana
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/binary"
|
||||||
|
"errors"
|
||||||
|
"io/ioutil"
|
||||||
|
"math/rand"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
seededIDGen = rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||||
|
seededIDLock sync.Mutex
|
||||||
|
)
|
||||||
|
|
||||||
|
func randomID() int64 {
|
||||||
|
seededIDLock.Lock()
|
||||||
|
defer seededIDLock.Unlock()
|
||||||
|
return int64(seededIDGen.Int63())
|
||||||
|
}
|
||||||
|
|
||||||
|
// ID2Header converts an Instana ID to a value that can be used in
|
||||||
|
// context propagation (such as HTTP headers). More specifically,
|
||||||
|
// this converts a signed 64 bit integer into an unsigned hex string.
|
||||||
|
func ID2Header(id int64) (string, error) {
|
||||||
|
// FIXME: We're assuming LittleEndian here
|
||||||
|
|
||||||
|
// Write out _signed_ 64bit integer to byte buffer
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
if err := binary.Write(buf, binary.LittleEndian, id); err == nil {
|
||||||
|
// Read bytes back into _unsigned_ 64 bit integer
|
||||||
|
var unsigned uint64
|
||||||
|
if err = binary.Read(buf, binary.LittleEndian, &unsigned); err == nil {
|
||||||
|
// Convert uint64 to hex string equivalent and return that
|
||||||
|
return strconv.FormatUint(unsigned, 16), nil
|
||||||
|
}
|
||||||
|
log.debug(err)
|
||||||
|
} else {
|
||||||
|
log.debug(err)
|
||||||
|
}
|
||||||
|
return "", errors.New("context corrupted; could not convert value")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Header2ID converts an header context value into an Instana ID. More
|
||||||
|
// specifically, this converts an unsigned 64 bit hex value into a signed
|
||||||
|
// 64bit integer.
|
||||||
|
func Header2ID(header string) (int64, error) {
|
||||||
|
// FIXME: We're assuming LittleEndian here
|
||||||
|
|
||||||
|
// Parse unsigned 64 bit hex string into unsigned 64 bit base 10 integer
|
||||||
|
if unsignedID, err := strconv.ParseUint(header, 16, 64); err == nil {
|
||||||
|
// Write out _unsigned_ 64bit integer to byte buffer
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
if err = binary.Write(buf, binary.LittleEndian, unsignedID); err == nil {
|
||||||
|
// Read bytes back into _signed_ 64 bit integer
|
||||||
|
var signedID int64
|
||||||
|
if err = binary.Read(buf, binary.LittleEndian, &signedID); err == nil {
|
||||||
|
// The success case
|
||||||
|
return signedID, nil
|
||||||
|
}
|
||||||
|
log.debug(err)
|
||||||
|
} else {
|
||||||
|
log.debug(err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.debug(err)
|
||||||
|
}
|
||||||
|
return int64(0), errors.New("context corrupted; could not convert value")
|
||||||
|
}
|
||||||
|
|
||||||
|
func getCommandLine() (string, []string) {
|
||||||
|
var cmdlinePath string = "/proc/" + strconv.Itoa(os.Getpid()) + "/cmdline"
|
||||||
|
|
||||||
|
cmdline, err := ioutil.ReadFile(cmdlinePath)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.debug("No /proc. Returning OS reported cmdline")
|
||||||
|
return os.Args[0], os.Args[1:]
|
||||||
|
}
|
||||||
|
|
||||||
|
parts := strings.FieldsFunc(string(cmdline), func(c rune) bool {
|
||||||
|
if c == '\u0000' {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
})
|
||||||
|
log.debug("cmdline says:", parts[0], parts[1:])
|
||||||
|
return parts[0], parts[1:]
|
||||||
|
}
|
||||||
|
|
||||||
|
func abs(x int64) int64 {
|
||||||
|
y := x >> 63
|
||||||
|
return (x + y) ^ y
|
||||||
|
}
|
191
vendor/github.com/looplab/fsm/LICENSE
generated
vendored
Normal file
191
vendor/github.com/looplab/fsm/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,191 @@
|
||||||
|
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:
|
||||||
|
|
||||||
|
You must give any other recipients of the Work or Derivative Works a copy of
|
||||||
|
this License; and
|
||||||
|
You must cause any modified files to carry prominent notices stating that You
|
||||||
|
changed the files; and
|
||||||
|
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
|
||||||
|
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.
|
100
vendor/github.com/looplab/fsm/errors.go
generated
vendored
Normal file
100
vendor/github.com/looplab/fsm/errors.go
generated
vendored
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
// Copyright (c) 2013 - Max Persson <max@looplab.se>
|
||||||
|
//
|
||||||
|
// 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 fsm
|
||||||
|
|
||||||
|
// InvalidEventError is returned by FSM.Event() when the event cannot be called
|
||||||
|
// in the current state.
|
||||||
|
type InvalidEventError struct {
|
||||||
|
Event string
|
||||||
|
State string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e InvalidEventError) Error() string {
|
||||||
|
return "event " + e.Event + " inappropriate in current state " + e.State
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnknownEventError is returned by FSM.Event() when the event is not defined.
|
||||||
|
type UnknownEventError struct {
|
||||||
|
Event string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e UnknownEventError) Error() string {
|
||||||
|
return "event " + e.Event + " does not exist"
|
||||||
|
}
|
||||||
|
|
||||||
|
// InTransitionError is returned by FSM.Event() when an asynchronous transition
|
||||||
|
// is already in progress.
|
||||||
|
type InTransitionError struct {
|
||||||
|
Event string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e InTransitionError) Error() string {
|
||||||
|
return "event " + e.Event + " inappropriate because previous transition did not complete"
|
||||||
|
}
|
||||||
|
|
||||||
|
// NotInTransitionError is returned by FSM.Transition() when an asynchronous
|
||||||
|
// transition is not in progress.
|
||||||
|
type NotInTransitionError struct{}
|
||||||
|
|
||||||
|
func (e NotInTransitionError) Error() string {
|
||||||
|
return "transition inappropriate because no state change in progress"
|
||||||
|
}
|
||||||
|
|
||||||
|
// NoTransitionError is returned by FSM.Event() when no transition have happened,
|
||||||
|
// for example if the source and destination states are the same.
|
||||||
|
type NoTransitionError struct {
|
||||||
|
Err error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e NoTransitionError) Error() string {
|
||||||
|
if e.Err != nil {
|
||||||
|
return "no transition with error: " + e.Err.Error()
|
||||||
|
}
|
||||||
|
return "no transition"
|
||||||
|
}
|
||||||
|
|
||||||
|
// CanceledError is returned by FSM.Event() when a callback have canceled a
|
||||||
|
// transition.
|
||||||
|
type CanceledError struct {
|
||||||
|
Err error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e CanceledError) Error() string {
|
||||||
|
if e.Err != nil {
|
||||||
|
return "transition canceled with error: " + e.Err.Error()
|
||||||
|
}
|
||||||
|
return "transition canceled"
|
||||||
|
}
|
||||||
|
|
||||||
|
// AsyncError is returned by FSM.Event() when a callback have initiated an
|
||||||
|
// asynchronous state transition.
|
||||||
|
type AsyncError struct {
|
||||||
|
Err error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e AsyncError) Error() string {
|
||||||
|
if e.Err != nil {
|
||||||
|
return "async started with error: " + e.Err.Error()
|
||||||
|
}
|
||||||
|
return "async started"
|
||||||
|
}
|
||||||
|
|
||||||
|
// InternalError is returned by FSM.Event() and should never occur. It is a
|
||||||
|
// probably because of a bug.
|
||||||
|
type InternalError struct{}
|
||||||
|
|
||||||
|
func (e InternalError) Error() string {
|
||||||
|
return "internal error on state transition"
|
||||||
|
}
|
62
vendor/github.com/looplab/fsm/event.go
generated
vendored
Normal file
62
vendor/github.com/looplab/fsm/event.go
generated
vendored
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
// Copyright (c) 2013 - Max Persson <max@looplab.se>
|
||||||
|
//
|
||||||
|
// 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 fsm
|
||||||
|
|
||||||
|
// Event is the info that get passed as a reference in the callbacks.
|
||||||
|
type Event struct {
|
||||||
|
// FSM is a reference to the current FSM.
|
||||||
|
FSM *FSM
|
||||||
|
|
||||||
|
// Event is the event name.
|
||||||
|
Event string
|
||||||
|
|
||||||
|
// Src is the state before the transition.
|
||||||
|
Src string
|
||||||
|
|
||||||
|
// Dst is the state after the transition.
|
||||||
|
Dst string
|
||||||
|
|
||||||
|
// Err is an optional error that can be returned from a callback.
|
||||||
|
Err error
|
||||||
|
|
||||||
|
// Args is a optinal list of arguments passed to the callback.
|
||||||
|
Args []interface{}
|
||||||
|
|
||||||
|
// canceled is an internal flag set if the transition is canceled.
|
||||||
|
canceled bool
|
||||||
|
|
||||||
|
// async is an internal flag set if the transition should be asynchronous
|
||||||
|
async bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cancel can be called in before_<EVENT> or leave_<STATE> to cancel the
|
||||||
|
// current transition before it happens. It takes an opitonal error, which will
|
||||||
|
// overwrite e.Err if set before.
|
||||||
|
func (e *Event) Cancel(err ...error) {
|
||||||
|
e.canceled = true
|
||||||
|
|
||||||
|
if len(err) > 0 {
|
||||||
|
e.Err = err[0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Async can be called in leave_<STATE> to do an asynchronous state transition.
|
||||||
|
//
|
||||||
|
// The current state transition will be on hold in the old state until a final
|
||||||
|
// call to Transition is made. This will comlete the transition and possibly
|
||||||
|
// call the other callbacks.
|
||||||
|
func (e *Event) Async() {
|
||||||
|
e.async = true
|
||||||
|
}
|
447
vendor/github.com/looplab/fsm/fsm.go
generated
vendored
Normal file
447
vendor/github.com/looplab/fsm/fsm.go
generated
vendored
Normal file
|
@ -0,0 +1,447 @@
|
||||||
|
// Copyright (c) 2013 - Max Persson <max@looplab.se>
|
||||||
|
//
|
||||||
|
// 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 fsm implements a finite state machine.
|
||||||
|
//
|
||||||
|
// It is heavily based on two FSM implementations:
|
||||||
|
//
|
||||||
|
// Javascript Finite State Machine
|
||||||
|
// https://github.com/jakesgordon/javascript-state-machine
|
||||||
|
//
|
||||||
|
// Fysom for Python
|
||||||
|
// https://github.com/oxplot/fysom (forked at https://github.com/mriehl/fysom)
|
||||||
|
//
|
||||||
|
package fsm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
// transitioner is an interface for the FSM's transition function.
|
||||||
|
type transitioner interface {
|
||||||
|
transition(*FSM) error
|
||||||
|
}
|
||||||
|
|
||||||
|
// FSM is the state machine that holds the current state.
|
||||||
|
//
|
||||||
|
// It has to be created with NewFSM to function properly.
|
||||||
|
type FSM struct {
|
||||||
|
// current is the state that the FSM is currently in.
|
||||||
|
current string
|
||||||
|
|
||||||
|
// transitions maps events and source states to destination states.
|
||||||
|
transitions map[eKey]string
|
||||||
|
|
||||||
|
// callbacks maps events and targers to callback functions.
|
||||||
|
callbacks map[cKey]Callback
|
||||||
|
|
||||||
|
// transition is the internal transition functions used either directly
|
||||||
|
// or when Transition is called in an asynchronous state transition.
|
||||||
|
transition func()
|
||||||
|
// transitionerObj calls the FSM's transition() function.
|
||||||
|
transitionerObj transitioner
|
||||||
|
|
||||||
|
// stateMu guards access to the current state.
|
||||||
|
stateMu sync.RWMutex
|
||||||
|
// eventMu guards access to Event() and Transition().
|
||||||
|
eventMu sync.Mutex
|
||||||
|
}
|
||||||
|
|
||||||
|
// EventDesc represents an event when initializing the FSM.
|
||||||
|
//
|
||||||
|
// The event can have one or more source states that is valid for performing
|
||||||
|
// the transition. If the FSM is in one of the source states it will end up in
|
||||||
|
// the specified destination state, calling all defined callbacks as it goes.
|
||||||
|
type EventDesc struct {
|
||||||
|
// Name is the event name used when calling for a transition.
|
||||||
|
Name string
|
||||||
|
|
||||||
|
// Src is a slice of source states that the FSM must be in to perform a
|
||||||
|
// state transition.
|
||||||
|
Src []string
|
||||||
|
|
||||||
|
// Dst is the destination state that the FSM will be in if the transition
|
||||||
|
// succeds.
|
||||||
|
Dst string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Callback is a function type that callbacks should use. Event is the current
|
||||||
|
// event info as the callback happens.
|
||||||
|
type Callback func(*Event)
|
||||||
|
|
||||||
|
// Events is a shorthand for defining the transition map in NewFSM.
|
||||||
|
type Events []EventDesc
|
||||||
|
|
||||||
|
// Callbacks is a shorthand for defining the callbacks in NewFSM.a
|
||||||
|
type Callbacks map[string]Callback
|
||||||
|
|
||||||
|
// NewFSM constructs a FSM from events and callbacks.
|
||||||
|
//
|
||||||
|
// The events and transitions are specified as a slice of Event structs
|
||||||
|
// specified as Events. Each Event is mapped to one or more internal
|
||||||
|
// transitions from Event.Src to Event.Dst.
|
||||||
|
//
|
||||||
|
// Callbacks are added as a map specified as Callbacks where the key is parsed
|
||||||
|
// as the callback event as follows, and called in the same order:
|
||||||
|
//
|
||||||
|
// 1. before_<EVENT> - called before event named <EVENT>
|
||||||
|
//
|
||||||
|
// 2. before_event - called before all events
|
||||||
|
//
|
||||||
|
// 3. leave_<OLD_STATE> - called before leaving <OLD_STATE>
|
||||||
|
//
|
||||||
|
// 4. leave_state - called before leaving all states
|
||||||
|
//
|
||||||
|
// 5. enter_<NEW_STATE> - called after entering <NEW_STATE>
|
||||||
|
//
|
||||||
|
// 6. enter_state - called after entering all states
|
||||||
|
//
|
||||||
|
// 7. after_<EVENT> - called after event named <EVENT>
|
||||||
|
//
|
||||||
|
// 8. after_event - called after all events
|
||||||
|
//
|
||||||
|
// There are also two short form versions for the most commonly used callbacks.
|
||||||
|
// They are simply the name of the event or state:
|
||||||
|
//
|
||||||
|
// 1. <NEW_STATE> - called after entering <NEW_STATE>
|
||||||
|
//
|
||||||
|
// 2. <EVENT> - called after event named <EVENT>
|
||||||
|
//
|
||||||
|
// If both a shorthand version and a full version is specified it is undefined
|
||||||
|
// which version of the callback will end up in the internal map. This is due
|
||||||
|
// to the psuedo random nature of Go maps. No checking for multiple keys is
|
||||||
|
// currently performed.
|
||||||
|
func NewFSM(initial string, events []EventDesc, callbacks map[string]Callback) *FSM {
|
||||||
|
f := &FSM{
|
||||||
|
transitionerObj: &transitionerStruct{},
|
||||||
|
current: initial,
|
||||||
|
transitions: make(map[eKey]string),
|
||||||
|
callbacks: make(map[cKey]Callback),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build transition map and store sets of all events and states.
|
||||||
|
allEvents := make(map[string]bool)
|
||||||
|
allStates := make(map[string]bool)
|
||||||
|
for _, e := range events {
|
||||||
|
for _, src := range e.Src {
|
||||||
|
f.transitions[eKey{e.Name, src}] = e.Dst
|
||||||
|
allStates[src] = true
|
||||||
|
allStates[e.Dst] = true
|
||||||
|
}
|
||||||
|
allEvents[e.Name] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Map all callbacks to events/states.
|
||||||
|
for name, fn := range callbacks {
|
||||||
|
var target string
|
||||||
|
var callbackType int
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case strings.HasPrefix(name, "before_"):
|
||||||
|
target = strings.TrimPrefix(name, "before_")
|
||||||
|
if target == "event" {
|
||||||
|
target = ""
|
||||||
|
callbackType = callbackBeforeEvent
|
||||||
|
} else if _, ok := allEvents[target]; ok {
|
||||||
|
callbackType = callbackBeforeEvent
|
||||||
|
}
|
||||||
|
case strings.HasPrefix(name, "leave_"):
|
||||||
|
target = strings.TrimPrefix(name, "leave_")
|
||||||
|
if target == "state" {
|
||||||
|
target = ""
|
||||||
|
callbackType = callbackLeaveState
|
||||||
|
} else if _, ok := allStates[target]; ok {
|
||||||
|
callbackType = callbackLeaveState
|
||||||
|
}
|
||||||
|
case strings.HasPrefix(name, "enter_"):
|
||||||
|
target = strings.TrimPrefix(name, "enter_")
|
||||||
|
if target == "state" {
|
||||||
|
target = ""
|
||||||
|
callbackType = callbackEnterState
|
||||||
|
} else if _, ok := allStates[target]; ok {
|
||||||
|
callbackType = callbackEnterState
|
||||||
|
}
|
||||||
|
case strings.HasPrefix(name, "after_"):
|
||||||
|
target = strings.TrimPrefix(name, "after_")
|
||||||
|
if target == "event" {
|
||||||
|
target = ""
|
||||||
|
callbackType = callbackAfterEvent
|
||||||
|
} else if _, ok := allEvents[target]; ok {
|
||||||
|
callbackType = callbackAfterEvent
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
target = name
|
||||||
|
if _, ok := allStates[target]; ok {
|
||||||
|
callbackType = callbackEnterState
|
||||||
|
} else if _, ok := allEvents[target]; ok {
|
||||||
|
callbackType = callbackAfterEvent
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if callbackType != callbackNone {
|
||||||
|
f.callbacks[cKey{target, callbackType}] = fn
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return f
|
||||||
|
}
|
||||||
|
|
||||||
|
// Current returns the current state of the FSM.
|
||||||
|
func (f *FSM) Current() string {
|
||||||
|
f.stateMu.RLock()
|
||||||
|
defer f.stateMu.RUnlock()
|
||||||
|
return f.current
|
||||||
|
}
|
||||||
|
|
||||||
|
// Is returns true if state is the current state.
|
||||||
|
func (f *FSM) Is(state string) bool {
|
||||||
|
f.stateMu.RLock()
|
||||||
|
defer f.stateMu.RUnlock()
|
||||||
|
return state == f.current
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetState allows the user to move to the given state from current state.
|
||||||
|
// The call does not trigger any callbacks, if defined.
|
||||||
|
func (f *FSM) SetState(state string) {
|
||||||
|
f.stateMu.Lock()
|
||||||
|
defer f.stateMu.Unlock()
|
||||||
|
f.current = state
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Can returns true if event can occur in the current state.
|
||||||
|
func (f *FSM) Can(event string) bool {
|
||||||
|
f.stateMu.RLock()
|
||||||
|
defer f.stateMu.RUnlock()
|
||||||
|
_, ok := f.transitions[eKey{event, f.current}]
|
||||||
|
return ok && (f.transition == nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AvailableTransitions returns a list of transitions avilable in the
|
||||||
|
// current state.
|
||||||
|
func (f *FSM) AvailableTransitions() []string {
|
||||||
|
f.stateMu.RLock()
|
||||||
|
defer f.stateMu.RUnlock()
|
||||||
|
var transitions []string
|
||||||
|
for key := range f.transitions {
|
||||||
|
if key.src == f.current {
|
||||||
|
transitions = append(transitions, key.event)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return transitions
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cannot returns true if event can not occure in the current state.
|
||||||
|
// It is a convenience method to help code read nicely.
|
||||||
|
func (f *FSM) Cannot(event string) bool {
|
||||||
|
return !f.Can(event)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Event initiates a state transition with the named event.
|
||||||
|
//
|
||||||
|
// The call takes a variable number of arguments that will be passed to the
|
||||||
|
// callback, if defined.
|
||||||
|
//
|
||||||
|
// It will return nil if the state change is ok or one of these errors:
|
||||||
|
//
|
||||||
|
// - event X inappropriate because previous transition did not complete
|
||||||
|
//
|
||||||
|
// - event X inappropriate in current state Y
|
||||||
|
//
|
||||||
|
// - event X does not exist
|
||||||
|
//
|
||||||
|
// - internal error on state transition
|
||||||
|
//
|
||||||
|
// The last error should never occur in this situation and is a sign of an
|
||||||
|
// internal bug.
|
||||||
|
func (f *FSM) Event(event string, args ...interface{}) error {
|
||||||
|
f.eventMu.Lock()
|
||||||
|
defer f.eventMu.Unlock()
|
||||||
|
|
||||||
|
f.stateMu.RLock()
|
||||||
|
defer f.stateMu.RUnlock()
|
||||||
|
|
||||||
|
if f.transition != nil {
|
||||||
|
return InTransitionError{event}
|
||||||
|
}
|
||||||
|
|
||||||
|
dst, ok := f.transitions[eKey{event, f.current}]
|
||||||
|
if !ok {
|
||||||
|
for ekey := range f.transitions {
|
||||||
|
if ekey.event == event {
|
||||||
|
return InvalidEventError{event, f.current}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return UnknownEventError{event}
|
||||||
|
}
|
||||||
|
|
||||||
|
e := &Event{f, event, f.current, dst, nil, args, false, false}
|
||||||
|
|
||||||
|
err := f.beforeEventCallbacks(e)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if f.current == dst {
|
||||||
|
f.afterEventCallbacks(e)
|
||||||
|
return NoTransitionError{e.Err}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup the transition, call it later.
|
||||||
|
f.transition = func() {
|
||||||
|
f.stateMu.Lock()
|
||||||
|
f.current = dst
|
||||||
|
f.stateMu.Unlock()
|
||||||
|
|
||||||
|
f.enterStateCallbacks(e)
|
||||||
|
f.afterEventCallbacks(e)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = f.leaveStateCallbacks(e); err != nil {
|
||||||
|
if _, ok := err.(CanceledError); ok {
|
||||||
|
f.transition = nil
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Perform the rest of the transition, if not asynchronous.
|
||||||
|
f.stateMu.RUnlock()
|
||||||
|
err = f.doTransition()
|
||||||
|
f.stateMu.RLock()
|
||||||
|
if err != nil {
|
||||||
|
return InternalError{}
|
||||||
|
}
|
||||||
|
|
||||||
|
return e.Err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transition wraps transitioner.transition.
|
||||||
|
func (f *FSM) Transition() error {
|
||||||
|
f.eventMu.Lock()
|
||||||
|
defer f.eventMu.Unlock()
|
||||||
|
return f.doTransition()
|
||||||
|
}
|
||||||
|
|
||||||
|
// doTransition wraps transitioner.transition.
|
||||||
|
func (f *FSM) doTransition() error {
|
||||||
|
return f.transitionerObj.transition(f)
|
||||||
|
}
|
||||||
|
|
||||||
|
// transitionerStruct is the default implementation of the transitioner
|
||||||
|
// interface. Other implementations can be swapped in for testing.
|
||||||
|
type transitionerStruct struct{}
|
||||||
|
|
||||||
|
// Transition completes an asynchrounous state change.
|
||||||
|
//
|
||||||
|
// The callback for leave_<STATE> must prviously have called Async on its
|
||||||
|
// event to have initiated an asynchronous state transition.
|
||||||
|
func (t transitionerStruct) transition(f *FSM) error {
|
||||||
|
if f.transition == nil {
|
||||||
|
return NotInTransitionError{}
|
||||||
|
}
|
||||||
|
f.transition()
|
||||||
|
f.transition = nil
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// beforeEventCallbacks calls the before_ callbacks, first the named then the
|
||||||
|
// general version.
|
||||||
|
func (f *FSM) beforeEventCallbacks(e *Event) error {
|
||||||
|
if fn, ok := f.callbacks[cKey{e.Event, callbackBeforeEvent}]; ok {
|
||||||
|
fn(e)
|
||||||
|
if e.canceled {
|
||||||
|
return CanceledError{e.Err}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if fn, ok := f.callbacks[cKey{"", callbackBeforeEvent}]; ok {
|
||||||
|
fn(e)
|
||||||
|
if e.canceled {
|
||||||
|
return CanceledError{e.Err}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// leaveStateCallbacks calls the leave_ callbacks, first the named then the
|
||||||
|
// general version.
|
||||||
|
func (f *FSM) leaveStateCallbacks(e *Event) error {
|
||||||
|
if fn, ok := f.callbacks[cKey{f.current, callbackLeaveState}]; ok {
|
||||||
|
fn(e)
|
||||||
|
if e.canceled {
|
||||||
|
return CanceledError{e.Err}
|
||||||
|
} else if e.async {
|
||||||
|
return AsyncError{e.Err}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if fn, ok := f.callbacks[cKey{"", callbackLeaveState}]; ok {
|
||||||
|
fn(e)
|
||||||
|
if e.canceled {
|
||||||
|
return CanceledError{e.Err}
|
||||||
|
} else if e.async {
|
||||||
|
return AsyncError{e.Err}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// enterStateCallbacks calls the enter_ callbacks, first the named then the
|
||||||
|
// general version.
|
||||||
|
func (f *FSM) enterStateCallbacks(e *Event) {
|
||||||
|
if fn, ok := f.callbacks[cKey{f.current, callbackEnterState}]; ok {
|
||||||
|
fn(e)
|
||||||
|
}
|
||||||
|
if fn, ok := f.callbacks[cKey{"", callbackEnterState}]; ok {
|
||||||
|
fn(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// afterEventCallbacks calls the after_ callbacks, first the named then the
|
||||||
|
// general version.
|
||||||
|
func (f *FSM) afterEventCallbacks(e *Event) {
|
||||||
|
if fn, ok := f.callbacks[cKey{e.Event, callbackAfterEvent}]; ok {
|
||||||
|
fn(e)
|
||||||
|
}
|
||||||
|
if fn, ok := f.callbacks[cKey{"", callbackAfterEvent}]; ok {
|
||||||
|
fn(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
callbackNone int = iota
|
||||||
|
callbackBeforeEvent
|
||||||
|
callbackLeaveState
|
||||||
|
callbackEnterState
|
||||||
|
callbackAfterEvent
|
||||||
|
)
|
||||||
|
|
||||||
|
// cKey is a struct key used for keeping the callbacks mapped to a target.
|
||||||
|
type cKey struct {
|
||||||
|
// target is either the name of a state or an event depending on which
|
||||||
|
// callback type the key refers to. It can also be "" for a non-targeted
|
||||||
|
// callback like before_event.
|
||||||
|
target string
|
||||||
|
|
||||||
|
// callbackType is the situation when the callback will be run.
|
||||||
|
callbackType int
|
||||||
|
}
|
||||||
|
|
||||||
|
// eKey is a struct key used for storing the transition map.
|
||||||
|
type eKey struct {
|
||||||
|
// event is the name of the event that the keys refers to.
|
||||||
|
event string
|
||||||
|
|
||||||
|
// src is the source from where the event can transition.
|
||||||
|
src string
|
||||||
|
}
|
45
vendor/github.com/looplab/fsm/utils.go
generated
vendored
Normal file
45
vendor/github.com/looplab/fsm/utils.go
generated
vendored
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
package fsm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Visualize outputs a visualization of a FSM in Graphviz format.
|
||||||
|
func Visualize(fsm *FSM) string {
|
||||||
|
var buf bytes.Buffer
|
||||||
|
|
||||||
|
states := make(map[string]int)
|
||||||
|
|
||||||
|
buf.WriteString(fmt.Sprintf(`digraph fsm {`))
|
||||||
|
buf.WriteString("\n")
|
||||||
|
|
||||||
|
// make sure the initial state is at top
|
||||||
|
for k, v := range fsm.transitions {
|
||||||
|
if k.src == fsm.current {
|
||||||
|
states[k.src]++
|
||||||
|
states[v]++
|
||||||
|
buf.WriteString(fmt.Sprintf(` "%s" -> "%s" [ label = "%s" ];`, k.src, v, k.event))
|
||||||
|
buf.WriteString("\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for k, v := range fsm.transitions {
|
||||||
|
if k.src != fsm.current {
|
||||||
|
states[k.src]++
|
||||||
|
states[v]++
|
||||||
|
buf.WriteString(fmt.Sprintf(` "%s" -> "%s" [ label = "%s" ];`, k.src, v, k.event))
|
||||||
|
buf.WriteString("\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
buf.WriteString("\n")
|
||||||
|
|
||||||
|
for k := range states {
|
||||||
|
buf.WriteString(fmt.Sprintf(` "%s";`, k))
|
||||||
|
buf.WriteString("\n")
|
||||||
|
}
|
||||||
|
buf.WriteString(fmt.Sprintln("}"))
|
||||||
|
|
||||||
|
return buf.String()
|
||||||
|
}
|
21
vendor/github.com/opentracing/basictracer-go/LICENSE
generated
vendored
Normal file
21
vendor/github.com/opentracing/basictracer-go/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2016 The OpenTracing Authors
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
42
vendor/github.com/opentracing/basictracer-go/context.go
generated
vendored
Normal file
42
vendor/github.com/opentracing/basictracer-go/context.go
generated
vendored
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
package basictracer
|
||||||
|
|
||||||
|
// SpanContext holds the basic Span metadata.
|
||||||
|
type SpanContext struct {
|
||||||
|
// A probabilistically unique identifier for a [multi-span] trace.
|
||||||
|
TraceID uint64
|
||||||
|
|
||||||
|
// A probabilistically unique identifier for a span.
|
||||||
|
SpanID uint64
|
||||||
|
|
||||||
|
// Whether the trace is sampled.
|
||||||
|
Sampled bool
|
||||||
|
|
||||||
|
// The span's associated baggage.
|
||||||
|
Baggage map[string]string // initialized on first use
|
||||||
|
}
|
||||||
|
|
||||||
|
// ForeachBaggageItem belongs to the opentracing.SpanContext interface
|
||||||
|
func (c SpanContext) ForeachBaggageItem(handler func(k, v string) bool) {
|
||||||
|
for k, v := range c.Baggage {
|
||||||
|
if !handler(k, v) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithBaggageItem returns an entirely new basictracer SpanContext with the
|
||||||
|
// given key:value baggage pair set.
|
||||||
|
func (c SpanContext) WithBaggageItem(key, val string) SpanContext {
|
||||||
|
var newBaggage map[string]string
|
||||||
|
if c.Baggage == nil {
|
||||||
|
newBaggage = map[string]string{key: val}
|
||||||
|
} else {
|
||||||
|
newBaggage = make(map[string]string, len(c.Baggage)+1)
|
||||||
|
for k, v := range c.Baggage {
|
||||||
|
newBaggage[k] = v
|
||||||
|
}
|
||||||
|
newBaggage[key] = val
|
||||||
|
}
|
||||||
|
// Use positional parameters so the compiler will help catch new fields.
|
||||||
|
return SpanContext{c.TraceID, c.SpanID, c.Sampled, newBaggage}
|
||||||
|
}
|
78
vendor/github.com/opentracing/basictracer-go/debug.go
generated
vendored
Normal file
78
vendor/github.com/opentracing/basictracer-go/debug.go
generated
vendored
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
package basictracer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"runtime"
|
||||||
|
"strconv"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
const debugGoroutineIDTag = "_initial_goroutine"
|
||||||
|
|
||||||
|
type errAssertionFailed struct {
|
||||||
|
span *spanImpl
|
||||||
|
msg string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error implements the error interface.
|
||||||
|
func (err *errAssertionFailed) Error() string {
|
||||||
|
return fmt.Sprintf("%s:\n%+v", err.msg, err.span)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *spanImpl) Lock() {
|
||||||
|
s.Mutex.Lock()
|
||||||
|
s.maybeAssertSanityLocked()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *spanImpl) maybeAssertSanityLocked() {
|
||||||
|
if s.tracer == nil {
|
||||||
|
s.Mutex.Unlock()
|
||||||
|
panic(&errAssertionFailed{span: s, msg: "span used after call to Finish()"})
|
||||||
|
}
|
||||||
|
if s.tracer.options.DebugAssertSingleGoroutine {
|
||||||
|
startID := curGoroutineID()
|
||||||
|
curID, ok := s.raw.Tags[debugGoroutineIDTag].(uint64)
|
||||||
|
if !ok {
|
||||||
|
// This is likely invoked in the context of the SetTag which sets
|
||||||
|
// debugGoroutineTag.
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if startID != curID {
|
||||||
|
s.Mutex.Unlock()
|
||||||
|
panic(&errAssertionFailed{
|
||||||
|
span: s,
|
||||||
|
msg: fmt.Sprintf("span started on goroutine %d, but now running on %d", startID, curID),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var goroutineSpace = []byte("goroutine ")
|
||||||
|
var littleBuf = sync.Pool{
|
||||||
|
New: func() interface{} {
|
||||||
|
buf := make([]byte, 64)
|
||||||
|
return &buf
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Credit to @bradfitz:
|
||||||
|
// https://github.com/golang/net/blob/master/http2/gotrack.go#L51
|
||||||
|
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 := strconv.ParseUint(string(b), 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
panic(fmt.Sprintf("Failed to parse goroutine ID out of %q: %v", b, err))
|
||||||
|
}
|
||||||
|
return n
|
||||||
|
}
|
62
vendor/github.com/opentracing/basictracer-go/event.go
generated
vendored
Normal file
62
vendor/github.com/opentracing/basictracer-go/event.go
generated
vendored
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
package basictracer
|
||||||
|
|
||||||
|
import "github.com/opentracing/opentracing-go"
|
||||||
|
|
||||||
|
// A SpanEvent is emitted when a mutating command is called on a Span.
|
||||||
|
type SpanEvent interface{}
|
||||||
|
|
||||||
|
// EventCreate is emitted when a Span is created.
|
||||||
|
type EventCreate struct{ OperationName string }
|
||||||
|
|
||||||
|
// EventTag is received when SetTag is called.
|
||||||
|
type EventTag struct {
|
||||||
|
Key string
|
||||||
|
Value interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// EventBaggage is received when SetBaggageItem is called.
|
||||||
|
type EventBaggage struct {
|
||||||
|
Key, Value string
|
||||||
|
}
|
||||||
|
|
||||||
|
// EventLogFields is received when LogFields or LogKV is called.
|
||||||
|
type EventLogFields opentracing.LogRecord
|
||||||
|
|
||||||
|
// EventLog is received when Log (or one of its derivatives) is called.
|
||||||
|
//
|
||||||
|
// DEPRECATED
|
||||||
|
type EventLog opentracing.LogData
|
||||||
|
|
||||||
|
// EventFinish is received when Finish is called.
|
||||||
|
type EventFinish RawSpan
|
||||||
|
|
||||||
|
func (s *spanImpl) onCreate(opName string) {
|
||||||
|
if s.event != nil {
|
||||||
|
s.event(EventCreate{OperationName: opName})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func (s *spanImpl) onTag(key string, value interface{}) {
|
||||||
|
if s.event != nil {
|
||||||
|
s.event(EventTag{Key: key, Value: value})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func (s *spanImpl) onLog(ld opentracing.LogData) {
|
||||||
|
if s.event != nil {
|
||||||
|
s.event(EventLog(ld))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func (s *spanImpl) onLogFields(lr opentracing.LogRecord) {
|
||||||
|
if s.event != nil {
|
||||||
|
s.event(EventLogFields(lr))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func (s *spanImpl) onBaggage(key, value string) {
|
||||||
|
if s.event != nil {
|
||||||
|
s.event(EventBaggage{Key: key, Value: value})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func (s *spanImpl) onFinish(sp RawSpan) {
|
||||||
|
if s.event != nil {
|
||||||
|
s.event(EventFinish(sp))
|
||||||
|
}
|
||||||
|
}
|
61
vendor/github.com/opentracing/basictracer-go/propagation.go
generated
vendored
Normal file
61
vendor/github.com/opentracing/basictracer-go/propagation.go
generated
vendored
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
package basictracer
|
||||||
|
|
||||||
|
import opentracing "github.com/opentracing/opentracing-go"
|
||||||
|
|
||||||
|
type accessorPropagator struct {
|
||||||
|
tracer *tracerImpl
|
||||||
|
}
|
||||||
|
|
||||||
|
// DelegatingCarrier is a flexible carrier interface which can be implemented
|
||||||
|
// by types which have a means of storing the trace metadata and already know
|
||||||
|
// how to serialize themselves (for example, protocol buffers).
|
||||||
|
type DelegatingCarrier interface {
|
||||||
|
SetState(traceID, spanID uint64, sampled bool)
|
||||||
|
State() (traceID, spanID uint64, sampled bool)
|
||||||
|
SetBaggageItem(key, value string)
|
||||||
|
GetBaggage(func(key, value string))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *accessorPropagator) Inject(
|
||||||
|
spanContext opentracing.SpanContext,
|
||||||
|
carrier interface{},
|
||||||
|
) error {
|
||||||
|
dc, ok := carrier.(DelegatingCarrier)
|
||||||
|
if !ok || dc == nil {
|
||||||
|
return opentracing.ErrInvalidCarrier
|
||||||
|
}
|
||||||
|
sc, ok := spanContext.(SpanContext)
|
||||||
|
if !ok {
|
||||||
|
return opentracing.ErrInvalidSpanContext
|
||||||
|
}
|
||||||
|
dc.SetState(sc.TraceID, sc.SpanID, sc.Sampled)
|
||||||
|
for k, v := range sc.Baggage {
|
||||||
|
dc.SetBaggageItem(k, v)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *accessorPropagator) Extract(
|
||||||
|
carrier interface{},
|
||||||
|
) (opentracing.SpanContext, error) {
|
||||||
|
dc, ok := carrier.(DelegatingCarrier)
|
||||||
|
if !ok || dc == nil {
|
||||||
|
return nil, opentracing.ErrInvalidCarrier
|
||||||
|
}
|
||||||
|
|
||||||
|
traceID, spanID, sampled := dc.State()
|
||||||
|
sc := SpanContext{
|
||||||
|
TraceID: traceID,
|
||||||
|
SpanID: spanID,
|
||||||
|
Sampled: sampled,
|
||||||
|
Baggage: nil,
|
||||||
|
}
|
||||||
|
dc.GetBaggage(func(k, v string) {
|
||||||
|
if sc.Baggage == nil {
|
||||||
|
sc.Baggage = map[string]string{}
|
||||||
|
}
|
||||||
|
sc.Baggage[k] = v
|
||||||
|
})
|
||||||
|
|
||||||
|
return sc, nil
|
||||||
|
}
|
180
vendor/github.com/opentracing/basictracer-go/propagation_ot.go
generated
vendored
Normal file
180
vendor/github.com/opentracing/basictracer-go/propagation_ot.go
generated
vendored
Normal file
|
@ -0,0 +1,180 @@
|
||||||
|
package basictracer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"io"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/gogo/protobuf/proto"
|
||||||
|
"github.com/opentracing/basictracer-go/wire"
|
||||||
|
opentracing "github.com/opentracing/opentracing-go"
|
||||||
|
)
|
||||||
|
|
||||||
|
type textMapPropagator struct {
|
||||||
|
tracer *tracerImpl
|
||||||
|
}
|
||||||
|
type binaryPropagator struct {
|
||||||
|
tracer *tracerImpl
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
prefixTracerState = "ot-tracer-"
|
||||||
|
prefixBaggage = "ot-baggage-"
|
||||||
|
|
||||||
|
tracerStateFieldCount = 3
|
||||||
|
fieldNameTraceID = prefixTracerState + "traceid"
|
||||||
|
fieldNameSpanID = prefixTracerState + "spanid"
|
||||||
|
fieldNameSampled = prefixTracerState + "sampled"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (p *textMapPropagator) Inject(
|
||||||
|
spanContext opentracing.SpanContext,
|
||||||
|
opaqueCarrier interface{},
|
||||||
|
) error {
|
||||||
|
sc, ok := spanContext.(SpanContext)
|
||||||
|
if !ok {
|
||||||
|
return opentracing.ErrInvalidSpanContext
|
||||||
|
}
|
||||||
|
carrier, ok := opaqueCarrier.(opentracing.TextMapWriter)
|
||||||
|
if !ok {
|
||||||
|
return opentracing.ErrInvalidCarrier
|
||||||
|
}
|
||||||
|
carrier.Set(fieldNameTraceID, strconv.FormatUint(sc.TraceID, 16))
|
||||||
|
carrier.Set(fieldNameSpanID, strconv.FormatUint(sc.SpanID, 16))
|
||||||
|
carrier.Set(fieldNameSampled, strconv.FormatBool(sc.Sampled))
|
||||||
|
|
||||||
|
for k, v := range sc.Baggage {
|
||||||
|
carrier.Set(prefixBaggage+k, v)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *textMapPropagator) Extract(
|
||||||
|
opaqueCarrier interface{},
|
||||||
|
) (opentracing.SpanContext, error) {
|
||||||
|
carrier, ok := opaqueCarrier.(opentracing.TextMapReader)
|
||||||
|
if !ok {
|
||||||
|
return nil, opentracing.ErrInvalidCarrier
|
||||||
|
}
|
||||||
|
requiredFieldCount := 0
|
||||||
|
var traceID, spanID uint64
|
||||||
|
var sampled bool
|
||||||
|
var err error
|
||||||
|
decodedBaggage := make(map[string]string)
|
||||||
|
err = carrier.ForeachKey(func(k, v string) error {
|
||||||
|
switch strings.ToLower(k) {
|
||||||
|
case fieldNameTraceID:
|
||||||
|
traceID, err = strconv.ParseUint(v, 16, 64)
|
||||||
|
if err != nil {
|
||||||
|
return opentracing.ErrSpanContextCorrupted
|
||||||
|
}
|
||||||
|
case fieldNameSpanID:
|
||||||
|
spanID, err = strconv.ParseUint(v, 16, 64)
|
||||||
|
if err != nil {
|
||||||
|
return opentracing.ErrSpanContextCorrupted
|
||||||
|
}
|
||||||
|
case fieldNameSampled:
|
||||||
|
sampled, err = strconv.ParseBool(v)
|
||||||
|
if err != nil {
|
||||||
|
return opentracing.ErrSpanContextCorrupted
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
lowercaseK := strings.ToLower(k)
|
||||||
|
if strings.HasPrefix(lowercaseK, prefixBaggage) {
|
||||||
|
decodedBaggage[strings.TrimPrefix(lowercaseK, prefixBaggage)] = v
|
||||||
|
}
|
||||||
|
// Balance off the requiredFieldCount++ just below...
|
||||||
|
requiredFieldCount--
|
||||||
|
}
|
||||||
|
requiredFieldCount++
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if requiredFieldCount < tracerStateFieldCount {
|
||||||
|
if requiredFieldCount == 0 {
|
||||||
|
return nil, opentracing.ErrSpanContextNotFound
|
||||||
|
}
|
||||||
|
return nil, opentracing.ErrSpanContextCorrupted
|
||||||
|
}
|
||||||
|
|
||||||
|
return SpanContext{
|
||||||
|
TraceID: traceID,
|
||||||
|
SpanID: spanID,
|
||||||
|
Sampled: sampled,
|
||||||
|
Baggage: decodedBaggage,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *binaryPropagator) Inject(
|
||||||
|
spanContext opentracing.SpanContext,
|
||||||
|
opaqueCarrier interface{},
|
||||||
|
) error {
|
||||||
|
sc, ok := spanContext.(SpanContext)
|
||||||
|
if !ok {
|
||||||
|
return opentracing.ErrInvalidSpanContext
|
||||||
|
}
|
||||||
|
carrier, ok := opaqueCarrier.(io.Writer)
|
||||||
|
if !ok {
|
||||||
|
return opentracing.ErrInvalidCarrier
|
||||||
|
}
|
||||||
|
|
||||||
|
state := wire.TracerState{}
|
||||||
|
state.TraceId = sc.TraceID
|
||||||
|
state.SpanId = sc.SpanID
|
||||||
|
state.Sampled = sc.Sampled
|
||||||
|
state.BaggageItems = sc.Baggage
|
||||||
|
|
||||||
|
b, err := proto.Marshal(&state)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write the length of the marshalled binary to the writer.
|
||||||
|
length := uint32(len(b))
|
||||||
|
if err := binary.Write(carrier, binary.BigEndian, &length); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = carrier.Write(b)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *binaryPropagator) Extract(
|
||||||
|
opaqueCarrier interface{},
|
||||||
|
) (opentracing.SpanContext, error) {
|
||||||
|
carrier, ok := opaqueCarrier.(io.Reader)
|
||||||
|
if !ok {
|
||||||
|
return nil, opentracing.ErrInvalidCarrier
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read the length of marshalled binary. io.ReadAll isn't that performant
|
||||||
|
// since it keeps resizing the underlying buffer as it encounters more bytes
|
||||||
|
// to read. By reading the length, we can allocate a fixed sized buf and read
|
||||||
|
// the exact amount of bytes into it.
|
||||||
|
var length uint32
|
||||||
|
if err := binary.Read(carrier, binary.BigEndian, &length); err != nil {
|
||||||
|
return nil, opentracing.ErrSpanContextCorrupted
|
||||||
|
}
|
||||||
|
buf := make([]byte, length)
|
||||||
|
if n, err := carrier.Read(buf); err != nil {
|
||||||
|
if n > 0 {
|
||||||
|
return nil, opentracing.ErrSpanContextCorrupted
|
||||||
|
}
|
||||||
|
return nil, opentracing.ErrSpanContextNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := wire.TracerState{}
|
||||||
|
if err := proto.Unmarshal(buf, &ctx); err != nil {
|
||||||
|
return nil, opentracing.ErrSpanContextCorrupted
|
||||||
|
}
|
||||||
|
|
||||||
|
return SpanContext{
|
||||||
|
TraceID: ctx.TraceId,
|
||||||
|
SpanID: ctx.SpanId,
|
||||||
|
Sampled: ctx.Sampled,
|
||||||
|
Baggage: ctx.BaggageItems,
|
||||||
|
}, nil
|
||||||
|
}
|
34
vendor/github.com/opentracing/basictracer-go/raw.go
generated
vendored
Normal file
34
vendor/github.com/opentracing/basictracer-go/raw.go
generated
vendored
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
package basictracer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
opentracing "github.com/opentracing/opentracing-go"
|
||||||
|
)
|
||||||
|
|
||||||
|
// RawSpan encapsulates all state associated with a (finished) Span.
|
||||||
|
type RawSpan struct {
|
||||||
|
// Those recording the RawSpan should also record the contents of its
|
||||||
|
// SpanContext.
|
||||||
|
Context SpanContext
|
||||||
|
|
||||||
|
// The SpanID of this SpanContext's first intra-trace reference (i.e.,
|
||||||
|
// "parent"), or 0 if there is no parent.
|
||||||
|
ParentSpanID uint64
|
||||||
|
|
||||||
|
// The name of the "operation" this span is an instance of. (Called a "span
|
||||||
|
// name" in some implementations)
|
||||||
|
Operation string
|
||||||
|
|
||||||
|
// We store <start, duration> rather than <start, end> so that only
|
||||||
|
// one of the timestamps has global clock uncertainty issues.
|
||||||
|
Start time.Time
|
||||||
|
Duration time.Duration
|
||||||
|
|
||||||
|
// Essentially an extension mechanism. Can be used for many purposes,
|
||||||
|
// not to be enumerated here.
|
||||||
|
Tags opentracing.Tags
|
||||||
|
|
||||||
|
// The span's "microlog".
|
||||||
|
Logs []opentracing.LogRecord
|
||||||
|
}
|
60
vendor/github.com/opentracing/basictracer-go/recorder.go
generated
vendored
Normal file
60
vendor/github.com/opentracing/basictracer-go/recorder.go
generated
vendored
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
package basictracer
|
||||||
|
|
||||||
|
import "sync"
|
||||||
|
|
||||||
|
// A SpanRecorder handles all of the `RawSpan` data generated via an
|
||||||
|
// associated `Tracer` (see `NewStandardTracer`) instance. It also names
|
||||||
|
// the containing process and provides access to a straightforward tag map.
|
||||||
|
type SpanRecorder interface {
|
||||||
|
// Implementations must determine whether and where to store `span`.
|
||||||
|
RecordSpan(span RawSpan)
|
||||||
|
}
|
||||||
|
|
||||||
|
// InMemorySpanRecorder is a simple thread-safe implementation of
|
||||||
|
// SpanRecorder that stores all reported spans in memory, accessible
|
||||||
|
// via reporter.GetSpans(). It is primarily intended for testing purposes.
|
||||||
|
type InMemorySpanRecorder struct {
|
||||||
|
sync.RWMutex
|
||||||
|
spans []RawSpan
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewInMemoryRecorder creates new InMemorySpanRecorder
|
||||||
|
func NewInMemoryRecorder() *InMemorySpanRecorder {
|
||||||
|
return new(InMemorySpanRecorder)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RecordSpan implements the respective method of SpanRecorder.
|
||||||
|
func (r *InMemorySpanRecorder) RecordSpan(span RawSpan) {
|
||||||
|
r.Lock()
|
||||||
|
defer r.Unlock()
|
||||||
|
r.spans = append(r.spans, span)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetSpans returns a copy of the array of spans accumulated so far.
|
||||||
|
func (r *InMemorySpanRecorder) GetSpans() []RawSpan {
|
||||||
|
r.RLock()
|
||||||
|
defer r.RUnlock()
|
||||||
|
spans := make([]RawSpan, len(r.spans))
|
||||||
|
copy(spans, r.spans)
|
||||||
|
return spans
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetSampledSpans returns a slice of spans accumulated so far which were sampled.
|
||||||
|
func (r *InMemorySpanRecorder) GetSampledSpans() []RawSpan {
|
||||||
|
r.RLock()
|
||||||
|
defer r.RUnlock()
|
||||||
|
spans := make([]RawSpan, 0, len(r.spans))
|
||||||
|
for _, span := range r.spans {
|
||||||
|
if span.Context.Sampled {
|
||||||
|
spans = append(spans, span)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return spans
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset clears the internal array of spans.
|
||||||
|
func (r *InMemorySpanRecorder) Reset() {
|
||||||
|
r.Lock()
|
||||||
|
defer r.Unlock()
|
||||||
|
r.spans = nil
|
||||||
|
}
|
274
vendor/github.com/opentracing/basictracer-go/span.go
generated
vendored
Normal file
274
vendor/github.com/opentracing/basictracer-go/span.go
generated
vendored
Normal file
|
@ -0,0 +1,274 @@
|
||||||
|
package basictracer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
opentracing "github.com/opentracing/opentracing-go"
|
||||||
|
"github.com/opentracing/opentracing-go/ext"
|
||||||
|
"github.com/opentracing/opentracing-go/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Span provides access to the essential details of the span, for use
|
||||||
|
// by basictracer consumers. These methods may only be called prior
|
||||||
|
// to (*opentracing.Span).Finish().
|
||||||
|
type Span interface {
|
||||||
|
opentracing.Span
|
||||||
|
|
||||||
|
// Operation names the work done by this span instance
|
||||||
|
Operation() string
|
||||||
|
|
||||||
|
// Start indicates when the span began
|
||||||
|
Start() time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implements the `Span` interface. Created via tracerImpl (see
|
||||||
|
// `basictracer.New()`).
|
||||||
|
type spanImpl struct {
|
||||||
|
tracer *tracerImpl
|
||||||
|
event func(SpanEvent)
|
||||||
|
sync.Mutex // protects the fields below
|
||||||
|
raw RawSpan
|
||||||
|
// The number of logs dropped because of MaxLogsPerSpan.
|
||||||
|
numDroppedLogs int
|
||||||
|
}
|
||||||
|
|
||||||
|
var spanPool = &sync.Pool{New: func() interface{} {
|
||||||
|
return &spanImpl{}
|
||||||
|
}}
|
||||||
|
|
||||||
|
func (s *spanImpl) reset() {
|
||||||
|
s.tracer, s.event = nil, nil
|
||||||
|
// Note: Would like to do the following, but then the consumer of RawSpan
|
||||||
|
// (the recorder) needs to make sure that they're not holding on to the
|
||||||
|
// baggage or logs when they return (i.e. they need to copy if they care):
|
||||||
|
//
|
||||||
|
// logs, baggage := s.raw.Logs[:0], s.raw.Baggage
|
||||||
|
// for k := range baggage {
|
||||||
|
// delete(baggage, k)
|
||||||
|
// }
|
||||||
|
// s.raw.Logs, s.raw.Baggage = logs, baggage
|
||||||
|
//
|
||||||
|
// That's likely too much to ask for. But there is some magic we should
|
||||||
|
// be able to do with `runtime.SetFinalizer` to reclaim that memory into
|
||||||
|
// a buffer pool when GC considers them unreachable, which should ease
|
||||||
|
// some of the load. Hard to say how quickly that would be in practice
|
||||||
|
// though.
|
||||||
|
s.raw = RawSpan{
|
||||||
|
Context: SpanContext{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *spanImpl) SetOperationName(operationName string) opentracing.Span {
|
||||||
|
s.Lock()
|
||||||
|
defer s.Unlock()
|
||||||
|
s.raw.Operation = operationName
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *spanImpl) trim() bool {
|
||||||
|
return !s.raw.Context.Sampled && s.tracer.options.TrimUnsampledSpans
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *spanImpl) SetTag(key string, value interface{}) opentracing.Span {
|
||||||
|
defer s.onTag(key, value)
|
||||||
|
s.Lock()
|
||||||
|
defer s.Unlock()
|
||||||
|
if key == string(ext.SamplingPriority) {
|
||||||
|
if v, ok := value.(uint16); ok {
|
||||||
|
s.raw.Context.Sampled = v != 0
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if s.trim() {
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.raw.Tags == nil {
|
||||||
|
s.raw.Tags = opentracing.Tags{}
|
||||||
|
}
|
||||||
|
s.raw.Tags[key] = value
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *spanImpl) LogKV(keyValues ...interface{}) {
|
||||||
|
fields, err := log.InterleavedKVToFields(keyValues...)
|
||||||
|
if err != nil {
|
||||||
|
s.LogFields(log.Error(err), log.String("function", "LogKV"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
s.LogFields(fields...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *spanImpl) appendLog(lr opentracing.LogRecord) {
|
||||||
|
maxLogs := s.tracer.options.MaxLogsPerSpan
|
||||||
|
if maxLogs == 0 || len(s.raw.Logs) < maxLogs {
|
||||||
|
s.raw.Logs = append(s.raw.Logs, lr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// We have too many logs. We don't touch the first numOld logs; we treat the
|
||||||
|
// rest as a circular buffer and overwrite the oldest log among those.
|
||||||
|
numOld := (maxLogs - 1) / 2
|
||||||
|
numNew := maxLogs - numOld
|
||||||
|
s.raw.Logs[numOld+s.numDroppedLogs%numNew] = lr
|
||||||
|
s.numDroppedLogs++
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *spanImpl) LogFields(fields ...log.Field) {
|
||||||
|
lr := opentracing.LogRecord{
|
||||||
|
Fields: fields,
|
||||||
|
}
|
||||||
|
defer s.onLogFields(lr)
|
||||||
|
s.Lock()
|
||||||
|
defer s.Unlock()
|
||||||
|
if s.trim() || s.tracer.options.DropAllLogs {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if lr.Timestamp.IsZero() {
|
||||||
|
lr.Timestamp = time.Now()
|
||||||
|
}
|
||||||
|
s.appendLog(lr)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *spanImpl) LogEvent(event string) {
|
||||||
|
s.Log(opentracing.LogData{
|
||||||
|
Event: event,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *spanImpl) LogEventWithPayload(event string, payload interface{}) {
|
||||||
|
s.Log(opentracing.LogData{
|
||||||
|
Event: event,
|
||||||
|
Payload: payload,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *spanImpl) Log(ld opentracing.LogData) {
|
||||||
|
defer s.onLog(ld)
|
||||||
|
s.Lock()
|
||||||
|
defer s.Unlock()
|
||||||
|
if s.trim() || s.tracer.options.DropAllLogs {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if ld.Timestamp.IsZero() {
|
||||||
|
ld.Timestamp = time.Now()
|
||||||
|
}
|
||||||
|
|
||||||
|
s.appendLog(ld.ToLogRecord())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *spanImpl) Finish() {
|
||||||
|
s.FinishWithOptions(opentracing.FinishOptions{})
|
||||||
|
}
|
||||||
|
|
||||||
|
// rotateLogBuffer rotates the records in the buffer: records 0 to pos-1 move at
|
||||||
|
// the end (i.e. pos circular left shifts).
|
||||||
|
func rotateLogBuffer(buf []opentracing.LogRecord, pos int) {
|
||||||
|
// This algorithm is described in:
|
||||||
|
// http://www.cplusplus.com/reference/algorithm/rotate
|
||||||
|
for first, middle, next := 0, pos, pos; first != middle; {
|
||||||
|
buf[first], buf[next] = buf[next], buf[first]
|
||||||
|
first++
|
||||||
|
next++
|
||||||
|
if next == len(buf) {
|
||||||
|
next = middle
|
||||||
|
} else if first == middle {
|
||||||
|
middle = next
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *spanImpl) FinishWithOptions(opts opentracing.FinishOptions) {
|
||||||
|
finishTime := opts.FinishTime
|
||||||
|
if finishTime.IsZero() {
|
||||||
|
finishTime = time.Now()
|
||||||
|
}
|
||||||
|
duration := finishTime.Sub(s.raw.Start)
|
||||||
|
|
||||||
|
s.Lock()
|
||||||
|
defer s.Unlock()
|
||||||
|
|
||||||
|
for _, lr := range opts.LogRecords {
|
||||||
|
s.appendLog(lr)
|
||||||
|
}
|
||||||
|
for _, ld := range opts.BulkLogData {
|
||||||
|
s.appendLog(ld.ToLogRecord())
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.numDroppedLogs > 0 {
|
||||||
|
// We dropped some log events, which means that we used part of Logs as a
|
||||||
|
// circular buffer (see appendLog). De-circularize it.
|
||||||
|
numOld := (len(s.raw.Logs) - 1) / 2
|
||||||
|
numNew := len(s.raw.Logs) - numOld
|
||||||
|
rotateLogBuffer(s.raw.Logs[numOld:], s.numDroppedLogs%numNew)
|
||||||
|
|
||||||
|
// Replace the log in the middle (the oldest "new" log) with information
|
||||||
|
// about the dropped logs. This means that we are effectively dropping one
|
||||||
|
// more "new" log.
|
||||||
|
numDropped := s.numDroppedLogs + 1
|
||||||
|
s.raw.Logs[numOld] = opentracing.LogRecord{
|
||||||
|
// Keep the timestamp of the last dropped event.
|
||||||
|
Timestamp: s.raw.Logs[numOld].Timestamp,
|
||||||
|
Fields: []log.Field{
|
||||||
|
log.String("event", "dropped Span logs"),
|
||||||
|
log.Int("dropped_log_count", numDropped),
|
||||||
|
log.String("component", "basictracer"),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
s.raw.Duration = duration
|
||||||
|
|
||||||
|
s.onFinish(s.raw)
|
||||||
|
s.tracer.options.Recorder.RecordSpan(s.raw)
|
||||||
|
|
||||||
|
// Last chance to get options before the span is possibly reset.
|
||||||
|
poolEnabled := s.tracer.options.EnableSpanPool
|
||||||
|
if s.tracer.options.DebugAssertUseAfterFinish {
|
||||||
|
// This makes it much more likely to catch a panic on any subsequent
|
||||||
|
// operation since s.tracer is accessed on every call to `Lock`.
|
||||||
|
// We don't call `reset()` here to preserve the logs in the Span
|
||||||
|
// which are printed when the assertion triggers.
|
||||||
|
s.tracer = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if poolEnabled {
|
||||||
|
spanPool.Put(s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *spanImpl) Tracer() opentracing.Tracer {
|
||||||
|
return s.tracer
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *spanImpl) Context() opentracing.SpanContext {
|
||||||
|
return s.raw.Context
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *spanImpl) SetBaggageItem(key, val string) opentracing.Span {
|
||||||
|
s.onBaggage(key, val)
|
||||||
|
if s.trim() {
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
s.Lock()
|
||||||
|
defer s.Unlock()
|
||||||
|
s.raw.Context = s.raw.Context.WithBaggageItem(key, val)
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *spanImpl) BaggageItem(key string) string {
|
||||||
|
s.Lock()
|
||||||
|
defer s.Unlock()
|
||||||
|
return s.raw.Context.Baggage[key]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *spanImpl) Operation() string {
|
||||||
|
return s.raw.Operation
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *spanImpl) Start() time.Time {
|
||||||
|
return s.raw.Start
|
||||||
|
}
|
262
vendor/github.com/opentracing/basictracer-go/tracer.go
generated
vendored
Normal file
262
vendor/github.com/opentracing/basictracer-go/tracer.go
generated
vendored
Normal file
|
@ -0,0 +1,262 @@
|
||||||
|
package basictracer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
opentracing "github.com/opentracing/opentracing-go"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Tracer extends the opentracing.Tracer interface with methods to
|
||||||
|
// probe implementation state, for use by basictracer consumers.
|
||||||
|
type Tracer interface {
|
||||||
|
opentracing.Tracer
|
||||||
|
|
||||||
|
// Options gets the Options used in New() or NewWithOptions().
|
||||||
|
Options() Options
|
||||||
|
}
|
||||||
|
|
||||||
|
// Options allows creating a customized Tracer via NewWithOptions. The object
|
||||||
|
// must not be updated when there is an active tracer using it.
|
||||||
|
type Options struct {
|
||||||
|
// ShouldSample is a function which is called when creating a new Span and
|
||||||
|
// determines whether that Span is sampled. The randomized TraceID is supplied
|
||||||
|
// to allow deterministic sampling decisions to be made across different nodes.
|
||||||
|
// For example,
|
||||||
|
//
|
||||||
|
// func(traceID uint64) { return traceID % 64 == 0 }
|
||||||
|
//
|
||||||
|
// samples every 64th trace on average.
|
||||||
|
ShouldSample func(traceID uint64) bool
|
||||||
|
// TrimUnsampledSpans turns potentially expensive operations on unsampled
|
||||||
|
// Spans into no-ops. More precisely, tags and log events are silently
|
||||||
|
// discarded. If NewSpanEventListener is set, the callbacks will still fire.
|
||||||
|
TrimUnsampledSpans bool
|
||||||
|
// Recorder receives Spans which have been finished.
|
||||||
|
Recorder SpanRecorder
|
||||||
|
// NewSpanEventListener can be used to enhance the tracer by effectively
|
||||||
|
// attaching external code to trace events. See NetTraceIntegrator for a
|
||||||
|
// practical example, and event.go for the list of possible events.
|
||||||
|
NewSpanEventListener func() func(SpanEvent)
|
||||||
|
// DropAllLogs turns log events on all Spans into no-ops.
|
||||||
|
// If NewSpanEventListener is set, the callbacks will still fire.
|
||||||
|
DropAllLogs bool
|
||||||
|
// MaxLogsPerSpan limits the number of Logs in a span (if set to a nonzero
|
||||||
|
// value). If a span has more logs than this value, logs are dropped as
|
||||||
|
// necessary (and replaced with a log describing how many were dropped).
|
||||||
|
//
|
||||||
|
// About half of the MaxLogPerSpan logs kept are the oldest logs, and about
|
||||||
|
// half are the newest logs.
|
||||||
|
//
|
||||||
|
// If NewSpanEventListener is set, the callbacks will still fire for all log
|
||||||
|
// events. This value is ignored if DropAllLogs is true.
|
||||||
|
MaxLogsPerSpan int
|
||||||
|
// DebugAssertSingleGoroutine internally records the ID of the goroutine
|
||||||
|
// creating each Span and verifies that no operation is carried out on
|
||||||
|
// it on a different goroutine.
|
||||||
|
// Provided strictly for development purposes.
|
||||||
|
// Passing Spans between goroutine without proper synchronization often
|
||||||
|
// results in use-after-Finish() errors. For a simple example, consider the
|
||||||
|
// following pseudocode:
|
||||||
|
//
|
||||||
|
// func (s *Server) Handle(req http.Request) error {
|
||||||
|
// sp := s.StartSpan("server")
|
||||||
|
// defer sp.Finish()
|
||||||
|
// wait := s.queueProcessing(opentracing.ContextWithSpan(context.Background(), sp), req)
|
||||||
|
// select {
|
||||||
|
// case resp := <-wait:
|
||||||
|
// return resp.Error
|
||||||
|
// case <-time.After(10*time.Second):
|
||||||
|
// sp.LogEvent("timed out waiting for processing")
|
||||||
|
// return ErrTimedOut
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// This looks reasonable at first, but a request which spends more than ten
|
||||||
|
// seconds in the queue is abandoned by the main goroutine and its trace
|
||||||
|
// finished, leading to use-after-finish when the request is finally
|
||||||
|
// processed. Note also that even joining on to a finished Span via
|
||||||
|
// StartSpanWithOptions constitutes an illegal operation.
|
||||||
|
//
|
||||||
|
// Code bases which do not require (or decide they do not want) Spans to
|
||||||
|
// be passed across goroutine boundaries can run with this flag enabled in
|
||||||
|
// tests to increase their chances of spotting wrong-doers.
|
||||||
|
DebugAssertSingleGoroutine bool
|
||||||
|
// DebugAssertUseAfterFinish is provided strictly for development purposes.
|
||||||
|
// When set, it attempts to exacerbate issues emanating from use of Spans
|
||||||
|
// after calling Finish by running additional assertions.
|
||||||
|
DebugAssertUseAfterFinish bool
|
||||||
|
// EnableSpanPool enables the use of a pool, so that the tracer reuses spans
|
||||||
|
// after Finish has been called on it. Adds a slight performance gain as it
|
||||||
|
// reduces allocations. However, if you have any use-after-finish race
|
||||||
|
// conditions the code may panic.
|
||||||
|
EnableSpanPool bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// DefaultOptions returns an Options object with a 1 in 64 sampling rate and
|
||||||
|
// all options disabled. A Recorder needs to be set manually before using the
|
||||||
|
// returned object with a Tracer.
|
||||||
|
func DefaultOptions() Options {
|
||||||
|
return Options{
|
||||||
|
ShouldSample: func(traceID uint64) bool { return traceID%64 == 0 },
|
||||||
|
MaxLogsPerSpan: 100,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewWithOptions creates a customized Tracer.
|
||||||
|
func NewWithOptions(opts Options) opentracing.Tracer {
|
||||||
|
rval := &tracerImpl{options: opts}
|
||||||
|
rval.textPropagator = &textMapPropagator{rval}
|
||||||
|
rval.binaryPropagator = &binaryPropagator{rval}
|
||||||
|
rval.accessorPropagator = &accessorPropagator{rval}
|
||||||
|
return rval
|
||||||
|
}
|
||||||
|
|
||||||
|
// New creates and returns a standard Tracer which defers completed Spans to
|
||||||
|
// `recorder`.
|
||||||
|
// Spans created by this Tracer support the ext.SamplingPriority tag: Setting
|
||||||
|
// ext.SamplingPriority causes the Span to be Sampled from that point on.
|
||||||
|
func New(recorder SpanRecorder) opentracing.Tracer {
|
||||||
|
opts := DefaultOptions()
|
||||||
|
opts.Recorder = recorder
|
||||||
|
return NewWithOptions(opts)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implements the `Tracer` interface.
|
||||||
|
type tracerImpl struct {
|
||||||
|
options Options
|
||||||
|
textPropagator *textMapPropagator
|
||||||
|
binaryPropagator *binaryPropagator
|
||||||
|
accessorPropagator *accessorPropagator
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tracerImpl) StartSpan(
|
||||||
|
operationName string,
|
||||||
|
opts ...opentracing.StartSpanOption,
|
||||||
|
) opentracing.Span {
|
||||||
|
sso := opentracing.StartSpanOptions{}
|
||||||
|
for _, o := range opts {
|
||||||
|
o.Apply(&sso)
|
||||||
|
}
|
||||||
|
return t.StartSpanWithOptions(operationName, sso)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tracerImpl) getSpan() *spanImpl {
|
||||||
|
if t.options.EnableSpanPool {
|
||||||
|
sp := spanPool.Get().(*spanImpl)
|
||||||
|
sp.reset()
|
||||||
|
return sp
|
||||||
|
}
|
||||||
|
return &spanImpl{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tracerImpl) StartSpanWithOptions(
|
||||||
|
operationName string,
|
||||||
|
opts opentracing.StartSpanOptions,
|
||||||
|
) opentracing.Span {
|
||||||
|
// Start time.
|
||||||
|
startTime := opts.StartTime
|
||||||
|
if startTime.IsZero() {
|
||||||
|
startTime = time.Now()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tags.
|
||||||
|
tags := opts.Tags
|
||||||
|
|
||||||
|
// Build the new span. This is the only allocation: We'll return this as
|
||||||
|
// an opentracing.Span.
|
||||||
|
sp := t.getSpan()
|
||||||
|
// Look for a parent in the list of References.
|
||||||
|
//
|
||||||
|
// TODO: would be nice if basictracer did something with all
|
||||||
|
// References, not just the first one.
|
||||||
|
ReferencesLoop:
|
||||||
|
for _, ref := range opts.References {
|
||||||
|
switch ref.Type {
|
||||||
|
case opentracing.ChildOfRef,
|
||||||
|
opentracing.FollowsFromRef:
|
||||||
|
|
||||||
|
refCtx := ref.ReferencedContext.(SpanContext)
|
||||||
|
sp.raw.Context.TraceID = refCtx.TraceID
|
||||||
|
sp.raw.Context.SpanID = randomID()
|
||||||
|
sp.raw.Context.Sampled = refCtx.Sampled
|
||||||
|
sp.raw.ParentSpanID = refCtx.SpanID
|
||||||
|
|
||||||
|
if l := len(refCtx.Baggage); l > 0 {
|
||||||
|
sp.raw.Context.Baggage = make(map[string]string, l)
|
||||||
|
for k, v := range refCtx.Baggage {
|
||||||
|
sp.raw.Context.Baggage[k] = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break ReferencesLoop
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if sp.raw.Context.TraceID == 0 {
|
||||||
|
// No parent Span found; allocate new trace and span ids and determine
|
||||||
|
// the Sampled status.
|
||||||
|
sp.raw.Context.TraceID, sp.raw.Context.SpanID = randomID2()
|
||||||
|
sp.raw.Context.Sampled = t.options.ShouldSample(sp.raw.Context.TraceID)
|
||||||
|
}
|
||||||
|
|
||||||
|
return t.startSpanInternal(
|
||||||
|
sp,
|
||||||
|
operationName,
|
||||||
|
startTime,
|
||||||
|
tags,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tracerImpl) startSpanInternal(
|
||||||
|
sp *spanImpl,
|
||||||
|
operationName string,
|
||||||
|
startTime time.Time,
|
||||||
|
tags opentracing.Tags,
|
||||||
|
) opentracing.Span {
|
||||||
|
sp.tracer = t
|
||||||
|
if t.options.NewSpanEventListener != nil {
|
||||||
|
sp.event = t.options.NewSpanEventListener()
|
||||||
|
}
|
||||||
|
sp.raw.Operation = operationName
|
||||||
|
sp.raw.Start = startTime
|
||||||
|
sp.raw.Duration = -1
|
||||||
|
sp.raw.Tags = tags
|
||||||
|
if t.options.DebugAssertSingleGoroutine {
|
||||||
|
sp.SetTag(debugGoroutineIDTag, curGoroutineID())
|
||||||
|
}
|
||||||
|
defer sp.onCreate(operationName)
|
||||||
|
return sp
|
||||||
|
}
|
||||||
|
|
||||||
|
type delegatorType struct{}
|
||||||
|
|
||||||
|
// Delegator is the format to use for DelegatingCarrier.
|
||||||
|
var Delegator delegatorType
|
||||||
|
|
||||||
|
func (t *tracerImpl) Inject(sc opentracing.SpanContext, format interface{}, carrier interface{}) error {
|
||||||
|
switch format {
|
||||||
|
case opentracing.TextMap, opentracing.HTTPHeaders:
|
||||||
|
return t.textPropagator.Inject(sc, carrier)
|
||||||
|
case opentracing.Binary:
|
||||||
|
return t.binaryPropagator.Inject(sc, carrier)
|
||||||
|
}
|
||||||
|
if _, ok := format.(delegatorType); ok {
|
||||||
|
return t.accessorPropagator.Inject(sc, carrier)
|
||||||
|
}
|
||||||
|
return opentracing.ErrUnsupportedFormat
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tracerImpl) Extract(format interface{}, carrier interface{}) (opentracing.SpanContext, error) {
|
||||||
|
switch format {
|
||||||
|
case opentracing.TextMap, opentracing.HTTPHeaders:
|
||||||
|
return t.textPropagator.Extract(carrier)
|
||||||
|
case opentracing.Binary:
|
||||||
|
return t.binaryPropagator.Extract(carrier)
|
||||||
|
}
|
||||||
|
if _, ok := format.(delegatorType); ok {
|
||||||
|
return t.accessorPropagator.Extract(carrier)
|
||||||
|
}
|
||||||
|
return nil, opentracing.ErrUnsupportedFormat
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tracerImpl) Options() Options {
|
||||||
|
return t.options
|
||||||
|
}
|
25
vendor/github.com/opentracing/basictracer-go/util.go
generated
vendored
Normal file
25
vendor/github.com/opentracing/basictracer-go/util.go
generated
vendored
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
package basictracer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math/rand"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
seededIDGen = rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||||
|
// The golang rand generators are *not* intrinsically thread-safe.
|
||||||
|
seededIDLock sync.Mutex
|
||||||
|
)
|
||||||
|
|
||||||
|
func randomID() uint64 {
|
||||||
|
seededIDLock.Lock()
|
||||||
|
defer seededIDLock.Unlock()
|
||||||
|
return uint64(seededIDGen.Int63())
|
||||||
|
}
|
||||||
|
|
||||||
|
func randomID2() (uint64, uint64) {
|
||||||
|
seededIDLock.Lock()
|
||||||
|
defer seededIDLock.Unlock()
|
||||||
|
return uint64(seededIDGen.Int63()), uint64(seededIDGen.Int63())
|
||||||
|
}
|
40
vendor/github.com/opentracing/basictracer-go/wire/carrier.go
generated
vendored
Normal file
40
vendor/github.com/opentracing/basictracer-go/wire/carrier.go
generated
vendored
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
package wire
|
||||||
|
|
||||||
|
// ProtobufCarrier is a DelegatingCarrier that uses protocol buffers as the
|
||||||
|
// the underlying datastructure. The reason for implementing DelagatingCarrier
|
||||||
|
// is to allow for end users to serialize the underlying protocol buffers using
|
||||||
|
// jsonpb or any other serialization forms they want.
|
||||||
|
type ProtobufCarrier TracerState
|
||||||
|
|
||||||
|
// SetState set's the tracer state.
|
||||||
|
func (p *ProtobufCarrier) SetState(traceID, spanID uint64, sampled bool) {
|
||||||
|
p.TraceId = traceID
|
||||||
|
p.SpanId = spanID
|
||||||
|
p.Sampled = sampled
|
||||||
|
}
|
||||||
|
|
||||||
|
// State returns the tracer state.
|
||||||
|
func (p *ProtobufCarrier) State() (traceID, spanID uint64, sampled bool) {
|
||||||
|
traceID = p.TraceId
|
||||||
|
spanID = p.SpanId
|
||||||
|
sampled = p.Sampled
|
||||||
|
return traceID, spanID, sampled
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetBaggageItem sets a baggage item.
|
||||||
|
func (p *ProtobufCarrier) SetBaggageItem(key, value string) {
|
||||||
|
if p.BaggageItems == nil {
|
||||||
|
p.BaggageItems = map[string]string{key: value}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
p.BaggageItems[key] = value
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetBaggage iterates over each baggage item and executes the callback with
|
||||||
|
// the key:value pair.
|
||||||
|
func (p *ProtobufCarrier) GetBaggage(f func(k, v string)) {
|
||||||
|
for k, v := range p.BaggageItems {
|
||||||
|
f(k, v)
|
||||||
|
}
|
||||||
|
}
|
6
vendor/github.com/opentracing/basictracer-go/wire/gen.go
generated
vendored
Normal file
6
vendor/github.com/opentracing/basictracer-go/wire/gen.go
generated
vendored
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
package wire
|
||||||
|
|
||||||
|
//go:generate protoc --gogofaster_out=$GOPATH/src/github.com/opentracing/basictracer-go/wire wire.proto
|
||||||
|
|
||||||
|
// Run `go get github.com/gogo/protobuf/protoc-gen-gogofaster` to install the
|
||||||
|
// gogofaster generator binary.
|
508
vendor/github.com/opentracing/basictracer-go/wire/wire.pb.go
generated
vendored
Normal file
508
vendor/github.com/opentracing/basictracer-go/wire/wire.pb.go
generated
vendored
Normal file
|
@ -0,0 +1,508 @@
|
||||||
|
// Code generated by protoc-gen-gogo.
|
||||||
|
// source: wire.proto
|
||||||
|
// DO NOT EDIT!
|
||||||
|
|
||||||
|
/*
|
||||||
|
Package wire is a generated protocol buffer package.
|
||||||
|
|
||||||
|
It is generated from these files:
|
||||||
|
wire.proto
|
||||||
|
|
||||||
|
It has these top-level messages:
|
||||||
|
TracerState
|
||||||
|
*/
|
||||||
|
package wire
|
||||||
|
|
||||||
|
import proto "github.com/gogo/protobuf/proto"
|
||||||
|
import fmt "fmt"
|
||||||
|
import math "math"
|
||||||
|
|
||||||
|
import io "io"
|
||||||
|
|
||||||
|
// Reference imports to suppress errors if they are not otherwise used.
|
||||||
|
var _ = proto.Marshal
|
||||||
|
var _ = fmt.Errorf
|
||||||
|
var _ = math.Inf
|
||||||
|
|
||||||
|
// This is a compile-time assertion to ensure that this generated file
|
||||||
|
// is compatible with the proto package it is being compiled against.
|
||||||
|
const _ = proto.GoGoProtoPackageIsVersion1
|
||||||
|
|
||||||
|
type TracerState struct {
|
||||||
|
TraceId uint64 `protobuf:"fixed64,1,opt,name=trace_id,json=traceId,proto3" json:"trace_id,omitempty"`
|
||||||
|
SpanId uint64 `protobuf:"fixed64,2,opt,name=span_id,json=spanId,proto3" json:"span_id,omitempty"`
|
||||||
|
Sampled bool `protobuf:"varint,3,opt,name=sampled,proto3" json:"sampled,omitempty"`
|
||||||
|
BaggageItems map[string]string `protobuf:"bytes,4,rep,name=baggage_items,json=baggageItems" json:"baggage_items,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *TracerState) Reset() { *m = TracerState{} }
|
||||||
|
func (m *TracerState) String() string { return proto.CompactTextString(m) }
|
||||||
|
func (*TracerState) ProtoMessage() {}
|
||||||
|
func (*TracerState) Descriptor() ([]byte, []int) { return fileDescriptorWire, []int{0} }
|
||||||
|
|
||||||
|
func (m *TracerState) GetBaggageItems() map[string]string {
|
||||||
|
if m != nil {
|
||||||
|
return m.BaggageItems
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
proto.RegisterType((*TracerState)(nil), "basictracer_go.wire.TracerState")
|
||||||
|
}
|
||||||
|
func (m *TracerState) Marshal() (data []byte, err error) {
|
||||||
|
size := m.Size()
|
||||||
|
data = make([]byte, size)
|
||||||
|
n, err := m.MarshalTo(data)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return data[:n], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *TracerState) MarshalTo(data []byte) (int, error) {
|
||||||
|
var i int
|
||||||
|
_ = i
|
||||||
|
var l int
|
||||||
|
_ = l
|
||||||
|
if m.TraceId != 0 {
|
||||||
|
data[i] = 0x9
|
||||||
|
i++
|
||||||
|
i = encodeFixed64Wire(data, i, uint64(m.TraceId))
|
||||||
|
}
|
||||||
|
if m.SpanId != 0 {
|
||||||
|
data[i] = 0x11
|
||||||
|
i++
|
||||||
|
i = encodeFixed64Wire(data, i, uint64(m.SpanId))
|
||||||
|
}
|
||||||
|
if m.Sampled {
|
||||||
|
data[i] = 0x18
|
||||||
|
i++
|
||||||
|
if m.Sampled {
|
||||||
|
data[i] = 1
|
||||||
|
} else {
|
||||||
|
data[i] = 0
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
if len(m.BaggageItems) > 0 {
|
||||||
|
for k, _ := range m.BaggageItems {
|
||||||
|
data[i] = 0x22
|
||||||
|
i++
|
||||||
|
v := m.BaggageItems[k]
|
||||||
|
mapSize := 1 + len(k) + sovWire(uint64(len(k))) + 1 + len(v) + sovWire(uint64(len(v)))
|
||||||
|
i = encodeVarintWire(data, i, uint64(mapSize))
|
||||||
|
data[i] = 0xa
|
||||||
|
i++
|
||||||
|
i = encodeVarintWire(data, i, uint64(len(k)))
|
||||||
|
i += copy(data[i:], k)
|
||||||
|
data[i] = 0x12
|
||||||
|
i++
|
||||||
|
i = encodeVarintWire(data, i, uint64(len(v)))
|
||||||
|
i += copy(data[i:], v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return i, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func encodeFixed64Wire(data []byte, offset int, v uint64) int {
|
||||||
|
data[offset] = uint8(v)
|
||||||
|
data[offset+1] = uint8(v >> 8)
|
||||||
|
data[offset+2] = uint8(v >> 16)
|
||||||
|
data[offset+3] = uint8(v >> 24)
|
||||||
|
data[offset+4] = uint8(v >> 32)
|
||||||
|
data[offset+5] = uint8(v >> 40)
|
||||||
|
data[offset+6] = uint8(v >> 48)
|
||||||
|
data[offset+7] = uint8(v >> 56)
|
||||||
|
return offset + 8
|
||||||
|
}
|
||||||
|
func encodeFixed32Wire(data []byte, offset int, v uint32) int {
|
||||||
|
data[offset] = uint8(v)
|
||||||
|
data[offset+1] = uint8(v >> 8)
|
||||||
|
data[offset+2] = uint8(v >> 16)
|
||||||
|
data[offset+3] = uint8(v >> 24)
|
||||||
|
return offset + 4
|
||||||
|
}
|
||||||
|
func encodeVarintWire(data []byte, offset int, v uint64) int {
|
||||||
|
for v >= 1<<7 {
|
||||||
|
data[offset] = uint8(v&0x7f | 0x80)
|
||||||
|
v >>= 7
|
||||||
|
offset++
|
||||||
|
}
|
||||||
|
data[offset] = uint8(v)
|
||||||
|
return offset + 1
|
||||||
|
}
|
||||||
|
func (m *TracerState) Size() (n int) {
|
||||||
|
var l int
|
||||||
|
_ = l
|
||||||
|
if m.TraceId != 0 {
|
||||||
|
n += 9
|
||||||
|
}
|
||||||
|
if m.SpanId != 0 {
|
||||||
|
n += 9
|
||||||
|
}
|
||||||
|
if m.Sampled {
|
||||||
|
n += 2
|
||||||
|
}
|
||||||
|
if len(m.BaggageItems) > 0 {
|
||||||
|
for k, v := range m.BaggageItems {
|
||||||
|
_ = k
|
||||||
|
_ = v
|
||||||
|
mapEntrySize := 1 + len(k) + sovWire(uint64(len(k))) + 1 + len(v) + sovWire(uint64(len(v)))
|
||||||
|
n += mapEntrySize + 1 + sovWire(uint64(mapEntrySize))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
|
func sovWire(x uint64) (n int) {
|
||||||
|
for {
|
||||||
|
n++
|
||||||
|
x >>= 7
|
||||||
|
if x == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
func sozWire(x uint64) (n int) {
|
||||||
|
return sovWire(uint64((x << 1) ^ uint64((int64(x) >> 63))))
|
||||||
|
}
|
||||||
|
func (m *TracerState) Unmarshal(data []byte) error {
|
||||||
|
l := len(data)
|
||||||
|
iNdEx := 0
|
||||||
|
for iNdEx < l {
|
||||||
|
preIndex := iNdEx
|
||||||
|
var wire uint64
|
||||||
|
for shift := uint(0); ; shift += 7 {
|
||||||
|
if shift >= 64 {
|
||||||
|
return ErrIntOverflowWire
|
||||||
|
}
|
||||||
|
if iNdEx >= l {
|
||||||
|
return io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
b := data[iNdEx]
|
||||||
|
iNdEx++
|
||||||
|
wire |= (uint64(b) & 0x7F) << shift
|
||||||
|
if b < 0x80 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fieldNum := int32(wire >> 3)
|
||||||
|
wireType := int(wire & 0x7)
|
||||||
|
if wireType == 4 {
|
||||||
|
return fmt.Errorf("proto: TracerState: wiretype end group for non-group")
|
||||||
|
}
|
||||||
|
if fieldNum <= 0 {
|
||||||
|
return fmt.Errorf("proto: TracerState: illegal tag %d (wire type %d)", fieldNum, wire)
|
||||||
|
}
|
||||||
|
switch fieldNum {
|
||||||
|
case 1:
|
||||||
|
if wireType != 1 {
|
||||||
|
return fmt.Errorf("proto: wrong wireType = %d for field TraceId", wireType)
|
||||||
|
}
|
||||||
|
m.TraceId = 0
|
||||||
|
if (iNdEx + 8) > l {
|
||||||
|
return io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
iNdEx += 8
|
||||||
|
m.TraceId = uint64(data[iNdEx-8])
|
||||||
|
m.TraceId |= uint64(data[iNdEx-7]) << 8
|
||||||
|
m.TraceId |= uint64(data[iNdEx-6]) << 16
|
||||||
|
m.TraceId |= uint64(data[iNdEx-5]) << 24
|
||||||
|
m.TraceId |= uint64(data[iNdEx-4]) << 32
|
||||||
|
m.TraceId |= uint64(data[iNdEx-3]) << 40
|
||||||
|
m.TraceId |= uint64(data[iNdEx-2]) << 48
|
||||||
|
m.TraceId |= uint64(data[iNdEx-1]) << 56
|
||||||
|
case 2:
|
||||||
|
if wireType != 1 {
|
||||||
|
return fmt.Errorf("proto: wrong wireType = %d for field SpanId", wireType)
|
||||||
|
}
|
||||||
|
m.SpanId = 0
|
||||||
|
if (iNdEx + 8) > l {
|
||||||
|
return io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
iNdEx += 8
|
||||||
|
m.SpanId = uint64(data[iNdEx-8])
|
||||||
|
m.SpanId |= uint64(data[iNdEx-7]) << 8
|
||||||
|
m.SpanId |= uint64(data[iNdEx-6]) << 16
|
||||||
|
m.SpanId |= uint64(data[iNdEx-5]) << 24
|
||||||
|
m.SpanId |= uint64(data[iNdEx-4]) << 32
|
||||||
|
m.SpanId |= uint64(data[iNdEx-3]) << 40
|
||||||
|
m.SpanId |= uint64(data[iNdEx-2]) << 48
|
||||||
|
m.SpanId |= uint64(data[iNdEx-1]) << 56
|
||||||
|
case 3:
|
||||||
|
if wireType != 0 {
|
||||||
|
return fmt.Errorf("proto: wrong wireType = %d for field Sampled", wireType)
|
||||||
|
}
|
||||||
|
var v int
|
||||||
|
for shift := uint(0); ; shift += 7 {
|
||||||
|
if shift >= 64 {
|
||||||
|
return ErrIntOverflowWire
|
||||||
|
}
|
||||||
|
if iNdEx >= l {
|
||||||
|
return io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
b := data[iNdEx]
|
||||||
|
iNdEx++
|
||||||
|
v |= (int(b) & 0x7F) << shift
|
||||||
|
if b < 0x80 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m.Sampled = bool(v != 0)
|
||||||
|
case 4:
|
||||||
|
if wireType != 2 {
|
||||||
|
return fmt.Errorf("proto: wrong wireType = %d for field BaggageItems", wireType)
|
||||||
|
}
|
||||||
|
var msglen int
|
||||||
|
for shift := uint(0); ; shift += 7 {
|
||||||
|
if shift >= 64 {
|
||||||
|
return ErrIntOverflowWire
|
||||||
|
}
|
||||||
|
if iNdEx >= l {
|
||||||
|
return io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
b := data[iNdEx]
|
||||||
|
iNdEx++
|
||||||
|
msglen |= (int(b) & 0x7F) << shift
|
||||||
|
if b < 0x80 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if msglen < 0 {
|
||||||
|
return ErrInvalidLengthWire
|
||||||
|
}
|
||||||
|
postIndex := iNdEx + msglen
|
||||||
|
if postIndex > l {
|
||||||
|
return io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
var keykey uint64
|
||||||
|
for shift := uint(0); ; shift += 7 {
|
||||||
|
if shift >= 64 {
|
||||||
|
return ErrIntOverflowWire
|
||||||
|
}
|
||||||
|
if iNdEx >= l {
|
||||||
|
return io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
b := data[iNdEx]
|
||||||
|
iNdEx++
|
||||||
|
keykey |= (uint64(b) & 0x7F) << shift
|
||||||
|
if b < 0x80 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var stringLenmapkey uint64
|
||||||
|
for shift := uint(0); ; shift += 7 {
|
||||||
|
if shift >= 64 {
|
||||||
|
return ErrIntOverflowWire
|
||||||
|
}
|
||||||
|
if iNdEx >= l {
|
||||||
|
return io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
b := data[iNdEx]
|
||||||
|
iNdEx++
|
||||||
|
stringLenmapkey |= (uint64(b) & 0x7F) << shift
|
||||||
|
if b < 0x80 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
intStringLenmapkey := int(stringLenmapkey)
|
||||||
|
if intStringLenmapkey < 0 {
|
||||||
|
return ErrInvalidLengthWire
|
||||||
|
}
|
||||||
|
postStringIndexmapkey := iNdEx + intStringLenmapkey
|
||||||
|
if postStringIndexmapkey > l {
|
||||||
|
return io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
mapkey := string(data[iNdEx:postStringIndexmapkey])
|
||||||
|
iNdEx = postStringIndexmapkey
|
||||||
|
var valuekey uint64
|
||||||
|
for shift := uint(0); ; shift += 7 {
|
||||||
|
if shift >= 64 {
|
||||||
|
return ErrIntOverflowWire
|
||||||
|
}
|
||||||
|
if iNdEx >= l {
|
||||||
|
return io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
b := data[iNdEx]
|
||||||
|
iNdEx++
|
||||||
|
valuekey |= (uint64(b) & 0x7F) << shift
|
||||||
|
if b < 0x80 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var stringLenmapvalue uint64
|
||||||
|
for shift := uint(0); ; shift += 7 {
|
||||||
|
if shift >= 64 {
|
||||||
|
return ErrIntOverflowWire
|
||||||
|
}
|
||||||
|
if iNdEx >= l {
|
||||||
|
return io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
b := data[iNdEx]
|
||||||
|
iNdEx++
|
||||||
|
stringLenmapvalue |= (uint64(b) & 0x7F) << shift
|
||||||
|
if b < 0x80 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
intStringLenmapvalue := int(stringLenmapvalue)
|
||||||
|
if intStringLenmapvalue < 0 {
|
||||||
|
return ErrInvalidLengthWire
|
||||||
|
}
|
||||||
|
postStringIndexmapvalue := iNdEx + intStringLenmapvalue
|
||||||
|
if postStringIndexmapvalue > l {
|
||||||
|
return io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
mapvalue := string(data[iNdEx:postStringIndexmapvalue])
|
||||||
|
iNdEx = postStringIndexmapvalue
|
||||||
|
if m.BaggageItems == nil {
|
||||||
|
m.BaggageItems = make(map[string]string)
|
||||||
|
}
|
||||||
|
m.BaggageItems[mapkey] = mapvalue
|
||||||
|
iNdEx = postIndex
|
||||||
|
default:
|
||||||
|
iNdEx = preIndex
|
||||||
|
skippy, err := skipWire(data[iNdEx:])
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if skippy < 0 {
|
||||||
|
return ErrInvalidLengthWire
|
||||||
|
}
|
||||||
|
if (iNdEx + skippy) > l {
|
||||||
|
return io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
iNdEx += skippy
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if iNdEx > l {
|
||||||
|
return io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
func skipWire(data []byte) (n int, err error) {
|
||||||
|
l := len(data)
|
||||||
|
iNdEx := 0
|
||||||
|
for iNdEx < l {
|
||||||
|
var wire uint64
|
||||||
|
for shift := uint(0); ; shift += 7 {
|
||||||
|
if shift >= 64 {
|
||||||
|
return 0, ErrIntOverflowWire
|
||||||
|
}
|
||||||
|
if iNdEx >= l {
|
||||||
|
return 0, io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
b := data[iNdEx]
|
||||||
|
iNdEx++
|
||||||
|
wire |= (uint64(b) & 0x7F) << shift
|
||||||
|
if b < 0x80 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
wireType := int(wire & 0x7)
|
||||||
|
switch wireType {
|
||||||
|
case 0:
|
||||||
|
for shift := uint(0); ; shift += 7 {
|
||||||
|
if shift >= 64 {
|
||||||
|
return 0, ErrIntOverflowWire
|
||||||
|
}
|
||||||
|
if iNdEx >= l {
|
||||||
|
return 0, io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
iNdEx++
|
||||||
|
if data[iNdEx-1] < 0x80 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return iNdEx, nil
|
||||||
|
case 1:
|
||||||
|
iNdEx += 8
|
||||||
|
return iNdEx, nil
|
||||||
|
case 2:
|
||||||
|
var length int
|
||||||
|
for shift := uint(0); ; shift += 7 {
|
||||||
|
if shift >= 64 {
|
||||||
|
return 0, ErrIntOverflowWire
|
||||||
|
}
|
||||||
|
if iNdEx >= l {
|
||||||
|
return 0, io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
b := data[iNdEx]
|
||||||
|
iNdEx++
|
||||||
|
length |= (int(b) & 0x7F) << shift
|
||||||
|
if b < 0x80 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
iNdEx += length
|
||||||
|
if length < 0 {
|
||||||
|
return 0, ErrInvalidLengthWire
|
||||||
|
}
|
||||||
|
return iNdEx, nil
|
||||||
|
case 3:
|
||||||
|
for {
|
||||||
|
var innerWire uint64
|
||||||
|
var start int = iNdEx
|
||||||
|
for shift := uint(0); ; shift += 7 {
|
||||||
|
if shift >= 64 {
|
||||||
|
return 0, ErrIntOverflowWire
|
||||||
|
}
|
||||||
|
if iNdEx >= l {
|
||||||
|
return 0, io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
b := data[iNdEx]
|
||||||
|
iNdEx++
|
||||||
|
innerWire |= (uint64(b) & 0x7F) << shift
|
||||||
|
if b < 0x80 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
innerWireType := int(innerWire & 0x7)
|
||||||
|
if innerWireType == 4 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
next, err := skipWire(data[start:])
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
iNdEx = start + next
|
||||||
|
}
|
||||||
|
return iNdEx, nil
|
||||||
|
case 4:
|
||||||
|
return iNdEx, nil
|
||||||
|
case 5:
|
||||||
|
iNdEx += 4
|
||||||
|
return iNdEx, nil
|
||||||
|
default:
|
||||||
|
return 0, fmt.Errorf("proto: illegal wireType %d", wireType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
panic("unreachable")
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrInvalidLengthWire = fmt.Errorf("proto: negative length found during unmarshaling")
|
||||||
|
ErrIntOverflowWire = fmt.Errorf("proto: integer overflow")
|
||||||
|
)
|
||||||
|
|
||||||
|
var fileDescriptorWire = []byte{
|
||||||
|
// 234 bytes of a gzipped FileDescriptorProto
|
||||||
|
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xe2, 0xe2, 0x2a, 0xcf, 0x2c, 0x4a,
|
||||||
|
0xd5, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x12, 0x4e, 0x4a, 0x2c, 0xce, 0x4c, 0x2e, 0x29, 0x4a,
|
||||||
|
0x4c, 0x4e, 0x2d, 0x8a, 0x4f, 0xcf, 0xd7, 0x03, 0x49, 0x29, 0x7d, 0x65, 0xe4, 0xe2, 0x0e, 0x01,
|
||||||
|
0x0b, 0x05, 0x97, 0x24, 0x96, 0xa4, 0x0a, 0x49, 0x72, 0x71, 0x80, 0x55, 0xc4, 0x67, 0xa6, 0x48,
|
||||||
|
0x30, 0x2a, 0x30, 0x6a, 0xb0, 0x05, 0xb1, 0x83, 0xf9, 0x9e, 0x29, 0x42, 0xe2, 0x5c, 0xec, 0xc5,
|
||||||
|
0x05, 0x89, 0x79, 0x20, 0x19, 0x26, 0xb0, 0x0c, 0x1b, 0x88, 0x0b, 0x94, 0x90, 0x00, 0x4a, 0x24,
|
||||||
|
0xe6, 0x16, 0xe4, 0xa4, 0xa6, 0x48, 0x30, 0x03, 0x25, 0x38, 0x82, 0x60, 0x5c, 0xa1, 0x70, 0x2e,
|
||||||
|
0xde, 0xa4, 0xc4, 0xf4, 0xf4, 0xc4, 0x74, 0xa0, 0x79, 0x25, 0xa9, 0xb9, 0xc5, 0x12, 0x2c, 0x0a,
|
||||||
|
0xcc, 0x1a, 0xdc, 0x46, 0x46, 0x7a, 0x58, 0x9c, 0xa2, 0x87, 0xe4, 0x0c, 0x3d, 0x27, 0x88, 0x2e,
|
||||||
|
0x4f, 0x90, 0x26, 0xd7, 0xbc, 0x92, 0xa2, 0xca, 0x20, 0x9e, 0x24, 0x24, 0x21, 0x29, 0x7b, 0x2e,
|
||||||
|
0x41, 0x0c, 0x25, 0x42, 0x02, 0x5c, 0xcc, 0xd9, 0xa9, 0x95, 0x60, 0x67, 0x73, 0x06, 0x81, 0x98,
|
||||||
|
0x42, 0x22, 0x5c, 0xac, 0x65, 0x89, 0x39, 0xa5, 0xa9, 0x60, 0x07, 0x73, 0x06, 0x41, 0x38, 0x56,
|
||||||
|
0x4c, 0x16, 0x8c, 0x4e, 0x62, 0x27, 0x1e, 0xc9, 0x31, 0x5e, 0x00, 0xe2, 0x07, 0x40, 0x3c, 0xe1,
|
||||||
|
0xb1, 0x1c, 0x43, 0x14, 0x0b, 0xc8, 0x11, 0x49, 0x6c, 0xe0, 0xb0, 0x32, 0x06, 0x04, 0x00, 0x00,
|
||||||
|
0xff, 0xff, 0x0a, 0x20, 0x89, 0x38, 0x39, 0x01, 0x00, 0x00,
|
||||||
|
}
|
Loading…
Reference in a new issue