Skip to content
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

Create OtelVersion class at build time. #5365

Merged
merged 10 commits into from
Apr 15, 2023
Merged
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package io.opentelemetry.gradle

import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.plugins.JavaPlugin
import org.gradle.api.plugins.JavaPluginExtension
import org.gradle.kotlin.dsl.the
import java.io.File

/**
* This gradle plugin will define a new task called generateOtelVersionClass.
* This task generates a Java source file that contains the project version
* as a string constant. The "compileJava" task is updated to depend on
* generateOtelVersionClass, and the project source set is updated to
* include the new file.
*/
class OtelVersionClassPlugin : Plugin<Project> {
override fun apply(project: Project) {
project.plugins.apply(JavaPlugin::class.java)

project.task("generateOtelVersionClass") {
doLast {
writeFile(project)
}
}
// Add dependency on this task
project.tasks.getByName("compileJava") {
dependsOn("generateOtelVersionClass")
}
// Add new source dir to the "main" source set
val outDir = buildOutDir(project)
val java = project.the<JavaPluginExtension>()
java.sourceSets.getByName("main").java {
srcDir(outDir)
}
}

private fun writeFile(project: Project) {
val group = "${project.group}".replace('.', '/')
val projectName = project.name.replace('-', '/')
val outDir = buildOutDir(project)
val filename = "$group/$projectName/internal/OtelVersion.java"
val outFile = File(outDir, filename)
val packageName = "${project.group}.${project.name.replace('-', '.')}.internal"
val classBody = getClassBody("${project.version}", packageName)

outFile.parentFile.mkdirs()
outFile.writeText(classBody)
}

private fun getClassBody(version: String, packageName: String): String {
return """
package $packageName;

import javax.annotation.Generated;

/** Autogenerated class do not edit. */
@Generated("io.opentelemetry.gradle.OtelVersionClassPlugin")
public final class OtelVersion {
public static final String VERSION = "$version";

private OtelVersion() {}
}
""".trimIndent()
}

private fun buildOutDir(project: Project): File {
return File(project.buildDir, "generated/sources/version/java/main")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ class ProtoFieldsWireHandler : SchemaHandler() {

for (field in type.fieldsAndOneOfFields) {
builder.addField(
FieldSpec.builder(PROTO_FIELD_INFO, field.name.toUpperCase(), PUBLIC, STATIC, FINAL)
FieldSpec.builder(PROTO_FIELD_INFO, field.name.uppercase(), PUBLIC, STATIC, FINAL)
.initializer("\$T.create(\$L, \$L, \"\$L\")",
PROTO_FIELD_INFO,
field.tag,
Expand Down
4 changes: 3 additions & 1 deletion sdk/common/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import io.opentelemetry.gradle.OtelVersionClassPlugin

plugins {
id("otel.java-conventions")
id("otel.publish-conventions")

id("otel.animalsniffer-conventions")
}
apply<OtelVersionClassPlugin>()
Copy link
Member

Choose a reason for hiding this comment

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

If we do this for :sdk:common, should we do it everywhere?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I only wanted to do this in the one place where it's used. If there are other places that ever need to reference the class, then those modules can apply the plugin. I don't think we need it floating around every module. Feels bloaty.

Copy link
Member

Choose a reason for hiding this comment

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

That seems reasonable. Here are some other places we read the version:

Copy link
Contributor Author

Choose a reason for hiding this comment

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

And those will still continue work, I didn't remove the properties behavior. Are you suggesting that we should tackle those all in this same PR?

Copy link
Member

Choose a reason for hiding this comment

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

Are you suggesting that we should tackle those all in this same PR?

If we have this pattern, it offers a pretty clean way of accessing the version. Adding a plugin to the gradle build is cleaner than copy / pasting the code to read from the resource.

Doesn't have to be in this PR, but if we like this pattern I think we should standardize on it.


description = "OpenTelemetry SDK Common"
otelJava.moduleName.set("io.opentelemetry.sdk.common")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
import io.opentelemetry.api.common.AttributesBuilder;
import io.opentelemetry.api.internal.StringUtils;
import io.opentelemetry.api.internal.Utils;
import io.opentelemetry.sdk.common.internal.OtelVersion;
import java.util.Objects;
import java.util.Properties;
import java.util.logging.Logger;
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
Expand Down Expand Up @@ -54,7 +54,7 @@ public abstract class Resource {
Attributes.builder()
.put(TELEMETRY_SDK_NAME, "opentelemetry")
.put(TELEMETRY_SDK_LANGUAGE, "java")
.put(TELEMETRY_SDK_VERSION, readVersion())
.put(TELEMETRY_SDK_VERSION, OtelVersion.VERSION)
.build());
}

Expand Down Expand Up @@ -109,18 +109,6 @@ public static Resource create(Attributes attributes, @Nullable String schemaUrl)
return new AutoValue_Resource(schemaUrl, attributes);
}

private static String readVersion() {
Properties properties = new Properties();
try {
properties.load(
Resource.class.getResourceAsStream("/io/opentelemetry/sdk/common/version.properties"));
} catch (Exception e) {
// we left the attribute empty
return "unknown";
}
return properties.getProperty("sdk.version", "unknown");
}

/**
* Returns the URL of the OpenTelemetry schema used by this resource. May be null.
*
Expand Down