Skip to content

Commit

Permalink
Prior to this PR, when pipeline refers to a remote pipeline, in the p…
Browse files Browse the repository at this point in the history
…ipeline-related metrics, the pipeline name tag will be set to 'anonymous'. Taskrun has the same situation.

This commit added some scenarios for obtaining pipeline or task names.
When the pipeline or task name cannot be determined accurately,
the value is obtained through the corresponding label.
  • Loading branch information
cugykw authored and tekton-robot committed May 17, 2024
1 parent 4413478 commit 66f1f9e
Show file tree
Hide file tree
Showing 4 changed files with 207 additions and 13 deletions.
27 changes: 23 additions & 4 deletions pkg/pipelinerunmetrics/metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
"time"

"github.com/tektoncd/pipeline/pkg/apis/config"
"github.com/tektoncd/pipeline/pkg/apis/pipeline"
v1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1"
listers "github.com/tektoncd/pipeline/pkg/client/listers/pipeline/v1"
"go.opencensus.io/stats"
Expand Down Expand Up @@ -76,6 +77,8 @@ const (
// ReasonCancelled indicates that a PipelineRun was cancelled.
// Aliased for backwards compatibility; additional reasons should not be added here.
ReasonCancelled = v1.PipelineRunReasonCancelled

anonymous = "anonymous"
)

// Recorder holds keys for Tekton metrics
Expand Down Expand Up @@ -233,6 +236,24 @@ func nilInsertTag(task, taskrun string) []tag.Mutator {
return []tag.Mutator{}
}

func getPipelineTagName(pr *v1.PipelineRun) string {
pipelineName := anonymous
switch {
case pr.Spec.PipelineRef != nil && pr.Spec.PipelineRef.Name != "":
pipelineName = pr.Spec.PipelineRef.Name
case pr.Spec.PipelineSpec != nil:
default:
if len(pr.Labels) > 0 {
pipelineLabel, hasPipelineLabel := pr.Labels[pipeline.PipelineLabelKey]
if hasPipelineLabel && len(pipelineLabel) > 0 {
pipelineName = pipelineLabel
}
}
}

return pipelineName
}

// DurationAndCount logs the duration of PipelineRun execution and
// count for number of PipelineRuns succeed or failed
// returns an error if its failed to log the metrics
Expand Down Expand Up @@ -268,10 +289,8 @@ func (r *Recorder) DurationAndCount(pr *v1.PipelineRun, beforeCondition *apis.Co
}
reason := cond.Reason

pipelineName := "anonymous"
if pr.Spec.PipelineRef != nil && pr.Spec.PipelineRef.Name != "" {
pipelineName = pr.Spec.PipelineRef.Name
}
pipelineName := getPipelineTagName(pr)

