集成OpenTelemetry时,Gradle启动脚本$ENV未正确求值的解决方法
问题:Gradle生成的启动脚本中环境变量$ENV无法被正确求值
我使用gradle installDist任务准备要复制到Docker镜像的文件,为集成OpenTelemetry Agent,最初的Gradle配置如下:
application { mainClass.set("com.vincent.AppKt") applicationDefaultJvmArgs = listOf("-javaagent:../lib/opentelemetry-javaagent-$openTelemetryJavaAgentVersion.jar") }
后续需要根据环境(staging或prod)加载不同的属性文件,于是修改配置为:
application { mainClass.set("com.vincent.AppKt") applicationDefaultJvmArgs = listOf( "-javaagent:../lib/opentelemetry-javaagent-$openTelemetryJavaAgentVersion.jar", "-Dotel.javaagent.configuration-file=../$ENV-otel.properties" ) } tasks { register("replaceInInstallDist") { dependsOn("installDist") doLast { val buildDir = file("${buildDir}/install/${project.name}") val scriptFile = file("${buildDir}/bin/${project.name}") scriptFile.writeText(scriptFile.readText().replace("\\\$ENV", "\$ENV")) } } }
生成的启动脚本中,DEFAULT_JVM_OPTS看起来符合预期:
DEFAULT_JVM_OPTS='"-javaagent:../lib/opentelemetry-javaagent-2.0.0.jar" "-Dotel.javaagent.configuration-file=../$ENV-otel.properties"'
但在容器中启动应用时,日志报错找不到配置文件:
ERROR io.opentelemetry.javaagent.tooling.config.ConfigurationPropertiesSupplier - Configuration file "../$ENV-otel.properties" not found.
奇怪的是,直接用命令行启动却能正常运行:
java -jar myJar.jar -javaagent:../lib/opentelemetry-javaagent-2.0.0.jar -Dotel.javaagent.configuration-file=../$ENV-otel.properties
问题出在生成的启动脚本使用exec "$JAVACMD" "$@"启动应用,包含$ENV的参数被包裹在$@中,无法被Shell正确解析求值。
解决方案
方案1:调整启动脚本的引号结构,让变量可被解析
修改replaceInInstallDist任务,调整参数的引号包裹方式,让$ENV能被Shell识别并求值:
tasks { register("replaceInInstallDist") { dependsOn("installDist") doLast { val buildDir = file("${buildDir}/install/${project.name}") val scriptFile = file("${buildDir}/bin/${project.name}") val originalContent = scriptFile.readText() val modifiedContent = originalContent // 移除参数的内层引号,同时替换转义的$ENV .replace("\"-Dotel.javaagent.configuration-file=../\\\$ENV-otel.properties\"", "-Dotel.javaagent.configuration-file=../\$ENV-otel.properties") // 把DEFAULT_JVM_OPTS的单引号替换为双引号,支持变量解析 .replace("DEFAULT_JVM_OPTS='", "DEFAULT_JVM_OPTS=\"") .replace("'", "\"") scriptFile.writeText(modifiedContent) } } }
修改后,启动脚本中的DEFAULT_JVM_OPTS会变为:
DEFAULT_JVM_OPTS=" -javaagent:../lib/opentelemetry-javaagent-2.0.0.jar -Dotel.javaagent.configuration-file=../$ENV-otel.properties"
Shell执行时会自动解析$ENV为实际环境值。
方案2:在启动脚本中添加变量解析逻辑
通过在启动脚本中提前解析$ENV变量,再赋值给DEFAULT_JVM_OPTS:
tasks { register("replaceInInstallDist") { dependsOn("installDist") doLast { val buildDir = file("${buildDir}/install/${project.name}") val scriptFile = file("${buildDir}/bin/${project.name}") val originalContent = scriptFile.readText() val modifiedContent = originalContent.replace( "DEFAULT_JVM_OPTS='\"-javaagent:../lib/opentelemetry-javaagent-2.0.0.jar\" \"-Dotel.javaagent.configuration-file=../\\\$ENV-otel.properties\"'", """ DEFAULT_JVM_OPTS_BASE='"-javaagent:../lib/opentelemetry-javaagent-2.0.0.jar" "-Dotel.javaagent.configuration-file=../${'$'}ENV-otel.properties"' DEFAULT_JVM_OPTS=$(eval echo "$DEFAULT_JVM_OPTS_BASE") """.trimIndent() ) scriptFile.writeText(modifiedContent) } } }
脚本会先通过eval解析DEFAULT_JVM_OPTS_BASE中的$ENV,再将结果赋值给DEFAULT_JVM_OPTS,确保启动时使用正确的参数。
方案3:Docker启动时动态传递参数(推荐)
完全避开Gradle生成脚本的引号问题,不在Gradle配置中硬编码属性文件路径,而是在Docker启动命令中动态添加:
CMD ["sh", "-c", "java -javaagent:../lib/opentelemetry-javaagent-2.0.0.jar -Dotel.javaagent.configuration-file=../$ENV-otel.properties -jar myJar.jar"]
由Shell直接解析$ENV变量,逻辑更清晰,也避免了Gradle配置的复杂修改。
内容的提问来源于stack exchange,提问作者Vincent F
相关产品推荐
相关产品推荐

