-
Notifications
You must be signed in to change notification settings - Fork 31
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add metrics for created operands (#837)
* Add metrics for created operands Signed-off-by: Ruben Vargas <[email protected]> * go mod tidy Signed-off-by: Ruben Vargas <[email protected]> * Add CHANGELOG entry Signed-off-by: Ruben Vargas <[email protected]> * Update internal/crdmetrics/tempo_stack_test.go Co-authored-by: Israel Blancas <[email protected]> * Fix linting issues Signed-off-by: Ruben Vargas <[email protected]> * Remove unused constants Signed-off-by: Ruben Vargas <[email protected]> * Add jaegerUI and multitenancy metrics Signed-off-by: Ruben Vargas <[email protected]> --------- Signed-off-by: Ruben Vargas <[email protected]> Co-authored-by: Israel Blancas <[email protected]>
- Loading branch information
1 parent
eed0197
commit 4cdfd50
Showing
9 changed files
with
490 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
# 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. operator, github action) | ||
component: operator | ||
|
||
# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). | ||
note: Add storage and managed operands gauge metric to the operator metrics. | ||
|
||
# One or more tracking issues related to the change | ||
issues: [838] | ||
|
||
# (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: |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
package crdmetrics | ||
|
||
import ( | ||
"go.opentelemetry.io/otel" | ||
"go.opentelemetry.io/otel/exporters/prometheus" | ||
"go.opentelemetry.io/otel/sdk/metric" | ||
"sigs.k8s.io/controller-runtime/pkg/client" | ||
"sigs.k8s.io/controller-runtime/pkg/metrics" | ||
) | ||
|
||
// Bootstrap configures the OpenTelemetry meter provider with the Prometheus exporter. | ||
func Bootstrap(client client.Client) error { | ||
exporter, err := prometheus.New(prometheus.WithRegisterer(metrics.Registry)) | ||
if err != nil { | ||
return err | ||
} | ||
provider := metric.NewMeterProvider(metric.WithReader(exporter)) | ||
otel.SetMeterProvider(provider) | ||
// Create metrics | ||
tempoStackMetrics := newTempoStackMetrics(client) | ||
err = tempoStackMetrics.Setup() | ||
return err | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
package crdmetrics | ||
|
||
const ( | ||
meterName = "grafana/tempo-operator" | ||
) | ||
|
||
// Metric labels | ||
|
||
const ( | ||
tempoStackMetricsPrefix = "tempo_operator_tempostack" | ||
storageBackendMetric = "storage_backend" | ||
managedMetric = "managed" | ||
jaegerUIUsage = "jaeger_ui" | ||
multitenancy = "multi_tenancy" | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
package crdmetrics | ||
|
||
import ( | ||
"go.opentelemetry.io/otel/attribute" | ||
"go.opentelemetry.io/otel/metric" | ||
"sigs.k8s.io/controller-runtime/pkg/client" | ||
) | ||
|
||
type countFn func(instance client.Object) (string, bool) | ||
|
||
// This structure contains the labels associated with the instances and a counter of the number of instances. | ||
type instancesView struct { | ||
Name string | ||
Label string | ||
Count map[string]int | ||
Gauge metric.Int64ObservableGauge | ||
KeyFn countFn | ||
} | ||
|
||
func (i *instancesView) reset() { | ||
for k := range i.Count { | ||
i.Count[k] = 0 | ||
} | ||
} | ||
|
||
func (i *instancesView) Record(instance client.Object) { | ||
label, counted := i.KeyFn(instance) | ||
if counted { | ||
i.Count[label]++ | ||
} | ||
} | ||
|
||
func (i *instancesView) Report(observer metric.Observer) { | ||
for key, count := range i.Count { | ||
opt := metric.WithAttributes( | ||
attribute.Key(i.Label).String(key), | ||
) | ||
observer.ObserveInt64(i.Gauge, int64(count), opt) | ||
} | ||
} | ||
|
||
func newObservation(meter metric.Meter, name, desc, label string, keyFn countFn) (instancesView, error) { | ||
observation := instancesView{ | ||
Name: name, | ||
Count: make(map[string]int), | ||
KeyFn: keyFn, | ||
Label: label, | ||
} | ||
|
||
g, err := meter.Int64ObservableGauge(instanceMetricName(name), metric.WithDescription(desc)) | ||
if err != nil { | ||
return instancesView{}, err | ||
} | ||
|
||
observation.Gauge = g | ||
return observation, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
package crdmetrics | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"strconv" | ||
|
||
"go.opentelemetry.io/otel" | ||
"go.opentelemetry.io/otel/metric" | ||
"sigs.k8s.io/controller-runtime/pkg/client" | ||
|
||
"github.com/grafana/tempo-operator/apis/tempo/v1alpha1" | ||
) | ||
|
||
type tempoStackMetrics struct { | ||
client client.Client | ||
observations []instancesView | ||
} | ||
|
||
func instanceMetricName(name string) string { | ||
return fmt.Sprintf("%s_%s", tempoStackMetricsPrefix, name) | ||
} | ||
|
||
func newTempoStackMetrics(client client.Client) *tempoStackMetrics { | ||
return &tempoStackMetrics{ | ||
client: client, | ||
} | ||
} | ||
|
||
func (i *tempoStackMetrics) Setup() error { | ||
meter := otel.Meter(meterName) | ||
|
||
obs, err := newObservation(meter, | ||
storageBackendMetric, | ||
"Number of instances per storage type", | ||
"type", | ||
func(instance client.Object) (string, bool) { | ||
tempoStack := instance.(*v1alpha1.TempoStack) | ||
return string(tempoStack.Spec.Storage.Secret.Type), true | ||
}) | ||
if err != nil { | ||
return err | ||
} | ||
i.observations = append(i.observations, obs) | ||
|
||
obs, err = newObservation(meter, | ||
managedMetric, | ||
"Instances managed by the operator", | ||
"state", | ||
func(instance client.Object) (string, bool) { | ||
tempoStack := instance.(*v1alpha1.TempoStack) | ||
return string(tempoStack.Spec.ManagementState), true | ||
}) | ||
if err != nil { | ||
return err | ||
} | ||
i.observations = append(i.observations, obs) | ||
|
||
obs, err = newObservation(meter, | ||
jaegerUIUsage, | ||
"Instances with jaeger UI enabled/disabled", | ||
"enabled", | ||
func(instance client.Object) (string, bool) { | ||
tempoStack := instance.(*v1alpha1.TempoStack) | ||
return strconv.FormatBool(tempoStack.Spec.Template.QueryFrontend.JaegerQuery.Enabled), true | ||
}) | ||
if err != nil { | ||
return err | ||
} | ||
i.observations = append(i.observations, obs) | ||
|
||
obs, err = newObservation(meter, | ||
multitenancy, | ||
"Instances with multi-tenancy mode static/openshift/disabled", | ||
"type", | ||
func(instance client.Object) (string, bool) { | ||
tempoStack := instance.(*v1alpha1.TempoStack) | ||
if tempoStack.Spec.Tenants != nil && tempoStack.Spec.Tenants.Mode != "" { | ||
return string(tempoStack.Spec.Tenants.Mode), true | ||
} | ||
return "disabled", true | ||
}) | ||
if err != nil { | ||
return err | ||
} | ||
i.observations = append(i.observations, obs) | ||
|
||
instruments := make([]metric.Observable, 0, len(i.observations)) | ||
for _, o := range i.observations { | ||
instruments = append(instruments, o.Gauge) | ||
} | ||
_, err = meter.RegisterCallback(i.callback, instruments...) | ||
return err | ||
} | ||
|
||
func (i *tempoStackMetrics) callback(ctx context.Context, observer metric.Observer) error { | ||
instances := &v1alpha1.TempoStackList{} | ||
if err := i.client.List(ctx, instances); err == nil { | ||
|
||
// Reset observations | ||
for _, o := range i.observations { | ||
o.reset() | ||
} | ||
|
||
for k := range instances.Items { | ||
tempoStack := instances.Items[k] | ||
for _, o := range i.observations { | ||
o.Record(&tempoStack) | ||
} | ||
} | ||
} | ||
|
||
// Report metrics | ||
for _, o := range i.observations { | ||
o.Report(observer) | ||
} | ||
|
||
return nil | ||
} |
Oops, something went wrong.