Skip to content

Commit

Permalink
Weights now uses trace_id to pick a choice (#44)
Browse files Browse the repository at this point in the history
* choice with the same weights are now consistent within the same trace_id

* propagate errors to parent spans
  • Loading branch information
paivagustavo authored Mar 3, 2023
1 parent 8bde50b commit ad46b63
Show file tree
Hide file tree
Showing 8 changed files with 49 additions and 19 deletions.
7 changes: 6 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 |
Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.11.11
0.11.12
13 changes: 9 additions & 4 deletions generatorreceiver/internal/generator/trace_generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand All @@ -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

Expand All @@ -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()))
}

Expand Down
10 changes: 7 additions & 3 deletions generatorreceiver/internal/topology/latency_percentiles.go
Original file line number Diff line number Diff line change
@@ -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 {
Expand All @@ -21,6 +24,7 @@ type LatencyPercentiles struct {
p999 time.Duration
p100 time.Duration
}
EmbeddedWeight `json:",inline" yaml:",inline"`
flags.EmbeddedFlags `json:",inline" yaml:",inline"`
}

Expand Down Expand Up @@ -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 {
Expand All @@ -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()
}
17 changes: 14 additions & 3 deletions generatorreceiver/internal/topology/pickable.go
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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 {
Expand All @@ -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()
Expand Down
6 changes: 4 additions & 2 deletions generatorreceiver/internal/topology/service_route.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import (
"fmt"
"math/rand"

"go.opentelemetry.io/collector/pdata/pcommon"

"github.com/lightstep/telemetry-generator/generatorreceiver/internal/flags"
)

Expand Down Expand Up @@ -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)
}
}
12 changes: 7 additions & 5 deletions generatorreceiver/internal/topology/service_tier.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package topology

import (
"fmt"

"go.opentelemetry.io/collector/pdata/pcommon"
)

type ServiceTier struct {
Expand All @@ -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 {
Expand All @@ -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 {
Expand Down

0 comments on commit ad46b63

Please sign in to comment.