traceattrs: Functions for the commonly-used OCI-related attributes

We have a number of trace attributes that we use across all of our OCI
Distribution-based functionality, so this centralizes their definitions
in package traceattrs.

This intentionally ignores a few additional attribute names that are used
only in the code that interacts with Docker-style credential helpers,
because all of those are used only in a single function and so adding
indirection for those doesn't have enough benefit to offset the cost of
additional indirection.

Signed-off-by: Martin Atkins <mart@degeneration.co.uk>
This commit is contained in:
Martin Atkins
2025-10-31 13:14:26 -07:00
parent 35cd016693
commit 93d095c67e
6 changed files with 100 additions and 29 deletions

View File

@@ -77,8 +77,8 @@ func getOCIRepositoryStore(ctx context.Context, registryDomain, repositoryName s
ctx, span := tracing.Tracer().Start(
ctx, "Authenticate to OCI Registry",
tracing.SpanAttributes(
traceattrs.String("opentofu.oci.registry.domain", registryDomain),
traceattrs.String("opentofu.oci.repository.name", repositoryName),
traceattrs.OpenTofuOCIRegistryDomain(registryDomain),
traceattrs.OpenTofuOCIRepositoryName(repositoryName),
),
)
defer span.End()

View File

@@ -221,8 +221,8 @@ func (g *ociDistributionGetter) resolveManifestDescriptor(ctx context.Context, r
ctx, span := tracing.Tracer().Start(
ctx, "Resolve reference",
tracing.SpanAttributes(
traceattrs.String("opentofu.oci.registry.domain", ref.Registry),
traceattrs.String("opentofu.oci.repository.name", ref.Repository),
traceattrs.OpenTofuOCIRegistryDomain(ref.Registry),
traceattrs.OpenTofuOCIRepositoryName(ref.Repository),
),
)
defer span.End()
@@ -279,7 +279,7 @@ func (g *ociDistributionGetter) resolveManifestDescriptor(ctx context.Context, r
// If we're starting with a tag name then we need to query the
// repository to find out which digest is currently selected.
span.SetAttributes(
traceattrs.String("opentofu.oci.reference.tag", wantTag),
traceattrs.OpenTofuOCIReferenceTag(wantTag),
)
desc, err = store.Resolve(ctx, wantTag)
if err != nil {
@@ -294,7 +294,7 @@ func (g *ociDistributionGetter) resolveManifestDescriptor(ctx context.Context, r
// and so we can't exercise this specific case from unit tests
// using in-memory or on-disk fakes. :(
span.SetAttributes(
traceattrs.String("opentofu.oci.reference.digest", wantDigest.String()),
traceattrs.OpenTofuOCIReferenceDigest(wantDigest.String()),
)
desc, err = store.Resolve(ctx, wantDigest.String())
if err != nil {
@@ -304,8 +304,8 @@ func (g *ociDistributionGetter) resolveManifestDescriptor(ctx context.Context, r
span.SetAttributes(
traceattrs.OCIManifestDigest(desc.Digest.String()),
traceattrs.String("opentofu.oci.manifest.media_type", desc.MediaType),
traceattrs.Int64("opentofu.oci.manifest.size", desc.Size),
traceattrs.OpenTofuOCIManifestMediaType(desc.MediaType),
traceattrs.OpenTofuOCIManifestSize(desc.Size),
)
// The initial request is only required to return a "plain" descriptor,
@@ -328,7 +328,7 @@ func fetchOCIImageManifest(ctx context.Context, desc ociv1.Descriptor, store OCI
ctx, "Fetch manifest",
tracing.SpanAttributes(
traceattrs.OCIManifestDigest(desc.Digest.String()),
traceattrs.Int64("opentofu.oci.manifest.size", desc.Size),
traceattrs.OpenTofuOCIManifestSize(desc.Size),
),
)
defer span.End()
@@ -356,8 +356,8 @@ func fetchOCIImageManifest(ctx context.Context, desc ociv1.Descriptor, store OCI
}
span.SetAttributes(
traceattrs.String("opentofu.oci.manifest.media_type", desc.MediaType),
traceattrs.String("opentofu.oci.manifest.artifact_type", desc.ArtifactType),
traceattrs.OpenTofuOCIManifestMediaType(desc.MediaType),
traceattrs.OpenTofuOCIManifestArtifactType(desc.ArtifactType),
)
// Now we'll make sure that what we decoded seems vaguely sensible before we
@@ -455,9 +455,9 @@ func fetchOCIBlobToTemporaryFile(ctx context.Context, desc ociv1.Descriptor, sto
ctx, span := tracing.Tracer().Start(
ctx, "Fetch module package",
tracing.SpanAttributes(
traceattrs.String("opentofu.oci.blob.digest", desc.Digest.String()),
traceattrs.String("opentofu.oci.blob.media_type", desc.MediaType),
traceattrs.Int64("opentofu.oci.blob.size", desc.Size),
traceattrs.OpenTofuOCIBlobDigest(desc.Digest.String()),
traceattrs.OpenTofuOCIBlobMediaType(desc.MediaType),
traceattrs.OpenTofuOCIBlobSize(desc.Size),
),
)
defer span.End()

View File

@@ -494,8 +494,8 @@ func fetchOCIDescriptorForVersion(ctx context.Context, version versions.Version,
}
span.SetAttributes(
traceattrs.OCIManifestDigest(desc.Digest.String()),
traceattrs.String("opentofu.oci.reference.tag", tagName),
traceattrs.String("opentofu.oci.manifest.media_type", desc.MediaType),
traceattrs.OpenTofuOCIReferenceTag(tagName),
traceattrs.OpenTofuOCIManifestMediaType(desc.MediaType),
)
// Not all store implementations can return the manifest's artifact type as part
// of the tag-resolution response, so we'll check this early if we can, but
@@ -505,7 +505,7 @@ func fetchOCIDescriptorForVersion(ctx context.Context, version versions.Version,
// one way or another.)
if desc.ArtifactType != "" && desc.ArtifactType != ociIndexManifestArtifactType {
span.SetAttributes(
traceattrs.String("opentofu.oci.manifest.artifact_type", desc.ArtifactType),
traceattrs.OpenTofuOCIManifestArtifactType(desc.ArtifactType),
)
switch desc.ArtifactType {
case "application/vnd.opentofu.provider-target":
@@ -546,7 +546,7 @@ func fetchOCIIndexManifest(ctx context.Context, desc ociv1.Descriptor, store OCI
ctx, "Fetch index manifest",
tracing.SpanAttributes(
traceattrs.OCIManifestDigest(desc.Digest.String()),
traceattrs.Int64("opentofu.oci.manifest.size", desc.Size),
traceattrs.OpenTofuOCIManifestSize(desc.Size),
),
)
defer span.End()
@@ -573,8 +573,8 @@ func fetchOCIIndexManifest(ctx context.Context, desc ociv1.Descriptor, store OCI
return nil, prepErr(fmt.Errorf("invalid manifest content: %w", err))
}
span.SetAttributes(
traceattrs.String("opentofu.oci.manifest.media_type", manifest.MediaType),
traceattrs.String("opentofu.oci.manifest.artifact_type", manifest.ArtifactType),
traceattrs.OpenTofuOCIManifestMediaType(manifest.MediaType),
traceattrs.OpenTofuOCIManifestArtifactType(manifest.ArtifactType),
)
// Now we'll make sure that what we decoded seems vaguely sensible before we
@@ -598,7 +598,7 @@ func fetchOCIImageManifest(ctx context.Context, desc ociv1.Descriptor, store OCI
ctx, "Fetch platform-specific manifest",
tracing.SpanAttributes(
traceattrs.OCIManifestDigest(desc.Digest.String()),
traceattrs.Int64("opentofu.oci.manifest.size", desc.Size),
traceattrs.OpenTofuOCIManifestSize(desc.Size),
),
)
defer span.End()
@@ -625,8 +625,8 @@ func fetchOCIImageManifest(ctx context.Context, desc ociv1.Descriptor, store OCI
return nil, prepErr(fmt.Errorf("invalid manifest content: %w", err))
}
span.SetAttributes(
traceattrs.String("opentofu.oci.manifest.media_type", manifest.MediaType),
traceattrs.String("opentofu.oci.manifest.artifact_type", manifest.ArtifactType),
traceattrs.OpenTofuOCIManifestMediaType(manifest.MediaType),
traceattrs.OpenTofuOCIManifestArtifactType(manifest.ArtifactType),
)
// Now we'll make sure that what we decoded seems vaguely sensible before we

View File

@@ -88,11 +88,11 @@ func (p PackageOCIBlobArchive) InstallProviderPackage(ctx context.Context, meta
ctx, span := tracing.Tracer().Start(
ctx, "Fetch provider package",
tracing.SpanAttributes(
traceattrs.String("opentofu.oci.registry.domain", p.registryDomain),
traceattrs.String("opentofu.oci.repository.name", p.repositoryName),
traceattrs.String("opentofu.oci.blob.digest", pkgDesc.Digest.String()),
traceattrs.String("opentofu.oci.blob.media_type", pkgDesc.MediaType),
traceattrs.Int64("opentofu.oci.blob.size", pkgDesc.Size),
traceattrs.OpenTofuOCIRegistryDomain(p.registryDomain),
traceattrs.OpenTofuOCIRepositoryName(p.repositoryName),
traceattrs.OpenTofuOCIBlobDigest(pkgDesc.Digest.String()),
traceattrs.OpenTofuOCIBlobMediaType(pkgDesc.MediaType),
traceattrs.OpenTofuOCIBlobSize(pkgDesc.Size),
traceattrs.String("opentofu.provider.local_dir", targetDir),
traceattrs.OpenTofuProviderAddress(meta.Provider.String()),
traceattrs.OpenTofuProviderVersion(meta.Version.String()),

View File

@@ -80,3 +80,74 @@ func OpenTofuModuleSource(addr string) attribute.KeyValue {
func OpenTofuModuleVersion(v string) attribute.KeyValue {
return attribute.String("opentofu.module.version", v)
}
// OpenTofuOCIReferenceTag returns an attribute definition for indicating
// which OCI repository tag is relevant to a particular trace span.
func OpenTofuOCIReferenceTag(name string) attribute.KeyValue {
return attribute.String("opentofu.oci.reference.tag", name)
}
// OpenTofuOCIReferenceDigest returns an attribute definition for indicating
// which OCI digest reference is relevant to a particular trace span.
func OpenTofuOCIReferenceDigest(digest string) attribute.KeyValue {
return attribute.String("opentofu.oci.reference.digest", digest)
}
// OpenTofuOCIManifestMediaType returns an attribute definition for indicating
// which OCI manifest media type is relevant to a particular trace span.
func OpenTofuOCIManifestMediaType(typ string) attribute.KeyValue {
return attribute.String("opentofu.oci.manifest.media_type", typ)
}
// OpenTofuOCIManifestArtifactType returns an attribute definition for indicating
// which OCI manifest artifact type is relevant to a particular trace span.
func OpenTofuOCIManifestArtifactType(typ string) attribute.KeyValue {
return attribute.String("opentofu.oci.manifest.artifact_type", typ)
}
// OpenTofuOCIManifestSize returns an attribute definition for indicating
// the size in bytes of an OCI manifest that is relevant to a particular
// trace span.
func OpenTofuOCIManifestSize(size int64) attribute.KeyValue {
return attribute.Int64("opentofu.oci.manifest.size", size)
}
// OpenTofuOCIBlobDigest returns an attribute definition for indicating
// which OCI blob digest is relevant to a particular trace span.
func OpenTofuOCIBlobDigest(digest string) attribute.KeyValue {
return attribute.String("opentofu.oci.blob.digest", digest)
}
// OpenTofuOCIBlobMediaType returns an attribute definition for indicating
// which OCI blob media type is relevant to a particular trace span.
func OpenTofuOCIBlobMediaType(typ string) attribute.KeyValue {
return attribute.String("opentofu.oci.blob.media_type", typ)
}
// OpenTofuOCIBlobArtifactType returns an attribute definition for indicating
// which OCI blob artifact type is relevant to a particular trace span.
func OpenTofuOCIBlobArtifactType(typ string) attribute.KeyValue {
return attribute.String("opentofu.oci.blob.artifact_type", typ)
}
// OpenTofuOCIBlobSize returns an attribute definition for indicating
// the size in bytes of an OCI blob that is relevant to a particular
// trace span.
func OpenTofuOCIBlobSize(size int64) attribute.KeyValue {
return attribute.Int64("opentofu.oci.blob.size", size)
}
// OpenTofuOCIRegistryDomain returns an attribute definition for indicating
// which OCI registry domain name is relevant to a particular trace span.
func OpenTofuOCIRegistryDomain(domain string) attribute.KeyValue {
return attribute.String("opentofu.oci.registry.domain", domain)
}
// OpenTofuOCIRepositoryName returns an attribute definition for indicating
// which OCI repository is relevant to a particular trace span.
//
// The value of this should not include the registry domain name. Use a
// separate attribute built from [OpenTofuOCIRegistryDomain] for that.
func OpenTofuOCIRepositoryName(name string) attribute.KeyValue {
return attribute.String("opentofu.oci.repository.name", name)
}

View File

@@ -89,7 +89,7 @@ func FileSize(val int) attribute.KeyValue {
return semconv.FileSize(val)
}
// OCIManifiestDigest returns an attribute representing an OCI manifest
// OCIManifestDigest returns an attribute representing an OCI manifest
// digest associated with a trace span, using the attribute name defined
// by our currently-selected version of the OpenTelemetry semantic conventions.
//