From 9e0b85d6e307705623e678aa255d04e0b528b2fe Mon Sep 17 00:00:00 2001 From: sengjea Date: Thu, 19 Feb 2026 17:36:48 +0000 Subject: [PATCH 1/4] Add more span attributes for tracing --- graph.go | 3 +++ task.go | 28 ++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/graph.go b/graph.go index 2f791c6..07e3fc0 100644 --- a/graph.go +++ b/graph.go @@ -169,6 +169,9 @@ func (gn *graphNode) execute(ctx context.Context, rs *runState) (err error) { if !providesSet.Contains(binding.ID()) { extra = append(extra, binding.ID().String()) } + if binding.Status() == Absent { + span.RecordError(binding.Error()) + } } if len(extra) > 0 || len(missing) > 0 { return wrapStackErrorf( diff --git a/task.go b/task.go index 9d5b2ec..d2c9174 100644 --- a/task.go +++ b/task.go @@ -4,6 +4,8 @@ import ( "context" set "github.com/deckarep/golang-set/v2" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/trace" ) // A TaskSet defines a nestable collection of tasks. A Task fulfils the TaskSet interface, acting as @@ -192,6 +194,8 @@ type Condition interface { Evaluate(ctx context.Context, b Binder) (bool, error) // Deps should return the IDs of the keys used by the Evaluate function. Deps() []ID + // Keys returns the keys in the conditional + Keys() []ReadOnlyKey[bool] } // ConditionAnd evaluates to true if and only if all of the keys it contains are bound to true. @@ -220,6 +224,11 @@ func (ca ConditionAnd) Deps() []ID { return deps } +// Keys returns the keys in the conditional +func (ca ConditionAnd) Keys() []ReadOnlyKey[bool] { + return ca +} + // ConditionOr evaluates to true if any of the keys it contains are bound to true. type ConditionOr []ReadOnlyKey[bool] @@ -246,6 +255,11 @@ func (co ConditionOr) Deps() []ID { return deps } +// Keys returns the keys in the conditional +func (co ConditionOr) Keys() []ReadOnlyKey[bool] { + return co +} + // Conditional wraps tasks such that they are only run if given Condition evaluates to true. If it // evaluates to false, the bindings in DefaultBindings are used, with any missing keys provided by // the wrapped tasks bound as absent. @@ -270,6 +284,10 @@ func (c Conditional) Locate() Conditional { return c } +const ( + traceTaskgraphConditionalPrefix = "taskgraph.conditional." +) + // Tasks satisfies TaskSet.Tasks. func (c Conditional) Tasks() []Task { defaultBindingsMap := map[ID]Binding{} @@ -291,6 +309,16 @@ func (c Conditional) Tasks() []Task { if err != nil { return nil, err } + span := trace.SpanFromContext(ctx) + span.SetAttributes(attribute.Bool(traceTaskgraphConditionalPrefix+"execute", shouldExecute)) + for _, k := range c.Condition.Keys() { + v, err := k.Get(b) + if err != nil { + span.SetAttributes(attribute.String(traceTaskgraphConditionalPrefix+k.ID().String(), err.Error())) + } else { + span.SetAttributes(attribute.Bool(traceTaskgraphConditionalPrefix+k.ID().String(), v)) + } + } if shouldExecute { return t.Execute(ctx, b) } From a1da0427684ec7ca519375c0d35c9fb7523c00ed Mon Sep 17 00:00:00 2001 From: sengjea Date: Thu, 19 Feb 2026 17:42:52 +0000 Subject: [PATCH 2/4] lint --- task.go | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/task.go b/task.go index d2c9174..f198d6f 100644 --- a/task.go +++ b/task.go @@ -310,13 +310,22 @@ func (c Conditional) Tasks() []Task { return nil, err } span := trace.SpanFromContext(ctx) - span.SetAttributes(attribute.Bool(traceTaskgraphConditionalPrefix+"execute", shouldExecute)) + span.SetAttributes( + attribute.Bool(traceTaskgraphConditionalPrefix+"execute", shouldExecute), + ) for _, k := range c.Condition.Keys() { v, err := k.Get(b) if err != nil { - span.SetAttributes(attribute.String(traceTaskgraphConditionalPrefix+k.ID().String(), err.Error())) + span.SetAttributes( + attribute.String( + traceTaskgraphConditionalPrefix+k.ID().String(), + err.Error(), + ), + ) } else { - span.SetAttributes(attribute.Bool(traceTaskgraphConditionalPrefix+k.ID().String(), v)) + span.SetAttributes( + attribute.Bool(traceTaskgraphConditionalPrefix+k.ID().String(), v), + ) } } if shouldExecute { From fa736a030c6d255213e89057cb5e0c95f78eeeab Mon Sep 17 00:00:00 2001 From: sengjea Date: Fri, 20 Feb 2026 14:30:12 +0000 Subject: [PATCH 3/4] use attributes --- graph.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/graph.go b/graph.go index 07e3fc0..1c58756 100644 --- a/graph.go +++ b/graph.go @@ -12,6 +12,7 @@ import ( "time" set "github.com/deckarep/golang-set/v2" + "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/trace" "go.opentelemetry.io/otel/trace/noop" "golang.org/x/sync/errgroup" @@ -123,6 +124,10 @@ type graphNode struct { tracer trace.Tracer } +const ( + traceTaskgraphAbsentKeysPrefix = "taskgraph.absent_keys." +) + // Execute the task against the binder provided in the runState. // // This assumes that all of the task's dependencies have been bound; it is the responsibility of the @@ -170,7 +175,7 @@ func (gn *graphNode) execute(ctx context.Context, rs *runState) (err error) { extra = append(extra, binding.ID().String()) } if binding.Status() == Absent { - span.RecordError(binding.Error()) + span.SetAttributes(attribute.String(traceTaskgraphAbsentKeysPrefix+binding.ID().String(), fmt.Sprintf("%v", binding.Error()))) } } if len(extra) > 0 || len(missing) > 0 { From 699bff246d90aa169de8803dcdbf0890103deac4 Mon Sep 17 00:00:00 2001 From: sengjea Date: Fri, 20 Feb 2026 14:31:55 +0000 Subject: [PATCH 4/4] lint --- graph.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/graph.go b/graph.go index 1c58756..516a161 100644 --- a/graph.go +++ b/graph.go @@ -175,7 +175,12 @@ func (gn *graphNode) execute(ctx context.Context, rs *runState) (err error) { extra = append(extra, binding.ID().String()) } if binding.Status() == Absent { - span.SetAttributes(attribute.String(traceTaskgraphAbsentKeysPrefix+binding.ID().String(), fmt.Sprintf("%v", binding.Error()))) + span.SetAttributes( + attribute.String( + traceTaskgraphAbsentKeysPrefix+binding.ID().String(), + fmt.Sprintf("%v", binding.Error()), + ), + ) } } if len(extra) > 0 || len(missing) > 0 {