Skip to content

feat: complete relocation from io.opentelemetry in output JAR #427

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 15 additions & 12 deletions instrumentation/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -40,27 +40,30 @@ tasks {

mergeServiceFiles()

relocate("com.blogspot.mydailyjava.weaklockfree", "io.opentelemetry.instrumentation.api.internal.shaded.weaklockfree")
relocate("com.blogspot.mydailyjava.weaklockfree", "ai.traceable.io.opentelemetry.instrumentation.api.internal.shaded.weaklockfree")
Copy link

@varkey98 varkey98 Aug 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

feels weird that we add traceable in hypertrace repos? Maybe org.hypertrace instead of ai.traceable?

Copy link
Contributor Author

@thugrock7 thugrock7 Aug 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will shift this entire repo to traceable javaagent

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, then lets do that first and do this there? Addng traceable package names in this repo which is part of the hypertrace opensource code feels weird

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. There is a waiting customer requiring this fix
  2. Also instead of how we did for goagent, I would like a complete relocation of instrumentations for traceable. As that helps with debuggers. So, it will take time
  3. We already do use traceable's name in this repo
    Like https://github.com/hypertrace/javaagent/blob/main/javaagent/src/main/java/org/hypertrace/agent/instrument/HypertraceAgent.java#L80

Copy link

@varkey98 varkey98 Aug 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. agreed
  2. agreed. When you migrate it, maybe worth it to switch these to hypertrace at that point, because we'll be archiving this repo at that point and its bad to leave the repo in a mangled state. Actually, just for my understanding, whats the issue when you add hypertrace in the name instead of traceable? I'd guess the shaded package can take any name as long as it doesnt conflict and not specifically require traceable.
  3. this is specifically checking for traceable agent, not adding traceable as part of its own code.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, just moving to org.hypertrace shouldn't be problem though, I am just saying merging with traceable repo will take time

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ohh then, coming back to my first point, maybe worth it to use org.hypertrace here instead of ai.traceable here, point being since we have separate repos we try to keep traceable out of this open source repo? But this is really a nit, if you feel we dont need that, lmk and I can approve

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But one thing I don't like is that, when we use traceable agent, due to current structure instrumentation scope of spans will be shown as
InstrumentationScope org.hypertrace.io.opentelemetry.netty-4.1 1.33.0-alpha in the case if we relocate to org.hypertrace instead.
which is a bit weird according to me as all customers would use traceable javaagent

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

which will anyways be fixed after you migrate this repo to the traceable one right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yup, should be. But till then
I am ok to change though, it is a nit call anyway


exclude("**/module-info.class")

relocate("org.slf4j", "io.opentelemetry.javaagent.slf4j")
relocate("java.util.logging.Logger", "io.opentelemetry.javaagent.bootstrap.PatchLogger")
relocate("org.slf4j", "ai.traceable.io.opentelemetry.javaagent.slf4j")
relocate("java.util.logging.Logger", "ai.traceable.io.opentelemetry.javaagent.bootstrap.PatchLogger")

// // prevents conflict with library instrumentation
relocate("io.opentelemetry.instrumentation.api", "io.opentelemetry.javaagent.shaded.instrumentation.api")

// prevents conflict with library instrumentation
relocate("io.opentelemetry.instrumentation.api", "ai.traceable.io.opentelemetry.javaagent.shaded.instrumentation.api")
//opentelemetry rewrite library instrumentation dependencies
relocate("io.opentelemetry.instrumentation", "io.opentelemetry.javaagent.shaded.instrumentation") {
relocate("io.opentelemetry.instrumentation", "ai.traceable.io.opentelemetry.javaagent.shaded.instrumentation") {
exclude("io.opentelemetry.javaagent.instrumentation.**")
}

// relocate OpenTelemetry API
relocate("io.opentelemetry.api", "io.opentelemetry.javaagent.shaded.io.opentelemetry.api")
relocate("io.opentelemetry.semconv", "io.opentelemetry.javaagent.shaded.io.opentelemetry.semconv")
relocate("io.opentelemetry.spi", "io.opentelemetry.javaagent.shaded.io.opentelemetry.spi")
relocate("io.opentelemetry.context", "io.opentelemetry.javaagent.shaded.io.opentelemetry.context")
relocate("io.opentelemetry.extension.kotlin", "io.opentelemetry.javaagent.shaded.io.opentelemetry.extension.kotlin")
relocate("io.opentelemetry.extension.aws", "io.opentelemetry.javaagent.shaded.io.opentelemetry.extension.aws")
relocate("io.opentelemetry.api", "ai.traceable.io.opentelemetry.javaagent.shaded.io.opentelemetry.api")
relocate("io.opentelemetry.semconv", "ai.traceable.io.opentelemetry.javaagent.shaded.io.opentelemetry.semconv")
relocate("io.opentelemetry.spi", "ai.traceable.io.opentelemetry.javaagent.shaded.io.opentelemetry.spi")
relocate("io.opentelemetry.context", "ai.traceable.io.opentelemetry.javaagent.shaded.io.opentelemetry.context")
relocate("io.opentelemetry.extension.kotlin", "ai.traceable.io.opentelemetry.javaagent.shaded.io.opentelemetry.extension.kotlin")
relocate("io.opentelemetry.extension.aws", "ai.traceable.io.opentelemetry.javaagent.shaded.io.opentelemetry.extension.aws")

relocate("io.opentelemetry", "ai.traceable.io.opentelemetry")
}
}

