api, core: make channel logger accessible through NameResolver.Args (#6430)


diff --git a/api/src/main/java/io/grpc/NameResolver.java b/api/src/main/java/io/grpc/NameResolver.java
index 6e36db6..fd73026 100644
--- a/api/src/main/java/io/grpc/NameResolver.java
+++ b/api/src/main/java/io/grpc/NameResolver.java
@@ -412,6 +412,7 @@
     private final ProxyDetector proxyDetector;
     private final SynchronizationContext syncContext;
     private final ServiceConfigParser serviceConfigParser;
+    @Nullable private final ChannelLogger channelLogger;
     @Nullable private final Executor executor;
 
     private Args(
@@ -419,11 +420,13 @@
         ProxyDetector proxyDetector,
         SynchronizationContext syncContext,
         ServiceConfigParser serviceConfigParser,
+        @Nullable ChannelLogger channelLogger,
         @Nullable Executor executor) {
       this.defaultPort = checkNotNull(defaultPort, "defaultPort not set");
       this.proxyDetector = checkNotNull(proxyDetector, "proxyDetector not set");
       this.syncContext = checkNotNull(syncContext, "syncContext not set");
       this.serviceConfigParser = checkNotNull(serviceConfigParser, "serviceConfigParser not set");
+      this.channelLogger = channelLogger;
       this.executor = executor;
     }
 
@@ -467,6 +470,19 @@
     }
 
     /**
+     * Returns the {@link ChannelLogger} for the Channel served by this NameResolver.
+     *
+     * @since 1.26.0
+     */
+    @ExperimentalApi("https://github.com/grpc/grpc-java/issues/6438")
+    public ChannelLogger getChannelLogger() {
+      if (channelLogger == null) {
+        throw new IllegalStateException("ChannelLogger is not set in Builder");
+      }
+      return channelLogger;
+    }
+
+    /**
      * Returns the Executor on which this resolver should execute long-running or I/O bound work.
      * Null if no Executor was set.
      *
@@ -485,6 +501,7 @@
           .add("proxyDetector", proxyDetector)
           .add("syncContext", syncContext)
           .add("serviceConfigParser", serviceConfigParser)
+          .add("channelLogger", channelLogger)
           .add("executor", executor)
           .toString();
     }
@@ -500,6 +517,7 @@
       builder.setProxyDetector(proxyDetector);
       builder.setSynchronizationContext(syncContext);
       builder.setServiceConfigParser(serviceConfigParser);
+      builder.setChannelLogger(channelLogger);
       builder.setOffloadExecutor(executor);
       return builder;
     }
@@ -523,6 +541,7 @@
       private ProxyDetector proxyDetector;
       private SynchronizationContext syncContext;
       private ServiceConfigParser serviceConfigParser;
+      private ChannelLogger channelLogger;
       private Executor executor;
 
       Builder() {
@@ -569,6 +588,17 @@
       }
 
       /**
+       * See {@link Args#getChannelLogger}.
+       *
+       * @since 1.26.0
+       */
+      @ExperimentalApi("https://github.com/grpc/grpc-java/issues/6438")
+      public Builder setChannelLogger(ChannelLogger channelLogger) {
+        this.channelLogger = checkNotNull(channelLogger);
+        return this;
+      }
+
+      /**
        * See {@link Args#getOffloadExecutor}. This is an optional field.
        *
        * @since 1.25.0
@@ -585,7 +615,10 @@
        * @since 1.21.0
        */
       public Args build() {
-        return new Args(defaultPort, proxyDetector, syncContext, serviceConfigParser, executor);
+        return
+            new Args(
+                defaultPort, proxyDetector, syncContext, serviceConfigParser,
+                channelLogger, executor);
       }
     }
   }
diff --git a/api/src/test/java/io/grpc/NameResolverRegistryTest.java b/api/src/test/java/io/grpc/NameResolverRegistryTest.java
index abbe10a..f35f2f0 100644
--- a/api/src/test/java/io/grpc/NameResolverRegistryTest.java
+++ b/api/src/test/java/io/grpc/NameResolverRegistryTest.java
@@ -39,6 +39,7 @@
       .setProxyDetector(mock(ProxyDetector.class))
       .setSynchronizationContext(new SynchronizationContext(mock(UncaughtExceptionHandler.class)))
       .setServiceConfigParser(mock(ServiceConfigParser.class))
