Browse Source

Extensions example (#3071)

* Simplify extensions example project

* Add external dependency and fat jar support

* spotless

* Apply suggestions from code review

Co-authored-by: Mateusz Rzeszutek <mrzeszutek@splunk.com>

* Apply suggestions from code review

Co-authored-by: Trask Stalnaker <trask.stalnaker@gmail.com>

Co-authored-by: Mateusz Rzeszutek <mrzeszutek@splunk.com>
Co-authored-by: Trask Stalnaker <trask.stalnaker@gmail.com>
Nikita Salnikov-Tarnovski 3 years ago
parent
commit
3cfd58c268
21 changed files with 207 additions and 110 deletions
  1. 75 0
      examples/extension/README.md
  2. 105 43
      examples/extension/build.gradle
  3. 0 19
      examples/extension/custom/build.gradle
  4. 0 4
      examples/extension/settings.gradle
  5. 0 32
      examples/extension/smoke-tests/build.gradle
  6. 0 0
      examples/extension/src/main/java/com/example/javaagent/DemoIdGenerator.java
  7. 0 0
      examples/extension/src/main/java/com/example/javaagent/DemoPropagator.java
  8. 0 0
      examples/extension/src/main/java/com/example/javaagent/DemoPropagatorProvider.java
  9. 0 0
      examples/extension/src/main/java/com/example/javaagent/DemoPropertySource.java
  10. 0 0
      examples/extension/src/main/java/com/example/javaagent/DemoResourceProvider.java
  11. 0 0
      examples/extension/src/main/java/com/example/javaagent/DemoSampler.java
  12. 0 0
      examples/extension/src/main/java/com/example/javaagent/DemoSdkTracerProviderConfigurer.java
  13. 0 0
      examples/extension/src/main/java/com/example/javaagent/DemoSpanExporter.java
  14. 7 0
      examples/extension/src/main/java/com/example/javaagent/DemoSpanProcessor.java
  15. 0 0
      examples/extension/src/main/java/com/example/javaagent/instrumentation/DemoServlet3InstrumentationModule.java
  16. 17 11
      examples/extension/src/test/java/com/example/javaagent/smoketest/IntegrationTest.java
  17. 0 0
      examples/extension/src/test/java/com/example/javaagent/smoketest/OkHttpUtils.java
  18. 1 1
      examples/extension/src/test/java/com/example/javaagent/smoketest/SpringBootIntegrationTest.java
  19. 0 0
      examples/extension/src/test/resources/logback.xml
  20. 0 0
      examples/extension/src/test/resources/otel.yaml
  21. 2 0
      javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/LoggingConfigurer.java

+ 75 - 0
examples/extension/README.md

@@ -0,0 +1,75 @@
+## Introduction
+
+This repository demonstrates how to create an extension archive to use with `otel.javaagent.experimental.extensions`
+configuration option of the OpenTelemetry Java instrumentation agent.
+
+For every extension point provided by OpenTelemetry Java instrumentation, this repository contains an example of
+its usage.
+
+Please carefully read both the source code and Gradle build script file `build.gradle`.
+They contain a lot of documentation and comments explaining the purpose of all major pieces.
+
+## How to use extension archive
+
+When you build this project by running `./gradlew build` you will get a jar file in
+`build/libs/opentelemetry-java-instrumentation-extension-demo-1.0-all.jar`.
+Copy this jar file to a machine running the application that you are monitoring with
+OpenTelemetry Java instrumentation agent.
+
+Assuming that your command line looks similar to this:
+```
+java -javaagent:path/to/opentelemetry-javaagent-all.jar \
+     -jar myapp.jar
+```
+change it to this:
+```
+java -javaagent:path/to/opentelemetry-javaagent-all.jar \
+     -Dotel.javaagent.experimental.extensions=path/to/extension.jar
+     -jar myapp.jar
+```
+specifying the full path and the correct name of your extensions jar.
+
+## Extensions examples
+
+* [DemoIdGenerator](src/main/java/com/example/javaagent/DemoIdGenerator.java) - custom `IdGenerator`
+* [DemoPropagator](src/main/java/com/example/javaagent/DemoPropagator.java) - custom `TextMapPropagator`
+* [DemoPropertySource](src/main/java/com/example/javaagent/DemoPropertySource.java) - default configuration
+* [DemoSampler](src/main/java/com/example/javaagent/DemoSampler.java) - custom `Sampler`
+* [DemoSpanProcessor](src/main/java/com/example/javaagent/DemoSpanProcessor.java) - custom `SpanProcessor`
+* [DemoSpanExporter](src/main/java/com/example/javaagent/DemoSpanExporter.java) - custom `SpanExporter`
+* [DemoServlet3InstrumentationModule](src/main/java/com/example/javaagent/instrumentation/DemoServlet3InstrumentationModule.java) - additional instrumentation
+
+## Instrumentation customisation
+
+There are several options to override or customise instrumentation provided by the upstream agent.
+The following description follows one specific use-case:
+
+> Instrumentation X from Otel distribution creates span that I don't like and I want to change it.
+
+As an example, let us take some database client instrumentation that creates a span for database call
+and extracts data from db connection to provide attributes for that span.
+
+### I don't want this span at all
+The easiest case. You can just pre-configure the agent in your extension and disable given instrumentation.
+
+### I want to add/modify some attributes and their values does NOT depend on a specific db connection instance.
+E.g. you want to add some data from call stack as span attribute. 
+In this case just provide your custom `SpanProcessor`.
+No need for touching instrumentation itself.
+
+### I want to add/modify some attributes and their values depend on a specific db connection instance.
+Write a _new_ instrumentation which injects its own advice into the same method as the original one.
+Use `order` method to ensure it is run after the original instrumentation.
+Now you can augment current span with new information.
+
+See [DemoServlet3InstrumentationModule](instrumentation/servlet-3/src/main/java/com/example/javaagent/instrumentation/DemoServlet3InstrumentationModule.java).
+
+### I want to remove some attributes
+Write custom exporter or use attribute filtering functionality in Collector.
+
+### I don't like Otel span at all. I want to significantly modify it and its lifecycle
+Disable existing instrumentation.
+Write a new one, which injects `Advice` into the same (or better) method as the original instrumentation.
+Write your own `Advice` for this.
+Use existing `Tracer` directly or extend it.
+As you have your own `Advice`, you can control which `Tracer` you use.

+ 105 - 43
examples/extension/build.gradle

@@ -1,52 +1,114 @@
+plugins {
+  id "java"
+
+  /*
+  Instrumentation agent extension mechanism expects a single jar containing everything required
+  for your extension. This also includes any external libraries that your extension uses and
+  cannot access from application classpath (see comment below about `javax.servlet-api` dependency).
+
+  Thus we use Shadow Gradle plugin to package our classes and all required runtime dependencies
+  into a single jar.
+  See https://imperceptiblethoughts.com/shadow/ for more details about Shadow plugin.
+   */
+  id "com.github.johnrengelman.shadow" version "6.1.0"
+}
+
 group 'io.opentelemetry.example'
-version '1.0-SNAPSHOT'
-
-subprojects {
-  version = rootProject.version
-
-  apply plugin: "java"
-
-  ext {
-    versions = [
-      opentelemetry         : "1.2.0",
-      opentelemetryJavaagent: "1.3.0-SNAPSHOT",
-      bytebuddy             : "1.10.18",
-      guava                 : "30.1-jre"
-    ]
-    versions.opentelemetryAlpha = "${versions.opentelemetry}-alpha"
-    versions.opentelemetryJavaagentAlpha = "1.3.0-alpha-SNAPSHOT"
-
-    deps = [
-      bytebuddy           : dependencies.create(group: 'net.bytebuddy', name: 'byte-buddy', version: versions.bytebuddy),
-      bytebuddyagent      : dependencies.create(group: 'net.bytebuddy', name: 'byte-buddy-agent', version: versions.bytebuddy),
-      autoservice         : [
-        dependencies.create(group: 'com.google.auto.service', name: 'auto-service', version: '1.0-rc7'),
-        dependencies.create(group: 'com.google.auto', name: 'auto-common', version: '0.8'),
-        dependencies.create(group: 'com.google.guava', name: 'guava', version: "${versions.guava}"),
-      ],
-      autoValueAnnotations: "com.google.auto.value:auto-value-annotations:${versions.autoValue}",
-    ]
-  }
+version '1.0'
 
-  repositories {
-    // needed because relying on locally built SNAPSHOT versions above for now
-    mavenLocal()
-    mavenCentral()
-  }
+ext {
+  versions = [
+    opentelemetry              : "1.2.0",
+    opentelemetryAlpha         : "1.2.0-alpha",
+    opentelemetryJavaagent     : "1.3.0-SNAPSHOT",
+    opentelemetryJavaagentAlpha: "1.3.0-alpha-SNAPSHOT",
+  ]
 
-  dependencies {
-    testImplementation("org.mockito:mockito-core:3.3.3")
-    testImplementation("org.junit.jupiter:junit-jupiter-api:5.6.2")
-    testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.6.2")
+  deps = [
+    autoservice: dependencies.create(group: 'com.google.auto.service', name: 'auto-service', version: '1.0')
+  ]
+}
+
+repositories {
+  mavenCentral()
+  maven {
+    url = uri("https://oss.sonatype.org/content/repositories/snapshots")
   }
+}
 
-  tasks {
-    test {
-      useJUnitPlatform()
-    }
+configurations {
+  /*
+  We create a separate gradle configuration to grab a published Otel instrumentation agent.
+  We don't need the agent during development of this extension module.
+  This agent is used only during integration test.
+  */
+  otel
+}
+
+dependencies {
+  /*
+  Interfaces and SPIs that we implement. We use `compileOnly` dependency because during
+  runtime all neccessary classes are provided by javaagent itself.
+   */
+  compileOnly("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure:${versions.opentelemetryAlpha}")
+  compileOnly("io.opentelemetry.javaagent:opentelemetry-javaagent-api:${versions.opentelemetryJavaagentAlpha}")
+  compileOnly("io.opentelemetry.javaagent:opentelemetry-javaagent-extension-api:${versions.opentelemetryJavaagentAlpha}")
+
+  //Provides @AutoService annotation that makes registration of our SPI implementations much easier
+  compileOnly deps.autoservice
+  annotationProcessor deps.autoservice
 
-    compileJava {
-      options.release.set(11)
+  /*
+   Used by our demo instrumentation module to reference classes of the target instrumented library.
+   We again use `compileOnly` here because during runtime these classes are provided by the
+   actual application that we instrument.
+
+   NB! Only Advice (and "helper") classes of instrumentation modules can access classes from application classpath.
+   See https://github.com/open-telemetry/opentelemetry-java-instrumentation/blob/main/docs/contributing/writing-instrumentation-module.md#advice-classes
+   */
+  compileOnly group: 'javax.servlet', name: 'javax.servlet-api', version: '3.0.1'
+
+  /*
+  This dependency is required for DemoSpanProcessor both during compile and runtime.
+  Only dependencies added to `implementation` configuration will be picked up by Shadow plugin
+  and added to the resulting jar for our extension's distribution.
+   */
+  implementation 'org.apache.commons:commons-lang3:3.11'
+
+  //All dependencies below are only for tests
+  testImplementation("org.testcontainers:testcontainers:1.15.2")
+  testImplementation("com.fasterxml.jackson.core:jackson-databind:2.11.2")
+  testImplementation("com.google.protobuf:protobuf-java-util:3.12.4")
+  testImplementation("com.squareup.okhttp3:okhttp:3.12.12")
+  testImplementation("io.opentelemetry:opentelemetry-api:${versions.opentelemetry}")
+  testImplementation("io.opentelemetry:opentelemetry-proto:${versions.opentelemetryAlpha}")
+
+  testImplementation("org.junit.jupiter:junit-jupiter-api:5.6.2")
+  testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.6.2")
+  testRuntimeOnly("ch.qos.logback:logback-classic:1.2.3")
+
+  //Otel Java instrumentation that we use and extend during integration tests
+  otel("io.opentelemetry.javaagent:opentelemetry-javaagent:${versions.opentelemetryJavaagent}:all")
+}
+
+tasks {
+  test {
+    useJUnitPlatform()
+
+    def extensionJar = tasks.shadowJar
+    inputs.files(layout.files(extensionJar))
+
+    doFirst {
+      //To run our tests with the javaagent published by OpenTelemetry Java instrumentation project
+      jvmArgs("-Dio.opentelemetry.smoketest.agentPath=${configurations.getByName("otel").resolve().find().absolutePath}")
+      //Instructs our integration test where to find our extension archive
+      jvmArgs("-Dio.opentelemetry.smoketest.extensionPath=${extensionJar.archiveFile.get()}")
     }
   }
+
+  compileJava {
+    options.release.set(11)
+  }
+
+  assemble.dependsOn(shadowJar)
 }

+ 0 - 19
examples/extension/custom/build.gradle

@@ -1,19 +0,0 @@
-plugins {
-  id "java"
-}
-
-dependencies {
-  compileOnly("io.opentelemetry:opentelemetry-sdk:${versions.opentelemetry}")
-  compileOnly("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure:${versions.opentelemetryAlpha}")
-
-  compileOnly("io.opentelemetry.javaagent:opentelemetry-javaagent-extension-api:${versions.opentelemetryJavaagentAlpha}")
-  compileOnly("io.opentelemetry.javaagent:opentelemetry-javaagent-api:${versions.opentelemetryJavaagentAlpha}")
-
-  compileOnly deps.bytebuddy
-  compileOnly deps.bytebuddyagent
-  annotationProcessor deps.autoservice
-  compileOnly deps.autoservice
-
-  compileOnly group: 'javax.servlet', name: 'javax.servlet-api', version: '3.0.1'
-
-}

+ 0 - 4
examples/extension/settings.gradle

@@ -1,5 +1 @@
 rootProject.name = 'opentelemetry-java-instrumentation-extension-demo'
-
-include "custom"
-include "smoke-tests"
-

+ 0 - 32
examples/extension/smoke-tests/build.gradle

@@ -1,32 +0,0 @@
-plugins {
-  id "java"
-}
-
-configurations {
-  otel
-}
-
-dependencies {
-  testImplementation("org.testcontainers:testcontainers:1.15.2")
-  testImplementation("com.fasterxml.jackson.core:jackson-databind:2.11.2")
-  testImplementation("com.google.protobuf:protobuf-java-util:3.12.4")
-  testImplementation("com.squareup.okhttp3:okhttp:3.12.12")
-  testImplementation("io.opentelemetry:opentelemetry-proto:1.0.0-alpha")
-  testImplementation("io.opentelemetry:opentelemetry-api:1.0.0")
-
-  testImplementation("ch.qos.logback:logback-classic:1.2.3")
-
-  otel("io.opentelemetry.javaagent:opentelemetry-javaagent:${versions.opentelemetryJavaagent}:all")
-}
-
-tasks.test {
-  useJUnitPlatform()
-
-  def customJar = project(":custom").tasks.jar
-  inputs.files(layout.files(customJar))
-
-  doFirst {
-    jvmArgs("-Dio.opentelemetry.smoketest.agent.shadowJar.path=${configurations.getByName("otel").resolve().find().absolutePath}")
-    jvmArgs("-Dio.opentelemetry.smoketest.agent.extensionPath=${customJar.archiveFile.get()}")
-  }
-}

+ 0 - 0
examples/extension/custom/src/main/java/com/example/javaagent/DemoIdGenerator.java → examples/extension/src/main/java/com/example/javaagent/DemoIdGenerator.java


+ 0 - 0
examples/extension/custom/src/main/java/com/example/javaagent/DemoPropagator.java → examples/extension/src/main/java/com/example/javaagent/DemoPropagator.java


+ 0 - 0
examples/extension/custom/src/main/java/com/example/javaagent/DemoPropagatorProvider.java → examples/extension/src/main/java/com/example/javaagent/DemoPropagatorProvider.java


+ 0 - 0
examples/extension/custom/src/main/java/com/example/javaagent/DemoPropertySource.java → examples/extension/src/main/java/com/example/javaagent/DemoPropertySource.java


+ 0 - 0
examples/extension/custom/src/main/java/com/example/javaagent/DemoResourceProvider.java → examples/extension/src/main/java/com/example/javaagent/DemoResourceProvider.java


+ 0 - 0
examples/extension/custom/src/main/java/com/example/javaagent/DemoSampler.java → examples/extension/src/main/java/com/example/javaagent/DemoSampler.java


+ 0 - 0
examples/extension/custom/src/main/java/com/example/javaagent/DemoSdkTracerProviderConfigurer.java → examples/extension/src/main/java/com/example/javaagent/DemoSdkTracerProviderConfigurer.java


+ 0 - 0
examples/extension/custom/src/main/java/com/example/javaagent/DemoSpanExporter.java → examples/extension/src/main/java/com/example/javaagent/DemoSpanExporter.java


+ 7 - 0
examples/extension/custom/src/main/java/com/example/javaagent/DemoSpanProcessor.java → examples/extension/src/main/java/com/example/javaagent/DemoSpanProcessor.java

@@ -5,6 +5,7 @@ import io.opentelemetry.sdk.common.CompletableResultCode;
 import io.opentelemetry.sdk.trace.ReadWriteSpan;
 import io.opentelemetry.sdk.trace.ReadableSpan;
 import io.opentelemetry.sdk.trace.SpanProcessor;
+import org.apache.commons.lang3.RandomStringUtils;
 
 /**
  * See <a href="https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/trace/sdk.md#span-processor">
@@ -13,8 +14,14 @@ import io.opentelemetry.sdk.trace.SpanProcessor;
  * @see DemoSdkTracerProviderConfigurer
  */
 public class DemoSpanProcessor implements SpanProcessor {
+
   @Override
   public void onStart(Context parentContext, ReadWriteSpan span) {
+    /*
+    The sole purpose of this attribute is to introduce runtime dependency on some external library.
+    We need this to demonstrate how extension can use them.
+     */
+    span.setAttribute("random", RandomStringUtils.random(10));
     span.setAttribute("custom", "demo");
   }
 

+ 0 - 0
examples/extension/custom/src/main/java/com/example/javaagent/instrumentation/DemoServlet3InstrumentationModule.java → examples/extension/src/main/java/com/example/javaagent/instrumentation/DemoServlet3InstrumentationModule.java


+ 17 - 11
examples/extension/smoke-tests/src/test/java/com/example/javaagent/smoketest/SmokeTest.java → examples/extension/src/test/java/com/example/javaagent/smoketest/IntegrationTest.java

@@ -28,8 +28,8 @@ import org.testcontainers.containers.output.Slf4jLogConsumer;
 import org.testcontainers.containers.wait.strategy.Wait;
 import org.testcontainers.utility.MountableFile;
 
-abstract class SmokeTest {
-  private static final Logger logger = LoggerFactory.getLogger(SmokeTest.class);
+abstract class IntegrationTest {
+  private static final Logger logger = LoggerFactory.getLogger(IntegrationTest.class);
 
   private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
 
@@ -37,9 +37,9 @@ abstract class SmokeTest {
 
   private static final Network network = Network.newNetwork();
   protected static final String agentPath =
-      System.getProperty("io.opentelemetry.smoketest.agent.shadowJar.path");
+      System.getProperty("io.opentelemetry.smoketest.agentPath");
   protected static final String extensionPath =
-      System.getProperty("io.opentelemetry.smoketest.agent.extensionPath");
+      System.getProperty("io.opentelemetry.smoketest.extensionPath");
 
   protected abstract String getTargetImage(int jdk);
 
@@ -57,7 +57,7 @@ abstract class SmokeTest {
   static void setupSpec() {
     backend =
         new GenericContainer<>(
-            "open-telemetry-docker-dev.bintray.io/java/smoke-fake-backend:latest")
+            "ghcr.io/open-telemetry/java-test-containers:smoke-fake-backend-20210324.684269693")
             .withExposedPorts(8080)
             .waitingFor(Wait.forHttp("/health").forPort(8080))
             .withNetwork(network)
@@ -77,7 +77,7 @@ abstract class SmokeTest {
     collector.start();
   }
 
-  protected GenericContainer target;
+  protected GenericContainer<?> target;
 
   void startTarget(int jdk) {
     target =
@@ -89,7 +89,10 @@ abstract class SmokeTest {
                 MountableFile.forHostPath(agentPath), "/opentelemetry-javaagent.jar")
             .withCopyFileToContainer(
                 MountableFile.forHostPath(extensionPath), "/opentelemetry-extensions.jar")
-            .withEnv("JAVA_TOOL_OPTIONS", "-javaagent:/opentelemetry-javaagent.jar -Dotel.javaagent.debug=true")
+            //Adds instrumentation agent with debug configuration to the targe application
+            .withEnv("JAVA_TOOL_OPTIONS",
+                "-javaagent:/opentelemetry-javaagent.jar -Dotel.javaagent.debug=true")
+            //Asks instrumentation agent to include this extension archive into its runtime
             .withEnv("OTEL_JAVAAGENT_EXPERIMENTAL_EXTENSIONS", "/opentelemetry-extensions.jar")
             .withEnv("OTEL_BSP_MAX_EXPORT_BATCH", "1")
             .withEnv("OTEL_BSP_SCHEDULE_DELAY", "10")
@@ -121,11 +124,13 @@ abstract class SmokeTest {
     collector.stop();
   }
 
-  protected static int countResourcesByValue(Collection<ExportTraceServiceRequest> traces, String resourceName, String value) {
+  protected static int countResourcesByValue(Collection<ExportTraceServiceRequest> traces,
+      String resourceName, String value) {
     return (int) traces.stream()
         .flatMap(it -> it.getResourceSpansList().stream())
         .flatMap(it -> it.getResource().getAttributesList().stream())
-        .filter(kv -> kv.getKey().equals(resourceName) && kv.getValue().getStringValue().equals(value))
+        .filter(
+            kv -> kv.getKey().equals(resourceName) && kv.getValue().getStringValue().equals(value))
         .count();
   }
 
@@ -138,7 +143,8 @@ abstract class SmokeTest {
       Collection<ExportTraceServiceRequest> traces, String attributeName, String attributeValue) {
     return (int) getSpanStream(traces)
         .flatMap(it -> it.getAttributesList().stream())
-        .filter(kv -> kv.getKey().equals(attributeName) && kv.getValue().getStringValue().equals(attributeValue))
+        .filter(kv -> kv.getKey().equals(attributeName) && kv.getValue().getStringValue()
+            .equals(attributeValue))
         .count();
   }
 
@@ -175,7 +181,7 @@ abstract class SmokeTest {
 
       Request request =
           new Request.Builder()
-              .url(String.format("http://localhost:%d/get-requests", backend.getMappedPort(8080)))
+              .url(String.format("http://localhost:%d/get-traces", backend.getMappedPort(8080)))
               .build();
 
       try (ResponseBody body = client.newCall(request).execute().body()) {

+ 0 - 0
examples/extension/smoke-tests/src/test/java/com/example/javaagent/smoketest/OkHttpUtils.java → examples/extension/src/test/java/com/example/javaagent/smoketest/OkHttpUtils.java


+ 1 - 1
examples/extension/smoke-tests/src/test/java/com/example/javaagent/smoketest/SpringBootSmokeTest.java → examples/extension/src/test/java/com/example/javaagent/smoketest/SpringBootIntegrationTest.java

@@ -11,7 +11,7 @@ import okhttp3.Response;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;
 
-class SpringBootSmokeTest extends SmokeTest {
+class SpringBootIntegrationTest extends IntegrationTest {
 
   protected String getTargetImage(int jdk) {
     return "ghcr.io/open-telemetry/java-test-containers:smoke-springboot-jdk" + jdk

+ 0 - 0
examples/extension/smoke-tests/src/test/resources/logback.xml → examples/extension/src/test/resources/logback.xml


+ 0 - 0
examples/extension/smoke-tests/src/test/resources/otel.yaml → examples/extension/src/test/resources/otel.yaml


+ 2 - 0
javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/LoggingConfigurer.java

@@ -32,6 +32,8 @@ class LoggingConfigurer {
       setSystemPropertyDefault(SIMPLE_LOGGER_PREFIX + "io.grpc.Context", "INFO");
       setSystemPropertyDefault(SIMPLE_LOGGER_PREFIX + "io.grpc.internal.ServerImplBuilder", "INFO");
       setSystemPropertyDefault(SIMPLE_LOGGER_PREFIX + "io.grpc.ManagedChannelRegistry", "INFO");
+      setSystemPropertyDefault(
+          SIMPLE_LOGGER_PREFIX + "io.netty.util.internal.NativeLibraryLoader", "INFO");
       setSystemPropertyDefault(
           SIMPLE_LOGGER_PREFIX + "io.grpc.internal.ManagedChannelImplBuilder", "INFO");
     } else {