ctx, err := tag.New(
context.Background(),
append([]tag.Mutator{tag.Insert(namespaceTag, pr.Namespace),
Expand Down
45 changes: 45 additions & 0 deletions pkg/pipelinerunmetrics/metrics_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ import (
"testing"
"time"

"github.com/tektoncd/pipeline/pkg/apis/pipeline"

"github.com/tektoncd/pipeline/pkg/apis/config"
v1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1"
fakepipelineruninformer "github.com/tektoncd/pipeline/pkg/client/injection/informers/pipeline/v1/pipelinerun/fake"
Expand Down Expand Up @@ -384,6 +386,49 @@ func TestRecordPipelineRunDurationCount(t *testing.T) {
expectedCount: 1,
beforeCondition: nil,
countWithReason: true,
}, {
name: "for failed pipeline with reference remote pipeline",
pipelineRun: &v1.PipelineRun{
ObjectMeta: metav1.ObjectMeta{
Name: "pipelinerun-1",
Namespace: "ns",
Labels: map[string]string{
pipeline.PipelineLabelKey: "pipeline-remote",
},
},
Spec: v1.PipelineRunSpec{
PipelineRef: &v1.PipelineRef{
ResolverRef: v1.ResolverRef{
Resolver: "git",
},
},
},
Status: v1.PipelineRunStatus{
Status: duckv1.Status{
Conditions: duckv1.Conditions{{
Type: apis.ConditionSucceeded,
Status: corev1.ConditionFalse,
}},
},
PipelineRunStatusFields: v1.PipelineRunStatusFields{
StartTime: &startTime,
CompletionTime: &completionTime,
},
},
},
expectedDurationTags: map[string]string{
"pipeline": "pipeline-remote",
"pipelinerun": "pipelinerun-1",
"namespace": "ns",
"status": "failed",
},
expectedCountTags: map[string]string{
"status": "failed",
},
expectedDuration: 60,
expectedCount: 1,
beforeCondition: nil,
countWithReason: false,
}} {
t.Run(test.name, func(t *testing.T) {
unregisterMetrics()
Expand Down
28 changes: 20 additions & 8 deletions pkg/taskrunmetrics/metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,24 @@ func nilInsertTag(task, taskrun string) []tag.Mutator {
return []tag.Mutator{}
}

func getTaskTagName(tr *v1.TaskRun) string {
taskName := anonymous
switch {
case tr.Spec.TaskRef != nil && len(tr.Spec.TaskRef.Name) > 0:
taskName = tr.Spec.TaskRef.Name
case tr.Spec.TaskSpec != nil:
default:
if len(tr.Labels) > 0 {
taskLabel, hasTaskLabel := tr.Labels[pipeline.TaskLabelKey]
if hasTaskLabel && len(taskLabel) > 0 {
taskName = taskLabel
}
}
}

return taskName
}

// DurationAndCount logs the duration of TaskRun execution and
// count for number of TaskRuns succeed or failed
// returns an error if its failed to log the metrics
Expand All @@ -329,10 +347,7 @@ func (r *Recorder) DurationAndCount(ctx context.Context, tr *v1.TaskRun, beforeC
duration = tr.Status.CompletionTime.Sub(tr.Status.StartTime.Time)
}

taskName := anonymous
if tr.Spec.TaskRef != nil {
taskName = tr.Spec.TaskRef.Name
}
taskName := getTaskTagName(tr)

cond := tr.Status.GetCondition(apis.ConditionSucceeded)
status := "success"
Expand Down Expand Up @@ -449,10 +464,7 @@ func (r *Recorder) RecordPodLatency(ctx context.Context, pod *corev1.Pod, tr *v1
}

latency := scheduledTime.Sub(pod.CreationTimestamp.Time)
taskName := anonymous
if tr.Spec.TaskRef != nil {
taskName = tr.Spec.TaskRef.Name
}
taskName := getTaskTagName(tr)

ctx, err := tag.New(
ctx,
Expand Down
120 changes: 119 additions & 1 deletion pkg/taskrunmetrics/metrics_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,50 @@ func TestRecordTaskRunDurationCount(t *testing.T) {
expectedCount: 1,
beforeCondition: nil,
countWithReason: false,
}, {
name: "for failed taskrun with reference remote task",
taskRun: &v1.TaskRun{
ObjectMeta: metav1.ObjectMeta{
Name: "taskrun-1",
Namespace: "ns",
Labels: map[string]string{
pipeline.TaskLabelKey: "task-remote",
},
},
Spec: v1.TaskRunSpec{
TaskRef: &v1.TaskRef{
ResolverRef: v1.ResolverRef{
Resolver: "git",
},
},
},
Status: v1.TaskRunStatus{
Status: duckv1.Status{
Conditions: duckv1.Conditions{{
Type: apis.ConditionSucceeded,
Status: corev1.ConditionFalse,
}},
},
TaskRunStatusFields: v1.TaskRunStatusFields{
StartTime: &startTime,
CompletionTime: &completionTime,
},
},
},
metricName: "taskrun_duration_seconds",
expectedDurationTags: map[string]string{
"task": "task-remote",
"taskrun": "taskrun-1",
"namespace": "ns",
"status": "failed",
},
expectedCountTags: map[string]string{
"status": "failed",
},
expectedDuration: 60,
expectedCount: 1,
beforeCondition: nil,
countWithReason: false,
}, {
name: "for succeeded taskrun in pipelinerun",
taskRun: &v1.TaskRun{
Expand Down Expand Up @@ -574,12 +618,38 @@ func TestRecordPodLatency(t *testing.T) {
TaskRef: &v1.TaskRef{Name: "task-1"},
},
}
trFromRemoteTask := &v1.TaskRun{
ObjectMeta: metav1.ObjectMeta{
Name: "test-taskrun",
Namespace: "foo",
Labels: map[string]string{
pipeline.TaskLabelKey: "task-remote",
},
},
Spec: v1.TaskRunSpec{
TaskRef: &v1.TaskRef{
ResolverRef: v1.ResolverRef{Resolver: "task-remote"},
},
},
}
emptyLabelTRFromRemoteTask := &v1.TaskRun{
ObjectMeta: metav1.ObjectMeta{
Name: "test-taskrun",
Namespace: "foo",
},
Spec: v1.TaskRunSpec{
TaskRef: &v1.TaskRef{
ResolverRef: v1.ResolverRef{Resolver: "task-remote"},
},
},
}
for _, td := range []struct {
name string
pod *corev1.Pod
expectedTags map[string]string
expectedValue float64
expectingError bool
taskRun *v1.TaskRun
}{{
name: "for scheduled pod",
pod: &corev1.Pod{
Expand All @@ -602,6 +672,53 @@ func TestRecordPodLatency(t *testing.T) {
"namespace": "foo",
},
expectedValue: 4000,
taskRun: taskRun,
}, {
name: "for scheduled pod with reference remote task",
pod: &corev1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "test-taskrun-pod-123456",
Namespace: "foo",
CreationTimestamp: creationTime,
},
Status: corev1.PodStatus{
Conditions: []corev1.PodCondition{{
Type: corev1.PodScheduled,
LastTransitionTime: metav1.Time{Time: creationTime.Add(4 * time.Second)},
}},
},
},
expectedTags: map[string]string{
"pod": "test-taskrun-pod-123456",
"task": "task-remote",
"taskrun": "test-taskrun",
"namespace": "foo",
},
expectedValue: 4000,
taskRun: trFromRemoteTask,
}, {
name: "for scheduled pod - empty label tr reference remote task",
pod: &corev1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "test-taskrun-pod-123456",
Namespace: "foo",
CreationTimestamp: creationTime,
},
Status: corev1.PodStatus{
Conditions: []corev1.PodCondition{{
Type: corev1.PodScheduled,
LastTransitionTime: metav1.Time{Time: creationTime.Add(4 * time.Second)},
}},
},
},
expectedTags: map[string]string{
"pod": "test-taskrun-pod-123456",
"task": anonymous,
"taskrun": "test-taskrun",
"namespace": "foo",
},
expectedValue: 4000,
taskRun: emptyLabelTRFromRemoteTask,
}, {
name: "for non scheduled pod",
pod: &corev1.Pod{
Expand All @@ -613,6 +730,7 @@ func TestRecordPodLatency(t *testing.T) {
Status: corev1.PodStatus{},
},
expectingError: true,
taskRun: taskRun,
}} {
t.Run(td.name, func(t *testing.T) {
unregisterMetrics()
Expand All @@ -623,7 +741,7 @@ func TestRecordPodLatency(t *testing.T) {
t.Fatalf("NewRecorder: %v", err)
}

if err := metrics.RecordPodLatency(ctx, td.pod, taskRun); td.expectingError && err == nil {
if err := metrics.RecordPodLatency(ctx, td.pod, td.taskRun); td.expectingError && err == nil {
t.Error("RecordPodLatency wanted error, got nil")
} else if !td.expectingError {
if err != nil {
Expand Down

0 comments on commit 66f1f9e

Please sign in to comment.