| 301 | } |
| 302 | |
| 303 | func (t *TraceInfo) ConstructTraceFromEpoch() (*tempopb.Trace, error) { |
| 304 | trace := &tempopb.Trace{} |
| 305 | |
| 306 | // Create a new trace from our timestamp to ensure a fresh rand.Rand is used for consistency. |
| 307 | info := NewTraceInfo(t.timestamp, t.tempoOrgID) |
| 308 | |
| 309 | addBatches := func(t *TraceInfo, trace *tempopb.Trace) error { |
| 310 | for i := int64(0); i < t.generateRandomInt(1, maxBatchesPerWrite); i++ { |
| 311 | batch := t.makeThriftBatch(t.traceIDHigh, t.traceIDLow) |
| 312 | internalTrace, err := jaegerTrans.ThriftToTraces(batch) |
| 313 | if err != nil { |
| 314 | return err |
| 315 | } |
| 316 | conv, err := (&ptrace.ProtoMarshaler{}).MarshalTraces(internalTrace) |
| 317 | if err != nil { |
| 318 | return err |
| 319 | } |
| 320 | |
| 321 | t := tempopb.Trace{} |
| 322 | err = t.Unmarshal(conv) |
| 323 | if err != nil { |
| 324 | return err |
| 325 | } |
| 326 | |
| 327 | // Due to the several transforms above, some manual mangling is required to |
| 328 | // get the parentSpanID to match. In the case of an empty []byte in place |
| 329 | // for the ParentSpanId, we set to nil here to ensure that the final result |
| 330 | // matches the json.Unmarshal value when tempo is queried. |
| 331 | for _, b := range t.ResourceSpans { |
| 332 | for _, l := range b.ScopeSpans { |
| 333 | for _, s := range l.Spans { |
| 334 | if len(s.GetParentSpanId()) == 0 { |
| 335 | s.ParentSpanId = nil |
| 336 | } |
| 337 | } |
| 338 | } |
| 339 | } |
| 340 | |
| 341 | trace.ResourceSpans = append(trace.ResourceSpans, t.ResourceSpans...) |
| 342 | } |
| 343 | |
| 344 | return nil |
| 345 | } |
| 346 | |
| 347 | err := addBatches(info, trace) |
| 348 | if err != nil { |
| 349 | return nil, err |
| 350 | } |
| 351 | |
| 352 | for info.longWritesRemaining > 0 { |
| 353 | info.Done() |
| 354 | err := addBatches(info, trace) |
| 355 | if err != nil { |
| 356 | return nil, err |
| 357 | } |
| 358 | } |
| 359 | |
| 360 | return trace, nil |