From d0a37ebc65e8ab8ea88acc9c07dbc3572246405a Mon Sep 17 00:00:00 2001 From: Shivanth Date: Thu, 17 Oct 2024 15:04:37 +0200 Subject: [PATCH 1/7] Add random histogram to telemetrygen --- .../internal/metrics/metrics_types.go | 9 +++++---- cmd/telemetrygen/internal/metrics/worker.go | 20 +++++++++++++++++++ 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/cmd/telemetrygen/internal/metrics/metrics_types.go b/cmd/telemetrygen/internal/metrics/metrics_types.go index 84318afc4fab..e07b26720acb 100644 --- a/cmd/telemetrygen/internal/metrics/metrics_types.go +++ b/cmd/telemetrygen/internal/metrics/metrics_types.go @@ -10,8 +10,9 @@ import ( type metricType string const ( - metricTypeGauge = "Gauge" - metricTypeSum = "Sum" + metricTypeGauge = "Gauge" + metricTypeSum = "Sum" + metricTypeHistogram = "Histogram" ) // String is used both by fmt.Print and by Cobra in help text @@ -22,11 +23,11 @@ func (e *metricType) String() string { // Set must have pointer receiver so it doesn't change the value of a copy func (e *metricType) Set(v string) error { switch v { - case "Gauge", "Sum": + case "Gauge", "Sum", "Histogram": *e = metricType(v) return nil default: - return errors.New(`must be one of "Gauge" or "Sum"`) + return errors.New(`must be one of "Gauge", "Sum", "Histogram"`) } } diff --git a/cmd/telemetrygen/internal/metrics/worker.go b/cmd/telemetrygen/internal/metrics/worker.go index 17978fb9bdf6..11e1fe272fdd 100644 --- a/cmd/telemetrygen/internal/metrics/worker.go +++ b/cmd/telemetrygen/internal/metrics/worker.go @@ -5,6 +5,7 @@ package metrics import ( "context" + rand "math/rand/v2" "sync" "sync/atomic" "time" @@ -38,6 +39,8 @@ func (w worker) simulateMetrics(res *resource.Resource, exporterFunc func() (sdk w.logger.Error("failed to create the exporter", zap.Error(err)) return } + randomPCG := rand.NewPCG(0, 0) + randomgenerator := rand.New(randomPCG) defer func() { w.logger.Info("stopping the exporter") @@ -82,6 +85,23 @@ func (w worker) simulateMetrics(res *resource.Resource, exporterFunc func() (sdk }, }, }) + case metricTypeHistogram: + metrics = append(metrics, metricdata.Metrics{ + Name: w.metricName, + Data: metricdata.Histogram[int64]{ + Temporality: metricdata.DeltaTemporality, + DataPoints: []metricdata.HistogramDataPoint[int64]{ + { + StartTime: time.Now().Add(-1 * time.Second), + Time: time.Now(), + Attributes: attribute.NewSet(signalAttrs...), + Exemplars: w.exemplars, + Count: uint64(randomgenerator.Int64N(10)), + Sum: randomgenerator.Int64N(10), + }, + }, + }, + }) default: w.logger.Fatal("unknown metric type") } From 4b99fe296eb2a59570f6392bbc56070236c4872e Mon Sep 17 00:00:00 2001 From: Shivanth Date: Tue, 12 Nov 2024 18:54:58 +0100 Subject: [PATCH 2/7] add bucket info for histograms --- cmd/telemetrygen/internal/metrics/worker.go | 22 +++++++++++++++++-- .../internal/metrics/worker_test.go | 18 +++++++++++++++ 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/cmd/telemetrygen/internal/metrics/worker.go b/cmd/telemetrygen/internal/metrics/worker.go index 11e1fe272fdd..2e239cac29a7 100644 --- a/cmd/telemetrygen/internal/metrics/worker.go +++ b/cmd/telemetrygen/internal/metrics/worker.go @@ -86,6 +86,8 @@ func (w worker) simulateMetrics(res *resource.Resource, exporterFunc func() (sdk }, }) case metricTypeHistogram: + iteration := uint64(i) % 5 + sum, bucketCounts := generateHistogramBuckets[int64](iteration, randomgenerator) metrics = append(metrics, metricdata.Metrics{ Name: w.metricName, Data: metricdata.Histogram[int64]{ @@ -96,8 +98,11 @@ func (w worker) simulateMetrics(res *resource.Resource, exporterFunc func() (sdk Time: time.Now(), Attributes: attribute.NewSet(signalAttrs...), Exemplars: w.exemplars, - Count: uint64(randomgenerator.Int64N(10)), - Sum: randomgenerator.Int64N(10), + Count: iteration, + Sum: sum, + // Simple bounds assumption + Bounds: []float64{0, 1, 2, 3, 4}, + BucketCounts: bucketCounts, }, }, }, @@ -128,3 +133,16 @@ func (w worker) simulateMetrics(res *resource.Resource, exporterFunc func() (sdk w.logger.Info("metrics generated", zap.Int64("metrics", i)) w.wg.Done() } + +func generateHistogramBuckets[T int64 | float64](count uint64, randomgenerator *rand.Rand) (sum T, bucketCounts []uint64) { + sum = 0 + bucketCounts = make([]uint64, 5) + var i uint64 + for i = 0; i < count; i++ { + sample := randomgenerator.IntN(5) + // See bounds above + sum += T(sample) + bucketCounts[sample] += 1 + } + return +} diff --git a/cmd/telemetrygen/internal/metrics/worker_test.go b/cmd/telemetrygen/internal/metrics/worker_test.go index 7574ac203757..b8e2bd7dff14 100644 --- a/cmd/telemetrygen/internal/metrics/worker_test.go +++ b/cmd/telemetrygen/internal/metrics/worker_test.go @@ -5,6 +5,7 @@ package metrics import ( "context" + rand "math/rand/v2" "testing" "time" @@ -390,3 +391,20 @@ func configWithMultipleAttributes(metric metricType, qty int) *Config { MetricType: metric, } } + +func TestGenerateHistogramBuckets(t *testing.T) { + randomPCG := rand.NewPCG(0, 0) + randomgenerator := rand.New(randomPCG) + for i := uint64(0); i < 5; i++ { + _, buckets := generateHistogramBuckets[int64](i, randomgenerator) + assert.Equal(t, sumofArray(buckets), i) + } +} + +func sumofArray[T int64 | float64 | uint64](array []T) T { + var sum T + for _, num := range array { + sum += num + } + return sum +} From 148837b164807a6d3ec062b1813be79a1f91b54d Mon Sep 17 00:00:00 2001 From: Shivanth Date: Tue, 12 Nov 2024 19:02:46 +0100 Subject: [PATCH 3/7] Add changelogs --- .chloggen/telemetrygen.yaml | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 .chloggen/telemetrygen.yaml diff --git a/.chloggen/telemetrygen.yaml b/.chloggen/telemetrygen.yaml new file mode 100644 index 000000000000..7f08aef5a9bd --- /dev/null +++ b/.chloggen/telemetrygen.yaml @@ -0,0 +1,27 @@ +# Use this changelog template to create an entry for release notes. + +# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix' +change_type: enhancement + +# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver) +component: cmd/telemetrygen + +# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). +note: Introduce support for generating histograms in telemetrygen + +# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists. +issues: [36322] + +# (Optional) One or more lines of additional information to render under the primary note. +# These lines will be padded with 2 spaces and then inserted directly into the document. +# Use pipe (|) for multiline entries. +subtext: + +# If your change doesn't affect end users or the exported elements of any package, +# you should instead start your pull request title with [chore] or use the "Skip Changelog" label. +# Optional: The change log or logs in which this entry should be included. +# e.g. '[user]' or '[user, api]' +# Include 'user' if the change is relevant to end users. +# Include 'api' if there is a change to a library API. +# Default: '[user]' +change_logs: [user] From 8bf7241289ad3fccd6e7952bb95dc87386431ee0 Mon Sep 17 00:00:00 2001 From: Shivanth Date: Wed, 13 Nov 2024 11:00:56 +0100 Subject: [PATCH 4/7] Lint fix --- cmd/telemetrygen/internal/metrics/worker.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/telemetrygen/internal/metrics/worker.go b/cmd/telemetrygen/internal/metrics/worker.go index 2e239cac29a7..0b220ee5a1bc 100644 --- a/cmd/telemetrygen/internal/metrics/worker.go +++ b/cmd/telemetrygen/internal/metrics/worker.go @@ -142,7 +142,7 @@ func generateHistogramBuckets[T int64 | float64](count uint64, randomgenerator * sample := randomgenerator.IntN(5) // See bounds above sum += T(sample) - bucketCounts[sample] += 1 + bucketCounts[sample]++ } return } From 168383372d26be47eaee88cefe89a93348439610 Mon Sep 17 00:00:00 2001 From: Shivanth Date: Wed, 13 Nov 2024 17:20:15 +0100 Subject: [PATCH 5/7] Cumulative temporality --- cmd/telemetrygen/internal/metrics/worker.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/telemetrygen/internal/metrics/worker.go b/cmd/telemetrygen/internal/metrics/worker.go index 0b220ee5a1bc..e0b2b381bac8 100644 --- a/cmd/telemetrygen/internal/metrics/worker.go +++ b/cmd/telemetrygen/internal/metrics/worker.go @@ -91,7 +91,7 @@ func (w worker) simulateMetrics(res *resource.Resource, exporterFunc func() (sdk metrics = append(metrics, metricdata.Metrics{ Name: w.metricName, Data: metricdata.Histogram[int64]{ - Temporality: metricdata.DeltaTemporality, + Temporality: metricdata.CumulativeTemporality, DataPoints: []metricdata.HistogramDataPoint[int64]{ { StartTime: time.Now().Add(-1 * time.Second), From 68c95b9b133781295676937d9fd5f04b72ae36cc Mon Sep 17 00:00:00 2001 From: Shivanth Date: Wed, 4 Dec 2024 13:03:08 +0100 Subject: [PATCH 6/7] Remove random number generator from histogram generation --- cmd/telemetrygen/internal/metrics/worker.go | 68 ++++++++++++++----- .../internal/metrics/worker_test.go | 18 ----- 2 files changed, 50 insertions(+), 36 deletions(-) diff --git a/cmd/telemetrygen/internal/metrics/worker.go b/cmd/telemetrygen/internal/metrics/worker.go index e0b2b381bac8..bde5891575fa 100644 --- a/cmd/telemetrygen/internal/metrics/worker.go +++ b/cmd/telemetrygen/internal/metrics/worker.go @@ -5,7 +5,6 @@ package metrics import ( "context" - rand "math/rand/v2" "sync" "sync/atomic" "time" @@ -31,6 +30,53 @@ type worker struct { index int // worker index } +var histogramBucketSamples = []struct { + bucketCounts []uint64 + sum int64 +}{ + { + []uint64{0, 0, 0, 0, 0}, + 0, + }, + + { + []uint64{0, 1, 0, 0, 0}, + 1, + }, + { + []uint64{0, 1, 0, 1, 0}, + 4, + }, + { + []uint64{1, 1, 1, 0, 0}, + 3, + }, + { + []uint64{0, 0, 1, 2, 1}, + 12, + }, + { + []uint64{0, 0, 0, 0, 0}, + 0, + }, + { + []uint64{0, 1, 0, 0, 0}, + 1, + }, + { + []uint64{0, 2, 0, 0, 0}, + 2, + }, + { + []uint64{1, 0, 1, 1, 0}, + 5, + }, + { + []uint64{2, 0, 1, 0, 1}, + 6, + }, +} + func (w worker) simulateMetrics(res *resource.Resource, exporterFunc func() (sdkmetric.Exporter, error), signalAttrs []attribute.KeyValue) { limiter := rate.NewLimiter(w.limitPerSecond, 1) @@ -39,8 +85,6 @@ func (w worker) simulateMetrics(res *resource.Resource, exporterFunc func() (sdk w.logger.Error("failed to create the exporter", zap.Error(err)) return } - randomPCG := rand.NewPCG(0, 0) - randomgenerator := rand.New(randomPCG) defer func() { w.logger.Info("stopping the exporter") @@ -86,8 +130,9 @@ func (w worker) simulateMetrics(res *resource.Resource, exporterFunc func() (sdk }, }) case metricTypeHistogram: - iteration := uint64(i) % 5 - sum, bucketCounts := generateHistogramBuckets[int64](iteration, randomgenerator) + iteration := uint64(i) % 10 + sum := histogramBucketSamples[iteration].sum + bucketCounts := histogramBucketSamples[iteration].bucketCounts metrics = append(metrics, metricdata.Metrics{ Name: w.metricName, Data: metricdata.Histogram[int64]{ @@ -133,16 +178,3 @@ func (w worker) simulateMetrics(res *resource.Resource, exporterFunc func() (sdk w.logger.Info("metrics generated", zap.Int64("metrics", i)) w.wg.Done() } - -func generateHistogramBuckets[T int64 | float64](count uint64, randomgenerator *rand.Rand) (sum T, bucketCounts []uint64) { - sum = 0 - bucketCounts = make([]uint64, 5) - var i uint64 - for i = 0; i < count; i++ { - sample := randomgenerator.IntN(5) - // See bounds above - sum += T(sample) - bucketCounts[sample]++ - } - return -} diff --git a/cmd/telemetrygen/internal/metrics/worker_test.go b/cmd/telemetrygen/internal/metrics/worker_test.go index b8e2bd7dff14..7574ac203757 100644 --- a/cmd/telemetrygen/internal/metrics/worker_test.go +++ b/cmd/telemetrygen/internal/metrics/worker_test.go @@ -5,7 +5,6 @@ package metrics import ( "context" - rand "math/rand/v2" "testing" "time" @@ -391,20 +390,3 @@ func configWithMultipleAttributes(metric metricType, qty int) *Config { MetricType: metric, } } - -func TestGenerateHistogramBuckets(t *testing.T) { - randomPCG := rand.NewPCG(0, 0) - randomgenerator := rand.New(randomPCG) - for i := uint64(0); i < 5; i++ { - _, buckets := generateHistogramBuckets[int64](i, randomgenerator) - assert.Equal(t, sumofArray(buckets), i) - } -} - -func sumofArray[T int64 | float64 | uint64](array []T) T { - var sum T - for _, num := range array { - sum += num - } - return sum -} From e6539aa9178a8bf905f0e0c50e9a86c7c6828d71 Mon Sep 17 00:00:00 2001 From: Shivanth Date: Tue, 17 Dec 2024 12:36:42 +0100 Subject: [PATCH 7/7] use bounds from specs --- cmd/telemetrygen/internal/metrics/worker.go | 45 ++++++++++----------- 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/cmd/telemetrygen/internal/metrics/worker.go b/cmd/telemetrygen/internal/metrics/worker.go index bde5891575fa..02a0c7ded490 100644 --- a/cmd/telemetrygen/internal/metrics/worker.go +++ b/cmd/telemetrygen/internal/metrics/worker.go @@ -35,45 +35,44 @@ var histogramBucketSamples = []struct { sum int64 }{ { - []uint64{0, 0, 0, 0, 0}, - 0, + []uint64{0, 0, 1, 0, 0, 0, 3, 4, 1, 1, 0, 0, 0, 0, 0}, + 3940, }, - { - []uint64{0, 1, 0, 0, 0}, - 1, + []uint64{0, 0, 0, 0, 0, 0, 2, 4, 4, 0, 0, 0, 0, 0, 0}, + 4455, }, { - []uint64{0, 1, 0, 1, 0}, - 4, + []uint64{0, 0, 0, 0, 0, 0, 1, 4, 3, 2, 0, 0, 0, 0, 0}, + 5337, }, { - []uint64{1, 1, 1, 0, 0}, - 3, + []uint64{0, 0, 1, 0, 1, 0, 2, 2, 1, 3, 0, 0, 0, 0, 0}, + 4477, }, { - []uint64{0, 0, 1, 2, 1}, - 12, + []uint64{0, 0, 0, 0, 0, 1, 3, 2, 2, 2, 0, 0, 0, 0, 0}, + 4670, }, { - []uint64{0, 0, 0, 0, 0}, - 0, + []uint64{0, 0, 0, 1, 1, 0, 1, 1, 1, 5, 0, 0, 0, 0, 0}, + 5670, }, { - []uint64{0, 1, 0, 0, 0}, - 1, + []uint64{0, 0, 0, 0, 0, 2, 1, 1, 4, 2, 0, 0, 0, 0, 0}, + 5091, }, { - []uint64{0, 2, 0, 0, 0}, - 2, + []uint64{0, 0, 2, 0, 0, 0, 2, 4, 1, 1, 0, 0, 0, 0, 0}, + 3420, }, { - []uint64{1, 0, 1, 1, 0}, - 5, + []uint64{0, 0, 0, 0, 0, 0, 1, 3, 2, 4, 0, 0, 0, 0, 0}, + 5917, }, { - []uint64{2, 0, 1, 0, 1}, - 6, + []uint64{0, 0, 1, 0, 1, 0, 0, 4, 4, 0, 0, 0, 0, 0, 0}, + 3988, }, } @@ -145,8 +144,8 @@ func (w worker) simulateMetrics(res *resource.Resource, exporterFunc func() (sdk Exemplars: w.exemplars, Count: iteration, Sum: sum, - // Simple bounds assumption - Bounds: []float64{0, 1, 2, 3, 4}, + // Bounds from https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/sdk.md#explicit-bucket-histogram-aggregation + Bounds: []float64{0, 5, 10, 25, 50, 75, 100, 250, 500, 750, 1000, 2500, 5000, 7500, 10000}, BucketCounts: bucketCounts, }, },