github.com/matrixorigin/matrixone@v1.2.0/pkg/util/trace/impl/motrace/mo_trace_test.go (about) 1 // Copyright The OpenTelemetry Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // Portions of this file are additionally subject to the following 16 // copyright. 17 // 18 // Copyright (C) 2022 Matrix Origin. 19 // 20 // Modified the behavior and the interface of the step. 21 22 package motrace 23 24 import ( 25 "context" 26 "fmt" 27 "io" 28 "os" 29 "path" 30 "path/filepath" 31 "runtime" 32 "sync" 33 "testing" 34 "time" 35 36 "github.com/matrixorigin/matrixone/pkg/util/export/table" 37 "github.com/matrixorigin/matrixone/pkg/util/trace" 38 "github.com/prashantv/gostub" 39 "github.com/stretchr/testify/assert" 40 "github.com/stretchr/testify/require" 41 "go.uber.org/zap" 42 ) 43 44 var _1TxnID = [16]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1} 45 var _1SesID = [16]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1} 46 var _1TraceID trace.TraceID = [16]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1} 47 var _2TraceID trace.TraceID = [16]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x2} 48 var _10F0TraceID trace.TraceID = [16]byte{0x09, 0x87, 0x65, 0x43, 0x21, 0xFF, 0xFF, 0xFF, 0, 0, 0, 0, 0, 0, 0, 0} 49 var _1SpanID trace.SpanID = [8]byte{0, 0, 0, 0, 0, 0, 0, 1} 50 var _2SpanID trace.SpanID = [8]byte{0, 0, 0, 0, 0, 0, 0, 2} 51 var _16SpanID trace.SpanID = [8]byte{0, 0, 0, 0, 0, 0x12, 0x34, 0x56} 52 53 func TestMOTracer_Start(t *testing.T) { 54 if runtime.GOOS == `linux` { 55 t.Skip() 56 return 57 } 58 type fields struct { 59 Enable bool 60 } 61 type args struct { 62 ctx context.Context 63 name string 64 opts []trace.SpanStartOption 65 } 66 rootCtx := trace.ContextWithSpanContext(context.Background(), trace.SpanContextWithIDs(_1TraceID, _1SpanID)) 67 stmCtx := trace.ContextWithSpanContext(context.Background(), trace.SpanContextWithID(_1TraceID, trace.SpanKindStatement)) 68 dAtA := make([]byte, 24) 69 span := trace.SpanFromContext(stmCtx) 70 c := span.SpanContext() 71 cnt, err := c.MarshalTo(dAtA) 72 require.Nil(t, err) 73 require.Equal(t, 24, cnt) 74 sc := &trace.SpanContext{} 75 err = sc.Unmarshal(dAtA) 76 require.Nil(t, err) 77 remoteCtx := trace.ContextWithSpanContext(context.Background(), *sc) 78 tests := []struct { 79 name string 80 fields fields 81 args args 82 wantNewRoot bool 83 wantTraceId trace.TraceID 84 wantParentSpanId trace.SpanID 85 wantKind trace.SpanKind 86 }{ 87 { 88 name: "normal", 89 fields: fields{Enable: true}, 90 args: args{ctx: rootCtx, name: "normal", opts: []trace.SpanStartOption{}}, 91 wantNewRoot: false, 92 wantTraceId: _1TraceID, 93 wantParentSpanId: _1SpanID, 94 wantKind: trace.SpanKindInternal, 95 }, 96 { 97 name: "newRoot", 98 fields: fields{Enable: true}, 99 args: args{ctx: rootCtx, name: "newRoot", opts: []trace.SpanStartOption{trace.WithNewRoot(true)}}, 100 wantNewRoot: true, 101 wantTraceId: _1TraceID, 102 wantParentSpanId: _1SpanID, 103 wantKind: trace.SpanKindInternal, 104 }, 105 { 106 name: "statement", 107 fields: fields{Enable: true}, 108 args: args{ctx: stmCtx, name: "newStmt", opts: []trace.SpanStartOption{}}, 109 wantNewRoot: false, 110 wantTraceId: _1TraceID, 111 wantParentSpanId: trace.NilSpanID, 112 wantKind: trace.SpanKindStatement, 113 }, 114 { 115 name: "empty", 116 fields: fields{Enable: true}, 117 args: args{ctx: context.Background(), name: "backgroundCtx", opts: []trace.SpanStartOption{}}, 118 wantNewRoot: true, 119 wantTraceId: trace.NilTraceID, 120 wantParentSpanId: _1SpanID, 121 wantKind: trace.SpanKindInternal, 122 }, 123 { 124 name: "remote", 125 fields: fields{Enable: true}, 126 args: args{ctx: remoteCtx, name: "remoteCtx", opts: []trace.SpanStartOption{}}, 127 wantNewRoot: false, 128 wantTraceId: _1TraceID, 129 wantParentSpanId: trace.NilSpanID, 130 wantKind: trace.SpanKindRemote, 131 }, 132 } 133 tracer := &MOTracer{ 134 TracerConfig: trace.TracerConfig{Name: "motrace_test"}, 135 provider: defaultMOTracerProvider(), 136 } 137 for _, tt := range tests { 138 t.Run(tt.name, func(t1 *testing.T) { 139 tracer.provider.enable = tt.fields.Enable 140 newCtx, span := tracer.Start(tt.args.ctx, tt.args.name, tt.args.opts...) 141 if !tt.wantNewRoot { 142 require.Equal(t1, tt.wantTraceId, span.SpanContext().TraceID) 143 require.Equal(t1, tt.wantParentSpanId, span.ParentSpanContext().SpanID) 144 require.Equal(t1, tt.wantParentSpanId, trace.SpanFromContext(newCtx).ParentSpanContext().SpanID) 145 } else { 146 require.NotEqualf(t1, tt.wantTraceId, span.SpanContext().TraceID, "want %s, but got %s", tt.wantTraceId.String(), span.SpanContext().TraceID.String()) 147 require.NotEqual(t1, tt.wantParentSpanId, span.ParentSpanContext().SpanID) 148 require.NotEqual(t1, tt.wantParentSpanId, trace.SpanFromContext(newCtx).ParentSpanContext().SpanID) 149 } 150 require.Equal(t1, tt.wantKind, trace.SpanFromContext(newCtx).ParentSpanContext().Kind) 151 require.Equal(t1, span, trace.SpanFromContext(newCtx)) 152 }) 153 } 154 } 155 156 func TestSpanContext_MarshalTo(t *testing.T) { 157 type fields struct { 158 TraceID trace.TraceID 159 SpanID trace.SpanID 160 } 161 type args struct { 162 dAtA []byte 163 } 164 tests := []struct { 165 name string 166 fields fields 167 args args 168 want int 169 wantBytes []byte 170 }{ 171 { 172 name: "normal", 173 fields: fields{ 174 TraceID: trace.NilTraceID, 175 SpanID: _16SpanID, 176 }, 177 args: args{dAtA: make([]byte, 24)}, 178 want: 24, 179 // 1 2 3 4 5 6 7 8, 1 2 3 4 5 6 7 8--1 2 3 4 5 6 7 8 180 wantBytes: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x12, 0x34, 0x56}, 181 }, 182 { 183 name: "not-zero", 184 fields: fields{ 185 TraceID: _10F0TraceID, 186 SpanID: _16SpanID, 187 }, 188 args: args{dAtA: make([]byte, 24)}, 189 want: 24, 190 // 1 2 3 4 5 6 7 8, 1 2 3 4 5 6 7 8--1 2 3 4 5 6 7 8 191 wantBytes: []byte{0x09, 0x87, 0x65, 0x43, 0x21, 0xff, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x12, 0x34, 0x56}, 192 }, 193 } 194 for _, tt := range tests { 195 t.Run(tt.name, func(t *testing.T) { 196 c := &trace.SpanContext{ 197 TraceID: tt.fields.TraceID, 198 SpanID: tt.fields.SpanID, 199 Kind: trace.SpanKindRemote, 200 } 201 got, err := c.MarshalTo(tt.args.dAtA) 202 require.Equal(t, nil, err) 203 require.Equal(t, got, tt.want) 204 require.Equal(t, tt.wantBytes, tt.args.dAtA) 205 newC := &trace.SpanContext{} 206 err = newC.Unmarshal(tt.args.dAtA) 207 require.Equal(t, nil, err) 208 require.Equal(t, c, newC) 209 require.Equal(t, tt.fields.TraceID, newC.TraceID) 210 require.Equal(t, tt.fields.SpanID, newC.SpanID) 211 }) 212 } 213 } 214 215 func TestMOSpan_End(t *testing.T) { 216 if runtime.NumCPU() < 4 { 217 t.Skip("machine's performance too low to handle time sensitive case, issue #11669") 218 return 219 } 220 221 s := gostub.Stub(&freeMOSpan, func(span *MOSpan) {}) 222 defer s.Reset() 223 224 ctx := context.TODO() 225 p := newMOTracerProvider(WithLongSpanTime(time.Hour), EnableTracer(true)) 226 tracer := &MOTracer{ 227 TracerConfig: trace.TracerConfig{Name: "test"}, 228 provider: p, 229 } 230 231 var WG sync.WaitGroup 232 233 // short time span 234 var shortTimeSpan trace.Span 235 WG.Add(1) 236 go func() { 237 _, shortTimeSpan = tracer.Start(ctx, "shortTimeSpan") 238 defer WG.Done() 239 defer shortTimeSpan.End() 240 }() 241 WG.Wait() 242 require.Equal(t, false, shortTimeSpan.(*MOSpan).needRecord) 243 require.Equal(t, 0, len(shortTimeSpan.(*MOSpan).ExtraFields)) 244 245 // span with LongTimeThreshold 246 // and set ExtraFields 247 var longTimeSpan trace.Span 248 WG.Add(1) 249 extraFields := []zap.Field{zap.String("str", "field"), zap.Int64("int", 0)} 250 go func() { 251 _, longTimeSpan = tracer.Start(ctx, "longTimeSpan", trace.WithLongTimeThreshold(time.Millisecond)) 252 defer WG.Done() 253 defer longTimeSpan.End() 254 255 longTimeSpan.AddExtraFields(extraFields...) 256 257 time.Sleep(10 * time.Millisecond) 258 }() 259 WG.Wait() 260 require.Equal(t, true, longTimeSpan.(*MOSpan).needRecord) 261 require.Equal(t, 2, len(longTimeSpan.(*MOSpan).ExtraFields)) 262 require.Equal(t, false, longTimeSpan.(*MOSpan).doneProfile) 263 require.Equal(t, extraFields, longTimeSpan.(*MOSpan).ExtraFields) 264 265 // span with deadline context 266 deadlineCtx, cancel := context.WithTimeout(ctx, time.Millisecond) 267 defer cancel() 268 var deadlineSpan trace.Span 269 WG.Add(1) 270 go func() { 271 _, deadlineSpan = tracer.Start(deadlineCtx, "deadlineCtx") 272 defer WG.Done() 273 defer deadlineSpan.End() 274 275 time.Sleep(10 * time.Millisecond) 276 }() 277 WG.Wait() 278 require.Equal(t, true, deadlineSpan.(*MOSpan).needRecord) 279 require.Equal(t, 1, len(deadlineSpan.(*MOSpan).ExtraFields)) 280 require.Equal(t, false, deadlineSpan.(*MOSpan).doneProfile) 281 require.Equal(t, []zap.Field{zap.Error(context.DeadlineExceeded)}, deadlineSpan.(*MOSpan).ExtraFields) 282 283 // span with deadline context (plus calling cancel2() before func return) 284 deadlineCtx2, cancel2 := context.WithTimeout(ctx, time.Millisecond) 285 var deadlineSpan2 trace.Span 286 WG.Add(1) 287 go func() { 288 _, deadlineSpan2 = tracer.Start(deadlineCtx2, "deadlineCtx") 289 defer WG.Done() 290 defer deadlineSpan2.End() 291 292 time.Sleep(10 * time.Millisecond) 293 cancel2() 294 }() 295 WG.Wait() 296 require.Equal(t, true, deadlineSpan2.(*MOSpan).needRecord) 297 require.Equal(t, 1, len(deadlineSpan2.(*MOSpan).ExtraFields)) 298 require.Equal(t, false, deadlineSpan2.(*MOSpan).doneProfile) 299 require.Equal(t, []zap.Field{zap.Error(context.DeadlineExceeded)}, deadlineSpan2.(*MOSpan).ExtraFields) 300 301 // span with hung option, with Deadline situation 302 caseHungOptionWithDeadline := func() { 303 var hungSpan trace.Span 304 WG.Add(1) 305 go func() { 306 _, hungSpan = tracer.Start(ctx, "hungCtx", trace.WithHungThreshold(time.Millisecond)) 307 defer WG.Done() 308 defer hungSpan.End() 309 310 time.Sleep(10 * time.Millisecond) 311 }() 312 WG.Wait() 313 require.Equal(t, true, hungSpan.(*MOHungSpan).needRecord) 314 require.Equal(t, 1, len(hungSpan.(*MOHungSpan).ExtraFields)) 315 require.Equal(t, true, hungSpan.(*MOHungSpan).doneProfile) 316 require.Equal(t, []zap.Field{zap.Error(context.DeadlineExceeded)}, hungSpan.(*MOHungSpan).ExtraFields) 317 } 318 caseHungOptionWithDeadline() 319 320 // span with hung option, with NO Deadline situation 321 caseHungOptionWithoutDeadline := func() { 322 var hungSpan trace.Span 323 WG.Add(1) 324 go func() { 325 _, hungSpan = tracer.Start(ctx, "hungCtx", trace.WithHungThreshold(time.Minute)) 326 defer WG.Done() 327 defer hungSpan.End() 328 329 time.Sleep(10 * time.Millisecond) 330 }() 331 WG.Wait() 332 require.Equal(t, false, hungSpan.(*MOHungSpan).needRecord) 333 require.Equal(t, 0, len(hungSpan.(*MOHungSpan).ExtraFields)) 334 require.Equal(t, false, hungSpan.(*MOHungSpan).doneProfile) 335 } 336 caseHungOptionWithoutDeadline() 337 338 } 339 340 type dummyFileWriterFactory struct{} 341 342 func (f *dummyFileWriterFactory) GetRowWriter(ctx context.Context, account string, tbl *table.Table, ts time.Time) table.RowWriter { 343 return &dummyStringWriter{} 344 } 345 func (f *dummyFileWriterFactory) GetWriter(ctx context.Context, fp string) io.WriteCloser { 346 selfDir, err := filepath.Abs(".") 347 if err != nil { 348 panic(err) 349 } 350 fmt.Printf("root: %s\n", selfDir) 351 dirname := path.Dir(fp) 352 if dirname != "." && dirname != "./" && dirname != "/" { 353 if err := os.Mkdir(dirname, os.ModeType|os.ModePerm); err != nil && !os.IsExist(err) { 354 panic(err) 355 } 356 } 357 fw, err := os.Create(fp) 358 if err != nil { 359 panic(err) 360 } 361 return fw 362 } 363 364 func TestMOSpan_doProfile(t *testing.T) { 365 type fields struct { 366 opts []trace.SpanStartOption 367 ctx context.Context 368 tracer *MOTracer 369 } 370 371 p := newMOTracerProvider(WithFSWriterFactory(&dummyFileWriterFactory{}), EnableTracer(true)) 372 tracer := p.Tracer("test").(*MOTracer) 373 ctx := context.TODO() 374 375 prepareCheckCpu := func(t *testing.T) { 376 if runtime.NumCPU() < 4 { 377 t.Skip("machine's performance too low to handle time sensitive case, issue #11864") 378 } 379 } 380 381 tests := []struct { 382 name string 383 fields fields 384 prepare func(t *testing.T) 385 want bool 386 }{ 387 { 388 name: "normal", 389 fields: fields{ 390 opts: nil, 391 ctx: ctx, 392 tracer: tracer, 393 }, 394 }, 395 { 396 name: "goroutine", 397 fields: fields{ 398 opts: []trace.SpanStartOption{trace.WithProfileGoroutine()}, // it will dump file into ETL folder. 399 ctx: ctx, 400 tracer: tracer, 401 }, 402 want: true, 403 }, 404 { 405 name: "heap", 406 fields: fields{ 407 opts: []trace.SpanStartOption{trace.WithProfileHeap()}, 408 ctx: ctx, 409 tracer: tracer, 410 }, 411 want: true, 412 }, 413 { 414 name: "threadcreate", 415 fields: fields{ 416 opts: []trace.SpanStartOption{trace.WithProfileThreadCreate()}, 417 ctx: ctx, 418 tracer: tracer, 419 }, 420 want: true, 421 }, 422 { 423 name: "allocs", 424 fields: fields{ 425 opts: []trace.SpanStartOption{trace.WithProfileAllocs()}, 426 ctx: ctx, 427 tracer: tracer, 428 }, 429 want: true, 430 }, 431 { 432 name: "block", 433 fields: fields{ 434 opts: []trace.SpanStartOption{trace.WithProfileBlock()}, 435 ctx: ctx, 436 tracer: tracer, 437 }, 438 want: true, 439 }, 440 { 441 name: "mutex", 442 fields: fields{ 443 opts: []trace.SpanStartOption{trace.WithProfileMutex()}, 444 ctx: ctx, 445 tracer: tracer, 446 }, 447 want: true, 448 }, 449 { 450 name: "cpu", 451 fields: fields{ 452 opts: []trace.SpanStartOption{trace.WithProfileCpuSecs(time.Second)}, 453 ctx: ctx, 454 tracer: tracer, 455 }, 456 prepare: prepareCheckCpu, 457 want: true, 458 }, 459 { 460 name: "trace", 461 fields: fields{ 462 opts: []trace.SpanStartOption{trace.WithProfileTraceSecs(time.Second)}, 463 ctx: ctx, 464 tracer: tracer, 465 }, 466 prepare: prepareCheckCpu, 467 want: true, 468 }, 469 } 470 for _, tt := range tests { 471 t.Run(tt.name, func(t *testing.T) { 472 if tt.prepare != nil { 473 tt.prepare(t) 474 } 475 _, s := tt.fields.tracer.Start(tt.fields.ctx, "test", tt.fields.opts...) 476 ms, _ := s.(*MOSpan) 477 t.Logf("span.LongTimeThreshold: %v", ms.LongTimeThreshold) 478 time.Sleep(time.Millisecond) 479 s.End() 480 t.Logf("span.LongTimeThreshold: %v, duration: %v, needRecord: %v, needProfile: %v, doneProfile: %v", 481 ms.LongTimeThreshold, ms.Duration, ms.needRecord, ms.NeedProfile(), ms.doneProfile) 482 require.Equal(t, tt.want, s.(*MOSpan).doneProfile) 483 }) 484 } 485 } 486 487 func TestMOHungSpan_EndBeforeDeadline_doProfile(t *testing.T) { 488 489 defer func() { 490 err := recover() 491 require.Nilf(t, err, "error: %s", err) 492 }() 493 494 p := newMOTracerProvider(WithFSWriterFactory(&dummyFileWriterFactory{}), EnableTracer(true)) 495 tracer := p.Tracer("test").(*MOTracer) 496 ctx := context.TODO() 497 498 var ctrlWG sync.WaitGroup 499 ctrlWG.Add(1) 500 501 _, span := tracer.Start(ctx, "test_loop", trace.WithHungThreshold(100*time.Millisecond)) 502 hungSpan := span.(*MOHungSpan) 503 504 hungSpan.mux.Lock() 505 // simulate the act of span.End() 506 // TIPs: remove trigger.Stop() 507 hungSpan.quitCancel() 508 hungSpan.stopped = true 509 hungSpan.MOSpan = nil 510 time.Sleep(300 * time.Millisecond) 511 t.Logf("hungSpan.quitCtx.Err: %s", hungSpan.quitCtx.Err()) 512 // END > simulate 513 hungSpan.mux.Unlock() 514 515 // wait for goroutine to finish 516 // should not panic 517 time.Sleep(time.Second) 518 } 519 520 func TestContextDeadlineAndCancel(t *testing.T) { 521 if runtime.NumCPU() < 4 { 522 t.Skip("machine's performance too low to handle time sensitive case") 523 return 524 } 525 quitCtx, quitCancel := context.WithCancel(context.TODO()) 526 deadlineCtx, deadlineCancel := context.WithTimeout(quitCtx, time.Microsecond) 527 defer deadlineCancel() 528 529 time.Sleep(time.Second) 530 t.Logf("deadlineCtx.Err: %s", deadlineCtx.Err()) 531 quitCancel() 532 require.Equal(t, context.DeadlineExceeded, deadlineCtx.Err()) 533 } 534 535 func TestMOTracer_FSSpanIsEnable(t *testing.T) { 536 537 tracer := &MOTracer{ 538 TracerConfig: trace.TracerConfig{Name: "motrace_test"}, 539 provider: defaultMOTracerProvider(), 540 } 541 tracer.provider.enable = true 542 543 trace.InitMOCtledSpan() 544 trace.SetMoCtledSpanState("local", true, 0) 545 546 ctx, cancel := context.WithTimeout(context.Background(), time.Second*10) 547 defer cancel() 548 _, span := tracer.Start(ctx, "test", trace.WithKind( 549 trace.SpanKindLocalFSVis)) 550 551 _, ok := span.(trace.NoopSpan) 552 553 assert.True(t, tracer.IsEnable(trace.WithKind(trace.SpanKindLocalFSVis))) 554 assert.False(t, ok) 555 span.End() 556 557 _, span = tracer.Start(context.Background(), "test", trace.WithKind( 558 trace.SpanKindRemoteFSVis)) 559 _, ok = span.(trace.NoopSpan) 560 assert.False(t, tracer.IsEnable(trace.WithKind(trace.SpanKindRemoteFSVis))) 561 assert.True(t, ok) 562 span.End() 563 564 } 565 566 func TestMOSpan_NeedRecord(t *testing.T) { 567 tracer := &MOTracer{ 568 TracerConfig: trace.TracerConfig{Name: "motrace_test"}, 569 provider: defaultMOTracerProvider(), 570 } 571 572 tracer.provider.enable = true 573 tracer.provider.longSpanTime = time.Millisecond * 20 574 trace.InitMOCtledSpan() 575 576 // ctx has deadline 577 ctx, cancel := context.WithTimeout(context.Background(), time.Second*1) 578 defer cancel() 579 580 _, span := tracer.Start(ctx, "normal span") 581 time.Sleep(time.Millisecond * 30) 582 // deadline not expired, no need to record 583 ret, _ := span.(*MOSpan).NeedRecord() 584 require.False(t, ret) 585 span.End() 586 587 _, span = tracer.Start(ctx, "normal span") 588 time.Sleep(time.Second) 589 span.(*MOSpan).EndTime = time.Now() 590 // ctx expired, record 591 ret, _ = span.(*MOSpan).NeedRecord() 592 require.True(t, ret) 593 span.End() 594 595 trace.SetMoCtledSpanState("statement", true, 0) 596 _, span = tracer.Start(ctx, "mo_ctl controlled span", 597 trace.WithKind(trace.SpanKindStatement)) 598 // ctx expired, but not to record 599 trace.SetMoCtledSpanState("statement", false, 0) 600 ret, _ = span.(*MOSpan).NeedRecord() 601 require.False(t, ret) 602 span.End() 603 604 trace.SetMoCtledSpanState("statement", true, 0) 605 _, span = tracer.Start(ctx, "mo_ctl controlled span", 606 trace.WithKind(trace.SpanKindStatement)) 607 // record 608 ret, _ = span.(*MOSpan).NeedRecord() 609 require.True(t, ret) 610 span.End() 611 612 // it won't record until this trace last more than 1000ms 613 trace.SetMoCtledSpanState("statement", true, 1000) 614 _, span = tracer.Start(ctx, "mo_ctl controlled span", 615 trace.WithKind(trace.SpanKindStatement)) 616 617 span.(*MOSpan).Duration = time.Since(span.(*MOSpan).StartTime) 618 619 ret, _ = span.(*MOSpan).NeedRecord() 620 require.False(t, ret) 621 span.End() 622 623 trace.SetMoCtledSpanState("statement", true, 100) 624 _, span = tracer.Start(ctx, "mo_ctl controlled span", 625 trace.WithKind(trace.SpanKindStatement)) 626 time.Sleep(time.Millisecond * 200) 627 // record 628 629 span.(*MOSpan).Duration = time.Since(span.(*MOSpan).StartTime) 630 631 ret, _ = span.(*MOSpan).NeedRecord() 632 require.True(t, ret) 633 span.End() 634 } 635 636 func TestMOCtledKindOverwrite(t *testing.T) { 637 tracer := &MOTracer{ 638 TracerConfig: trace.TracerConfig{Name: "motrace_test"}, 639 provider: defaultMOTracerProvider(), 640 } 641 tracer.provider.enable = true 642 643 trace.InitMOCtledSpan() 644 645 fctx, fspan := tracer.Start(context.Background(), "test2", trace.WithKind(trace.SpanKindRemote)) 646 defer fspan.End() 647 require.Equal(t, fspan.SpanContext().Kind, trace.SpanKindRemote) 648 649 trace.SetMoCtledSpanState("statement", true, 0) 650 // won't be overwritten 651 _, span := tracer.Start(fctx, "test3", trace.WithKind(trace.SpanKindStatement)) 652 defer span.End() 653 require.NotEqual(t, span.SpanContext().Kind, fspan.SpanContext().Kind) 654 require.Equal(t, span.SpanContext().Kind, trace.SpanKindStatement) 655 656 } 657 658 func TestMOCtledKindPassDown(t *testing.T) { 659 tracer := &MOTracer{ 660 TracerConfig: trace.TracerConfig{Name: "motrace_test"}, 661 provider: defaultMOTracerProvider(), 662 } 663 tracer.provider.enable = true 664 665 trace.InitMOCtledSpan() 666 trace.SetMoCtledSpanState("s3", true, 0) 667 specialCtx, specialSpan := tracer.Start(context.Background(), "special span", 668 trace.WithKind(trace.SpanKindRemoteFSVis)) 669 defer specialSpan.End() 670 require.Equal(t, specialSpan.SpanContext().Kind, trace.SpanKindRemoteFSVis) 671 672 // won't pass down kind to child 673 _, span := tracer.Start(specialCtx, "child span") 674 defer span.End() 675 require.NotEqual(t, span.SpanContext().Kind, specialSpan.SpanContext().Kind) 676 677 }