diff --git a/pkg/cri/sbserver/image_pull.go b/pkg/cri/sbserver/image_pull.go index b2409372c..2151221fe 100644 --- a/pkg/cri/sbserver/image_pull.go +++ b/pkg/cri/sbserver/image_pull.go @@ -36,7 +36,6 @@ import ( "github.com/containerd/imgcrypt" "github.com/containerd/imgcrypt/images/encryption" imagespec "github.com/opencontainers/image-spec/specs-go/v1" - "go.opentelemetry.io/otel/attribute" runtime "k8s.io/cri-api/pkg/apis/runtime/v1" "github.com/containerd/containerd" @@ -137,8 +136,8 @@ func (c *criService) PullImage(ctx context.Context, r *runtime.PullImageRequest) } log.G(ctx).Debugf("PullImage %q with snapshotter %s", ref, snapshotter) span.SetAttributes( - attribute.String("image.ref", ref), - attribute.String("snapshotter.name", snapshotter), + tracing.SpanAttribute("image.ref", ref), + tracing.SpanAttribute("snapshotter.name", snapshotter), ) pullOpts := []containerd.RemoteOpt{ diff --git a/pkg/cri/sbserver/image_remove.go b/pkg/cri/sbserver/image_remove.go index af9e1cf5f..7806b5dd7 100644 --- a/pkg/cri/sbserver/image_remove.go +++ b/pkg/cri/sbserver/image_remove.go @@ -23,7 +23,6 @@ import ( "github.com/containerd/containerd/errdefs" "github.com/containerd/containerd/images" "github.com/containerd/containerd/tracing" - "go.opentelemetry.io/otel/attribute" runtime "k8s.io/cri-api/pkg/apis/runtime/v1" ) @@ -45,7 +44,7 @@ func (c *criService) RemoveImage(ctx context.Context, r *runtime.RemoveImageRequ } return nil, fmt.Errorf("can not resolve %q locally: %w", r.GetImage().GetImage(), err) } - span.SetAttributes(attribute.String("image.id", image.ID)) + span.SetAttributes(tracing.SpanAttribute("image.id", image.ID)) // Remove all image references. for i, ref := range image.References { var opts []images.DeleteOpt diff --git a/pkg/cri/sbserver/image_status.go b/pkg/cri/sbserver/image_status.go index 6c2d98783..5caebfdf9 100644 --- a/pkg/cri/sbserver/image_status.go +++ b/pkg/cri/sbserver/image_status.go @@ -25,7 +25,6 @@ import ( "github.com/containerd/containerd/log" imagestore "github.com/containerd/containerd/pkg/cri/store/image" "github.com/containerd/containerd/tracing" - "go.opentelemetry.io/otel/attribute" imagespec "github.com/opencontainers/image-spec/specs-go/v1" runtime "k8s.io/cri-api/pkg/apis/runtime/v1" @@ -45,7 +44,7 @@ func (c *criService) ImageStatus(ctx context.Context, r *runtime.ImageStatusRequ } return nil, fmt.Errorf("can not resolve %q locally: %w", r.GetImage().GetImage(), err) } - span.SetAttributes(attribute.String("image.id", image.ID)) + span.SetAttributes(tracing.SpanAttribute("image.id", image.ID)) // TODO(random-liu): [P0] Make sure corresponding snapshot exists. What if snapshot // doesn't exist? diff --git a/pkg/cri/server/image_pull.go b/pkg/cri/server/image_pull.go index 31c723ee8..e885a95b6 100644 --- a/pkg/cri/server/image_pull.go +++ b/pkg/cri/server/image_pull.go @@ -36,7 +36,6 @@ import ( "github.com/containerd/imgcrypt" "github.com/containerd/imgcrypt/images/encryption" imagespec "github.com/opencontainers/image-spec/specs-go/v1" - "go.opentelemetry.io/otel/attribute" runtime "k8s.io/cri-api/pkg/apis/runtime/v1" "github.com/containerd/containerd" @@ -137,8 +136,8 @@ func (c *criService) PullImage(ctx context.Context, r *runtime.PullImageRequest) } log.G(ctx).Debugf("PullImage %q with snapshotter %s", ref, snapshotter) span.SetAttributes( - attribute.String("image.ref", ref), - attribute.String("snapshotter.name", snapshotter), + tracing.SpanAttribute("image.ref", ref), + tracing.SpanAttribute("snapshotter.name", snapshotter), ) pullOpts := []containerd.RemoteOpt{ containerd.WithSchema1Conversion, //nolint:staticcheck // Ignore SA1019. Need to keep deprecated package for compatibility. diff --git a/pkg/cri/server/image_remove.go b/pkg/cri/server/image_remove.go index e2fc285cd..df071a1d1 100644 --- a/pkg/cri/server/image_remove.go +++ b/pkg/cri/server/image_remove.go @@ -23,7 +23,6 @@ import ( "github.com/containerd/containerd/errdefs" "github.com/containerd/containerd/images" "github.com/containerd/containerd/tracing" - "go.opentelemetry.io/otel/attribute" runtime "k8s.io/cri-api/pkg/apis/runtime/v1" ) @@ -45,7 +44,7 @@ func (c *criService) RemoveImage(ctx context.Context, r *runtime.RemoveImageRequ } return nil, fmt.Errorf("can not resolve %q locally: %w", r.GetImage().GetImage(), err) } - span.SetAttributes(attribute.String("image.id", image.ID)) + span.SetAttributes(tracing.SpanAttribute("image.id", image.ID)) // Remove all image references. for i, ref := range image.References { var opts []images.DeleteOpt diff --git a/pkg/cri/server/image_status.go b/pkg/cri/server/image_status.go index cf535cd2d..dc96d2835 100644 --- a/pkg/cri/server/image_status.go +++ b/pkg/cri/server/image_status.go @@ -25,7 +25,6 @@ import ( "github.com/containerd/containerd/log" imagestore "github.com/containerd/containerd/pkg/cri/store/image" "github.com/containerd/containerd/tracing" - "go.opentelemetry.io/otel/attribute" imagespec "github.com/opencontainers/image-spec/specs-go/v1" runtime "k8s.io/cri-api/pkg/apis/runtime/v1" @@ -45,7 +44,7 @@ func (c *criService) ImageStatus(ctx context.Context, r *runtime.ImageStatusRequ } return nil, fmt.Errorf("can not resolve %q locally: %w", r.GetImage().GetImage(), err) } - span.SetAttributes(attribute.String("image.id", image.ID)) + span.SetAttributes(tracing.SpanAttribute("image.id", image.ID)) // TODO(random-liu): [P0] Make sure corresponding snapshot exists. What if snapshot // doesn't exist? diff --git a/pkg/unpack/unpacker.go b/pkg/unpack/unpacker.go index d137dbd12..a9f93182a 100644 --- a/pkg/unpack/unpacker.go +++ b/pkg/unpack/unpacker.go @@ -42,7 +42,6 @@ import ( "github.com/opencontainers/image-spec/identity" ocispec "github.com/opencontainers/image-spec/specs-go/v1" "github.com/sirupsen/logrus" - "go.opentelemetry.io/otel/attribute" "golang.org/x/sync/errgroup" "golang.org/x/sync/semaphore" ) @@ -166,8 +165,8 @@ func (u *Unpacker) Unpack(h images.Handler) images.Handler { ctx, span := tracing.StartSpan(ctx, "pkg.unpack.unpacker.UnpackHandler") defer span.End() span.SetAttributes( - attribute.String("descriptor.media.type", desc.MediaType), - attribute.String("descriptor.digest", desc.Digest.String())) + tracing.SpanAttribute("descriptor.media.type", desc.MediaType), + tracing.SpanAttribute("descriptor.digest", desc.Digest.String())) unlock, err := u.lockBlobDescriptor(ctx, desc) if err != nil { return nil, err @@ -186,7 +185,7 @@ func (u *Unpacker) Unpack(h images.Handler) images.Handler { // the config for i, child := range children { span.SetAttributes( - attribute.StringSlice("descriptor.child."+strconv.Itoa(i), []string{child.MediaType, child.Digest.String()}), + tracing.SpanAttribute("descriptor.child."+strconv.Itoa(i), []string{child.MediaType, child.Digest.String()}), ) if images.IsLayerType(child.MediaType) { manifestLayers = append(manifestLayers, child) @@ -412,9 +411,9 @@ func (u *Unpacker) unpack( for i, desc := range layers { _, layerSpan := tracing.StartSpan(ctx, "pkg.unpack.unpacker.unpackLayer") layerSpan.SetAttributes( - attribute.String("layer.media.type", desc.MediaType), - attribute.Int64("layer.media.size", desc.Size), - attribute.String("layer.media.digest", desc.Digest.String()), + tracing.SpanAttribute("layer.media.type", desc.MediaType), + tracing.SpanAttribute("layer.media.size", desc.Size), + tracing.SpanAttribute("layer.media.digest", desc.Digest.String()), ) if err := doUnpackFn(i, desc); err != nil { layerSpan.RecordError(err) @@ -448,9 +447,9 @@ func (u *Unpacker) fetch(ctx context.Context, h images.Handler, layers []ocispec for i, desc := range layers { ctx2, layerSpan := tracing.StartSpan(ctx2, "pkg.unpack.unpacker.fetchLayer") layerSpan.SetAttributes( - attribute.String("layer.media.type", desc.MediaType), - attribute.Int64("layer.media.size", desc.Size), - attribute.String("layer.media.digest", desc.Digest.String()), + tracing.SpanAttribute("layer.media.type", desc.MediaType), + tracing.SpanAttribute("layer.media.size", desc.Size), + tracing.SpanAttribute("layer.media.digest", desc.Digest.String()), ) desc := desc i := i diff --git a/pull.go b/pull.go index b5c8d24d8..293e5e5ce 100644 --- a/pull.go +++ b/pull.go @@ -30,7 +30,6 @@ import ( "github.com/containerd/containerd/remotes/docker/schema1" //nolint:staticcheck // Ignore SA1019. Need to keep deprecated package for compatibility. "github.com/containerd/containerd/tracing" ocispec "github.com/opencontainers/image-spec/specs-go/v1" - "go.opentelemetry.io/otel/attribute" "golang.org/x/sync/semaphore" ) @@ -64,11 +63,11 @@ func (c *Client) Pull(ctx context.Context, ref string, opts ...RemoteOpt) (_ Ima } span.SetAttributes( - attribute.String("image.ref", ref), - attribute.Bool("unpack", pullCtx.Unpack), - attribute.Int("max.concurrent.downloads", pullCtx.MaxConcurrentDownloads), - attribute.Int("max.concurrent.upload.layers", pullCtx.MaxConcurrentUploadedLayers), - attribute.Int("platforms.count", len(pullCtx.Platforms)), + tracing.SpanAttribute("image.ref", ref), + tracing.SpanAttribute("unpack", pullCtx.Unpack), + tracing.SpanAttribute("max.concurrent.downloads", pullCtx.MaxConcurrentDownloads), + tracing.SpanAttribute("max.concurrent.upload.layers", pullCtx.MaxConcurrentUploadedLayers), + tracing.SpanAttribute("platforms.count", len(pullCtx.Platforms)), ) ctx, done, err := c.WithLease(ctx) @@ -84,7 +83,7 @@ func (c *Client) Pull(ctx context.Context, ref string, opts ...RemoteOpt) (_ Ima if err != nil { return nil, fmt.Errorf("unable to resolve snapshotter: %w", err) } - span.SetAttributes(attribute.String("snapshotter.name", snapshotterName)) + span.SetAttributes(tracing.SpanAttribute("snapshotter.name", snapshotterName)) var uconfig UnpackConfig for _, opt := range pullCtx.UnpackOpts { if err := opt(ctx, &uconfig); err != nil { @@ -157,7 +156,7 @@ func (c *Client) Pull(ctx context.Context, ref string, opts ...RemoteOpt) (_ Ima } i := NewImageWithPlatform(c, img, pullCtx.PlatformMatcher) - span.SetAttributes(attribute.String("image.ref", i.Name())) + span.SetAttributes(tracing.SpanAttribute("image.ref", i.Name())) if unpacker != nil && ur.Unpacks == 0 { // Unpack was tried previously but nothing was unpacked diff --git a/tracing/helpers.go b/tracing/helpers.go new file mode 100644 index 000000000..035770998 --- /dev/null +++ b/tracing/helpers.go @@ -0,0 +1,85 @@ +/* + Copyright The containerd 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 tracing + +import ( + "encoding/json" + "fmt" + + "go.opentelemetry.io/otel/attribute" +) + +func any(k string, v interface{}) attribute.KeyValue { + if v == nil { + return attribute.String(k, "") + } + + switch typed := v.(type) { + case bool: + return attribute.Bool(k, typed) + case []bool: + return attribute.BoolSlice(k, typed) + case int: + return attribute.Int(k, typed) + case []int: + return attribute.IntSlice(k, typed) + case int8: + return attribute.Int(k, int(typed)) + case []int8: + ls := make([]int, 0, len(typed)) + for _, i := range typed { + ls = append(ls, int(i)) + } + return attribute.IntSlice(k, ls) + case int16: + return attribute.Int(k, int(typed)) + case []int16: + ls := make([]int, 0, len(typed)) + for _, i := range typed { + ls = append(ls, int(i)) + } + return attribute.IntSlice(k, ls) + case int32: + return attribute.Int64(k, int64(typed)) + case []int32: + ls := make([]int64, 0, len(typed)) + for _, i := range typed { + ls = append(ls, int64(i)) + } + return attribute.Int64Slice(k, ls) + case int64: + return attribute.Int64(k, typed) + case []int64: + return attribute.Int64Slice(k, typed) + case float64: + return attribute.Float64(k, typed) + case []float64: + return attribute.Float64Slice(k, typed) + case string: + return attribute.String(k, typed) + case []string: + return attribute.StringSlice(k, typed) + } + + if stringer, ok := v.(fmt.Stringer); ok { + return attribute.String(k, stringer.String()) + } + if b, err := json.Marshal(v); b != nil && err == nil { + return attribute.String(k, string(b)) + } + return attribute.String(k, fmt.Sprintf("%v", v)) +} diff --git a/tracing/log.go b/tracing/log.go index 6c6dd6d7e..98fa16f93 100644 --- a/tracing/log.go +++ b/tracing/log.go @@ -17,9 +17,6 @@ package tracing import ( - "encoding/json" - "fmt" - "github.com/sirupsen/logrus" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/trace" @@ -67,64 +64,3 @@ func logrusDataToAttrs(data logrus.Fields) []attribute.KeyValue { } return attrs } - -func any(k string, v interface{}) attribute.KeyValue { - if v == nil { - return attribute.String(k, "") - } - - switch typed := v.(type) { - case bool: - return attribute.Bool(k, typed) - case []bool: - return attribute.BoolSlice(k, typed) - case int: - return attribute.Int(k, typed) - case []int: - return attribute.IntSlice(k, typed) - case int8: - return attribute.Int(k, int(typed)) - case []int8: - ls := make([]int, 0, len(typed)) - for _, i := range typed { - ls = append(ls, int(i)) - } - return attribute.IntSlice(k, ls) - case int16: - return attribute.Int(k, int(typed)) - case []int16: - ls := make([]int, 0, len(typed)) - for _, i := range typed { - ls = append(ls, int(i)) - } - return attribute.IntSlice(k, ls) - case int32: - return attribute.Int64(k, int64(typed)) - case []int32: - ls := make([]int64, 0, len(typed)) - for _, i := range typed { - ls = append(ls, int64(i)) - } - return attribute.Int64Slice(k, ls) - case int64: - return attribute.Int64(k, typed) - case []int64: - return attribute.Int64Slice(k, typed) - case float64: - return attribute.Float64(k, typed) - case []float64: - return attribute.Float64Slice(k, typed) - case string: - return attribute.String(k, typed) - case []string: - return attribute.StringSlice(k, typed) - } - - if stringer, ok := v.(fmt.Stringer); ok { - return attribute.String(k, stringer.String()) - } - if b, err := json.Marshal(v); b != nil && err == nil { - return attribute.String(k, string(b)) - } - return attribute.String(k, fmt.Sprintf("%v", v)) -} diff --git a/tracing/tracing.go b/tracing/tracing.go index 147af372e..37366e4fc 100644 --- a/tracing/tracing.go +++ b/tracing/tracing.go @@ -20,6 +20,7 @@ import ( "context" "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/codes" "go.opentelemetry.io/otel/trace" ) @@ -52,3 +53,7 @@ func SetSpanStatus(span trace.Span, err error) { span.SetStatus(codes.Ok, "") } } + +func SpanAttribute(k string, v interface{}) attribute.KeyValue { + return any(k, v) +}