jaegerproto_to_traces_test.go 28 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088
  1. // Copyright The OpenTelemetry Authors
  2. // SPDX-License-Identifier: Apache-2.0
  3. package jaeger
  4. import (
  5. "encoding/binary"
  6. "strconv"
  7. "testing"
  8. "time"
  9. "github.com/jaegertracing/jaeger/model"
  10. "github.com/stretchr/testify/assert"
  11. "github.com/stretchr/testify/require"
  12. "go.opentelemetry.io/collector/pdata/pcommon"
  13. "go.opentelemetry.io/collector/pdata/ptrace"
  14. conventions "go.opentelemetry.io/collector/semconv/v1.9.0"
  15. "github.com/open-telemetry/opentelemetry-collector-contrib/internal/coreinternal/idutils"
  16. "github.com/open-telemetry/opentelemetry-collector-contrib/internal/coreinternal/testdata"
  17. "github.com/open-telemetry/opentelemetry-collector-contrib/internal/coreinternal/tracetranslator"
  18. )
  19. // Use timespamp with microsecond granularity to work well with jaeger thrift translation
  20. var (
  21. testSpanStartTime = time.Date(2020, 2, 11, 20, 26, 12, 321000, time.UTC)
  22. testSpanStartTimestamp = pcommon.NewTimestampFromTime(testSpanStartTime)
  23. testSpanEventTime = time.Date(2020, 2, 11, 20, 26, 13, 123000, time.UTC)
  24. testSpanEventTimestamp = pcommon.NewTimestampFromTime(testSpanEventTime)
  25. testSpanEndTime = time.Date(2020, 2, 11, 20, 26, 13, 789000, time.UTC)
  26. testSpanEndTimestamp = pcommon.NewTimestampFromTime(testSpanEndTime)
  27. )
  28. func TestCodeFromAttr(t *testing.T) {
  29. tests := []struct {
  30. name string
  31. attr pcommon.Value
  32. code int64
  33. err error
  34. }{
  35. {
  36. name: "ok-string",
  37. attr: pcommon.NewValueStr("0"),
  38. code: 0,
  39. },
  40. {
  41. name: "ok-int",
  42. attr: pcommon.NewValueInt(1),
  43. code: 1,
  44. },
  45. {
  46. name: "wrong-type",
  47. attr: pcommon.NewValueBool(true),
  48. code: 0,
  49. err: errType,
  50. },
  51. {
  52. name: "invalid-string",
  53. attr: pcommon.NewValueStr("inf"),
  54. code: 0,
  55. err: strconv.ErrSyntax,
  56. },
  57. }
  58. for _, test := range tests {
  59. t.Run(test.name, func(t *testing.T) {
  60. code, err := codeFromAttr(test.attr)
  61. if test.err != nil {
  62. assert.ErrorIs(t, err, test.err)
  63. } else {
  64. assert.NoError(t, err)
  65. }
  66. assert.Equal(t, test.code, code)
  67. })
  68. }
  69. }
  70. func TestGetStatusCodeFromHTTPStatusAttr(t *testing.T) {
  71. tests := []struct {
  72. name string
  73. attr pcommon.Value
  74. kind ptrace.SpanKind
  75. code ptrace.StatusCode
  76. }{
  77. {
  78. name: "string-unknown",
  79. attr: pcommon.NewValueStr("10"),
  80. kind: ptrace.SpanKindClient,
  81. code: ptrace.StatusCodeError,
  82. },
  83. {
  84. name: "string-ok",
  85. attr: pcommon.NewValueStr("101"),
  86. kind: ptrace.SpanKindClient,
  87. code: ptrace.StatusCodeUnset,
  88. },
  89. {
  90. name: "int-not-found",
  91. attr: pcommon.NewValueInt(404),
  92. kind: ptrace.SpanKindClient,
  93. code: ptrace.StatusCodeError,
  94. },
  95. {
  96. name: "int-not-found-client-span",
  97. attr: pcommon.NewValueInt(404),
  98. kind: ptrace.SpanKindServer,
  99. code: ptrace.StatusCodeUnset,
  100. },
  101. {
  102. name: "int-invalid-arg",
  103. attr: pcommon.NewValueInt(408),
  104. kind: ptrace.SpanKindClient,
  105. code: ptrace.StatusCodeError,
  106. },
  107. {
  108. name: "int-internal",
  109. attr: pcommon.NewValueInt(500),
  110. kind: ptrace.SpanKindClient,
  111. code: ptrace.StatusCodeError,
  112. },
  113. }
  114. for _, test := range tests {
  115. t.Run(test.name, func(t *testing.T) {
  116. code, err := getStatusCodeFromHTTPStatusAttr(test.attr, test.kind)
  117. assert.NoError(t, err)
  118. assert.Equal(t, test.code, code)
  119. })
  120. }
  121. }
  122. func TestJTagsToInternalAttributes(t *testing.T) {
  123. tags := []model.KeyValue{
  124. {
  125. Key: "bool-val",
  126. VType: model.ValueType_BOOL,
  127. VBool: true,
  128. },
  129. {
  130. Key: "int-val",
  131. VType: model.ValueType_INT64,
  132. VInt64: 123,
  133. },
  134. {
  135. Key: "string-val",
  136. VType: model.ValueType_STRING,
  137. VStr: "abc",
  138. },
  139. {
  140. Key: "double-val",
  141. VType: model.ValueType_FLOAT64,
  142. VFloat64: 1.23,
  143. },
  144. {
  145. Key: "binary-val",
  146. VType: model.ValueType_BINARY,
  147. VBinary: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x7D, 0x98},
  148. },
  149. }
  150. expected := pcommon.NewMap()
  151. expected.PutBool("bool-val", true)
  152. expected.PutInt("int-val", 123)
  153. expected.PutStr("string-val", "abc")
  154. expected.PutDouble("double-val", 1.23)
  155. expected.PutStr("binary-val", "AAAAAABkfZg=")
  156. got := pcommon.NewMap()
  157. jTagsToInternalAttributes(tags, got)
  158. require.EqualValues(t, expected, got)
  159. }
  160. func TestProtoToTraces(t *testing.T) {
  161. tests := []struct {
  162. name string
  163. jb []*model.Batch
  164. td ptrace.Traces
  165. }{
  166. {
  167. name: "empty",
  168. jb: []*model.Batch{},
  169. td: ptrace.NewTraces(),
  170. },
  171. {
  172. name: "no-spans",
  173. jb: []*model.Batch{
  174. {
  175. Process: generateProtoProcess(),
  176. }},
  177. td: generateTracesResourceOnly(),
  178. },
  179. {
  180. name: "no-resource-attrs",
  181. jb: []*model.Batch{
  182. {
  183. Process: &model.Process{
  184. ServiceName: tracetranslator.ResourceNoServiceName,
  185. },
  186. }},
  187. td: generateTracesResourceOnlyWithNoAttrs(),
  188. },
  189. {
  190. name: "one-span-no-resources",
  191. jb: []*model.Batch{
  192. {
  193. Process: &model.Process{
  194. ServiceName: tracetranslator.ResourceNoServiceName,
  195. },
  196. Spans: []*model.Span{
  197. generateProtoSpanWithTraceState(),
  198. },
  199. }},
  200. td: generateTracesOneSpanNoResourceWithTraceState(),
  201. },
  202. {
  203. name: "two-spans-child-parent",
  204. jb: []*model.Batch{
  205. {
  206. Process: &model.Process{
  207. ServiceName: tracetranslator.ResourceNoServiceName,
  208. },
  209. Spans: []*model.Span{
  210. generateProtoSpan(),
  211. generateProtoChildSpan(),
  212. },
  213. }},
  214. td: generateTracesTwoSpansChildParent(),
  215. },
  216. {
  217. name: "two-spans-with-follower",
  218. jb: []*model.Batch{
  219. {
  220. Process: &model.Process{
  221. ServiceName: tracetranslator.ResourceNoServiceName,
  222. },
  223. Spans: []*model.Span{
  224. generateProtoSpan(),
  225. generateProtoFollowerSpan(),
  226. },
  227. }},
  228. td: generateTracesTwoSpansWithFollower(),
  229. },
  230. {
  231. name: "a-spans-with-two-parent",
  232. jb: []*model.Batch{
  233. {
  234. Process: &model.Process{
  235. ServiceName: tracetranslator.ResourceNoServiceName,
  236. },
  237. Spans: []*model.Span{
  238. generateProtoSpan(),
  239. generateProtoFollowerSpan(),
  240. generateProtoTwoParentsSpan(),
  241. },
  242. }},
  243. td: generateTracesSpanWithTwoParents(),
  244. },
  245. {
  246. name: "no-error-from-server-span-with-4xx-http-code",
  247. jb: []*model.Batch{
  248. {
  249. Process: &model.Process{
  250. ServiceName: tracetranslator.ResourceNoServiceName,
  251. },
  252. Spans: []*model.Span{
  253. {
  254. StartTime: testSpanStartTime,
  255. Duration: testSpanEndTime.Sub(testSpanStartTime),
  256. Tags: []model.KeyValue{
  257. {
  258. Key: tracetranslator.TagSpanKind,
  259. VType: model.ValueType_STRING,
  260. VStr: string(tracetranslator.OpenTracingSpanKindServer),
  261. },
  262. {
  263. Key: conventions.AttributeHTTPStatusCode,
  264. VType: model.ValueType_STRING,
  265. VStr: "404",
  266. },
  267. },
  268. },
  269. },
  270. }},
  271. td: func() ptrace.Traces {
  272. traces := ptrace.NewTraces()
  273. span := traces.ResourceSpans().AppendEmpty().ScopeSpans().AppendEmpty().Spans().AppendEmpty()
  274. span.SetStartTimestamp(testSpanStartTimestamp)
  275. span.SetEndTimestamp(testSpanEndTimestamp)
  276. span.SetKind(ptrace.SpanKindClient)
  277. span.SetKind(ptrace.SpanKindServer)
  278. span.Status().SetCode(ptrace.StatusCodeUnset)
  279. span.Attributes().PutStr(conventions.AttributeHTTPStatusCode, "404")
  280. return traces
  281. }(),
  282. },
  283. }
  284. for _, test := range tests {
  285. t.Run(test.name, func(t *testing.T) {
  286. td, err := ProtoToTraces(test.jb)
  287. assert.NoError(t, err)
  288. assert.EqualValues(t, test.td, td)
  289. })
  290. }
  291. }
  292. func TestProtoBatchToInternalTracesWithTwoLibraries(t *testing.T) {
  293. jb := &model.Batch{
  294. Process: &model.Process{
  295. ServiceName: tracetranslator.ResourceNoServiceName,
  296. },
  297. Spans: []*model.Span{
  298. {
  299. StartTime: testSpanStartTime,
  300. Duration: testSpanEndTime.Sub(testSpanStartTime),
  301. OperationName: "operation2",
  302. Tags: []model.KeyValue{
  303. {
  304. Key: conventions.OtelLibraryName,
  305. VType: model.ValueType_STRING,
  306. VStr: "library2",
  307. }, {
  308. Key: conventions.OtelLibraryVersion,
  309. VType: model.ValueType_STRING,
  310. VStr: "0.42.0",
  311. },
  312. },
  313. },
  314. {
  315. TraceID: model.NewTraceID(0, 0),
  316. StartTime: testSpanStartTime,
  317. Duration: testSpanEndTime.Sub(testSpanStartTime),
  318. OperationName: "operation1",
  319. Tags: []model.KeyValue{
  320. {
  321. Key: conventions.OtelLibraryName,
  322. VType: model.ValueType_STRING,
  323. VStr: "library1",
  324. }, {
  325. Key: conventions.OtelLibraryVersion,
  326. VType: model.ValueType_STRING,
  327. VStr: "0.42.0",
  328. },
  329. },
  330. },
  331. },
  332. }
  333. expected := generateTracesTwoSpansFromTwoLibraries()
  334. library1Span := expected.ResourceSpans().At(0).ScopeSpans().At(0)
  335. library2Span := expected.ResourceSpans().At(0).ScopeSpans().At(1)
  336. actual, err := ProtoToTraces([]*model.Batch{jb})
  337. assert.NoError(t, err)
  338. assert.Equal(t, actual.ResourceSpans().Len(), 1)
  339. assert.Equal(t, actual.ResourceSpans().At(0).ScopeSpans().Len(), 2)
  340. ils0 := actual.ResourceSpans().At(0).ScopeSpans().At(0)
  341. ils1 := actual.ResourceSpans().At(0).ScopeSpans().At(1)
  342. if ils0.Scope().Name() == "library1" {
  343. assert.EqualValues(t, library1Span, ils0)
  344. assert.EqualValues(t, library2Span, ils1)
  345. } else {
  346. assert.EqualValues(t, library1Span, ils1)
  347. assert.EqualValues(t, library2Span, ils0)
  348. }
  349. }
  350. func TestSetInternalSpanStatus(t *testing.T) {
  351. emptyStatus := ptrace.NewStatus()
  352. okStatus := ptrace.NewStatus()
  353. okStatus.SetCode(ptrace.StatusCodeOk)
  354. errorStatus := ptrace.NewStatus()
  355. errorStatus.SetCode(ptrace.StatusCodeError)
  356. errorStatusWithMessage := ptrace.NewStatus()
  357. errorStatusWithMessage.SetCode(ptrace.StatusCodeError)
  358. errorStatusWithMessage.SetMessage("Error: Invalid argument")
  359. errorStatusWith404Message := ptrace.NewStatus()
  360. errorStatusWith404Message.SetCode(ptrace.StatusCodeError)
  361. errorStatusWith404Message.SetMessage("HTTP 404: Not Found")
  362. tests := []struct {
  363. name string
  364. attrs map[string]any
  365. status ptrace.Status
  366. kind ptrace.SpanKind
  367. attrsModifiedLen int // Length of attributes map after dropping converted fields
  368. }{
  369. {
  370. name: "No tags set -> OK status",
  371. status: emptyStatus,
  372. attrsModifiedLen: 0,
  373. },
  374. {
  375. name: "error tag set -> Error status",
  376. attrs: map[string]any{
  377. tracetranslator.TagError: true,
  378. },
  379. status: errorStatus,
  380. attrsModifiedLen: 0,
  381. },
  382. {
  383. name: "status.code is set as string",
  384. attrs: map[string]any{
  385. conventions.OtelStatusCode: statusOk,
  386. },
  387. status: okStatus,
  388. attrsModifiedLen: 0,
  389. },
  390. {
  391. name: "status.code, status.message and error tags are set",
  392. attrs: map[string]any{
  393. tracetranslator.TagError: true,
  394. conventions.OtelStatusCode: statusError,
  395. conventions.OtelStatusDescription: "Error: Invalid argument",
  396. },
  397. status: errorStatusWithMessage,
  398. attrsModifiedLen: 0,
  399. },
  400. {
  401. name: "http.status_code tag is set as string",
  402. attrs: map[string]any{
  403. conventions.AttributeHTTPStatusCode: "404",
  404. },
  405. status: errorStatus,
  406. attrsModifiedLen: 1,
  407. },
  408. {
  409. name: "http.status_code, http.status_message and error tags are set",
  410. attrs: map[string]any{
  411. tracetranslator.TagError: true,
  412. conventions.AttributeHTTPStatusCode: 404,
  413. tracetranslator.TagHTTPStatusMsg: "HTTP 404: Not Found",
  414. },
  415. status: errorStatusWith404Message,
  416. attrsModifiedLen: 2,
  417. },
  418. {
  419. name: "status.code has precedence over http.status_code.",
  420. attrs: map[string]any{
  421. conventions.OtelStatusCode: statusOk,
  422. conventions.AttributeHTTPStatusCode: 500,
  423. tracetranslator.TagHTTPStatusMsg: "Server Error",
  424. },
  425. status: okStatus,
  426. attrsModifiedLen: 2,
  427. },
  428. {
  429. name: "Ignore http.status_code == 200 if error set to true.",
  430. attrs: map[string]any{
  431. tracetranslator.TagError: true,
  432. conventions.AttributeHTTPStatusCode: 200,
  433. },
  434. status: errorStatus,
  435. attrsModifiedLen: 1,
  436. },
  437. {
  438. name: "the 4xx range span status MUST be left unset in case of SpanKind.SERVER",
  439. kind: ptrace.SpanKindServer,
  440. attrs: map[string]any{
  441. tracetranslator.TagError: false,
  442. conventions.AttributeHTTPStatusCode: 404,
  443. },
  444. status: emptyStatus,
  445. attrsModifiedLen: 2,
  446. },
  447. }
  448. for _, test := range tests {
  449. t.Run(test.name, func(t *testing.T) {
  450. span := ptrace.NewSpan()
  451. span.SetKind(test.kind)
  452. status := span.Status()
  453. attrs := pcommon.NewMap()
  454. assert.NoError(t, attrs.FromRaw(test.attrs))
  455. setInternalSpanStatus(attrs, span)
  456. assert.EqualValues(t, test.status, status)
  457. assert.Equal(t, test.attrsModifiedLen, attrs.Len())
  458. })
  459. }
  460. }
  461. func TestProtoBatchesToInternalTraces(t *testing.T) {
  462. batches := []*model.Batch{
  463. {
  464. Process: generateProtoProcess(),
  465. Spans: []*model.Span{
  466. generateProtoSpan(),
  467. },
  468. },
  469. {
  470. Spans: []*model.Span{
  471. generateProtoSpan(),
  472. generateProtoChildSpan(),
  473. },
  474. },
  475. {
  476. // should be skipped
  477. Spans: []*model.Span{},
  478. },
  479. }
  480. expected := generateTracesOneSpanNoResource()
  481. resource := generateTracesResourceOnly().ResourceSpans().At(0).Resource()
  482. resource.CopyTo(expected.ResourceSpans().At(0).Resource())
  483. tgt := expected.ResourceSpans().AppendEmpty()
  484. twoSpans := generateTracesTwoSpansChildParent().ResourceSpans().At(0)
  485. twoSpans.CopyTo(tgt)
  486. got, err := ProtoToTraces(batches)
  487. assert.NoError(t, err)
  488. assert.Equal(t, expected.ResourceSpans().Len(), got.ResourceSpans().Len())
  489. assert.Equal(t, expected.SpanCount(), got.SpanCount())
  490. lenbatches := expected.ResourceSpans().Len()
  491. found := 0
  492. for i := 0; i < lenbatches; i++ {
  493. rsExpected := expected.ResourceSpans().At(i)
  494. for j := 0; j < lenbatches; j++ {
  495. got.ResourceSpans().RemoveIf(func(rs ptrace.ResourceSpans) bool {
  496. nameExpected := rsExpected.ScopeSpans().At(0).Spans().At(0).Name()
  497. nameGot := got.ResourceSpans().At(j).ScopeSpans().At(0).Scope().Name()
  498. if nameExpected == nameGot {
  499. assert.Equal(t, nameGot, found)
  500. assert.Equal(t, got.SpanCount(), found)
  501. }
  502. return nameExpected == nameGot
  503. })
  504. }
  505. }
  506. }
  507. func TestJSpanKindToInternal(t *testing.T) {
  508. tests := []struct {
  509. jSpanKind string
  510. otlpSpanKind ptrace.SpanKind
  511. }{
  512. {
  513. jSpanKind: "client",
  514. otlpSpanKind: ptrace.SpanKindClient,
  515. },
  516. {
  517. jSpanKind: "server",
  518. otlpSpanKind: ptrace.SpanKindServer,
  519. },
  520. {
  521. jSpanKind: "producer",
  522. otlpSpanKind: ptrace.SpanKindProducer,
  523. },
  524. {
  525. jSpanKind: "consumer",
  526. otlpSpanKind: ptrace.SpanKindConsumer,
  527. },
  528. {
  529. jSpanKind: "internal",
  530. otlpSpanKind: ptrace.SpanKindInternal,
  531. },
  532. {
  533. jSpanKind: "all-others",
  534. otlpSpanKind: ptrace.SpanKindUnspecified,
  535. },
  536. }
  537. for _, test := range tests {
  538. t.Run(test.jSpanKind, func(t *testing.T) {
  539. assert.Equal(t, test.otlpSpanKind, jSpanKindToInternal(test.jSpanKind))
  540. })
  541. }
  542. }
  543. func TestRegroup(t *testing.T) {
  544. // prepare
  545. process := &model.Process{
  546. ServiceName: "batch-process",
  547. }
  548. spanWithoutProcess := &model.Span{
  549. OperationName: "span-without-process",
  550. }
  551. spanWithProcess := &model.Span{
  552. Process: &model.Process{
  553. ServiceName: "custom-service-name",
  554. },
  555. }
  556. originalBatches := []*model.Batch{
  557. {
  558. Process: process,
  559. Spans: []*model.Span{spanWithProcess, spanWithoutProcess},
  560. },
  561. }
  562. expected := []*model.Batch{
  563. {
  564. Process: process,
  565. Spans: []*model.Span{spanWithoutProcess},
  566. },
  567. {
  568. Process: spanWithProcess.Process,
  569. Spans: []*model.Span{spanWithProcess},
  570. },
  571. }
  572. // test
  573. result := regroup(originalBatches)
  574. // verify
  575. assert.ElementsMatch(t, expected, result)
  576. }
  577. func TestChecksum(t *testing.T) {
  578. testCases := []struct {
  579. desc string
  580. input *model.Process
  581. expected uint64
  582. }{
  583. {
  584. desc: "valid process",
  585. input: &model.Process{
  586. ServiceName: "some-service-name",
  587. },
  588. expected: 0x974574e8529af5dd, // acquired by running it once
  589. },
  590. {
  591. desc: "nil process",
  592. input: nil,
  593. expected: 0xcbf29ce484222325, // acquired by running it once
  594. },
  595. }
  596. for _, tC := range testCases {
  597. t.Run(tC.desc, func(t *testing.T) {
  598. out := checksum(tC.input)
  599. assert.Equal(t, tC.expected, out)
  600. })
  601. }
  602. }
  603. func generateTracesResourceOnly() ptrace.Traces {
  604. td := testdata.GenerateTracesOneEmptyResourceSpans()
  605. rs := td.ResourceSpans().At(0).Resource()
  606. rs.Attributes().PutStr(conventions.AttributeServiceName, "service-1")
  607. rs.Attributes().PutInt("int-attr-1", 123)
  608. return td
  609. }
  610. func generateTracesResourceOnlyWithNoAttrs() ptrace.Traces {
  611. return testdata.GenerateTracesOneEmptyResourceSpans()
  612. }
  613. func generateProtoProcess() *model.Process {
  614. return &model.Process{
  615. ServiceName: "service-1",
  616. Tags: []model.KeyValue{
  617. {
  618. Key: "int-attr-1",
  619. VType: model.ValueType_INT64,
  620. VInt64: 123,
  621. },
  622. },
  623. }
  624. }
  625. func generateTracesOneSpanNoResource() ptrace.Traces {
  626. td := testdata.GenerateTracesOneSpanNoResource()
  627. span := td.ResourceSpans().At(0).ScopeSpans().At(0).Spans().At(0)
  628. span.SetSpanID([8]byte{0xAF, 0xAE, 0xAD, 0xAC, 0xAB, 0xAA, 0xA9, 0xA8})
  629. span.SetTraceID(
  630. [16]byte{0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF, 0x80})
  631. span.SetDroppedAttributesCount(0)
  632. span.SetDroppedEventsCount(0)
  633. span.SetStartTimestamp(testSpanStartTimestamp)
  634. span.SetEndTimestamp(testSpanEndTimestamp)
  635. span.SetKind(ptrace.SpanKindClient)
  636. span.Status().SetCode(ptrace.StatusCodeError)
  637. span.Events().At(0).SetTimestamp(testSpanEventTimestamp)
  638. span.Events().At(0).SetDroppedAttributesCount(0)
  639. span.Events().At(0).SetName("event-with-attr")
  640. span.Events().At(1).SetTimestamp(testSpanEventTimestamp)
  641. span.Events().At(1).SetDroppedAttributesCount(0)
  642. span.Events().At(1).SetName("")
  643. span.Events().At(1).Attributes().PutInt("attr-int", 123)
  644. return td
  645. }
  646. func generateTracesWithLibraryInfo() ptrace.Traces {
  647. td := generateTracesOneSpanNoResource()
  648. rs0 := td.ResourceSpans().At(0)
  649. rs0ils0 := rs0.ScopeSpans().At(0)
  650. rs0ils0.Scope().SetName("io.opentelemetry.test")
  651. rs0ils0.Scope().SetVersion("0.42.0")
  652. return td
  653. }
  654. func generateTracesOneSpanNoResourceWithTraceState() ptrace.Traces {
  655. td := generateTracesOneSpanNoResource()
  656. span := td.ResourceSpans().At(0).ScopeSpans().At(0).Spans().At(0)
  657. span.TraceState().FromRaw("lasterror=f39cd56cc44274fd5abd07ef1164246d10ce2955")
  658. return td
  659. }
  660. func generateProtoSpan() *model.Span {
  661. return &model.Span{
  662. TraceID: model.NewTraceID(
  663. binary.BigEndian.Uint64([]byte{0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8}),
  664. binary.BigEndian.Uint64([]byte{0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF, 0x80}),
  665. ),
  666. SpanID: model.NewSpanID(binary.BigEndian.Uint64([]byte{0xAF, 0xAE, 0xAD, 0xAC, 0xAB, 0xAA, 0xA9, 0xA8})),
  667. OperationName: "operationA",
  668. StartTime: testSpanStartTime,
  669. Duration: testSpanEndTime.Sub(testSpanStartTime),
  670. Logs: []model.Log{
  671. {
  672. Timestamp: testSpanEventTime,
  673. Fields: []model.KeyValue{
  674. {
  675. Key: eventNameAttr,
  676. VType: model.ValueType_STRING,
  677. VStr: "event-with-attr",
  678. },
  679. {
  680. Key: "span-event-attr",
  681. VType: model.ValueType_STRING,
  682. VStr: "span-event-attr-val",
  683. },
  684. },
  685. },
  686. {
  687. Timestamp: testSpanEventTime,
  688. Fields: []model.KeyValue{
  689. {
  690. Key: "attr-int",
  691. VType: model.ValueType_INT64,
  692. VInt64: 123,
  693. },
  694. },
  695. },
  696. },
  697. Tags: []model.KeyValue{
  698. {
  699. Key: tracetranslator.TagSpanKind,
  700. VType: model.ValueType_STRING,
  701. VStr: string(tracetranslator.OpenTracingSpanKindClient),
  702. },
  703. {
  704. Key: conventions.OtelStatusCode,
  705. VType: model.ValueType_STRING,
  706. VStr: statusError,
  707. },
  708. {
  709. Key: tracetranslator.TagError,
  710. VBool: true,
  711. VType: model.ValueType_BOOL,
  712. },
  713. {
  714. Key: conventions.OtelStatusDescription,
  715. VType: model.ValueType_STRING,
  716. VStr: "status-cancelled",
  717. },
  718. },
  719. }
  720. }
  721. func generateProtoSpanWithLibraryInfo(libraryName string) *model.Span {
  722. span := generateProtoSpan()
  723. span.Tags = append([]model.KeyValue{
  724. {
  725. Key: conventions.OtelLibraryName,
  726. VType: model.ValueType_STRING,
  727. VStr: libraryName,
  728. }, {
  729. Key: conventions.OtelLibraryVersion,
  730. VType: model.ValueType_STRING,
  731. VStr: "0.42.0",
  732. },
  733. }, span.Tags...)
  734. return span
  735. }
  736. func generateProtoSpanWithTraceState() *model.Span {
  737. return &model.Span{
  738. TraceID: model.NewTraceID(
  739. binary.BigEndian.Uint64([]byte{0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8}),
  740. binary.BigEndian.Uint64([]byte{0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF, 0x80}),
  741. ),
  742. SpanID: model.NewSpanID(binary.BigEndian.Uint64([]byte{0xAF, 0xAE, 0xAD, 0xAC, 0xAB, 0xAA, 0xA9, 0xA8})),
  743. OperationName: "operationA",
  744. StartTime: testSpanStartTime,
  745. Duration: testSpanEndTime.Sub(testSpanStartTime),
  746. Logs: []model.Log{
  747. {
  748. Timestamp: testSpanEventTime,
  749. Fields: []model.KeyValue{
  750. {
  751. Key: eventNameAttr,
  752. VType: model.ValueType_STRING,
  753. VStr: "event-with-attr",
  754. },
  755. {
  756. Key: "span-event-attr",
  757. VType: model.ValueType_STRING,
  758. VStr: "span-event-attr-val",
  759. },
  760. },
  761. },
  762. {
  763. Timestamp: testSpanEventTime,
  764. Fields: []model.KeyValue{
  765. {
  766. Key: "attr-int",
  767. VType: model.ValueType_INT64,
  768. VInt64: 123,
  769. },
  770. },
  771. },
  772. },
  773. Tags: []model.KeyValue{
  774. {
  775. Key: tracetranslator.TagSpanKind,
  776. VType: model.ValueType_STRING,
  777. VStr: string(tracetranslator.OpenTracingSpanKindClient),
  778. },
  779. {
  780. Key: conventions.OtelStatusCode,
  781. VType: model.ValueType_STRING,
  782. VStr: statusError,
  783. },
  784. {
  785. Key: tracetranslator.TagError,
  786. VBool: true,
  787. VType: model.ValueType_BOOL,
  788. },
  789. {
  790. Key: conventions.OtelStatusDescription,
  791. VType: model.ValueType_STRING,
  792. VStr: "status-cancelled",
  793. },
  794. {
  795. Key: tracetranslator.TagW3CTraceState,
  796. VType: model.ValueType_STRING,
  797. VStr: "lasterror=f39cd56cc44274fd5abd07ef1164246d10ce2955",
  798. },
  799. },
  800. }
  801. }
  802. func generateTracesTwoSpansChildParent() ptrace.Traces {
  803. td := generateTracesOneSpanNoResource()
  804. spans := td.ResourceSpans().At(0).ScopeSpans().At(0).Spans()
  805. span := spans.AppendEmpty()
  806. span.SetName("operationB")
  807. span.SetSpanID([8]byte{0x1F, 0x1E, 0x1D, 0x1C, 0x1B, 0x1A, 0x19, 0x18})
  808. span.SetParentSpanID(spans.At(0).SpanID())
  809. span.SetKind(ptrace.SpanKindServer)
  810. span.SetTraceID(spans.At(0).TraceID())
  811. span.SetStartTimestamp(spans.At(0).StartTimestamp())
  812. span.SetEndTimestamp(spans.At(0).EndTimestamp())
  813. span.Status().SetCode(ptrace.StatusCodeUnset)
  814. span.Attributes().PutInt(conventions.AttributeHTTPStatusCode, 404)
  815. return td
  816. }
  817. func generateProtoChildSpan() *model.Span {
  818. traceID := model.NewTraceID(
  819. binary.BigEndian.Uint64([]byte{0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8}),
  820. binary.BigEndian.Uint64([]byte{0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF, 0x80}),
  821. )
  822. return &model.Span{
  823. TraceID: traceID,
  824. SpanID: model.NewSpanID(binary.BigEndian.Uint64([]byte{0x1F, 0x1E, 0x1D, 0x1C, 0x1B, 0x1A, 0x19, 0x18})),
  825. OperationName: "operationB",
  826. StartTime: testSpanStartTime,
  827. Duration: testSpanEndTime.Sub(testSpanStartTime),
  828. Tags: []model.KeyValue{
  829. {
  830. Key: conventions.AttributeHTTPStatusCode,
  831. VType: model.ValueType_INT64,
  832. VInt64: 404,
  833. },
  834. {
  835. Key: tracetranslator.TagSpanKind,
  836. VType: model.ValueType_STRING,
  837. VStr: string(tracetranslator.OpenTracingSpanKindServer),
  838. },
  839. },
  840. References: []model.SpanRef{
  841. {
  842. TraceID: traceID,
  843. SpanID: model.NewSpanID(binary.BigEndian.Uint64([]byte{0xAF, 0xAE, 0xAD, 0xAC, 0xAB, 0xAA, 0xA9, 0xA8})),
  844. RefType: model.SpanRefType_CHILD_OF,
  845. },
  846. },
  847. }
  848. }
  849. func generateTracesTwoSpansWithFollower() ptrace.Traces {
  850. td := generateTracesOneSpanNoResource()
  851. spans := td.ResourceSpans().At(0).ScopeSpans().At(0).Spans()
  852. span := spans.AppendEmpty()
  853. span.SetName("operationC")
  854. span.SetSpanID([8]byte{0x1F, 0x1E, 0x1D, 0x1C, 0x1B, 0x1A, 0x19, 0x18})
  855. span.SetTraceID(spans.At(0).TraceID())
  856. span.SetStartTimestamp(spans.At(0).EndTimestamp())
  857. span.SetEndTimestamp(spans.At(0).EndTimestamp() + 1000000)
  858. span.SetKind(ptrace.SpanKindConsumer)
  859. span.Status().SetCode(ptrace.StatusCodeOk)
  860. span.Status().SetMessage("status-ok")
  861. link := span.Links().AppendEmpty()
  862. link.SetTraceID(span.TraceID())
  863. link.SetSpanID(spans.At(0).SpanID())
  864. link.Attributes().PutStr(
  865. conventions.AttributeOpentracingRefType,
  866. conventions.AttributeOpentracingRefTypeFollowsFrom,
  867. )
  868. return td
  869. }
  870. func generateProtoFollowerSpan() *model.Span {
  871. traceID := model.NewTraceID(
  872. binary.BigEndian.Uint64([]byte{0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8}),
  873. binary.BigEndian.Uint64([]byte{0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF, 0x80}),
  874. )
  875. return &model.Span{
  876. TraceID: traceID,
  877. SpanID: model.NewSpanID(binary.BigEndian.Uint64([]byte{0x1F, 0x1E, 0x1D, 0x1C, 0x1B, 0x1A, 0x19, 0x18})),
  878. OperationName: "operationC",
  879. StartTime: testSpanEndTime,
  880. Duration: time.Millisecond,
  881. Tags: []model.KeyValue{
  882. {
  883. Key: tracetranslator.TagSpanKind,
  884. VType: model.ValueType_STRING,
  885. VStr: string(tracetranslator.OpenTracingSpanKindConsumer),
  886. },
  887. {
  888. Key: conventions.OtelStatusCode,
  889. VType: model.ValueType_STRING,
  890. VStr: statusOk,
  891. },
  892. {
  893. Key: conventions.OtelStatusDescription,
  894. VType: model.ValueType_STRING,
  895. VStr: "status-ok",
  896. },
  897. },
  898. References: []model.SpanRef{
  899. {
  900. TraceID: traceID,
  901. SpanID: model.NewSpanID(binary.BigEndian.Uint64([]byte{0xAF, 0xAE, 0xAD, 0xAC, 0xAB, 0xAA, 0xA9, 0xA8})),
  902. RefType: model.SpanRefType_FOLLOWS_FROM,
  903. },
  904. },
  905. }
  906. }
  907. func generateTracesSpanWithTwoParents() ptrace.Traces {
  908. td := generateTracesTwoSpansWithFollower()
  909. spans := td.ResourceSpans().At(0).ScopeSpans().At(0).Spans()
  910. parent := spans.At(0)
  911. parent2 := spans.At(1)
  912. span := spans.AppendEmpty()
  913. span.SetName("operationD")
  914. span.SetSpanID([8]byte{0x1F, 0x1E, 0x1D, 0x1C, 0x1B, 0x1A, 0x19, 0x20})
  915. span.SetTraceID(parent.TraceID())
  916. span.SetStartTimestamp(parent.StartTimestamp())
  917. span.SetEndTimestamp(parent.EndTimestamp())
  918. span.SetParentSpanID(parent.SpanID())
  919. span.SetKind(ptrace.SpanKindConsumer)
  920. span.Status().SetCode(ptrace.StatusCodeOk)
  921. span.Status().SetMessage("status-ok")
  922. link := span.Links().AppendEmpty()
  923. link.SetTraceID(parent2.TraceID())
  924. link.SetSpanID(parent2.SpanID())
  925. link.Attributes().PutStr(
  926. conventions.AttributeOpentracingRefType,
  927. conventions.AttributeOpentracingRefTypeChildOf,
  928. )
  929. return td
  930. }
  931. func generateProtoTwoParentsSpan() *model.Span {
  932. traceID := model.NewTraceID(
  933. binary.BigEndian.Uint64([]byte{0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8}),
  934. binary.BigEndian.Uint64([]byte{0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF, 0x80}),
  935. )
  936. return &model.Span{
  937. TraceID: traceID,
  938. SpanID: model.NewSpanID(binary.BigEndian.Uint64([]byte{0x1F, 0x1E, 0x1D, 0x1C, 0x1B, 0x1A, 0x19, 0x20})),
  939. OperationName: "operationD",
  940. StartTime: testSpanStartTime,
  941. Duration: testSpanEndTime.Sub(testSpanStartTime),
  942. Tags: []model.KeyValue{
  943. {
  944. Key: tracetranslator.TagSpanKind,
  945. VType: model.ValueType_STRING,
  946. VStr: string(tracetranslator.OpenTracingSpanKindConsumer),
  947. },
  948. {
  949. Key: conventions.OtelStatusCode,
  950. VType: model.ValueType_STRING,
  951. VStr: statusOk,
  952. },
  953. {
  954. Key: conventions.OtelStatusDescription,
  955. VType: model.ValueType_STRING,
  956. VStr: "status-ok",
  957. },
  958. },
  959. References: []model.SpanRef{
  960. {
  961. TraceID: traceID,
  962. SpanID: model.NewSpanID(binary.BigEndian.Uint64([]byte{0xAF, 0xAE, 0xAD, 0xAC, 0xAB, 0xAA, 0xA9, 0xA8})),
  963. RefType: model.SpanRefType_CHILD_OF,
  964. },
  965. {
  966. TraceID: traceID,
  967. SpanID: model.NewSpanID(binary.BigEndian.Uint64([]byte{0x1F, 0x1E, 0x1D, 0x1C, 0x1B, 0x1A, 0x19, 0x18})),
  968. RefType: model.SpanRefType_CHILD_OF,
  969. },
  970. },
  971. }
  972. }
  973. func BenchmarkProtoBatchToInternalTraces(b *testing.B) {
  974. jb := []*model.Batch{
  975. {
  976. Process: generateProtoProcess(),
  977. Spans: []*model.Span{
  978. generateProtoSpan(),
  979. generateProtoChildSpan(),
  980. },
  981. }}
  982. b.ResetTimer()
  983. for n := 0; n < b.N; n++ {
  984. _, err := ProtoToTraces(jb)
  985. assert.NoError(b, err)
  986. }
  987. }
  988. func generateTracesTwoSpansFromTwoLibraries() ptrace.Traces {
  989. td := testdata.GenerateTracesOneEmptyResourceSpans()
  990. rs0 := td.ResourceSpans().At(0)
  991. rs0.ScopeSpans().EnsureCapacity(2)
  992. rs0ils0 := rs0.ScopeSpans().AppendEmpty()
  993. rs0ils0.Scope().SetName("library1")
  994. rs0ils0.Scope().SetVersion("0.42.0")
  995. span1 := rs0ils0.Spans().AppendEmpty()
  996. span1.SetTraceID(idutils.UInt64ToTraceID(0, 0))
  997. span1.SetSpanID(idutils.UInt64ToSpanID(0))
  998. span1.SetName("operation1")
  999. span1.SetStartTimestamp(testSpanStartTimestamp)
  1000. span1.SetEndTimestamp(testSpanEndTimestamp)
  1001. rs0ils1 := rs0.ScopeSpans().AppendEmpty()
  1002. rs0ils1.Scope().SetName("library2")
  1003. rs0ils1.Scope().SetVersion("0.42.0")
  1004. span2 := rs0ils1.Spans().AppendEmpty()
  1005. span2.SetTraceID(span1.TraceID())
  1006. span2.SetSpanID(span1.SpanID())
  1007. span2.SetName("operation2")
  1008. span2.SetStartTimestamp(testSpanStartTimestamp)
  1009. span2.SetEndTimestamp(testSpanEndTimestamp)
  1010. return td
  1011. }