diff --git a/CHANGELOG.md b/CHANGELOG.md index 120d5d2..dbbd997 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,9 +4,14 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [Unreleased](https://github.com/lightstep/telemetry-generator/compare/v0.11.11...HEAD) +## [Unreleased](https://github.com/lightstep/telemetry-generator/compare/v0.11.12...HEAD) +## [0.11.12](https://github.com/lightstep/telemetry-generator/compare/v0.11.11...v0.11.12) - 2023-3-03 +### Changed +* Weights the last two digits of a trace_id to generate their randomness. +* Errors are now propagated up to the parent span. + ## [0.11.11](https://github.com/lightstep/telemetry-generator/compare/v0.11.10...v0.11.11) - 2023-3-02 ### Fixed * Fixed a bug where multiple traces were being created with the same trace_id and span_id. diff --git a/README.md b/README.md index 249cac9..e9938c3 100644 --- a/README.md +++ b/README.md @@ -119,6 +119,7 @@ version for the 10 most recent telemetry-generator versions. | Telemetry Generator | OpenTelemetry Collector | |---------------------|-------------------------| +| v0.11.12 | v0.69.1 | | v0.11.11 | v0.69.1 | | v0.11.10 | v0.69.1 | | v0.11.9 | v0.68.0 | diff --git a/VERSION b/VERSION index 1a77547..bd0119f 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.11.11 +0.11.12 diff --git a/generatorreceiver/internal/generator/trace_generator.go b/generatorreceiver/internal/generator/trace_generator.go index 3286d65..e705c92 100644 --- a/generatorreceiver/internal/generator/trace_generator.go +++ b/generatorreceiver/internal/generator/trace_generator.go @@ -75,7 +75,7 @@ func (g *TraceGenerator) createSpanForServiceRouteCall(traces *ptrace.Traces, se resource.Attributes().PutStr(string(semconv.ServiceNameKey), serviceTier.ServiceName) - resourceAttributeSet := serviceTier.GetResourceAttributeSet() + resourceAttributeSet := serviceTier.GetResourceAttributeSet(traceId) attrs := resource.Attributes() resourceAttributeSet.GetAttributes().InsertTags(&attrs) @@ -92,7 +92,7 @@ func (g *TraceGenerator) createSpanForServiceRouteCall(traces *ptrace.Traces, se span.SetKind(ptrace.SpanKindServer) span.Attributes().PutStr("load_generator.seq_num", fmt.Sprintf("%v", g.sequenceNumber)) - ts := serviceTier.GetTagSet(routeName) // ts is single TagSet consisting of tags from the service AND route + ts := serviceTier.GetTagSet(routeName, traceId) // ts is single TagSet consisting of tags from the service AND route attr := span.Attributes() ts.Tags.InsertTags(&attr) // add service and route tags to span attributes @@ -106,11 +106,16 @@ func (g *TraceGenerator) createSpanForServiceRouteCall(traces *ptrace.Traces, se // TODO: this is still a bit weird - we're calling each downstream route // after a sample of the current route's latency, which doesn't really // make sense - but maybe it's realistic enough? - endTime := startTimeNanos + route.SampleLatency() + endTime := startTimeNanos + route.SampleLatency(traceId) for _, c := range route.DownstreamCalls { - var childStartTimeNanos = startTimeNanos + route.SampleLatency() + var childStartTimeNanos = startTimeNanos + route.SampleLatency(traceId) childSpan := g.createSpanForServiceRouteCall(traces, c.Service, c.Route, childStartTimeNanos, traceId, newSpanId) + val, ok := childSpan.Attributes().Get("error") + if ok { + errorAttr := span.Attributes().PutEmpty("error") + val.CopyTo(errorAttr) + } endTime = Max(endTime, int64(childSpan.EndTimestamp())) } diff --git a/generatorreceiver/internal/topology/latency_percentiles.go b/generatorreceiver/internal/topology/latency_percentiles.go index 52c0362..8473542 100644 --- a/generatorreceiver/internal/topology/latency_percentiles.go +++ b/generatorreceiver/internal/topology/latency_percentiles.go @@ -1,9 +1,12 @@ package topology import ( - "github.com/lightstep/telemetry-generator/generatorreceiver/internal/flags" "math/rand" "time" + + "go.opentelemetry.io/collector/pdata/pcommon" + + "github.com/lightstep/telemetry-generator/generatorreceiver/internal/flags" ) type LatencyPercentiles struct { @@ -21,6 +24,7 @@ type LatencyPercentiles struct { p999 time.Duration p100 time.Duration } + EmbeddedWeight `json:",inline" yaml:",inline"` flags.EmbeddedFlags `json:",inline" yaml:",inline"` } @@ -80,7 +84,7 @@ func (l *LatencyPercentiles) loadDurations() error { type LatencyConfigs []*LatencyPercentiles -func (lcfg *LatencyConfigs) Sample() int64 { +func (lcfg *LatencyConfigs) Sample(traceID pcommon.TraceID) int64 { var defaultCfg *LatencyPercentiles var enabled []*LatencyPercentiles for _, cfg := range *lcfg { @@ -91,7 +95,7 @@ func (lcfg *LatencyConfigs) Sample() int64 { } } if len(enabled) > 0 { - return enabled[rand.Intn(len(enabled))].Sample() + return pickBasedOnWeight(enabled, traceID).Sample() } return defaultCfg.Sample() } diff --git a/generatorreceiver/internal/topology/pickable.go b/generatorreceiver/internal/topology/pickable.go index be2e4a8..cef3f12 100644 --- a/generatorreceiver/internal/topology/pickable.go +++ b/generatorreceiver/internal/topology/pickable.go @@ -1,6 +1,10 @@ package topology -import "math/rand" +import ( + "encoding/binary" + + "go.opentelemetry.io/collector/pdata/pcommon" +) type Pickable interface { // currently TagSet and ResourceAttributeSet satisfy this interface GetWeight() float64 @@ -15,7 +19,7 @@ func (w EmbeddedWeight) GetWeight() float64 { return w.Weight } -func pickBasedOnWeight[P Pickable](ps []P) P { +func pickBasedOnWeight[P Pickable](ps []P, traceID pcommon.TraceID) P { var activeSets []P totalWeight := 0.0 for _, set := range ps { @@ -25,7 +29,14 @@ func pickBasedOnWeight[P Pickable](ps []P) P { } } - choice := rand.Float64() * totalWeight + // Take out last 8 bytes from trace id + secondHalf := traceID[8:16] + // Transform them into a uint64 + traceUint := binary.BigEndian.Uint64(secondHalf) + // Use the last two digits as percentage. + choice := float64(traceUint%100) / 100.0 + + choice = choice * totalWeight current := 0.0 for _, set := range activeSets { current += set.GetWeight() diff --git a/generatorreceiver/internal/topology/service_route.go b/generatorreceiver/internal/topology/service_route.go index abb9d0e..4528c0a 100644 --- a/generatorreceiver/internal/topology/service_route.go +++ b/generatorreceiver/internal/topology/service_route.go @@ -4,6 +4,8 @@ import ( "fmt" "math/rand" + "go.opentelemetry.io/collector/pdata/pcommon" + "github.com/lightstep/telemetry-generator/generatorreceiver/internal/flags" ) @@ -77,10 +79,10 @@ func (r *ServiceRoute) load(route string) error { return nil } -func (r *ServiceRoute) SampleLatency() int64 { +func (r *ServiceRoute) SampleLatency(traceID pcommon.TraceID) int64 { if r.LatencyConfigs == nil { return rand.Int63n(r.MaxLatencyMillis * 1000000) } else { - return r.LatencyConfigs.Sample() + return r.LatencyConfigs.Sample(traceID) } } diff --git a/generatorreceiver/internal/topology/service_tier.go b/generatorreceiver/internal/topology/service_tier.go index 7377eb5..69beedb 100644 --- a/generatorreceiver/internal/topology/service_tier.go +++ b/generatorreceiver/internal/topology/service_tier.go @@ -2,6 +2,8 @@ package topology import ( "fmt" + + "go.opentelemetry.io/collector/pdata/pcommon" ) type ServiceTier struct { @@ -12,9 +14,9 @@ type ServiceTier struct { Metrics []Metric `json:"metrics" yaml:"metrics"` } -func (st *ServiceTier) GetTagSet(routeName string) TagSet { - serviceTagSet := pickBasedOnWeight(st.TagSets) - routeTagSet := pickBasedOnWeight(st.GetRoute(routeName).TagSets) +func (st *ServiceTier) GetTagSet(routeName string, traceID pcommon.TraceID) TagSet { + serviceTagSet := pickBasedOnWeight(st.TagSets, traceID) + routeTagSet := pickBasedOnWeight(st.GetRoute(routeName).TagSets, traceID) combinedTags := TagMap{} for k, v := range serviceTagSet.Tags { @@ -30,9 +32,9 @@ func (st *ServiceTier) GetTagSet(routeName string) TagSet { } } -func (st *ServiceTier) GetResourceAttributeSet() ResourceAttributeSet { +func (st *ServiceTier) GetResourceAttributeSet(traceID pcommon.TraceID) ResourceAttributeSet { // TODO: also support resource attributes on routes - return pickBasedOnWeight(st.ResourceAttributeSets) + return pickBasedOnWeight(st.ResourceAttributeSets, traceID) } func (st *ServiceTier) GetRoute(routeName string) *ServiceRoute {