Expand Down
158 changes: 135 additions & 23 deletions javaagent/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -17,41 +17,153 @@ dependencies {

base.archivesBaseName = "hypertrace-agent"

tasks {
processResources {
val customizationShadowTask = project(":instrumentation").tasks.named<Jar>("shadowJar")
val providerArchive = customizationShadowTask.get().archiveFile
from(zipTree(providerArchive)) {
into("inst")
rename("(^.*)\\.class$", "$1.classdata")
// Step 1: Extract instrumentation project's shadowJar into inst/ folder
tasks.register<Copy>("extractCustomInstrumentationToInst") {
description = "Extracts instrumentation project's shadowJar into inst/ folder"

val customizationShadowTask = project(":instrumentation").tasks.named<Jar>("shadowJar")
val providerArchive = customizationShadowTask.get().archiveFile

from(zipTree(providerArchive)) {
into("inst")
rename("(^.*)\\.class$", "$1.classdata")
}

into("$buildDir/resources/main")

exclude("**/META-INF/LICENSE")
dependsOn(customizationShadowTask)
}

// Step 2: Extract OpenTelemetry Java Agent's inst/ files and rename .classdata to .class
tasks.register<Copy>("extractOtelAgentJarInstClassdata") {
description = "Extracts OpenTelemetry Java Agent's .classdata files and renames them to .class"

val otelJavaAgentJar = configurations.compileClasspath.get()
.filter { it.name.contains("opentelemetry-javaagent") }
.singleOrNull() ?: throw GradleException("OpenTelemetry Java Agent JAR not found")

doFirst {
println("OpenTelemetry Java Agent JAR: $otelJavaAgentJar")
}

from(zipTree(otelJavaAgentJar)) {
include("inst/**")
rename("(^.*)\\.classdata$", "$1.class")
}

// Output to a temporary directory
into("$buildDir/tmp/otel-classdata-for-relocation")
}

// Step 3: Move contents to inst/ folder with relocated paths
tasks.register<com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar>("relocateOtelClassesToInst") {
description = "Relocates OpenTelemetry classes to inst/ folder with ai.traceable prefix"

dependsOn("extractOtelAgentJarInstClassdata")

from("$buildDir/tmp/otel-classdata-for-relocation/inst")

destinationDirectory.set(file("$buildDir/tmp/relocated-otel-classdata"))
archiveFileName.set("relocated-otel-classdata.jar")

relocate("io.opentelemetry", "ai.traceable.io.opentelemetry")

eachFile {
path = "inst/ai/traceable/$path"
}
}

// Step 3b: Extract the relocated JAR
tasks.register<Copy>("extractRelocatedOtelClasses") {
description = "Extracts relocated OpenTelemetry classes"

dependsOn("relocateOtelClassesToInst")

from(zipTree("$buildDir/tmp/relocated-otel-classdata/relocated-otel-classdata.jar"))
into("$buildDir/tmp/relocated-otel-classes")
}

tasks.register("extractOtelInstrumentationToInst") {
description = "Removes empty directories from the relocated classes directory"

dependsOn("extractRelocatedOtelClasses")

doLast {
// Find and delete empty directories
val instDir = file("$buildDir/tmp/relocated-otel-classes")
if (instDir.exists()) {
deleteEmptyDirs(instDir)
}
exclude("**/META-INF/LICENSE")
dependsOn(customizationShadowTask)
}
}

// Helper function to recursively delete empty directories
fun deleteEmptyDirs(dir: File) {
if (!dir.isDirectory) return

val children = dir.listFiles() ?: return

// Recursively process subdirectories
children.filter { it.isDirectory }.forEach { deleteEmptyDirs(it) }

// Check if directory is empty after processing subdirectories
if (dir.listFiles()?.isEmpty() == true) {
dir.delete()
}
}

// Step 4: Convert all .class files to .classdata and combine with instrumentation files
tasks.register<Copy>("combineAndConvertToClassdata") {
description = "Combines all classes and converts to .classdata"

dependsOn("extractCustomInstrumentationToInst", "extractOtelInstrumentationToInst")

// include the relocated OpenTelemetry classes
from("$buildDir/tmp/relocated-otel-classes") {
rename("(^.*)\\.class$", "$1.classdata")
}

// Output to the resources directory for inclusion in the final JAR
into("$buildDir/resources/main")

// If there are conflicts, our instrumentation project files win
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
}

// Modify the existing processResources task to depend on our new task
tasks.named<ProcessResources>("processResources") {
dependsOn("combineAndConvertToClassdata")
exclude("**/META-INF/LICENSE")
}

tasks {

shadowJar {
relocate("com.blogspot.mydailyjava.weaklockfree", "io.opentelemetry.instrumentation.api.internal.shaded.weaklockfree")
relocate("com.blogspot.mydailyjava.weaklockfree", "ai.traceable.io.opentelemetry.instrumentation.api.internal.shaded.weaklockfree")

dependencies {
exclude(dependency("org.codehaus.mojo:animal-sniffer-annotations"))
exclude(dependency("javax.annotation:javax.annotation-api"))
}

relocate("org.slf4j", "io.opentelemetry.javaagent.slf4j")
relocate("java.util.logging.Logger", "io.opentelemetry.javaagent.bootstrap.PatchLogger")
relocate("com.fasterxml.jackson", "io.opentelemetry.javaagent.shaded.org.hypertrace.shaded.com.fasterxml.jackson")
relocate("org.yaml", "io.opentelemetry.javaagent.shaded.org.hypertrace.shaded.org.yaml")
relocate("org.slf4j", "ai.traceable.io.opentelemetry.javaagent.slf4j")
relocate("java.util.logging.Logger", "ai.traceable.io.opentelemetry.javaagent.bootstrap.PatchLogger")
relocate("com.fasterxml.jackson", "ai.traceable.io.opentelemetry.javaagent.shaded.org.hypertrace.shaded.com.fasterxml.jackson")
relocate("org.yaml", "ai.traceable.io.opentelemetry.javaagent.shaded.org.hypertrace.shaded.org.yaml")

// prevents conflict with library instrumentation
relocate("io.opentelemetry.instrumentation.api", "io.opentelemetry.javaagent.shaded.instrumentation.api")
relocate("io.opentelemetry.instrumentation.api", "ai.traceable.io.opentelemetry.javaagent.shaded.instrumentation.api")

// relocate OpenTelemetry API
relocate("io.opentelemetry.api", "io.opentelemetry.javaagent.shaded.io.opentelemetry.api")
relocate("io.opentelemetry.semconv", "io.opentelemetry.javaagent.shaded.io.opentelemetry.semconv")
relocate("io.opentelemetry.spi", "io.opentelemetry.javaagent.shaded.io.opentelemetry.spi")
relocate("io.opentelemetry.context", "io.opentelemetry.javaagent.shaded.io.opentelemetry.context")
relocate("io.opentelemetry.extension.kotlin", "io.opentelemetry.javaagent.shaded.io.opentelemetry.extension.kotlin")
relocate("io.opentelemetry.extension.aws", "io.opentelemetry.javaagent.shaded.io.opentelemetry.extension.aws")
relocate("io.opentelemetry.api", "ai.traceable.io.opentelemetry.javaagent.shaded.io.opentelemetry.api")
relocate("io.opentelemetry.semconv", "ai.traceable.io.opentelemetry.javaagent.shaded.io.opentelemetry.semconv")
relocate("io.opentelemetry.spi", "ai.traceable.io.opentelemetry.javaagent.shaded.io.opentelemetry.spi")
relocate("io.opentelemetry.context", "ai.traceable.io.opentelemetry.javaagent.shaded.io.opentelemetry.context")
relocate("io.opentelemetry.extension.kotlin", "ai.traceable.io.opentelemetry.javaagent.shaded.io.opentelemetry.extension.kotlin")
relocate("io.opentelemetry.extension.aws", "ai.traceable.io.opentelemetry.javaagent.shaded.io.opentelemetry.extension.aws")
// Shade everything else of io.opentelemetry into ai.traceable.io.opentelemetry
relocate("io.opentelemetry", "ai.traceable.io.opentelemetry")

mergeServiceFiles {
include("inst/META-INF/services/*")
Expand All @@ -61,15 +173,15 @@ tasks {
// Fix CVE-2024-7254, opentelemetry-javaagent brings in io.prometheus.metrics which uses deps of high vulnerability protobuf-java version
// This was fixed in 2.x.x versions of opentelemetry-javaagent(which needs us to upgrade from 1.33.0)
// TODO: Remove this exclusion after otel-javaagent upgrade which has CVE-2024-7254 fix
exclude("inst/io/prometheus/metrics/shaded/com_google_protobuf_3_21_7/**")
exclude("inst/ai/traceable/io/prometheus/metrics/shaded/com_google_protobuf_3_21_7/**")
exclude("**/module-info.class")
manifest {
attributes.put("Implementation-Title", "javaagent")
attributes.put("Implementation-Version", project.version)
attributes.put("OpenTelemetry-Instrumentation-Version", "${versions["opentelemetry_java_agent"]}")
attributes.put("Implementation-Vendor", "Hypertrace.org")
attributes.put("Implementation-Url", "https://github.com/hypertrace/javaagent")
attributes.put("Main-Class", "io.opentelemetry.javaagent.OpenTelemetryAgent")
attributes.put("Main-Class", "ai.traceable.io.opentelemetry.javaagent.OpenTelemetryAgent")
attributes.put("Agent-Class", "org.hypertrace.agent.instrument.HypertraceAgent")
attributes.put("Premain-Class", "org.hypertrace.agent.instrument.HypertraceAgent")
attributes.put("Can-Redefine-Classes", true)
Expand Down
29 changes: 15 additions & 14 deletions tests-extension/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -36,28 +36,29 @@ tasks{

// relocate these in sync with
// https://github.com/hypertrace/javaagent/blob/main/instrumentation/build.gradle.kts#L56-L82
relocate("com.fasterxml.jackson", "io.opentelemetry.javaagent.shaded.org.hypertrace.shaded.com.fasterxml.jackson")
relocate("com.google", "io.opentelemetry.javaagent.shaded.org.hypertrace.shaded.com.google")
relocate("google.protobuf", "io.opentelemetry.javaagent.shaded.org.hypertrace.shaded.google.protobuf")
relocate("org.checkerframework", "io.opentelemetry.javaagent.shaded.org.hypertrace.shaded.com.checkerframework") // transitive dependency form ht-filter-api
relocate("org.yaml", "io.opentelemetry.javaagent.shaded.org.hypertrace.shaded.org.yaml") // transitive dependency form ht-filter-api
relocate("com.blogspot.mydailyjava.weaklockfree", "io.opentelemetry.instrumentation.api.internal.shaded.weaklockfree") // transitive dependency from ht-filter-api
relocate("org.slf4j", "io.opentelemetry.javaagent.slf4j")
relocate("java.util.logging.Logger", "io.opentelemetry.javaagent.bootstrap.PatchLogger")
relocate("com.fasterxml.jackson", "ai.traceable.io.opentelemetry.javaagent.shaded.org.hypertrace.shaded.com.fasterxml.jackson")
relocate("com.google", "ai.traceable.io.opentelemetry.javaagent.shaded.org.hypertrace.shaded.com.google")
relocate("google.protobuf", "ai.traceable.io.opentelemetry.javaagent.shaded.org.hypertrace.shaded.google.protobuf")
relocate("org.checkerframework", "ai.traceable.io.opentelemetry.javaagent.shaded.org.hypertrace.shaded.com.checkerframework") // transitive dependency form ht-filter-api
relocate("org.yaml", "ai.traceable.io.opentelemetry.javaagent.shaded.org.hypertrace.shaded.org.yaml") // transitive dependency form ht-filter-api
relocate("com.blogspot.mydailyjava.weaklockfree", "ai.traceable.io.opentelemetry.instrumentation.api.internal.shaded.weaklockfree") // transitive dependency from ht-filter-api
relocate("org.slf4j", "ai.traceable.io.opentelemetry.javaagent.slf4j")
relocate("java.util.logging.Logger", "ai.traceable.io.opentelemetry.javaagent.bootstrap.PatchLogger")

relocate("okhttp3", "org.hypertrace.javaagent.filter.com.squareup.okhttp3")
relocate("okio", "org.hypertrace.javaagent.filter.com.squareup.okio") // transitive dependency from okhttp
relocate("org.codehaus", "org.hypertrace.javaagent.filter.org.codehaus") // transitive dependency from ht-filter-api

// relocate OpenTelemetry API in sync with
// https://github.com/hypertrace/javaagent/blob/main/javaagent/build.gradle.kts#L58-L63
relocate("io.opentelemetry.api", "io.opentelemetry.javaagent.shaded.io.opentelemetry.api")
relocate("io.opentelemetry.semconv", "io.opentelemetry.javaagent.shaded.io.opentelemetry.semconv")
relocate("io.opentelemetry.spi", "io.opentelemetry.javaagent.shaded.io.opentelemetry.spi")
relocate("io.opentelemetry.context", "io.opentelemetry.javaagent.shaded.io.opentelemetry.context")
relocate("io.opentelemetry.extension.kotlin", "io.opentelemetry.javaagent.shaded.io.opentelemetry.extension.kotlin")
relocate("io.opentelemetry.extension.aws", "io.opentelemetry.javaagent.shaded.io.opentelemetry.extension.aws")
relocate("io.opentelemetry.api", "ai.traceable.io.opentelemetry.javaagent.shaded.io.opentelemetry.api")
relocate("io.opentelemetry.semconv", "ai.traceable.io.opentelemetry.javaagent.shaded.io.opentelemetry.semconv")
relocate("io.opentelemetry.spi", "ai.traceable.io.opentelemetry.javaagent.shaded.io.opentelemetry.spi")
relocate("io.opentelemetry.context", "ai.traceable.io.opentelemetry.javaagent.shaded.io.opentelemetry.context")
relocate("io.opentelemetry.extension.kotlin", "ai.traceable.io.opentelemetry.javaagent.shaded.io.opentelemetry.extension.kotlin")
relocate("io.opentelemetry.extension.aws", "ai.traceable.io.opentelemetry.javaagent.shaded.io.opentelemetry.extension.aws")

relocate("io.opentelemetry", "ai.traceable.io.opentelemetry")

manifest {
attributes.put("Implementation-Title", "test-filter-impl")
Expand Down
Loading