+      .setChannelLogger(mock(ChannelLogger.class))
       .build();
 
   @Test
diff --git a/api/src/test/java/io/grpc/NameResolverTest.java b/api/src/test/java/io/grpc/NameResolverTest.java
index 3206f4b..8280474 100644
--- a/api/src/test/java/io/grpc/NameResolverTest.java
+++ b/api/src/test/java/io/grpc/NameResolverTest.java
@@ -45,6 +45,7 @@
   private final SynchronizationContext syncContext =
       new SynchronizationContext(mock(UncaughtExceptionHandler.class));
   private final ServiceConfigParser parser = mock(ServiceConfigParser.class);
+  private final ChannelLogger channelLogger = mock(ChannelLogger.class);
   private final Executor executor = Executors.newSingleThreadExecutor();
   private URI uri;
   private final NameResolver nameResolver = mock(NameResolver.class);
@@ -61,6 +62,7 @@
     assertThat(args.getProxyDetector()).isSameInstanceAs(proxyDetector);
     assertThat(args.getSynchronizationContext()).isSameInstanceAs(syncContext);
     assertThat(args.getServiceConfigParser()).isSameInstanceAs(parser);
+    assertThat(args.getChannelLogger()).isSameInstanceAs(channelLogger);
     assertThat(args.getOffloadExecutor()).isSameInstanceAs(executor);
 
     NameResolver.Args args2 = args.toBuilder().build();
@@ -68,6 +70,7 @@
     assertThat(args2.getProxyDetector()).isSameInstanceAs(proxyDetector);
     assertThat(args2.getSynchronizationContext()).isSameInstanceAs(syncContext);
     assertThat(args2.getServiceConfigParser()).isSameInstanceAs(parser);
+    assertThat(args2.getChannelLogger()).isSameInstanceAs(channelLogger);
     assertThat(args2.getOffloadExecutor()).isSameInstanceAs(executor);
 
     assertThat(args2).isNotSameInstanceAs(args);
@@ -251,6 +254,7 @@
         .setProxyDetector(proxyDetector)
         .setSynchronizationContext(syncContext)
         .setServiceConfigParser(parser)
+        .setChannelLogger(channelLogger)
         .setOffloadExecutor(executor)
         .build();
   }
diff --git a/core/src/main/java/io/grpc/internal/ManagedChannelImpl.java b/core/src/main/java/io/grpc/internal/ManagedChannelImpl.java
index 560f8cb..de3a472 100644
--- a/core/src/main/java/io/grpc/internal/ManagedChannelImpl.java
+++ b/core/src/main/java/io/grpc/internal/ManagedChannelImpl.java
@@ -561,6 +561,12 @@
       final TimeProvider timeProvider) {
     this.target = checkNotNull(builder.target, "target");
     this.logId = InternalLogId.allocate("Channel", target);
+    this.timeProvider = checkNotNull(timeProvider, "timeProvider");
+    maxTraceEvents = builder.maxTraceEvents;
+    channelTracer = new ChannelTracer(
+        logId, builder.maxTraceEvents, timeProvider.currentTimeNanos(),
+        "Channel for '" + target + "'");
+    channelLogger = new ChannelLoggerImpl(channelTracer, timeProvider);
     this.nameResolverFactory = builder.getNameResolverFactory();
     ProxyDetector proxyDetector =
         builder.proxyDetector != null ? builder.proxyDetector : GrpcUtil.DEFAULT_PROXY_DETECTOR;
@@ -581,6 +587,7 @@
                     builder.maxRetryAttempts,
                     builder.maxHedgedAttempts,
                     loadBalancerFactory))
+            .setChannelLogger(channelLogger)
             .setOffloadExecutor(
                 // Avoid creating the offloadExecutor until it is first used
                 new Executor() {
@@ -591,12 +598,6 @@
                 })
             .build();
     this.nameResolver = getNameResolver(target, nameResolverFactory, nameResolverArgs);
