github.com/icyphox/x@v0.0.355-0.20220311094250-029bd783e8b8/tracing/tracer_test.go (about) 1 package tracing_test 2 3 import ( 4 "bytes" 5 "compress/gzip" 6 "compress/zlib" 7 "encoding/json" 8 "fmt" 9 "io" 10 "io/ioutil" 11 "net/http" 12 "net/http/httptest" 13 "net/url" 14 "os" 15 "strings" 16 "testing" 17 "time" 18 19 "github.com/stretchr/testify/require" 20 "google.golang.org/protobuf/proto" 21 22 "github.com/opentracing/opentracing-go" 23 "github.com/stretchr/testify/assert" 24 25 "github.com/ory/x/logrusx" 26 "github.com/ory/x/tracing" 27 28 coltracepb "go.opentelemetry.io/proto/otlp/collector/trace/v1" 29 30 "go.elastic.co/apm/transport" 31 ) 32 33 type zipkinSpanRequest struct { 34 Id string 35 TraceId string 36 Timestamp uint64 37 Name string 38 LocalEndpoint struct { 39 ServiceName string 40 } 41 Tags map[string]string 42 } 43 44 type elasticMetadataRequest struct { 45 Metadata struct { 46 Service struct { 47 Name string 48 } 49 } 50 } 51 52 type elasticSpanRequest struct { 53 Transaction struct { 54 Name string 55 Id string 56 Timestamp uint64 57 TraceId string 58 Type string 59 Context struct { 60 Tags map[string]string 61 } 62 } 63 } 64 65 func TestZipkinTracer(t *testing.T) { 66 done := make(chan struct{}) 67 ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 68 defer close(done) 69 70 body, err := ioutil.ReadAll(r.Body) 71 assert.NoError(t, err) 72 73 var spans []zipkinSpanRequest 74 err = json.Unmarshal(body, &spans) 75 76 assert.NoError(t, err) 77 78 assert.NotEmpty(t, spans[0].Id) 79 assert.NotEmpty(t, spans[0].TraceId) 80 assert.Equal(t, "testoperation", spans[0].Name) 81 assert.Equal(t, "ory x", spans[0].LocalEndpoint.ServiceName) 82 assert.NotNil(t, spans[0].Tags["testTag"]) 83 assert.Equal(t, "true", spans[0].Tags["testTag"]) 84 })) 85 defer ts.Close() 86 87 _, err := tracing.New(logrusx.New("ory/x", "1"), &tracing.Config{ 88 ServiceName: "ORY X", 89 Provider: "zipkin", 90 Providers: &tracing.ProvidersConfig{ 91 Zipkin: &tracing.ZipkinConfig{ 92 ServerURL: ts.URL, 93 }, 94 }, 95 }) 96 assert.NoError(t, err) 97 98 span := opentracing.GlobalTracer().StartSpan("testOperation") 99 span.SetTag("testTag", true) 100 span.Finish() 101 102 select { 103 case <-done: 104 case <-time.After(time.Millisecond * 1500): 105 t.Fatalf("Test server did not receive spans") 106 } 107 } 108 109 func TestElastcApmTracer(t *testing.T) { 110 done := make(chan struct{}, 2) 111 defer close(done) 112 ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 113 t.Log("Got connection!") 114 done <- struct{}{} 115 116 switch r.URL.String() { 117 case "/config/v1/agents?service.name=ORY+X": 118 break 119 case "/intake/v2/events": 120 body := decodeResponseBody(t, r) 121 fmt.Println(string(body)) 122 data := bytes.Split(body, []byte("\n")) 123 assert.GreaterOrEqual(t, len(data), 2) 124 var metadata elasticMetadataRequest 125 err := json.Unmarshal(data[0], &metadata) 126 assert.NoError(t, err) 127 assert.Equal(t, "ORY X", metadata.Metadata.Service.Name) 128 129 var spans elasticSpanRequest 130 err = json.Unmarshal(data[1], &spans) 131 assert.Equal(t, "testOperation", spans.Transaction.Name) 132 assert.Equal(t, "custom", spans.Transaction.Type) 133 assert.Equal(t, "true", spans.Transaction.Context.Tags["testTag"]) 134 135 break 136 default: 137 t.Fatalf("Unknown request:" + r.URL.String()) 138 } 139 })) 140 defer ts.Close() 141 142 require.NoError(t, os.Setenv("ELASTIC_APM_SERVER_URL", ts.URL)) 143 // Reset env vars in APM Library 144 _, err := transport.InitDefault() 145 require.NoError(t, err) 146 147 _, err = tracing.New(logrusx.New("ory/x", "1"), &tracing.Config{ 148 ServiceName: "ORY X", 149 Provider: "elastic-apm", 150 Providers: &tracing.ProvidersConfig{ 151 Zipkin: &tracing.ZipkinConfig{ 152 ServerURL: ts.URL, 153 }, 154 }, 155 }) 156 require.NoError(t, err) 157 158 span := opentracing.GlobalTracer().StartSpan("testOperation") 159 span.SetTag("testTag", true) 160 span.Finish() 161 162 for i := 0; i < 2; i++ { 163 select { 164 case _, ok := <-done: 165 if !ok { 166 return 167 } 168 case <-time.After(time.Millisecond * 1500): 169 t.Fatalf("Test server did not receive spans") 170 return 171 } 172 } 173 } 174 175 func decodeResponseBody(t *testing.T, r *http.Request) []byte { 176 var reader io.ReadCloser 177 switch r.Header.Get("Content-Encoding") { 178 case "gzip": 179 var err error 180 reader, err = gzip.NewReader(r.Body) 181 if err != nil { 182 t.Fatal(err) 183 } 184 case "deflate": 185 var err error 186 reader, err = zlib.NewReader(r.Body) 187 if err != nil { 188 t.Fatal(err) 189 } 190 191 default: 192 reader = r.Body 193 } 194 respBody, err := ioutil.ReadAll(reader) 195 require.NoError(t, err) 196 require.NoError(t, reader.Close()) 197 return respBody 198 } 199 200 func TestInstanaTracer(t *testing.T) { 201 done := make(chan struct{}) 202 203 type discoveryRequest struct { 204 PID int `json:"pid"` 205 Name string `json:"name"` 206 Args []string `json:"args"` 207 Fd string `json:"fd"` 208 Inode string `json:"inode"` 209 } 210 211 type discoveryResponse struct { 212 Pid uint32 `json:"pid"` 213 HostID string `json:"agentUuid"` 214 Secrets struct { 215 Matcher string `json:"matcher"` 216 List []string `json:"list"` 217 } `json:"secrets"` 218 ExtraHTTPHeaders []string `json:"extraHeaders"` 219 } 220 221 type traceRequest struct { 222 Timestamp uint64 `json:"ts"` 223 Data struct { 224 Service string `json:"service"` 225 Sdk struct { 226 Name string `json:"name"` 227 Type string `json:"type"` 228 Custom struct { 229 Baggage map[string]interface{} `json:"baggage"` 230 Logs map[uint64]map[string]interface{} `json:"logs"` 231 Tags map[string]interface{} `json:"tags"` 232 } `json:"custom"` 233 } `json:"sdk"` 234 } `json:"data"` 235 } 236 237 ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 238 if r.URL.Path == "/" { 239 t.Log("Got Agent check request") 240 241 w.Header().Set("Server", "Instana Agent") 242 w.WriteHeader(http.StatusOK) 243 return 244 } 245 246 if r.URL.Path == "/com.instana.plugin.golang.discovery" { 247 t.Log("Got Agent discovery request") 248 249 body, err := ioutil.ReadAll(r.Body) 250 assert.NoError(t, err) 251 252 var dReq discoveryRequest 253 assert.NoError(t, json.Unmarshal(body, &dReq)) 254 255 agentResponse := discoveryResponse{ 256 Pid: 1, 257 HostID: "1", 258 } 259 resp, err := json.Marshal(&agentResponse) 260 assert.NoError(t, err) 261 w.Header().Set("Server", "Instana Agent") 262 w.Write(resp) 263 return 264 } 265 266 if strings.Contains(r.URL.Path, "/com.instana.plugin.golang/traces.") { 267 t.Log("Got trace request") 268 269 body, err := ioutil.ReadAll(r.Body) 270 assert.NoError(t, err) 271 272 var req []traceRequest 273 assert.NoError(t, json.Unmarshal(body, &req)) 274 275 assert.Equal(t, "ORY X", req[0].Data.Service) 276 assert.Equal(t, "testOperation", req[0].Data.Sdk.Name) 277 assert.Equal(t, true, req[0].Data.Sdk.Custom.Tags["testTag"]) 278 assert.Equal(t, "biValue", req[0].Data.Sdk.Custom.Baggage["testBi"]) 279 //assert.Equal(t, "testValue", req[0].Data.Sdk.Custom.Logs[req[0].Timestamp]["testKey"]) 280 281 w.Header().Set("Server", "Instana Agent") 282 w.WriteHeader(http.StatusOK) 283 284 close(done) 285 return 286 } 287 })) 288 defer ts.Close() 289 290 agentUrl, err := url.Parse(ts.URL) 291 require.NoError(t, err) 292 293 require.NoError(t, os.Setenv("INSTANA_AGENT_HOST", agentUrl.Hostname())) 294 require.NoError(t, os.Setenv("INSTANA_AGENT_PORT", agentUrl.Port())) 295 296 _, err = tracing.New(logrusx.New("ory/x", "1"), &tracing.Config{ 297 ServiceName: "ORY X", 298 Provider: "instana", 299 }) 300 assert.NoError(t, err) 301 302 time.Sleep(1 * time.Second) 303 304 span := opentracing.GlobalTracer().StartSpan("testOperation") 305 span.SetTag("testTag", true) 306 span.LogKV("testKey", "testValue") 307 span.SetBaggageItem("testBi", "biValue") 308 span.Finish() 309 310 select { 311 case <-done: 312 case <-time.After(time.Second * 3): 313 t.Fatalf("Test server did not receive spans") 314 } 315 } 316 317 func TestOtlpTracer(t *testing.T) { 318 done := make(chan struct{}) 319 320 ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 321 body := decodeResponseBody(t, r) 322 323 var res coltracepb.ExportTraceServiceRequest 324 err := proto.Unmarshal(body, &res) 325 require.NoError(t, err, "must be able to unmarshal traces") 326 receivedSpan := res.ResourceSpans[0].InstrumentationLibrarySpans[0].Spans[0] 327 assert.Equal(t, "testOperation", receivedSpan.GetName()) 328 attributes := receivedSpan.GetAttributes() 329 assert.Equal(t, "testTag", attributes[0].GetKey()) 330 331 close(done) 332 })) 333 defer ts.Close() 334 335 require.NoError(t, os.Setenv("OTEL_EXPORTER_OTLP_ENDPOINT", ts.URL)) 336 337 _, err := tracing.New(logrusx.New("ory/x", "1"), &tracing.Config{ 338 ServiceName: "ORY X", 339 Provider: "otel", 340 }) 341 assert.NoError(t, err) 342 343 span := opentracing.GlobalTracer().StartSpan("testOperation") 344 span.SetTag("testTag", true) 345 span.Finish() 346 347 select { 348 case <-done: 349 case <-time.After(3 * time.Second): 350 t.Fatalf("Test server did not receive spans") 351 } 352 }