Розширення

Розширення додають можливості агенту без необхідності створювати окремий дистрибутив.

Вступ

Розширення додають нові функції та можливості агенту OpenTelemetry Java без необхідності створювати окремий дистрибутив (власну версію всього агента). Думайте про розширення як про втулки, які налаштовують поведінку агента.

Розширення дозволяють:

  • Додавати нові інструментальні засоби для бібліотек, які наразі не підтримуються
  • Налаштовувати поведінку наявних інструментувань
  • Реалізовувати власні компоненти SDK (семплери, експортери, поширювачі)
  • Модифікувати збір та обробку телеметричних даних

Швидкий старт

Ось мінімальне розширення, яке додає користувацький обробник відрізків, щоб почати роботу:

Створіть проєкт Gradle (build.gradle.kts):

plugins {
    id("java")
    id("com.gradleup.shadow")
}

java {
    toolchain {
        languageVersion.set(JavaLanguageVersion.of(8))
    }
}

dependencies {
    // Використовуйте BOM для керування версіями залежностей OpenTelemetry
    compileOnly(platform("io.opentelemetry:opentelemetry-bom:1.61.0"))

    // OpenTelemetry SDK autoconfiguration SPI (надається агентом)
    compileOnly("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure-spi")

    // OpenTelemetry SDK (потрібно для SpanProcessor та класів трасування)
    compileOnly("io.opentelemetry:opentelemetry-sdk")

    // Процесор анотацій для автоматичної реєстрації SPI
    compileOnly("com.google.auto.service:auto-service:1.1.1")
    annotationProcessor("com.google.auto.service:auto-service:1.1.1")

    // Додайте будь-які зовнішні залежності з областю 'implementation'
    // implementation("org.apache.commons:commons-lang3:3.19.0")
}

tasks.assemble {
    dependsOn(tasks.shadowJar)
}

Створіть реалізацію SpanProcessor:

public class MySpanProcessor implements SpanProcessor {

  @Override
  public void onStart(Context parentContext, ReadWriteSpan span) {
    // Додайте власні атрибути, коли span починається
    span.setAttribute("custom.processor", "active");
  }

  @Override
  public boolean isStartRequired() {
    return true;
  }

  @Override
  public void onEnd(ReadableSpan span) {
    // Обробіть span, коли він закінчується (необов'язково)
  }

  @Override
  public boolean isEndRequired() {
    return false;
  }

  @Override
  public CompletableResultCode shutdown() {
    return CompletableResultCode.ofSuccess();
  }
}

Створіть клас розширення, який використовує SPI AutoConfigurationCustomizerProvider:

@AutoService(AutoConfigurationCustomizerProvider.class)
public class MyExtensionProvider implements AutoConfigurationCustomizerProvider {

  @Override
  public void customize(AutoConfigurationCustomizer config) {
    config.addTracerProviderCustomizer(this::configureTracer);
  }

  private SdkTracerProviderBuilder configureTracer(
      SdkTracerProviderBuilder tracerProvider, ConfigProperties config) {
    return tracerProvider
        .setSpanLimits(SpanLimits.builder().setMaxNumberOfAttributes(1024).build())
        .addSpanProcessor(new MySpanProcessor());
  }
}

Збірка розширення:

./gradlew shadowJar

Використання розширення:

java -javaagent:opentelemetry-javaagent.jar \
     -Dotel.javaagent.extensions=build/libs/my-extension-all.jar \
     -jar myapp.jar

Використання розширень

Існує два способи використання розширень з Java агентом:

  • Завантаження як окремий JAR файл - Гнучко для розробки та тестування
  • Вбудування в агент - Один JAR для розгортання для робочого середовища
ПідхідПеревагиНедолікиНайкраще для
Runtime LoadingЛегко змінювати розширення, не потрібно перебудовуватиПотрібен додатковий параметр командного рядкаРозробка, тестування
EmbeddingОдин JAR, простіше розгортання, не можна забути завантажитиПотрібна перебудова для зміни розширеньРобоче середовище, розповсюдження

Завантаження розширень під час виконання

Розширення можна завантажувати під час виконання, використовуючи системну властивість otel.javaagent.extensions або змінну середовища OTEL_JAVAAGENT_EXTENSIONS. Ця опція конфігурації приймає шляхи до JAR-файлів розширень або теки, що містять JAR-файли розширень, розділені комами.

Одне розширення

java -javaagent:path/to/opentelemetry-javaagent.jar \
     -Dotel.javaagent.extensions=/path/to/my-extension.jar \
     -jar myapp.jar

Кілька розширень

java -javaagent:path/to/opentelemetry-javaagent.jar \
     -Dotel.javaagent.extensions=/path/to/extension1.jar,/path/to/extension2.jar \
     -jar myapp.jar

Тека розширень

Ви можете вказати теку, що містить кілька JAR-файлів розширень, і всі JAR-файли в цій теці будуть завантажені:

java -javaagent:path/to/opentelemetry-javaagent.jar \
     -Dotel.javaagent.extensions=/path/to/extensions-directory \
     -jar myapp.jar

Змішані шляхи

Ви можете комбінувати окремі JAR-файли та теки:

java -javaagent:path/to/opentelemetry-javaagent.jar \
     -Dotel.javaagent.extensions=/path/to/extension1.jar,/opt/extensions,/tmp/custom.jar \
     -jar myapp.jar

Як працює завантаження розширень

