From 2415e82d5b7802ba50141d627609fc04ab45859d Mon Sep 17 00:00:00 2001 From: Dimitrij Drus Date: Wed, 2 Jun 2021 11:05:03 +0200 Subject: [PATCH] feat: Instana support (#349) Closes #348 --- go.mod | 1 + go.sum | 6 +++ tracing/tracer.go | 14 +++++ tracing/tracer_test.go | 119 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 140 insertions(+) diff --git a/go.mod b/go.mod index 7bf58b86..ca025b61 100644 --- a/go.mod +++ b/go.mod @@ -35,6 +35,7 @@ require ( github.com/gorilla/websocket v1.4.2 github.com/hashicorp/go-retryablehttp v0.6.8 github.com/inhies/go-bytesize v0.0.0-20201103132853-d0aed0d254f8 + github.com/instana/go-sensor v1.29.0 github.com/jackc/pgconn v1.8.0 github.com/jackc/pgx/v4 v4.10.1 github.com/jandelgado/gcov2lcov v1.0.4 diff --git a/go.sum b/go.sum index 281d2995..87410c8e 100644 --- a/go.sum +++ b/go.sum @@ -816,6 +816,10 @@ github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANyt github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= github.com/inhies/go-bytesize v0.0.0-20201103132853-d0aed0d254f8 h1:RrGCja4Grfz7QM2hw+SUZIYlbHoqBfbvzlWRT3seXB8= github.com/inhies/go-bytesize v0.0.0-20201103132853-d0aed0d254f8/go.mod h1:KrtyD5PFj++GKkFS/7/RRrfnRhAMGQwy75GLCHWrCNs= +github.com/instana/go-sensor v1.29.0 h1:WoLxTJNjcPDfOYU4E+JCBqdQNcCpyQ2lJ2bYd5izND0= +github.com/instana/go-sensor v1.29.0/go.mod h1:Uh9j3eF2mBw/FLk2MxISmVDIj8mtJBFRj2S19M6CVyQ= +github.com/instana/testify v1.6.2-0.20200721153833-94b1851f4d65 h1:T25FL3WEzgmKB0m6XCJNZ65nw09/QIp3T1yXr487D+A= +github.com/instana/testify v1.6.2-0.20200721153833-94b1851f4d65/go.mod h1:nYhEREG/B7HUY7P+LKOrqy53TpIqmJ9JyUShcaEKtGw= github.com/jackc/chunkreader v1.0.0 h1:4s39bBR8ByfqH+DKm8rQA3E1LHZWB9XWcrz8fqaZbe0= github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo= github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= @@ -964,6 +968,8 @@ github.com/lib/pq v1.10.0 h1:Zx5DJFEYQXio93kgXnQ09fXNiUKsqv4OUEu2UtGcB1E= github.com/lib/pq v1.10.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= +github.com/looplab/fsm v0.1.0 h1:Qte7Zdn/5hBNbXzP7yxVU4OIFHWXBovyTT2LaBTyC20= +github.com/looplab/fsm v0.1.0/go.mod h1:m2VaOfDHxqXBBMgc26m6yUOwkFn8H2AlJDE+jd/uafI= github.com/luna-duclos/instrumentedsql v0.0.0-20181127104832-b7d587d28109/go.mod h1:PWUIzhtavmOR965zfawVsHXbEuU1G29BPZ/CB3C7jXk= github.com/luna-duclos/instrumentedsql v1.1.2/go.mod h1:4LGbEqDnopzNAiyxPPDXhLspyunZxgPTMJBKtC6U0BQ= github.com/luna-duclos/instrumentedsql v1.1.3 h1:t7mvC0z1jUt5A0UQ6I/0H31ryymuQRnJcWCiqV3lSAA= diff --git a/tracing/tracer.go b/tracing/tracer.go index 51674ad8..98984824 100644 --- a/tracing/tracer.go +++ b/tracing/tracer.go @@ -5,6 +5,7 @@ import ( "os" "strings" + instana "github.com/instana/go-sensor" "github.com/uber/jaeger-client-go" "github.com/opentracing/opentracing-go" @@ -150,6 +151,19 @@ func (t *Tracer) setup() error { t.tracer = opentracing.GlobalTracer() t.l.Infof("Elastic APM tracer configured!") + case "instana": + opts := instana.DefaultOptions() + var serviceName = os.Getenv("INSTANA_SERVICE_NAME") + if serviceName == "" { + serviceName = t.Config.ServiceName + } + opts.Service = serviceName + // all other settings can be configured using environment variables + + t.tracer = instana.NewTracerWithOptions(opts) + opentracing.SetGlobalTracer(t.tracer) + + t.l.Infof("Instana tracer configured!") case "": t.l.Infof("No tracer configured - skipping tracing setup") default: diff --git a/tracing/tracer_test.go b/tracing/tracer_test.go index 2de62b34..27840d57 100644 --- a/tracing/tracer_test.go +++ b/tracing/tracer_test.go @@ -10,7 +10,9 @@ import ( "io/ioutil" "net/http" "net/http/httptest" + "net/url" "os" + "strings" "testing" "time" @@ -187,3 +189,120 @@ func decodeResponseBody(t *testing.T, r *http.Request) []byte { require.NoError(t, reader.Close()) return respBody } + +func TestInstanaTracer(t *testing.T) { + done := make(chan struct{}) + + type discoveryRequest struct { + PID int `json:"pid"` + Name string `json:"name"` + Args []string `json:"args"` + Fd string `json:"fd"` + Inode string `json:"inode"` + } + + type discoveryResponse struct { + Pid uint32 `json:"pid"` + HostID string `json:"agentUuid"` + Secrets struct { + Matcher string `json:"matcher"` + List []string `json:"list"` + } `json:"secrets"` + ExtraHTTPHeaders []string `json:"extraHeaders"` + } + + type traceRequest struct { + Timestamp uint64 `json:"ts"` + Data struct { + Service string `json:"service"` + Sdk struct { + Name string `json:"name"` + Type string `json:"type"` + Custom struct { + Baggage map[string]interface{} `json:"baggage"` + Logs map[uint64]map[string]interface{} `json:"logs"` + Tags map[string]interface{} `json:"tags"` + } `json:"custom"` + } `json:"sdk"` + } `json:"data"` + } + + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.URL.Path == "/" { + t.Log("Got Agent check request") + + w.Header().Set("Server", "Instana Agent") + w.WriteHeader(http.StatusOK) + return + } + + if r.URL.Path == "/com.instana.plugin.golang.discovery" { + t.Log("Got Agent discovery request") + + body, err := ioutil.ReadAll(r.Body) + assert.NoError(t, err) + + var dReq discoveryRequest + assert.NoError(t, json.Unmarshal(body, &dReq)) + + agentResponse := discoveryResponse{ + Pid: 1, + HostID: "1", + } + resp, err := json.Marshal(&agentResponse) + assert.NoError(t, err) + w.Header().Set("Server", "Instana Agent") + w.Write(resp) + return + } + + if strings.Contains(r.URL.Path, "/com.instana.plugin.golang/traces.") { + t.Log("Got trace request") + + body, err := ioutil.ReadAll(r.Body) + assert.NoError(t, err) + + var req []traceRequest + assert.NoError(t,json.Unmarshal(body, &req)) + + assert.Equal(t, "ORY X", req[0].Data.Service) + assert.Equal(t, "testOperation", req[0].Data.Sdk.Name) + assert.Equal(t, true, req[0].Data.Sdk.Custom.Tags["testTag"]) + assert.Equal(t, "biValue", req[0].Data.Sdk.Custom.Baggage["testBi"]) + assert.Equal(t, "testValue", req[0].Data.Sdk.Custom.Logs[req[0].Timestamp]["testKey"]) + + w.Header().Set("Server", "Instana Agent") + w.WriteHeader(http.StatusOK) + + close(done) + return + } + })) + defer ts.Close() + + agentUrl, err := url.Parse(ts.URL) + require.NoError(t, err) + + require.NoError(t, os.Setenv("INSTANA_AGENT_HOST", agentUrl.Hostname())) + require.NoError(t, os.Setenv("INSTANA_AGENT_PORT", agentUrl.Port())) + + _, err = tracing.New(logrusx.New("ory/x", "1"), &tracing.Config{ + ServiceName: "ORY X", + Provider: "instana", + }) + assert.NoError(t, err) + + time.Sleep(1 * time.Second) + + span := opentracing.GlobalTracer().StartSpan("testOperation") + span.SetTag("testTag", true) + span.LogKV("testKey", "testValue") + span.SetBaggageItem("testBi", "biValue") + span.Finish() + + select { + case <-done: + case <-time.After(time.Second * 3): + t.Fatalf("Test server did not receive spans") + } +}