背景:
线上部署的jar包(不管是直接运行jar包,还是通过容器运行的jar)有时出现问题时需要查看源代码,需要知道该jar包是从哪个分支、哪个commit、哪个时间打包的。 有了这些信息能更好辅助我们分析判断问题。 这里以gradle工程为例子,给出一种简单添加构建信息的例子。 go工程可以参看k8s的源码中的构建脚本
具体步骤
这里是一个springboot工程,使用gradle. 只有运行打包好的jar请求api才有信息,直接在IDE中启动时,请求时没有构建信息返回,因为这些信息读取的jar包中的资源文件。所以必须是jar启动的才行
1, 在build.gradle中添加如下内容
备注:内容简单,就不添加注释了,就是执行gradle bootJar进行打包时,将这些git-branch、git-commit、git-commit-time.
// 将Git信息和构建时间等元数据注入MANIFEST.MF文件
manifest {
attributes(
'Implementation-Title': project.name,
'Implementation-Version': project.version,
'Built-By': System.getProperty('user.name'),
'Built-Time': new Date(),
'Git-Branch': getGitBranch(),
'Git-Commit': getGitCommit(),
'Git-Commit-Time': getGitCommitTime()
)
}
}
// 获取当前分支名称
static def getGitBranch() {
try {
def branch = 'git rev-parse --abbrev-ref HEAD'.execute().text.trim()
return branch ?: 'unknown'
} catch (Exception e) {
System.err.println("fail to get branch, errMsg:" + e.getMessage())
return 'unknown'
}
}
// 获取当前提交的记录的commitId
static def getGitCommit() {
try {
def commit = 'git rev-parse HEAD'.execute().text.trim()
return commit ?: 'unknown'
} catch (Exception e) {
System.err.println("fail to get commit id, errMsg:" + e.getMessage())
return 'unknown'
}
}
// 获取当前Git提交的时间
static def getGitCommitTime() {
try {
def commitTime = 'git show -s --format=%ct HEAD'.execute().text.trim()
return commitTime ? new Date(Long.parseLong(commitTime) * 1000L) : 'unknown'
} catch (Exception e) {
System.err.println("fail to get commit time, errMsg:" + e.getMessage())
return 'unknown'
}
}
2, 增加一个MyBuildInfo类
@Getter
@Accessors(fluent = true)
@FieldDefaults(level = AccessLevel.PRIVATE)
@JsonIgnoreProperties(ignoreUnknown = true)
@NoArgsConstructor(force = true, access = AccessLevel.PRIVATE)
@AllArgsConstructor
public class MyBuildInfo
{
String gitBranch;
String gitCommitId;
String gitCommitTime;
String builtTime;
}
3, 在service层提供构建信息
在对对应的service类方法中添加如下代码
static final String GIT_BRANCH = "Git-Branch";
static final String GIT_COMMIT_ID = "Git-Commit";
static final String GIT_COMMIT_TIME = "Git-Commit-Time";
static final String BUILD_TIME = "Built-Time";
@Override
public Response<MyBuildInfo> getBuildInfo()
{
String gitBranch = BuildUtils.getManifestAttribute(GIT_BRANCH);
String gitCommitId = BuildUtils.getManifestAttribute(GIT_COMMIT_ID);
String gitCommitTime = BuildUtils.getManifestAttribute(GIT_COMMIT_TIME);
String builtTime = BuildUtils.getManifestAttribute(BUILD_TIME);
gitBranch = StringUtils.isNoneBlank(gitBranch) ? gitBranch : UNKNOWN;
gitCommitId = StringUtils.isNoneBlank(gitCommitId) ? gitCommitId : UNKNOWN;
gitCommitTime = StringUtils.isNoneBlank(gitCommitTime) ? gitCommitTime : UNKNOWN;
builtTime = StringUtils.isNoneBlank(builtTime) ? builtTime : UNKNOWN;
MyBuildInfo buildInfo = new MyBuildInfo(gitBranch, gitCommitId, gitCommitTime, builtTime);
// 这里的new Response(buildInfo, "buildInfo done");以每个具体项目为准,这里这是实例返回符合工程规范的resp格式信息
return new Response(buildInfo, "buildInfo done");
}
其中BuildUtils是读取jar中资源的文件的具体类
import lombok.extern.slf4j.Slf4j;
import java.io.IOException;
import java.util.jar.Attributes;
import java.util.jar.Manifest;
@Slf4j
public class BuildUtils
{
public static String getManifestAttribute(String attributeName)
{
try {
Manifest manifest = new Manifest(BuildUtils.class.getResourceAsStream("/META-INF/MANIFEST.MF"));
Attributes attributes = manifest.getMainAttributes();
return attributes.getValue(attributeName);
} catch (IOException e) {
log.warn("fail to get info from manifest file, errMsg:{}", e.getMessage(), e);
return "unknown";
}
}
}
jar包中资源文件实际是构建的这个文件
4, 在controller中暴露构建信息
在某个controller中添加可以查询构建信息的api。 其中@Operation是swagger的注解信息,如果没有使用swagger, 需要删除。
@Operation(
summary = "查询具体构建信息"
)
@GetMapping("/buildInfo")
public Response<MyBuildInfo> getBuildInfo()
{
Response res = xxxService.getBuildInfo();
return res;
}