Коли ви завантажуєте розширення під час виконання, агент:

  1. Робить OpenTelemetry API доступними для вашого розширення без необхідності пакувати їх у ваш JAR-файл розширення
  2. Виявляє компоненти вашого розширення за допомогою механізму ServiceLoader Java (наприклад, через анотації @AutoService у вашому коді)

Вбудовування розширень в агент

Інший варіант розгортання — створити один JAR-файл, який містить як OpenTelemetry Java агент, так і ваші розширення. Цей підхід спрощує розгортання (тільки один JAR-файл для керування) і усуває необхідність у параметрі командного рядка -Dotel.javaagent.extensions, що зменшує ймовірність випадково забути завантажити ваше розширення.

Як це працює

Агент автоматично шукає розширення в спеціальній теці extensions/ всередині JAR-файлу агента, тому ми можемо використовувати завдання Gradle для:

  1. Завантаження JAR-файлу OpenTelemetry Java агента
  2. Розпакування його вмісту
  3. Додавання вашого JAR-файлу(ів) розширень у теку extensions/
  4. Перепакування всього в один JAR-файл

Завдання Gradle extendedAgent

Додайте наступне до файлу build.gradle.kts вашого проекту розширення:

plugins {
    id("java")

    // Shadow plugin: обʼєднує весь код розширення та його залежності в один JAR-файл
    // Це необхідно, оскільки розширення мають бути упаковані у вигляді одного JAR-файлу
    id("com.gradleup.shadow") version "9.2.2"
}

group = "com.example"
version = "1.0"

configurations {
    // Створюємо тимчасову конфігурацію для завантаження JAR-файлу агента
    // Подумайте про це як про "слот для завантаження", який відокремлений від залежностей вашого розширення
    create("otel")
}

dependencies {
    // Завантажуємо офіційний JAR-файл OpenTelemetry Java агента в конфігурацію 'otel'
    "otel"("io.opentelemetry.javaagent:opentelemetry-javaagent:2.26.1")

    /*
      Інтерфейси та SPI, які ми реалізуємо. Ми використовуємо залежність `compileOnly`, оскільки під час
      виконання всі необхідні класи надаються самим javaagent.
     */
    compileOnly("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure-spi:1.61.0")
    compileOnly("io.opentelemetry:opentelemetry-sdk:1.61.0")
    compileOnly("io.opentelemetry:opentelemetry-api:1.61.0")

    // Необхідно для власної інструментації
    compileOnly("io.opentelemetry.javaagent:opentelemetry-javaagent-extension-api:2.26.1-alpha")
    compileOnly("io.opentelemetry.instrumentation:opentelemetry-instrumentation-api-incubator:2.26.1-alpha")
    compileOnly("net.bytebuddy:byte-buddy:1.15.10")

    // Надає анотацію @AutoService, яка значно спрощує реєстрацію наших реалізацій SPI
    compileOnly("com.google.auto.service:auto-service:1.1.1")
    annotationProcessor("com.google.auto.service:auto-service:1.1.1")
}

// Завдання: Створити розширений JAR-файл агента (агент + ваше розширення)
val extendedAgent by tasks.registering(Jar::class) {
    dependsOn(configurations["otel"])
    archiveFileName.set("opentelemetry-javaagent.jar")

    // Крок 1: Розпакувати JAR-файл офіційного агента
    from(zipTree(configurations["otel"].singleFile))

    // Крок 2: Додати JAR-файл вашого розширення до теки "extensions/"
    from(tasks.shadowJar.get().archiveFile) {
        into("extensions")
    }

    // Крок 3: Зберегти конфігурацію запуску агента (MANIFEST.MF)
    doFirst {
        manifest.from(
            zipTree(configurations["otel"].singleFile).matching {
                include("META-INF/MANIFEST.MF")
            }.singleFile
        )
    }
}

tasks {
    // Переконайтеся, що shadow JAR будується під час звичайного процесу збірки
    assemble {
        dependsOn(shadowJar)
    }
}

Для повного прикладу, зверніться до файлу gradle з прикладу розширення.

Створення та використання розширеного агента

Після того як ви додали завдання extendedAgent до вашого build.gradle.kts:

# 1. Збірка вашого розширення та створення розширеного агента
./gradlew extendedAgent

# 2. Знайдіть вихідний файл у build/libs/
ls build/libs/opentelemetry-javaagent.jar

# 3. Використовуйте його з вашим додатком (немає потреби у -Dotel.javaagent.extensions)
java -javaagent:build/libs/opentelemetry-javaagent.jar -jar myapp.jar

Вбудовування кількох розширень

Щоб вбудувати кілька розширень, змініть завдання extendedAgent, щоб включити кілька JAR-файлів розширень:

val extendedAgent by tasks.registering(Jar::class) {
  dependsOn(configurations["otel"])
  archiveFileName.set("opentelemetry-javaagent.jar")

  from(zipTree(configurations["otel"].singleFile))

  // Додати кілька розширень
  from(tasks.shadowJar.get().archiveFile) {
    into("extensions")
  }
  from(file("../other-extension/build/libs/other-extension-all.jar")) {
    into("extensions")
  }

  doFirst {
    manifest.from(
      zipTree(configurations["otel"].singleFile).matching {
        include("META-INF/MANIFEST.MF")
      }.singleFile
    )
  }
}

Приклади розширень

Для отримання додаткових прикладів розширень дивіться проект розширень у репозиторії Java інструментування.


Востаннє змінено December 26, 2024: [uk] Ukrainian documentation for OpenTelemetry (091c99cf)