Repository: grpc/grpc-go

Issue:
Dependency on "testing" from "google.golang.org/grpc/experimental/stats"
### What version of gRPC are you using?
v1.66.0
### What version of Go are you using (`go version`)?
v1.22
### What operating system (Linux, Windows, …) and version?
N/A
### What did you do?
Verified my code didn't depend on "testing" in production binaries.

### What did you expect to see?
No production dependency on "testing".

### What did you see instead?
```
$ go list -deps google.golang.org/grpc | grep testing
testing
```

This comes from https://github.com/grpc/grpc-go/blob/005b092ca3c279e352f1247c4316b0351dec3a56/experimental/stats/metricregistry.go#L255

Discussion:
@aaronbee: To add a bit more color here, in our repo we check for unexpected dependencies of our binaries. This is done to reduce binary bloat, to avoid side effects of those dependencies (eg. importing "testing" use to register flags that are exposed by the final binary, but this is no longer the case), and just generally to have a cleaner dependency tree.

A dependency we disallow in production binaries is "testing", which is how we noticed that grpc started depending on it.@easwars: @aaronbee : Thanks for filing this issue. How do you check for unexpected dependencies of your binaries in your repo? Is that something that you can share with us? @aaronbee: We have a small program (that's not open source, sorry) that uses [golang.org/x/tools/go/packages](https://pkg.go.dev/golang.org/x/tools/go/packages) to load a package and walk its dependency tree, reporting any uses of forbidden dependencies. Another simple way to this is with `go list -deps` which will just print out all the dependencies of a package.@easwars: The change to remove the testing dependency got merged in https://github.com/grpc/grpc-go/pull/7579. Now, we need to do a patch release for this, and also need to think about if we want to add something simple like `go list -deps google.golang.org/grpc | grep testing` to our vet.sh.
@AlekSi: Do you have any timeline for the patch release?@AlekSi: Actually, it was released in 1.66.2. So this issue probably could be closed.

Solution patch:
diff --git a/examples/features/csm_observability/client/main.go b/examples/features/csm_observability/client/main.go
index c89676c1..8ba1e863 100644
--- a/examples/features/csm_observability/client/main.go
+++ b/examples/features/csm_observability/client/main.go
@@ -16,6 +16,7 @@
  *
  */
 
+// Binary client is a client for the CSM Observability example.
 package main
 
 import (
diff --git a/examples/features/csm_observability/server/main.go b/examples/features/csm_observability/server/main.go
index 399e00c5..b87f859a 100644
--- a/examples/features/csm_observability/server/main.go
+++ b/examples/features/csm_observability/server/main.go
@@ -16,6 +16,7 @@
  *
  */
 
+// Binary server is a server for the CSM Observability example.
 package main
 
 import (
diff --git a/examples/features/customloadbalancer/client/main.go b/examples/features/customloadbalancer/client/main.go
index 47497043..02170029 100644
--- a/examples/features/customloadbalancer/client/main.go
+++ b/examples/features/customloadbalancer/client/main.go
@@ -16,6 +16,7 @@
  *
  */
 
+// Binary client is a client for the custom load balancer example.
 package main
 
 import (
diff --git a/examples/features/customloadbalancer/server/main.go b/examples/features/customloadbalancer/server/main.go
index 5bcf2c59..9f2cb24e 100644
--- a/examples/features/customloadbalancer/server/main.go
+++ b/examples/features/customloadbalancer/server/main.go
@@ -16,6 +16,7 @@
  *
  */
 
+// Binary server is a server for the custom load balancer example.
 package main
 
 import (
diff --git a/examples/features/opentelemetry/client/main.go b/examples/features/opentelemetry/client/main.go
index 4bc3d5af..071d7ba6 100644
--- a/examples/features/opentelemetry/client/main.go
+++ b/examples/features/opentelemetry/client/main.go
@@ -16,6 +16,7 @@
  *
  */
 
+// Binary client is a client for the OpenTelemetry example.
 package main
 
 import (
diff --git a/examples/features/opentelemetry/server/main.go b/examples/features/opentelemetry/server/main.go
index 78fbf6bf..2bda0080 100644
--- a/examples/features/opentelemetry/server/main.go
+++ b/examples/features/opentelemetry/server/main.go
@@ -16,6 +16,7 @@
  *
  */
 
+// Binary server is a server for the OpenTelemetry example.
 package main
 
 import (
diff --git a/examples/features/unix_abstract/server/main.go b/examples/features/unix_abstract/server/main.go
index 7013466b..19b15dba 100644
--- a/examples/features/unix_abstract/server/main.go
+++ b/examples/features/unix_abstract/server/main.go
@@ -44,7 +44,7 @@ type ecServer struct {
 	addr string
 }
 
-func (s *ecServer) UnaryEcho(ctx context.Context, req *pb.EchoRequest) (*pb.EchoResponse, error) {
+func (s *ecServer) UnaryEcho(_ context.Context, req *pb.EchoRequest) (*pb.EchoResponse, error) {
 	return &pb.EchoResponse{Message: fmt.Sprintf("%s (from %s)", req.Message, s.addr)}, nil
 }
 
diff --git a/experimental/stats/metricregistry.go b/experimental/stats/metricregistry.go
index 930140f5..1d827dd5 100644
--- a/experimental/stats/metricregistry.go
+++ b/experimental/stats/metricregistry.go
@@ -20,7 +20,6 @@ package stats
 
 import (
 	"maps"
-	"testing"
 
 	"google.golang.org/grpc/grpclog"
 	"google.golang.org/grpc/internal"
@@ -250,9 +249,9 @@ func RegisterInt64Gauge(descriptor MetricDescriptor) *Int64GaugeHandle {
 }
 
 // snapshotMetricsRegistryForTesting snapshots the global data of the metrics
-// registry. Registers a cleanup function on the provided testing.T that sets
-// the metrics registry to its original state. Only called in testing functions.
-func snapshotMetricsRegistryForTesting(t *testing.T) {
+// registry. Returns a cleanup function that sets the metrics registry to its
+// original state.
+func snapshotMetricsRegistryForTesting() func() {
 	oldDefaultMetrics := DefaultMetrics
 	oldRegisteredMetrics := registeredMetrics
 	oldMetricsRegistry := metricsRegistry
@@ -262,9 +261,9 @@ func snapshotMetricsRegistryForTesting(t *testing.T) {
 	maps.Copy(registeredMetrics, registeredMetrics)
 	maps.Copy(metricsRegistry, metricsRegistry)
 
-	t.Cleanup(func() {
+	return func() {
 		DefaultMetrics = oldDefaultMetrics
 		registeredMetrics = oldRegisteredMetrics
 		metricsRegistry = oldMetricsRegistry
-	})
+	}
 }
diff --git a/internal/internal.go b/internal/internal.go
index 71cbc3bd..7aae9240 100644
--- a/internal/internal.go
+++ b/internal/internal.go
@@ -217,10 +217,9 @@ var (
 	SetConnectedAddress any // func(scs *SubConnState, addr resolver.Address)
 
 	// SnapshotMetricRegistryForTesting snapshots the global data of the metric
-	// registry. Registers a cleanup function on the provided testing.T that
-	// sets the metric registry to its original state. Only called in testing
-	// functions.
-	SnapshotMetricRegistryForTesting any // func(t *testing.T)
+	// registry. Returns a cleanup function that sets the metric registry to its
+	// original state. Only called in testing functions.
+	SnapshotMetricRegistryForTesting func() func()
 
 	// SetDefaultBufferPoolForTesting updates the default buffer pool, for
 	// testing purposes.
diff --git a/interop/grpclb_fallback/client_linux.go b/interop/grpclb_fallback/client_linux.go
index f8a1ac37..94981824 100644
--- a/interop/grpclb_fallback/client_linux.go
+++ b/interop/grpclb_fallback/client_linux.go
@@ -75,7 +75,7 @@ func doRPCAndGetPath(client testgrpc.TestServiceClient, timeout time.Duration) t
 }
 
 func dialTCPUserTimeout(ctx context.Context, addr string) (net.Conn, error) {
-	control := func(network, address string, c syscall.RawConn) error {
+	control := func(_, _ string, c syscall.RawConn) error {
 		var syscallErr error
 		controlErr := c.Control(func(fd uintptr) {
 			syscallErr = syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, unix.TCP_USER_TIMEOUT, 20000)
diff --git a/interop/observability/client/client.go b/interop/observability/client/client.go
index 5478efdb..0a07994b 100644
--- a/interop/observability/client/client.go
+++ b/interop/observability/client/client.go
@@ -16,6 +16,11 @@
  *
  */
 
+// Binary client is an interop client for Observability.
+//
+// See interop test case descriptions [here].
+//
+// [here]: https://github.com/grpc/grpc/blob/master/doc/interop-test-descriptions.md
 package main
 
 import (
diff --git a/interop/observability/server/server.go b/interop/observability/server/server.go
index 7efab04b..06209947 100644
--- a/interop/observability/server/server.go
+++ b/interop/observability/server/server.go
@@ -16,6 +16,11 @@
  *
  */
 
+// Binary server is an interop server for Observability.
+//
+// See interop test case descriptions [here].
+//
+// [here]: https://github.com/grpc/grpc/blob/master/doc/interop-test-descriptions.md
 package main
 
 import (
diff --git a/stats/opentelemetry/client_metrics.go b/stats/opentelemetry/client_metrics.go
index d5b9aa46..4af7f933 100644
--- a/stats/opentelemetry/client_metrics.go
+++ b/stats/opentelemetry/client_metrics.go
@@ -128,9 +128,13 @@ func (h *clientStatsHandler) streamInterceptor(ctx context.Context, desc *grpc.S
 }
 
 func (h *clientStatsHandler) perCallMetrics(ctx context.Context, err error, startTime time.Time, ci *callInfo) {
-	s := status.Convert(err)
-	callLatency := float64(time.Since(startTime)) / float64(time.Second)
-	h.clientMetrics.callDuration.Record(ctx, callLatency, otelmetric.WithAttributes(otelattribute.String("grpc.method", ci.method), otelattribute.String("grpc.target", ci.target), otelattribute.String("grpc.status", canonicalString(s.Code()))))
+	callLatency := float64(time.Since(startTime)) / float64(time.Second) // calculate ASAP
+	attrs := otelmetric.WithAttributeSet(otelattribute.NewSet(
+		otelattribute.String("grpc.method", ci.method),
+		otelattribute.String("grpc.target", ci.target),
+		otelattribute.String("grpc.status", canonicalString(status.Code(err))),
+	))
+	h.clientMetrics.callDuration.Record(ctx, callLatency, attrs)
 }
 
 // TagConn exists to satisfy stats.Handler.
@@ -188,7 +192,11 @@ func (h *clientStatsHandler) processRPCEvent(ctx context.Context, s stats.RPCSta
 			return
 		}
 
-		h.clientMetrics.attemptStarted.Add(ctx, 1, otelmetric.WithAttributes(otelattribute.String("grpc.method", ci.method), otelattribute.String("grpc.target", ci.target)))
+		attrs := otelmetric.WithAttributeSet(otelattribute.NewSet(
+			otelattribute.String("grpc.method", ci.method),
+			otelattribute.String("grpc.target", ci.target),
+		))
+		h.clientMetrics.attemptStarted.Add(ctx, 1, attrs)
 	case *stats.OutPayload:
 		atomic.AddInt64(&ai.sentCompressedBytes, int64(st.CompressedLength))
 	case *stats.InPayload:
@@ -244,10 +252,11 @@ func (h *clientStatsHandler) processRPCEnd(ctx context.Context, ai *attemptInfo,
 		}
 	}
 
-	clientAttributeOption := otelmetric.WithAttributes(attributes...)
-	h.clientMetrics.attemptDuration.Record(ctx, latency, clientAttributeOption)
-	h.clientMetrics.attemptSentTotalCompressedMessageSize.Record(ctx, atomic.LoadInt64(&ai.sentCompressedBytes), clientAttributeOption)
-	h.clientMetrics.attemptRcvdTotalCompressedMessageSize.Record(ctx, atomic.LoadInt64(&ai.recvCompressedBytes), clientAttributeOption)
+	// Allocate vararg slice once.
+	opts := []otelmetric.RecordOption{otelmetric.WithAttributeSet(otelattribute.NewSet(attributes...))}
+	h.clientMetrics.attemptDuration.Record(ctx, latency, opts...)
+	h.clientMetrics.attemptSentTotalCompressedMessageSize.Record(ctx, atomic.LoadInt64(&ai.sentCompressedBytes), opts...)
+	h.clientMetrics.attemptRcvdTotalCompressedMessageSize.Record(ctx, atomic.LoadInt64(&ai.recvCompressedBytes), opts...)
 }
 
 const (
diff --git a/stats/opentelemetry/opentelemetry.go b/stats/opentelemetry/opentelemetry.go
index b0d0cde7..cc5ad387 100644
--- a/stats/opentelemetry/opentelemetry.go
+++ b/stats/opentelemetry/opentelemetry.go
@@ -283,7 +283,7 @@ func optionFromLabels(labelKeys []string, optionalLabelKeys []string, optionalLa
 			}
 		}
 	}
-	return otelmetric.WithAttributes(attributes...)
+	return otelmetric.WithAttributeSet(otelattribute.NewSet(attributes...))
 }
 
 // registryMetrics implements MetricsRecorder for the client and server stats
@@ -330,41 +330,40 @@ func (rm *registryMetrics) registerMetrics(metrics *estats.Metrics, meter otelme
 
 func (rm *registryMetrics) RecordInt64Count(handle *estats.Int64CountHandle, incr int64, labels ...string) {
 	desc := handle.Descriptor()
-	ao := optionFromLabels(desc.Labels, desc.OptionalLabels, rm.optionalLabels, labels...)
-
 	if ic, ok := rm.intCounts[desc]; ok {
+		ao := optionFromLabels(desc.Labels, desc.OptionalLabels, rm.optionalLabels, labels...)
 		ic.Add(context.TODO(), incr, ao)
 	}
 }
 
 func (rm *registryMetrics) RecordFloat64Count(handle *estats.Float64CountHandle, incr float64, labels ...string) {
 	desc := handle.Descriptor()
-	ao := optionFromLabels(desc.Labels, desc.OptionalLabels, rm.optionalLabels, labels...)
 	if fc, ok := rm.floatCounts[desc]; ok {
+		ao := optionFromLabels(desc.Labels, desc.OptionalLabels, rm.optionalLabels, labels...)
 		fc.Add(context.TODO(), incr, ao)
 	}
 }
 
 func (rm *registryMetrics) RecordInt64Histo(handle *estats.Int64HistoHandle, incr int64, labels ...string) {
 	desc := handle.Descriptor()
-	ao := optionFromLabels(desc.Labels, desc.OptionalLabels, rm.optionalLabels, labels...)
 	if ih, ok := rm.intHistos[desc]; ok {
+		ao := optionFromLabels(desc.Labels, desc.OptionalLabels, rm.optionalLabels, labels...)
 		ih.Record(context.TODO(), incr, ao)
 	}
 }
 
 func (rm *registryMetrics) RecordFloat64Histo(handle *estats.Float64HistoHandle, incr float64, labels ...string) {
 	desc := handle.Descriptor()
-	ao := optionFromLabels(desc.Labels, desc.OptionalLabels, rm.optionalLabels, labels...)
 	if fh, ok := rm.floatHistos[desc]; ok {
+		ao := optionFromLabels(desc.Labels, desc.OptionalLabels, rm.optionalLabels, labels...)
 		fh.Record(context.TODO(), incr, ao)
 	}
 }
 
 func (rm *registryMetrics) RecordInt64Gauge(handle *estats.Int64GaugeHandle, incr int64, labels ...string) {
 	desc := handle.Descriptor()
-	ao := optionFromLabels(desc.Labels, desc.OptionalLabels, rm.optionalLabels, labels...)
 	if ig, ok := rm.intGauges[desc]; ok {
+		ao := optionFromLabels(desc.Labels, desc.OptionalLabels, rm.optionalLabels, labels...)
 		ig.Record(context.TODO(), incr, ao)
 	}
 }
diff --git a/stats/opentelemetry/server_metrics.go b/stats/opentelemetry/server_metrics.go
index 528fced8..75c7c43b 100644
--- a/stats/opentelemetry/server_metrics.go
+++ b/stats/opentelemetry/server_metrics.go
@@ -227,7 +227,10 @@ func (h *serverStatsHandler) processRPCData(ctx context.Context, s stats.RPCStat
 			}
 			ai.pluginOptionLabels = labels
 		}
-		h.serverMetrics.callStarted.Add(ctx, 1, otelmetric.WithAttributes(otelattribute.String("grpc.method", ai.method)))
+		attrs := otelmetric.WithAttributeSet(otelattribute.NewSet(
+			otelattribute.String("grpc.method", ai.method),
+		))
+		h.serverMetrics.callStarted.Add(ctx, 1, attrs)
 	case *stats.OutPayload:
 		atomic.AddInt64(&ai.sentCompressedBytes, int64(st.CompressedLength))
 	case *stats.InPayload:
@@ -253,10 +256,11 @@ func (h *serverStatsHandler) processRPCEnd(ctx context.Context, ai *attemptInfo,
 		attributes = append(attributes, otelattribute.String(k, v))
 	}
 
-	serverAttributeOption := otelmetric.WithAttributes(attributes...)
-	h.serverMetrics.callDuration.Record(ctx, latency, serverAttributeOption)
-	h.serverMetrics.callSentTotalCompressedMessageSize.Record(ctx, atomic.LoadInt64(&ai.sentCompressedBytes), serverAttributeOption)
-	h.serverMetrics.callRcvdTotalCompressedMessageSize.Record(ctx, atomic.LoadInt64(&ai.recvCompressedBytes), serverAttributeOption)
+	// Allocate vararg slice once.
+	opts := []otelmetric.RecordOption{otelmetric.WithAttributeSet(otelattribute.NewSet(attributes...))}
+	h.serverMetrics.callDuration.Record(ctx, latency, opts...)
+	h.serverMetrics.callSentTotalCompressedMessageSize.Record(ctx, atomic.LoadInt64(&ai.sentCompressedBytes), opts...)
+	h.serverMetrics.callRcvdTotalCompressedMessageSize.Record(ctx, atomic.LoadInt64(&ai.recvCompressedBytes), opts...)
 }
 
 const (
diff --git a/xds/internal/balancer/clusterimpl/clusterimpl.go b/xds/internal/balancer/clusterimpl/clusterimpl.go
index c8017c7e..0dc71dfe 100644
--- a/xds/internal/balancer/clusterimpl/clusterimpl.go
+++ b/xds/internal/balancer/clusterimpl/clusterimpl.go
@@ -275,7 +275,7 @@ func (b *clusterImplBalancer) ResolverError(err error) {
 	})
 }
 
-func (b *clusterImplBalancer) updateSubConnState(sc balancer.SubConn, s balancer.SubConnState, cb func(balancer.SubConnState)) {
+func (b *clusterImplBalancer) updateSubConnState(_ balancer.SubConn, s balancer.SubConnState, cb func(balancer.SubConnState)) {
 	// Trigger re-resolution when a SubConn turns transient failure. This is
 	// necessary for the LogicalDNS in cluster_resolver policy to re-resolve.
 	//
@@ -297,7 +297,7 @@ func (b *clusterImplBalancer) UpdateSubConnState(sc balancer.SubConn, s balancer
 }
 
 func (b *clusterImplBalancer) Close() {
-	b.serializer.TrySchedule(func(ctx context.Context) {
+	b.serializer.TrySchedule(func(_ context.Context) {
 		b.child.Close()
 		b.childState = balancer.State{}
 



Test patch:
diff --git a/credentials/alts/alts_test.go b/credentials/alts/alts_test.go
index a0ded43d..6c083a2f 100644
--- a/credentials/alts/alts_test.go
+++ b/credentials/alts/alts_test.go
@@ -467,7 +467,7 @@ type testServer struct {
 	testgrpc.UnimplementedTestServiceServer
 }
 
-func (s *testServer) UnaryCall(ctx context.Context, in *testpb.SimpleRequest) (*testpb.SimpleResponse, error) {
+func (s *testServer) UnaryCall(_ context.Context, _ *testpb.SimpleRequest) (*testpb.SimpleResponse, error) {
 	return &testpb.SimpleResponse{
 		Payload: &testpb.Payload{},
 	}, nil
diff --git a/experimental/stats/metricregistry_test.go b/experimental/stats/metricregistry_test.go
index 6db7cf9e..83d7a583 100644
--- a/experimental/stats/metricregistry_test.go
+++ b/experimental/stats/metricregistry_test.go
@@ -38,7 +38,9 @@ func Test(t *testing.T) {
 // TestPanic tests that registering two metrics with the same name across any
 // type of metric triggers a panic.
 func (s) TestPanic(t *testing.T) {
-	snapshotMetricsRegistryForTesting(t)
+	cleanup := snapshotMetricsRegistryForTesting()
+	defer cleanup()
+
 	want := "metric simple counter already registered"
 	defer func() {
 		if r := recover(); !strings.Contains(fmt.Sprint(r), want) {
@@ -64,7 +66,9 @@ func (s) TestPanic(t *testing.T) {
 // this tests the interactions between the metrics recorder and the metrics
 // registry.
 func (s) TestMetricRegistry(t *testing.T) {
-	snapshotMetricsRegistryForTesting(t)
+	cleanup := snapshotMetricsRegistryForTesting()
+	defer cleanup()
+
 	intCountHandle1 := RegisterInt64Count(MetricDescriptor{
 		Name:           "simple counter",
 		Description:    "sum of all emissions from tests",
@@ -141,7 +145,9 @@ func (s) TestMetricRegistry(t *testing.T) {
 // metric registry. A component (simulated by test) should be able to record on
 // the different registered int count metrics.
 func TestNumerousIntCounts(t *testing.T) {
-	snapshotMetricsRegistryForTesting(t)
+	cleanup := snapshotMetricsRegistryForTesting()
+	defer cleanup()
+
 	intCountHandle1 := RegisterInt64Count(MetricDescriptor{
 		Name:           "int counter",
 		Description:    "sum of all emissions from tests",
diff --git a/gcp/observability/logging_test.go b/gcp/observability/logging_test.go
index efabfe05..78af38ec 100644
--- a/gcp/observability/logging_test.go
+++ b/gcp/observability/logging_test.go
@@ -589,7 +589,7 @@ func (s) TestBothClientAndServerRPCEvents(t *testing.T) {
 	defer cleanup()
 
 	ss := &stubserver.StubServer{
-		UnaryCallF: func(ctx context.Context, in *testpb.SimpleRequest) (*testpb.SimpleResponse, error) {
+		UnaryCallF: func(_ context.Context, _ *testpb.SimpleRequest) (*testpb.SimpleResponse, error) {
 			return &testpb.SimpleResponse{}, nil
 		},
 		FullDuplexCallF: func(stream testgrpc.TestService_FullDuplexCallServer) error {
@@ -650,7 +650,7 @@ func (s) TestClientRPCEventsTruncateHeaderAndMetadata(t *testing.T) {
 		newLoggingExporter = ne
 	}(newLoggingExporter)
 
-	newLoggingExporter = func(ctx context.Context, config *config) (loggingExporter, error) {
+	newLoggingExporter = func(_ context.Context, _ *config) (loggingExporter, error) {
 		return fle, nil
 	}
 
@@ -673,7 +673,7 @@ func (s) TestClientRPCEventsTruncateHeaderAndMetadata(t *testing.T) {
 	defer cleanup()
 
 	ss := &stubserver.StubServer{
-		UnaryCallF: func(ctx context.Context, in *testpb.SimpleRequest) (*testpb.SimpleResponse, error) {
+		UnaryCallF: func(_ context.Context, _ *testpb.SimpleRequest) (*testpb.SimpleResponse, error) {
 			return &testpb.SimpleResponse{}, nil
 		},
 	}
@@ -787,7 +787,7 @@ func (s) TestPrecedenceOrderingInConfiguration(t *testing.T) {
 		newLoggingExporter = ne
 	}(newLoggingExporter)
 
-	newLoggingExporter = func(ctx context.Context, config *config) (loggingExporter, error) {
+	newLoggingExporter = func(_ context.Context, _ *config) (loggingExporter, error) {
 		return fle, nil
 	}
 
@@ -822,10 +822,10 @@ func (s) TestPrecedenceOrderingInConfiguration(t *testing.T) {
 	defer cleanup()
 
 	ss := &stubserver.StubServer{
-		EmptyCallF: func(ctx context.Context, in *testpb.Empty) (*testpb.Empty, error) {
+		EmptyCallF: func(_ context.Context, _ *testpb.Empty) (*testpb.Empty, error) {
 			return &testpb.Empty{}, nil
 		},
-		UnaryCallF: func(ctx context.Context, in *testpb.SimpleRequest) (*testpb.SimpleResponse, error) {
+		UnaryCallF: func(_ context.Context, _ *testpb.SimpleRequest) (*testpb.SimpleResponse, error) {
 			return &testpb.SimpleResponse{}, nil
 		},
 		FullDuplexCallF: func(stream testgrpc.TestService_FullDuplexCallServer) error {
@@ -1125,7 +1125,7 @@ func (s) TestMetadataTruncationAccountsKey(t *testing.T) {
 		newLoggingExporter = ne
 	}(newLoggingExporter)
 
-	newLoggingExporter = func(ctx context.Context, config *config) (loggingExporter, error) {
+	newLoggingExporter = func(_ context.Context, _ *config) (loggingExporter, error) {
 		return fle, nil
 	}
 
@@ -1149,7 +1149,7 @@ func (s) TestMetadataTruncationAccountsKey(t *testing.T) {
 	defer cleanup()
 
 	ss := &stubserver.StubServer{
-		UnaryCallF: func(ctx context.Context, in *testpb.SimpleRequest) (*testpb.SimpleResponse, error) {
+		UnaryCallF: func(_ context.Context, _ *testpb.SimpleRequest) (*testpb.SimpleResponse, error) {
 			return &testpb.SimpleResponse{}, nil
 		},
 	}
@@ -1240,6 +1240,7 @@ func (s) TestMetadataTruncationAccountsKey(t *testing.T) {
 // TestMethodInConfiguration tests different method names with an expectation on
 // whether they should error or not.
 func (s) TestMethodInConfiguration(t *testing.T) {
+
 	// To skip creating a stackdriver exporter.
 	fle := &fakeLoggingExporter{
 		t: t,
@@ -1249,7 +1250,7 @@ func (s) TestMethodInConfiguration(t *testing.T) {
 		newLoggingExporter = ne
 	}(newLoggingExporter)
 
-	newLoggingExporter = func(ctx context.Context, config *config) (loggingExporter, error) {
+	newLoggingExporter = func(_ context.Context, _ *config) (loggingExporter, error) {
 		return fle, nil
 	}
 
diff --git a/internal/stats/metrics_recorder_list_test.go b/internal/stats/metrics_recorder_list_test.go
index c58266a3..15139f12 100644
--- a/internal/stats/metrics_recorder_list_test.go
+++ b/internal/stats/metrics_recorder_list_test.go
@@ -132,7 +132,9 @@ type recordingLoadBalancer struct {
 // test then asserts that the recorded metrics show up on both configured stats
 // handlers.
 func (s) TestMetricsRecorderList(t *testing.T) {
-	internal.SnapshotMetricRegistryForTesting.(func(t *testing.T))(t)
+	cleanup := internal.SnapshotMetricRegistryForTesting()
+	defer cleanup()
+
 	mr := manual.NewBuilderWithScheme("test-metrics-recorder-list")
 	defer mr.Close()
 
@@ -212,7 +214,9 @@ func (s) TestMetricsRecorderList(t *testing.T) {
 // TestMetricRecorderListPanic tests that the metrics recorder list panics if
 // received the wrong number of labels for a particular metric.
 func (s) TestMetricRecorderListPanic(t *testing.T) {
-	internal.SnapshotMetricRegistryForTesting.(func(t *testing.T))(t)
+	cleanup := internal.SnapshotMetricRegistryForTesting()
+	defer cleanup()
+
 	intCountHandle := estats.RegisterInt64Count(estats.MetricDescriptor{
 		Name:           "simple counter",
 		Description:    "sum of all emissions from tests",
diff --git a/stats/opentelemetry/metricsregistry_test.go b/stats/opentelemetry/metricsregistry_test.go
index 0d2bb956..67a2d7fa 100644
--- a/stats/opentelemetry/metricsregistry_test.go
+++ b/stats/opentelemetry/metricsregistry_test.go
@@ -61,7 +61,9 @@ func newServerStatsHandler(options MetricsOptions) metricsRecorderForTest {
 // the expected metrics emissions, which includes default metrics and optional
 // label assertions.
 func (s) TestMetricsRegistryMetrics(t *testing.T) {
-	internal.SnapshotMetricRegistryForTesting.(func(t *testing.T))(t)
+	cleanup := internal.SnapshotMetricRegistryForTesting()
+	defer cleanup()
+
 	intCountHandle1 := estats.RegisterInt64Count(estats.MetricDescriptor{
 		Name:           "int-counter-1",
 		Description:    "Sum of calls from test",