-    this.timeProvider = checkNotNull(timeProvider, "timeProvider");
-    maxTraceEvents = builder.maxTraceEvents;
-    channelTracer = new ChannelTracer(
-        logId, builder.maxTraceEvents, timeProvider.currentTimeNanos(),
-        "Channel for '" + target + "'");
-    channelLogger = new ChannelLoggerImpl(channelTracer, timeProvider);
     this.executorPool = checkNotNull(builder.executorPool, "executorPool");
     this.balancerRpcExecutorPool = checkNotNull(balancerRpcExecutorPool, "balancerRpcExecutorPool");
     this.balancerRpcExecutorHolder = new ExecutorHolder(balancerRpcExecutorPool);
diff --git a/core/src/test/java/io/grpc/internal/DnsNameResolverProviderTest.java b/core/src/test/java/io/grpc/internal/DnsNameResolverProviderTest.java
index 3f5df9b..fa52a7d 100644
--- a/core/src/test/java/io/grpc/internal/DnsNameResolverProviderTest.java
+++ b/core/src/test/java/io/grpc/internal/DnsNameResolverProviderTest.java
@@ -24,6 +24,7 @@
 import static org.junit.Assume.assumeTrue;
 import static org.mockito.Mockito.mock;
 
+import io.grpc.ChannelLogger;
 import io.grpc.NameResolver;
 import io.grpc.NameResolver.ServiceConfigParser;
 import io.grpc.SynchronizationContext;
@@ -47,6 +48,7 @@
       .setProxyDetector(GrpcUtil.DEFAULT_PROXY_DETECTOR)
       .setSynchronizationContext(syncContext)
       .setServiceConfigParser(mock(ServiceConfigParser.class))
+      .setChannelLogger(mock(ChannelLogger.class))
       .build();
 
   private DnsNameResolverProvider provider = new DnsNameResolverProvider();
diff --git a/core/src/test/java/io/grpc/internal/DnsNameResolverTest.java b/core/src/test/java/io/grpc/internal/DnsNameResolverTest.java
index 4edc247..192d03d 100644
--- a/core/src/test/java/io/grpc/internal/DnsNameResolverTest.java
+++ b/core/src/test/java/io/grpc/internal/DnsNameResolverTest.java
@@ -36,6 +36,7 @@
 import com.google.common.collect.Iterables;
 import com.google.common.net.InetAddresses;
 import com.google.common.testing.FakeTicker;
+import io.grpc.ChannelLogger;
 import io.grpc.EquivalentAddressGroup;
 import io.grpc.HttpConnectProxiedSocketAddress;
 import io.grpc.NameResolver;
@@ -115,6 +116,7 @@
       .setProxyDetector(GrpcUtil.DEFAULT_PROXY_DETECTOR)
       .setSynchronizationContext(syncContext)
       .setServiceConfigParser(mock(ServiceConfigParser.class))
+      .setChannelLogger(mock(ChannelLogger.class))
       .build();
 
   private final DnsNameResolverProvider provider = new DnsNameResolverProvider();
@@ -175,6 +177,7 @@
             .setProxyDetector(proxyDetector)
             .setSynchronizationContext(syncContext)
             .setServiceConfigParser(mock(ServiceConfigParser.class))
+            .setChannelLogger(mock(ChannelLogger.class))
             .build();
     return newResolver(name, stopwatch, isAndroid, args);
   }
@@ -331,6 +334,7 @@
             .setProxyDetector(GrpcUtil.NOOP_PROXY_DETECTOR)
             .setSynchronizationContext(syncContext)
             .setServiceConfigParser(mock(ServiceConfigParser.class))
