Skip to content

Commit

Permalink
Add Metrics for TektonResult
Browse files Browse the repository at this point in the history
Added Metrics `results_reconciled` which tells us
what type of logging is being used for results installation.
This metric can be use for telemetry.
  • Loading branch information
khrm authored and tekton-robot committed Sep 8, 2023
1 parent 8265d80 commit 66473ca
Show file tree
Hide file tree
Showing 9 changed files with 818 additions and 14 deletions.
3 changes: 3 additions & 0 deletions pkg/reconciler/common/initcontroller.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,9 @@ func (ctrl Controller) fetchSourceManifests(ctx context.Context, opts PayloadOpt
case "chains":
var chain v1alpha1.TektonChain
return AppendTarget(ctx, ctrl.Manifest, &chain)
case "results":
var results v1alpha1.TektonResult
return AppendTarget(ctx, ctrl.Manifest, &results)
case "pipelines-as-code":
pacLocation := filepath.Join(os.Getenv(KoEnvKey), "tekton-addon", "pipelines-as-code")
return AppendManifest(ctrl.Manifest, pacLocation)
Expand Down
27 changes: 14 additions & 13 deletions pkg/reconciler/kubernetes/tektonresult/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,13 @@ package tektonresult
import (
"context"

"github.com/go-logr/zapr"
mfc "github.com/manifestival/client-go-client"
mf "github.com/manifestival/manifestival"
"github.com/tektoncd/operator/pkg/apis/operator/v1alpha1"
operatorclient "github.com/tektoncd/operator/pkg/client/injection/client"
tektonInstallerinformer "github.com/tektoncd/operator/pkg/client/injection/informers/operator/v1alpha1/tektoninstallerset"
tektonPipelineInformer "github.com/tektoncd/operator/pkg/client/injection/informers/operator/v1alpha1/tektonpipeline"
tektonResultInformer "github.com/tektoncd/operator/pkg/client/injection/informers/operator/v1alpha1/tektonresult"
tektonResultReconciler "github.com/tektoncd/operator/pkg/client/injection/reconciler/operator/v1alpha1/tektonresult"
"github.com/tektoncd/operator/pkg/reconciler/common"
"go.uber.org/zap"
"k8s.io/client-go/tools/cache"
kubeclient "knative.dev/pkg/client/injection/kube/client"
"knative.dev/pkg/configmap"
Expand All @@ -38,6 +34,8 @@ import (
"knative.dev/pkg/logging"
)

const versionConfigMap = "results-info"

// NewController initializes the controller and is called by the generated code
// Registers event handlers to enqueue events
func NewController(ctx context.Context, cmw configmap.Watcher) *controller.Impl {
Expand All @@ -49,23 +47,24 @@ func NewExtendedController(generator common.ExtensionGenerator) injection.Contro
return func(ctx context.Context, cmw configmap.Watcher) *controller.Impl {
logger := logging.FromContext(ctx)

mfclient, err := mfc.NewClient(injection.GetConfig(ctx))
if err != nil {
logger.Fatalw("Error creating client from injected config", zap.Error(err))
ctrl := common.Controller{
Logger: logger,
VersionConfigMap: versionConfigMap,
}
mflogger := zapr.NewLogger(logger.Named("manifestival").Desugar())
manifest, err := mf.ManifestFrom(mf.Slice{}, mf.UseClient(mfclient), mf.UseLogger(mflogger))
if err != nil {
logger.Fatalw("Error creating initial manifest", zap.Error(err))

manifest, resultsVer := ctrl.InitController(ctx, common.PayloadOptions{})
if resultsVer == common.ReleaseVersionUnknown {
resultsVer = "devel"
}

operatorVer, err := common.OperatorVersion(ctx)
if err != nil {
logger.Fatal(err)
}

if err := common.AppendTarget(ctx, &manifest, &v1alpha1.TektonResult{}); err != nil {
logger.Fatalw("Error fetching manifests", zap.Error(err))
recorder, err := NewRecorder()
if err != nil {
logger.Fatalw("Error starting Results metrics")
}

c := &Reconciler{
Expand All @@ -75,6 +74,8 @@ func NewExtendedController(generator common.ExtensionGenerator) injection.Contro
manifest: manifest,
pipelineInformer: tektonPipelineInformer.Get(ctx),
operatorVersion: operatorVer,
resultsVersion: resultsVer,
recorder: recorder,
}
impl := tektonResultReconciler.NewImpl(ctx, c)

Expand Down
108 changes: 108 additions & 0 deletions pkg/reconciler/kubernetes/tektonresult/metrics.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
/*
Copyright 2023 The Tekton Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package tektonresult

import (
"context"
"fmt"

"github.com/tektoncd/operator/pkg/apis/operator/v1alpha1"
"go.opencensus.io/stats"
"go.opencensus.io/stats/view"
"go.opencensus.io/tag"
"go.uber.org/zap"
"knative.dev/pkg/metrics"
)

var (
rReconcileCount = stats.Float64("results_reconciled",
"results reconciled with their log type",
stats.UnitDimensionless)
rReconcilerCountView *view.View

errUninitializedRecorder = fmt.Errorf("ignoring the metrics recording for result failed to initialize the metrics recorder")
)

// Recorder holds keys for Tekton metrics
type Recorder struct {
initialized bool
version tag.Key
logType tag.Key
}

// NewRecorder creates a new metrics recorder instance
// to log the PipelineRun related metrics
func NewRecorder() (*Recorder, error) {
r := &Recorder{
initialized: true,
}

version, err := tag.NewKey("version")
if err != nil {
return nil, err
}
r.version = version

logType, err := tag.NewKey("log_type")
if err != nil {
return nil, err
}
r.logType = logType

rReconcilerCountView = &view.View{
Description: rReconcileCount.Description(),
Measure: rReconcileCount,
Aggregation: view.LastValue(),
TagKeys: []tag.Key{r.version, r.logType},
}

err = view.Register(rReconcilerCountView)

if err != nil {
r.initialized = false
return r, err
}

return r, nil
}

// Record the Results reconciled with their log type
func (r *Recorder) Count(version, logType string) error {
if !r.initialized {
return errUninitializedRecorder
}

ctx, err := tag.New(
context.Background(),
tag.Insert(r.version, version),
tag.Insert(r.logType, logType),
)

if err != nil {
return err
}

metrics.Record(ctx, rReconcileCount.M(float64(1)))
return nil
}

func (m *Recorder) LogMetrics(version string, spec v1alpha1.TektonResultSpec, logger *zap.SugaredLogger) {
err := m.Count(version, spec.LogsType)
if err != nil {
logger.Warnf("%v: Failed to log the metrics : %v", v1alpha1.KindTektonResult, err)
}
}
47 changes: 47 additions & 0 deletions pkg/reconciler/kubernetes/tektonresult/metrics_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
Copyright 2023 The Tekton Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package tektonresult

import (
"testing"

"knative.dev/pkg/metrics/metricstest" // Required to setup metrics env for testing
_ "knative.dev/pkg/metrics/testing"
)

func TestUninitializedMetrics(t *testing.T) {
recorder := Recorder{}
if err := recorder.Count("v0.1", "GCS"); err != errUninitializedRecorder {
t.Errorf("recorder.Count recording expected to return error %s but got %s", errUninitializedRecorder.Error(), err.Error())
}
}

func TestMetricsCount(t *testing.T) {

metricstest.Unregister("results_reconciled")

recorder, err := NewRecorder()
if err != nil {
t.Errorf("failed to initilized recorder, got %s", err.Error())

}
if err := recorder.Count("v0.1", "GCS"); err != nil {
t.Errorf("recorder.Count recording failed got %s", err.Error())
}
metricstest.CheckStatsReported(t, "results_reconciled")
metricstest.CheckLastValueData(t, "results_reconciled", map[string]string{"version": "v0.1", "log_type": "GCS"}, float64(1))
}
5 changes: 4 additions & 1 deletion pkg/reconciler/kubernetes/tektonresult/tektonresult.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ type Reconciler struct {
pipelineInformer pipelineInformer.TektonPipelineInformer

operatorVersion string
resultsVersion string
recorder *Recorder
}

// Check that our Reconciler implements controller.Reconciler
Expand Down Expand Up @@ -103,6 +105,8 @@ func (r *Reconciler) FinalizeKind(ctx context.Context, original *v1alpha1.Tekton
// converge the two.
func (r *Reconciler) ReconcileKind(ctx context.Context, tr *v1alpha1.TektonResult) pkgreconciler.Event {
logger := logging.FromContext(ctx)
defer r.recorder.LogMetrics(r.resultsVersion, tr.Spec, logger)

tr.Status.InitializeConditions()
tr.Status.ObservedGeneration = tr.Generation

Expand Down Expand Up @@ -157,7 +161,6 @@ func (r *Reconciler) ReconcileKind(ctx context.Context, tr *v1alpha1.TektonResul
if err != nil {
return err
}

return r.updateTektonResultsStatus(ctx, tr, createdIs)
}

Expand Down
Loading

0 comments on commit 66473ca

Please sign in to comment.