Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.
 
 
 

898 строки
24 KiB

  1. // Copyright 2017, OpenCensus 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. package trace
  15. import (
  16. "context"
  17. "fmt"
  18. "reflect"
  19. "sync/atomic"
  20. "testing"
  21. "time"
  22. "go.opencensus.io/trace/tracestate"
  23. )
  24. var (
  25. tid = TraceID{1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 4, 8, 16, 32, 64, 128}
  26. sid = SpanID{1, 2, 4, 8, 16, 32, 64, 128}
  27. testTracestate, _ = tracestate.New(nil, tracestate.Entry{Key: "foo", Value: "bar"})
  28. )
  29. func init() {
  30. // no random sampling, but sample children of sampled spans.
  31. ApplyConfig(Config{DefaultSampler: ProbabilitySampler(0)})
  32. }
  33. func TestStrings(t *testing.T) {
  34. if got, want := tid.String(), "01020304050607080102040810204080"; got != want {
  35. t.Errorf("TraceID.String: got %q want %q", got, want)
  36. }
  37. if got, want := sid.String(), "0102040810204080"; got != want {
  38. t.Errorf("SpanID.String: got %q want %q", got, want)
  39. }
  40. }
  41. func TestFromContext(t *testing.T) {
  42. want := &Span{}
  43. ctx := NewContext(context.Background(), want)
  44. got := FromContext(ctx)
  45. if got != want {
  46. t.Errorf("got Span pointer %p want %p", got, want)
  47. }
  48. }
  49. type foo int
  50. func (f foo) String() string {
  51. return "foo"
  52. }
  53. // checkChild tests that c has fields set appropriately, given that it is a child span of p.
  54. func checkChild(p SpanContext, c *Span) error {
  55. if c == nil {
  56. return fmt.Errorf("got nil child span, want non-nil")
  57. }
  58. if got, want := c.spanContext.TraceID, p.TraceID; got != want {
  59. return fmt.Errorf("got child trace ID %s, want %s", got, want)
  60. }
  61. if childID, parentID := c.spanContext.SpanID, p.SpanID; childID == parentID {
  62. return fmt.Errorf("got child span ID %s, parent span ID %s; want unequal IDs", childID, parentID)
  63. }
  64. if got, want := c.spanContext.TraceOptions, p.TraceOptions; got != want {
  65. return fmt.Errorf("got child trace options %d, want %d", got, want)
  66. }
  67. if got, want := c.spanContext.Tracestate, p.Tracestate; got != want {
  68. return fmt.Errorf("got child tracestate %v, want %v", got, want)
  69. }
  70. return nil
  71. }
  72. func TestStartSpan(t *testing.T) {
  73. ctx, _ := StartSpan(context.Background(), "StartSpan")
  74. if FromContext(ctx).data != nil {
  75. t.Error("StartSpan: new span is recording events")
  76. }
  77. }
  78. func TestSampling(t *testing.T) {
  79. for _, test := range []struct {
  80. remoteParent bool
  81. localParent bool
  82. parentTraceOptions TraceOptions
  83. sampler Sampler
  84. wantTraceOptions TraceOptions
  85. }{
  86. {true, false, 0, nil, 0},
  87. {true, false, 1, nil, 1},
  88. {true, false, 0, NeverSample(), 0},
  89. {true, false, 1, NeverSample(), 0},
  90. {true, false, 0, AlwaysSample(), 1},
  91. {true, false, 1, AlwaysSample(), 1},
  92. {false, true, 0, NeverSample(), 0},
  93. {false, true, 1, NeverSample(), 0},
  94. {false, true, 0, AlwaysSample(), 1},
  95. {false, true, 1, AlwaysSample(), 1},
  96. {false, false, 0, nil, 0},
  97. {false, false, 0, NeverSample(), 0},
  98. {false, false, 0, AlwaysSample(), 1},
  99. } {
  100. var ctx context.Context
  101. if test.remoteParent {
  102. sc := SpanContext{
  103. TraceID: tid,
  104. SpanID: sid,
  105. TraceOptions: test.parentTraceOptions,
  106. }
  107. ctx, _ = StartSpanWithRemoteParent(context.Background(), "foo", sc, WithSampler(test.sampler))
  108. } else if test.localParent {
  109. sampler := NeverSample()
  110. if test.parentTraceOptions == 1 {
  111. sampler = AlwaysSample()
  112. }
  113. ctx2, _ := StartSpan(context.Background(), "foo", WithSampler(sampler))
  114. ctx, _ = StartSpan(ctx2, "foo", WithSampler(test.sampler))
  115. } else {
  116. ctx, _ = StartSpan(context.Background(), "foo", WithSampler(test.sampler))
  117. }
  118. sc := FromContext(ctx).SpanContext()
  119. if (sc == SpanContext{}) {
  120. t.Errorf("case %#v: starting new span: no span in context", test)
  121. continue
  122. }
  123. if sc.SpanID == (SpanID{}) {
  124. t.Errorf("case %#v: starting new span: got zero SpanID, want nonzero", test)
  125. }
  126. if sc.TraceOptions != test.wantTraceOptions {
  127. t.Errorf("case %#v: starting new span: got TraceOptions %x, want %x", test, sc.TraceOptions, test.wantTraceOptions)
  128. }
  129. }
  130. // Test that for children of local spans, the default sampler has no effect.
  131. for _, test := range []struct {
  132. parentTraceOptions TraceOptions
  133. wantTraceOptions TraceOptions
  134. }{
  135. {0, 0},
  136. {0, 0},
  137. {1, 1},
  138. {1, 1},
  139. } {
  140. for _, defaultSampler := range []Sampler{
  141. NeverSample(),
  142. AlwaysSample(),
  143. ProbabilitySampler(0),
  144. } {
  145. ApplyConfig(Config{DefaultSampler: defaultSampler})
  146. sampler := NeverSample()
  147. if test.parentTraceOptions == 1 {
  148. sampler = AlwaysSample()
  149. }
  150. ctx2, _ := StartSpan(context.Background(), "foo", WithSampler(sampler))
  151. ctx, _ := StartSpan(ctx2, "foo")
  152. sc := FromContext(ctx).SpanContext()
  153. if (sc == SpanContext{}) {
  154. t.Errorf("case %#v: starting new child of local span: no span in context", test)
  155. continue
  156. }
  157. if sc.SpanID == (SpanID{}) {
  158. t.Errorf("case %#v: starting new child of local span: got zero SpanID, want nonzero", test)
  159. }
  160. if sc.TraceOptions != test.wantTraceOptions {
  161. t.Errorf("case %#v: starting new child of local span: got TraceOptions %x, want %x", test, sc.TraceOptions, test.wantTraceOptions)
  162. }
  163. }
  164. }
  165. ApplyConfig(Config{DefaultSampler: ProbabilitySampler(0)}) // reset the default sampler.
  166. }
  167. func TestProbabilitySampler(t *testing.T) {
  168. exported := 0
  169. for i := 0; i < 1000; i++ {
  170. _, span := StartSpan(context.Background(), "foo", WithSampler(ProbabilitySampler(0.3)))
  171. if span.SpanContext().IsSampled() {
  172. exported++
  173. }
  174. }
  175. if exported < 200 || exported > 400 {
  176. t.Errorf("got %f%% exported spans, want approximately 30%%", float64(exported)*0.1)
  177. }
  178. }
  179. func TestStartSpanWithRemoteParent(t *testing.T) {
  180. sc := SpanContext{
  181. TraceID: tid,
  182. SpanID: sid,
  183. TraceOptions: 0x0,
  184. }
  185. ctx, _ := StartSpanWithRemoteParent(context.Background(), "startSpanWithRemoteParent", sc)
  186. if err := checkChild(sc, FromContext(ctx)); err != nil {
  187. t.Error(err)
  188. }
  189. ctx, _ = StartSpanWithRemoteParent(context.Background(), "startSpanWithRemoteParent", sc)
  190. if err := checkChild(sc, FromContext(ctx)); err != nil {
  191. t.Error(err)
  192. }
  193. sc = SpanContext{
  194. TraceID: tid,
  195. SpanID: sid,
  196. TraceOptions: 0x1,
  197. Tracestate: testTracestate,
  198. }
  199. ctx, _ = StartSpanWithRemoteParent(context.Background(), "startSpanWithRemoteParent", sc)
  200. if err := checkChild(sc, FromContext(ctx)); err != nil {
  201. t.Error(err)
  202. }
  203. ctx, _ = StartSpanWithRemoteParent(context.Background(), "startSpanWithRemoteParent", sc)
  204. if err := checkChild(sc, FromContext(ctx)); err != nil {
  205. t.Error(err)
  206. }
  207. ctx2, _ := StartSpan(ctx, "StartSpan")
  208. parent := FromContext(ctx).SpanContext()
  209. if err := checkChild(parent, FromContext(ctx2)); err != nil {
  210. t.Error(err)
  211. }
  212. }
  213. // startSpan returns a context with a new Span that is recording events and will be exported.
  214. func startSpan(o StartOptions) *Span {
  215. _, span := StartSpanWithRemoteParent(context.Background(), "span0",
  216. SpanContext{
  217. TraceID: tid,
  218. SpanID: sid,
  219. TraceOptions: 1,
  220. },
  221. WithSampler(o.Sampler),
  222. WithSpanKind(o.SpanKind),
  223. )
  224. return span
  225. }
  226. type testExporter struct {
  227. spans []*SpanData
  228. }
  229. func (t *testExporter) ExportSpan(s *SpanData) {
  230. t.spans = append(t.spans, s)
  231. }
  232. // endSpan ends the Span in the context and returns the exported SpanData.
  233. //
  234. // It also does some tests on the Span, and tests and clears some fields in the SpanData.
  235. func endSpan(span *Span) (*SpanData, error) {
  236. if !span.IsRecordingEvents() {
  237. return nil, fmt.Errorf("IsRecordingEvents: got false, want true")
  238. }
  239. if !span.SpanContext().IsSampled() {
  240. return nil, fmt.Errorf("IsSampled: got false, want true")
  241. }
  242. var te testExporter
  243. RegisterExporter(&te)
  244. span.End()
  245. UnregisterExporter(&te)
  246. if len(te.spans) != 1 {
  247. return nil, fmt.Errorf("got exported spans %#v, want one span", te.spans)
  248. }
  249. got := te.spans[0]
  250. if got.SpanContext.SpanID == (SpanID{}) {
  251. return nil, fmt.Errorf("exporting span: expected nonzero SpanID")
  252. }
  253. got.SpanContext.SpanID = SpanID{}
  254. if !checkTime(&got.StartTime) {
  255. return nil, fmt.Errorf("exporting span: expected nonzero StartTime")
  256. }
  257. if !checkTime(&got.EndTime) {
  258. return nil, fmt.Errorf("exporting span: expected nonzero EndTime")
  259. }
  260. return got, nil
  261. }
  262. // checkTime checks that a nonzero time was set in x, then clears it.
  263. func checkTime(x *time.Time) bool {
  264. if x.IsZero() {
  265. return false
  266. }
  267. *x = time.Time{}
  268. return true
  269. }
  270. func TestSpanKind(t *testing.T) {
  271. tests := []struct {
  272. name string
  273. startOptions StartOptions
  274. want *SpanData
  275. }{
  276. {
  277. name: "zero StartOptions",
  278. startOptions: StartOptions{},
  279. want: &SpanData{
  280. SpanContext: SpanContext{
  281. TraceID: tid,
  282. SpanID: SpanID{},
  283. TraceOptions: 0x1,
  284. },
  285. ParentSpanID: sid,
  286. Name: "span0",
  287. SpanKind: SpanKindUnspecified,
  288. HasRemoteParent: true,
  289. },
  290. },
  291. {
  292. name: "client span",
  293. startOptions: StartOptions{
  294. SpanKind: SpanKindClient,
  295. },
  296. want: &SpanData{
  297. SpanContext: SpanContext{
  298. TraceID: tid,
  299. SpanID: SpanID{},
  300. TraceOptions: 0x1,
  301. },
  302. ParentSpanID: sid,
  303. Name: "span0",
  304. SpanKind: SpanKindClient,
  305. HasRemoteParent: true,
  306. },
  307. },
  308. {
  309. name: "server span",
  310. startOptions: StartOptions{
  311. SpanKind: SpanKindServer,
  312. },
  313. want: &SpanData{
  314. SpanContext: SpanContext{
  315. TraceID: tid,
  316. SpanID: SpanID{},
  317. TraceOptions: 0x1,
  318. },
  319. ParentSpanID: sid,
  320. Name: "span0",
  321. SpanKind: SpanKindServer,
  322. HasRemoteParent: true,
  323. },
  324. },
  325. }
  326. for _, tt := range tests {
  327. span := startSpan(tt.startOptions)
  328. got, err := endSpan(span)
  329. if err != nil {
  330. t.Fatal(err)
  331. }
  332. if !reflect.DeepEqual(got, tt.want) {
  333. t.Errorf("exporting span: got %#v want %#v", got, tt.want)
  334. }
  335. }
  336. }
  337. func TestSetSpanAttributes(t *testing.T) {
  338. span := startSpan(StartOptions{})
  339. span.AddAttributes(StringAttribute("key1", "value1"))
  340. got, err := endSpan(span)
  341. if err != nil {
  342. t.Fatal(err)
  343. }
  344. want := &SpanData{
  345. SpanContext: SpanContext{
  346. TraceID: tid,
  347. SpanID: SpanID{},
  348. TraceOptions: 0x1,
  349. },
  350. ParentSpanID: sid,
  351. Name: "span0",
  352. Attributes: map[string]interface{}{"key1": "value1"},
  353. HasRemoteParent: true,
  354. }
  355. if !reflect.DeepEqual(got, want) {
  356. t.Errorf("exporting span: got %#v want %#v", got, want)
  357. }
  358. }
  359. func TestSetSpanAttributesOverLimit(t *testing.T) {
  360. cfg := Config{MaxAttributesPerSpan: 2}
  361. ApplyConfig(cfg)
  362. span := startSpan(StartOptions{})
  363. span.AddAttributes(StringAttribute("key1", "value1"))
  364. span.AddAttributes(StringAttribute("key2", "value2"))
  365. span.AddAttributes(StringAttribute("key1", "value3")) // Replace key1.
  366. span.AddAttributes(StringAttribute("key4", "value4")) // Remove key2 and add key4
  367. got, err := endSpan(span)
  368. if err != nil {
  369. t.Fatal(err)
  370. }
  371. want := &SpanData{
  372. SpanContext: SpanContext{
  373. TraceID: tid,
  374. SpanID: SpanID{},
  375. TraceOptions: 0x1,
  376. },
  377. ParentSpanID: sid,
  378. Name: "span0",
  379. Attributes: map[string]interface{}{"key1": "value3", "key4": "value4"},
  380. HasRemoteParent: true,
  381. DroppedAttributeCount: 1,
  382. }
  383. if !reflect.DeepEqual(got, want) {
  384. t.Errorf("exporting span: got %#v want %#v", got, want)
  385. }
  386. }
  387. func TestAnnotations(t *testing.T) {
  388. span := startSpan(StartOptions{})
  389. span.Annotatef([]Attribute{StringAttribute("key1", "value1")}, "%f", 1.5)
  390. span.Annotate([]Attribute{StringAttribute("key2", "value2")}, "Annotate")
  391. got, err := endSpan(span)
  392. if err != nil {
  393. t.Fatal(err)
  394. }
  395. for i := range got.Annotations {
  396. if !checkTime(&got.Annotations[i].Time) {
  397. t.Error("exporting span: expected nonzero Annotation Time")
  398. }
  399. }
  400. want := &SpanData{
  401. SpanContext: SpanContext{
  402. TraceID: tid,
  403. SpanID: SpanID{},
  404. TraceOptions: 0x1,
  405. },
  406. ParentSpanID: sid,
  407. Name: "span0",
  408. Annotations: []Annotation{
  409. {Message: "1.500000", Attributes: map[string]interface{}{"key1": "value1"}},
  410. {Message: "Annotate", Attributes: map[string]interface{}{"key2": "value2"}},
  411. },
  412. HasRemoteParent: true,
  413. }
  414. if !reflect.DeepEqual(got, want) {
  415. t.Errorf("exporting span: got %#v want %#v", got, want)
  416. }
  417. }
  418. func TestAnnotationsOverLimit(t *testing.T) {
  419. cfg := Config{MaxAnnotationEventsPerSpan: 2}
  420. ApplyConfig(cfg)
  421. span := startSpan(StartOptions{})
  422. span.Annotatef([]Attribute{StringAttribute("key4", "value4")}, "%d", 1)
  423. span.Annotate([]Attribute{StringAttribute("key3", "value3")}, "Annotate oldest")
  424. span.Annotatef([]Attribute{StringAttribute("key1", "value1")}, "%f", 1.5)
  425. span.Annotate([]Attribute{StringAttribute("key2", "value2")}, "Annotate")
  426. got, err := endSpan(span)
  427. if err != nil {
  428. t.Fatal(err)
  429. }
  430. for i := range got.Annotations {
  431. if !checkTime(&got.Annotations[i].Time) {
  432. t.Error("exporting span: expected nonzero Annotation Time")
  433. }
  434. }
  435. want := &SpanData{
  436. SpanContext: SpanContext{
  437. TraceID: tid,
  438. SpanID: SpanID{},
  439. TraceOptions: 0x1,
  440. },
  441. ParentSpanID: sid,
  442. Name: "span0",
  443. Annotations: []Annotation{
  444. {Message: "1.500000", Attributes: map[string]interface{}{"key1": "value1"}},
  445. {Message: "Annotate", Attributes: map[string]interface{}{"key2": "value2"}},
  446. },
  447. DroppedAnnotationCount: 2,
  448. HasRemoteParent: true,
  449. }
  450. if !reflect.DeepEqual(got, want) {
  451. t.Errorf("exporting span: got %#v want %#v", got, want)
  452. }
  453. }
  454. func TestMessageEvents(t *testing.T) {
  455. span := startSpan(StartOptions{})
  456. span.AddMessageReceiveEvent(3, 400, 300)
  457. span.AddMessageSendEvent(1, 200, 100)
  458. got, err := endSpan(span)
  459. if err != nil {
  460. t.Fatal(err)
  461. }
  462. for i := range got.MessageEvents {
  463. if !checkTime(&got.MessageEvents[i].Time) {
  464. t.Error("exporting span: expected nonzero MessageEvent Time")
  465. }
  466. }
  467. want := &SpanData{
  468. SpanContext: SpanContext{
  469. TraceID: tid,
  470. SpanID: SpanID{},
  471. TraceOptions: 0x1,
  472. },
  473. ParentSpanID: sid,
  474. Name: "span0",
  475. MessageEvents: []MessageEvent{
  476. {EventType: 2, MessageID: 0x3, UncompressedByteSize: 0x190, CompressedByteSize: 0x12c},
  477. {EventType: 1, MessageID: 0x1, UncompressedByteSize: 0xc8, CompressedByteSize: 0x64},
  478. },
  479. HasRemoteParent: true,
  480. }
  481. if !reflect.DeepEqual(got, want) {
  482. t.Errorf("exporting span: got %#v want %#v", got, want)
  483. }
  484. }
  485. func TestMessageEventsOverLimit(t *testing.T) {
  486. cfg := Config{MaxMessageEventsPerSpan: 2}
  487. ApplyConfig(cfg)
  488. span := startSpan(StartOptions{})
  489. span.AddMessageReceiveEvent(5, 300, 120)
  490. span.AddMessageSendEvent(4, 100, 50)
  491. span.AddMessageReceiveEvent(3, 400, 300)
  492. span.AddMessageSendEvent(1, 200, 100)
  493. got, err := endSpan(span)
  494. if err != nil {
  495. t.Fatal(err)
  496. }
  497. for i := range got.MessageEvents {
  498. if !checkTime(&got.MessageEvents[i].Time) {
  499. t.Error("exporting span: expected nonzero MessageEvent Time")
  500. }
  501. }
  502. want := &SpanData{
  503. SpanContext: SpanContext{
  504. TraceID: tid,
  505. SpanID: SpanID{},
  506. TraceOptions: 0x1,
  507. },
  508. ParentSpanID: sid,
  509. Name: "span0",
  510. MessageEvents: []MessageEvent{
  511. {EventType: 2, MessageID: 0x3, UncompressedByteSize: 0x190, CompressedByteSize: 0x12c},
  512. {EventType: 1, MessageID: 0x1, UncompressedByteSize: 0xc8, CompressedByteSize: 0x64},
  513. },
  514. DroppedMessageEventCount: 2,
  515. HasRemoteParent: true,
  516. }
  517. if !reflect.DeepEqual(got, want) {
  518. t.Errorf("exporting span: got %#v want %#v", got, want)
  519. }
  520. }
  521. func TestSetSpanName(t *testing.T) {
  522. want := "SpanName-1"
  523. span := startSpan(StartOptions{})
  524. span.SetName(want)
  525. got, err := endSpan(span)
  526. if err != nil {
  527. t.Fatal(err)
  528. }
  529. if got.Name != want {
  530. t.Errorf("span.Name=%q; want %q", got.Name, want)
  531. }
  532. }
  533. func TestSetSpanNameUnsampledSpan(t *testing.T) {
  534. var nilSpanData *SpanData
  535. span := startSpan(StartOptions{Sampler: NeverSample()})
  536. span.SetName("NoopName")
  537. if want, got := nilSpanData, span.data; want != got {
  538. t.Errorf("span.data=%+v; want %+v", got, want)
  539. }
  540. }
  541. func TestSetSpanNameAfterSpanEnd(t *testing.T) {
  542. want := "SpanName-2"
  543. span := startSpan(StartOptions{})
  544. span.SetName(want)
  545. got, err := endSpan(span)
  546. if err != nil {
  547. t.Fatal(err)
  548. }
  549. // updating name after span.End
  550. span.SetName("NoopName")
  551. // exported span should not be updated by previous call to SetName
  552. if got.Name != want {
  553. t.Errorf("span.Name=%q; want %q", got.Name, want)
  554. }
  555. // span should not be exported again
  556. var te testExporter
  557. RegisterExporter(&te)
  558. span.End()
  559. UnregisterExporter(&te)
  560. if len(te.spans) != 0 {
  561. t.Errorf("got exported spans %#v, wanted no spans", te.spans)
  562. }
  563. }
  564. func TestSetSpanStatus(t *testing.T) {
  565. span := startSpan(StartOptions{})
  566. span.SetStatus(Status{Code: int32(1), Message: "request failed"})
  567. got, err := endSpan(span)
  568. if err != nil {
  569. t.Fatal(err)
  570. }
  571. want := &SpanData{
  572. SpanContext: SpanContext{
  573. TraceID: tid,
  574. SpanID: SpanID{},
  575. TraceOptions: 0x1,
  576. },
  577. ParentSpanID: sid,
  578. Name: "span0",
  579. Status: Status{Code: 1, Message: "request failed"},
  580. HasRemoteParent: true,
  581. }
  582. if !reflect.DeepEqual(got, want) {
  583. t.Errorf("exporting span: got %#v want %#v", got, want)
  584. }
  585. }
  586. func TestAddLink(t *testing.T) {
  587. span := startSpan(StartOptions{})
  588. span.AddLink(Link{
  589. TraceID: tid,
  590. SpanID: sid,
  591. Type: LinkTypeParent,
  592. Attributes: map[string]interface{}{"key5": "value5"},
  593. })
  594. got, err := endSpan(span)
  595. if err != nil {
  596. t.Fatal(err)
  597. }
  598. want := &SpanData{
  599. SpanContext: SpanContext{
  600. TraceID: tid,
  601. SpanID: SpanID{},
  602. TraceOptions: 0x1,
  603. },
  604. ParentSpanID: sid,
  605. Name: "span0",
  606. Links: []Link{{
  607. TraceID: tid,
  608. SpanID: sid,
  609. Type: 2,
  610. Attributes: map[string]interface{}{"key5": "value5"},
  611. }},
  612. HasRemoteParent: true,
  613. }
  614. if !reflect.DeepEqual(got, want) {
  615. t.Errorf("exporting span: got %#v want %#v", got, want)
  616. }
  617. }
  618. func TestAddLinkOverLimit(t *testing.T) {
  619. cfg := Config{MaxLinksPerSpan: 1}
  620. ApplyConfig(cfg)
  621. span := startSpan(StartOptions{})
  622. span.AddLink(Link{
  623. TraceID: tid,
  624. SpanID: sid,
  625. Type: LinkTypeParent,
  626. Attributes: map[string]interface{}{"key4": "value4"},
  627. })
  628. span.AddLink(Link{
  629. TraceID: tid,
  630. SpanID: sid,
  631. Type: LinkTypeParent,
  632. Attributes: map[string]interface{}{"key5": "value5"},
  633. })
  634. got, err := endSpan(span)
  635. if err != nil {
  636. t.Fatal(err)
  637. }
  638. want := &SpanData{
  639. SpanContext: SpanContext{
  640. TraceID: tid,
  641. SpanID: SpanID{},
  642. TraceOptions: 0x1,
  643. },
  644. ParentSpanID: sid,
  645. Name: "span0",
  646. Links: []Link{{
  647. TraceID: tid,
  648. SpanID: sid,
  649. Type: 2,
  650. Attributes: map[string]interface{}{"key5": "value5"},
  651. }},
  652. DroppedLinkCount: 1,
  653. HasRemoteParent: true,
  654. }
  655. if !reflect.DeepEqual(got, want) {
  656. t.Errorf("exporting span: got %#v want %#v", got, want)
  657. }
  658. }
  659. func TestUnregisterExporter(t *testing.T) {
  660. var te testExporter
  661. RegisterExporter(&te)
  662. UnregisterExporter(&te)
  663. ctx := startSpan(StartOptions{})
  664. endSpan(ctx)
  665. if len(te.spans) != 0 {
  666. t.Error("unregistered Exporter was called")
  667. }
  668. }
  669. func TestBucket(t *testing.T) {
  670. // make a bucket of size 5 and add 10 spans
  671. b := makeBucket(5)
  672. for i := 1; i <= 10; i++ {
  673. b.nextTime = time.Time{} // reset the time so that the next span is accepted.
  674. // add a span, with i stored in the TraceID so we can test for it later.
  675. b.add(&SpanData{SpanContext: SpanContext{TraceID: TraceID{byte(i)}}, EndTime: time.Now()})
  676. if i <= 5 {
  677. if b.size() != i {
  678. t.Fatalf("got bucket size %d, want %d %#v\n", b.size(), i, b)
  679. }
  680. for j := 0; j < i; j++ {
  681. if b.span(j).TraceID[0] != byte(j+1) {
  682. t.Errorf("got span index %d, want %d\n", b.span(j).TraceID[0], j+1)
  683. }
  684. }
  685. } else {
  686. if b.size() != 5 {
  687. t.Fatalf("got bucket size %d, want 5\n", b.size())
  688. }
  689. for j := 0; j < 5; j++ {
  690. want := i - 4 + j
  691. if b.span(j).TraceID[0] != byte(want) {
  692. t.Errorf("got span index %d, want %d\n", b.span(j).TraceID[0], want)
  693. }
  694. }
  695. }
  696. }
  697. // expand the bucket
  698. b.resize(20)
  699. if b.size() != 5 {
  700. t.Fatalf("after resizing upwards: got bucket size %d, want 5\n", b.size())
  701. }
  702. for i := 0; i < 5; i++ {
  703. want := 6 + i
  704. if b.span(i).TraceID[0] != byte(want) {
  705. t.Errorf("after resizing upwards: got span index %d, want %d\n", b.span(i).TraceID[0], want)
  706. }
  707. }
  708. // shrink the bucket
  709. b.resize(3)
  710. if b.size() != 3 {
  711. t.Fatalf("after resizing downwards: got bucket size %d, want 3\n", b.size())
  712. }
  713. for i := 0; i < 3; i++ {
  714. want := 8 + i
  715. if b.span(i).TraceID[0] != byte(want) {
  716. t.Errorf("after resizing downwards: got span index %d, want %d\n", b.span(i).TraceID[0], want)
  717. }
  718. }
  719. }
  720. type exporter map[string]*SpanData
  721. func (e exporter) ExportSpan(s *SpanData) {
  722. e[s.Name] = s
  723. }
  724. func Test_Issue328_EndSpanTwice(t *testing.T) {
  725. spans := make(exporter)
  726. RegisterExporter(&spans)
  727. defer UnregisterExporter(&spans)
  728. ctx := context.Background()
  729. ctx, span := StartSpan(ctx, "span-1", WithSampler(AlwaysSample()))
  730. span.End()
  731. span.End()
  732. UnregisterExporter(&spans)
  733. if len(spans) != 1 {
  734. t.Fatalf("expected only a single span, got %#v", spans)
  735. }
  736. }
  737. func TestStartSpanAfterEnd(t *testing.T) {
  738. spans := make(exporter)
  739. RegisterExporter(&spans)
  740. defer UnregisterExporter(&spans)
  741. ctx, span0 := StartSpan(context.Background(), "parent", WithSampler(AlwaysSample()))
  742. ctx1, span1 := StartSpan(ctx, "span-1", WithSampler(AlwaysSample()))
  743. span1.End()
  744. // Start a new span with the context containing span-1
  745. // even though span-1 is ended, we still add this as a new child of span-1
  746. _, span2 := StartSpan(ctx1, "span-2", WithSampler(AlwaysSample()))
  747. span2.End()
  748. span0.End()
  749. UnregisterExporter(&spans)
  750. if got, want := len(spans), 3; got != want {
  751. t.Fatalf("len(%#v) = %d; want %d", spans, got, want)
  752. }
  753. if got, want := spans["span-1"].TraceID, spans["parent"].TraceID; got != want {
  754. t.Errorf("span-1.TraceID=%q; want %q", got, want)
  755. }
  756. if got, want := spans["span-2"].TraceID, spans["parent"].TraceID; got != want {
  757. t.Errorf("span-2.TraceID=%q; want %q", got, want)
  758. }
  759. if got, want := spans["span-1"].ParentSpanID, spans["parent"].SpanID; got != want {
  760. t.Errorf("span-1.ParentSpanID=%q; want %q (parent.SpanID)", got, want)
  761. }
  762. if got, want := spans["span-2"].ParentSpanID, spans["span-1"].SpanID; got != want {
  763. t.Errorf("span-2.ParentSpanID=%q; want %q (span1.SpanID)", got, want)
  764. }
  765. }
  766. func TestChildSpanCount(t *testing.T) {
  767. spans := make(exporter)
  768. RegisterExporter(&spans)
  769. defer UnregisterExporter(&spans)
  770. ctx, span0 := StartSpan(context.Background(), "parent", WithSampler(AlwaysSample()))
  771. ctx1, span1 := StartSpan(ctx, "span-1", WithSampler(AlwaysSample()))
  772. _, span2 := StartSpan(ctx1, "span-2", WithSampler(AlwaysSample()))
  773. span2.End()
  774. span1.End()
  775. _, span3 := StartSpan(ctx, "span-3", WithSampler(AlwaysSample()))
  776. span3.End()
  777. span0.End()
  778. UnregisterExporter(&spans)
  779. if got, want := len(spans), 4; got != want {
  780. t.Fatalf("len(%#v) = %d; want %d", spans, got, want)
  781. }
  782. if got, want := spans["span-3"].ChildSpanCount, 0; got != want {
  783. t.Errorf("span-3.ChildSpanCount=%q; want %q", got, want)
  784. }
  785. if got, want := spans["span-2"].ChildSpanCount, 0; got != want {
  786. t.Errorf("span-2.ChildSpanCount=%q; want %q", got, want)
  787. }
  788. if got, want := spans["span-1"].ChildSpanCount, 1; got != want {
  789. t.Errorf("span-1.ChildSpanCount=%q; want %q", got, want)
  790. }
  791. if got, want := spans["parent"].ChildSpanCount, 2; got != want {
  792. t.Errorf("parent.ChildSpanCount=%q; want %q", got, want)
  793. }
  794. }
  795. func TestNilSpanEnd(t *testing.T) {
  796. var span *Span
  797. span.End()
  798. }
  799. func TestExecutionTracerTaskEnd(t *testing.T) {
  800. var n uint64
  801. executionTracerTaskEnd := func() {
  802. atomic.AddUint64(&n, 1)
  803. }
  804. var spans []*Span
  805. _, span := StartSpan(context.Background(), "foo", WithSampler(NeverSample()))
  806. span.executionTracerTaskEnd = executionTracerTaskEnd
  807. spans = append(spans, span) // never sample
  808. _, span = StartSpanWithRemoteParent(context.Background(), "foo", SpanContext{
  809. TraceID: TraceID{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
  810. SpanID: SpanID{0, 1, 2, 3, 4, 5, 6, 7},
  811. TraceOptions: 0,
  812. })
  813. span.executionTracerTaskEnd = executionTracerTaskEnd
  814. spans = append(spans, span) // parent not sampled
  815. _, span = StartSpan(context.Background(), "foo", WithSampler(AlwaysSample()))
  816. span.executionTracerTaskEnd = executionTracerTaskEnd
  817. spans = append(spans, span) // always sample
  818. for _, span := range spans {
  819. span.End()
  820. }
  821. if got, want := n, uint64(len(spans)); got != want {
  822. t.Fatalf("Execution tracer task ended for %v spans; want %v", got, want)
  823. }
  824. }