+            .setChannelLogger(mock(ChannelLogger.class))
             .setOffloadExecutor(
                 new Executor() {
                   @Override
diff --git a/core/src/test/java/io/grpc/internal/ManagedChannelImplGetNameResolverTest.java b/core/src/test/java/io/grpc/internal/ManagedChannelImplGetNameResolverTest.java
index c620ce2..c1d84eb 100644
--- a/core/src/test/java/io/grpc/internal/ManagedChannelImplGetNameResolverTest.java
+++ b/core/src/test/java/io/grpc/internal/ManagedChannelImplGetNameResolverTest.java
@@ -21,6 +21,7 @@
 import static org.junit.Assert.fail;
 import static org.mockito.Mockito.mock;
 
+import io.grpc.ChannelLogger;
 import io.grpc.NameResolver;
 import io.grpc.NameResolver.Factory;
 import io.grpc.NameResolver.ServiceConfigParser;
@@ -40,6 +41,7 @@
       .setProxyDetector(mock(ProxyDetector.class))
       .setSynchronizationContext(new SynchronizationContext(mock(UncaughtExceptionHandler.class)))
       .setServiceConfigParser(mock(ServiceConfigParser.class))
+      .setChannelLogger(mock(ChannelLogger.class))
       .build();
 
   @Test
diff --git a/core/src/test/java/io/grpc/internal/OverrideAuthorityNameResolverTest.java b/core/src/test/java/io/grpc/internal/OverrideAuthorityNameResolverTest.java
index 58b17d5..8d23ce3 100644
--- a/core/src/test/java/io/grpc/internal/OverrideAuthorityNameResolverTest.java
+++ b/core/src/test/java/io/grpc/internal/OverrideAuthorityNameResolverTest.java
@@ -23,6 +23,7 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import io.grpc.ChannelLogger;
 import io.grpc.NameResolver;
 import io.grpc.NameResolver.ServiceConfigParser;
 import io.grpc.ProxyDetector;
@@ -41,6 +42,7 @@
       .setProxyDetector(mock(ProxyDetector.class))
       .setSynchronizationContext(new SynchronizationContext(mock(UncaughtExceptionHandler.class)))
       .setServiceConfigParser(mock(ServiceConfigParser.class))
+      .setChannelLogger(mock(ChannelLogger.class))
       .build();
 
   @Test
diff --git a/xds/src/test/java/io/grpc/xds/XdsNameResolverProviderTest.java b/xds/src/test/java/io/grpc/xds/XdsNameResolverProviderTest.java
index 549c3c6..275cf72 100644
--- a/xds/src/test/java/io/grpc/xds/XdsNameResolverProviderTest.java
+++ b/xds/src/test/java/io/grpc/xds/XdsNameResolverProviderTest.java
@@ -20,6 +20,7 @@
 import static org.junit.Assert.fail;
 import static org.mockito.Mockito.mock;
 
+import io.grpc.ChannelLogger;
 import io.grpc.InternalServiceProviders;
 import io.grpc.NameResolver;
 import io.grpc.NameResolver.ServiceConfigParser;
@@ -46,6 +47,7 @@
       .setProxyDetector(GrpcUtil.NOOP_PROXY_DETECTOR)
       .setSynchronizationContext(syncContext)
       .setServiceConfigParser(mock(ServiceConfigParser.class))
+      .setChannelLogger(mock(ChannelLogger.class))
       .build();
 
   private XdsNameResolverProvider provider = new XdsNameResolverProvider();
diff --git a/xds/src/test/java/io/grpc/xds/XdsNameResolverTest.java b/xds/src/test/java/io/grpc/xds/XdsNameResolverTest.java
index d581106..d3efc82 100644
--- a/xds/src/test/java/io/grpc/xds/XdsNameResolverTest.java
+++ b/xds/src/test/java/io/grpc/xds/XdsNameResolverTest.java
@@ -24,6 +24,7 @@
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Iterables;
 import io.envoyproxy.envoy.api.v2.core.Node;
+import io.grpc.ChannelLogger;
 import io.grpc.NameResolver;
 import io.grpc.NameResolver.ResolutionResult;
 import io.grpc.NameResolver.ServiceConfigParser;
@@ -69,6 +70,7 @@
           .setProxyDetector(GrpcUtil.NOOP_PROXY_DETECTOR)
           .setSynchronizationContext(syncContext)
           .setServiceConfigParser(mock(ServiceConfigParser.class))
+          .setChannelLogger(mock(ChannelLogger.class))
           .build();
 
   private final XdsNameResolverProvider provider = new XdsNameResolverProvider();