Skip to content

feat: Emit git commit metric and add a commit version to sys.servers for validations#19123

Merged
abhishekrb19 merged 13 commits intoapache:masterfrom
razinbouzar:git-commit-sha-metric
Mar 30, 2026
Merged

feat: Emit git commit metric and add a commit version to sys.servers for validations#19123
abhishekrb19 merged 13 commits intoapache:masterfrom
razinbouzar:git-commit-sha-metric

Conversation

@razinbouzar
Copy link
Copy Markdown
Contributor

@razinbouzar razinbouzar commented Mar 10, 2026

Adding a git commit sha as an emitted metric for version tracking. Additionally added a column to sys.servers which does the same, using #18542 as motivation.

This feature will be useful in troubleshooting/debugging, dashboards, and as a deployment status signal.

Description

Fixed the bug ...

Renamed the class ...

Added a forbidden-apis entry ...

Release note

New: You can now verify the exact build revision of each Druid node.

Two new fields expose the git commit SHA of the JAR running on each node:

  • buildRevision metric dimension — emitted on every metric so you can confirm all nodes in a cluster are running the intended revision during rolling deployments. Empty string when
    running outside a packaged JAR (e.g., during mvn test).
  • build_revision column in sys.servers — query it directly with SELECT server, version, build_revision FROM sys.servers. For more information, see SERVERS table.

Key changed/added classes in this PR
  • EmitterModule — reads Build-Revision from the JAR manifest using the class's own JAR URL (avoiding the "first manifest on classpath" pitfall) and binds it as the buildRevision extra
    service dimension on every emitted metric
    • EmitterModuleTest — tests that buildRevision is present in emitted events, falls back to empty string when not in a JAR, and that getBuildRevision() is overridable
    • DruidNode — adds a buildRevision field (populated from the manifest at construction, serialized as @JsonProperty so it propagates through service discovery)
    • SystemSchema — adds build_revision column to the sys.servers table, populated from DruidNode.getBuildRevision()
    • SystemSchemaTest — updates expected rows in the servers table test to include build_revision
    • pom.xml — fixes dotGitDirectory to use ${session.executionRootDirectory}/.git so git.commit.id is correctly populated for all submodules during the build
    • docs/operations/metrics.md and docs/querying/sql-metadata-tables.md — document the new buildRevision metric dimension and build_revision sys.servers column respectively

This PR has:

  • been self-reviewed.
  • added documentation for new or modified features or behaviors.
  • a release note entry in the PR description.
  • added Javadocs for most classes and all non-trivial methods. Linked related entities via Javadoc links.
  • added or updated version, license, or notice information in licenses.yaml
  • added comments explaining the "why" and the intent of the code wherever would not be obvious for an unfamiliar reader.
  • added unit tests or modified existing tests to cover new code paths, ensuring the threshold for code coverage is met.
  • added integration tests.
  • been tested in a test Druid cluster.

Added a method to load git properties from the classpath and include the git commit SHA in emitted metrics.
Copy link
Copy Markdown
Contributor

@abhishekrb19 abhishekrb19 left a comment

Choose a reason for hiding this comment

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

Thanks @razinbouzar! It’s useful to have this to track service health across rolling deployments with the same version. Left some high-level thoughts.

  1. Please document the new dimension in metrics.md: https://druid.apache.org/docs/latest/operations/metrics/ (something like a high level info note would suffice)
  2. Once the new dimension is in, we can also add the same info to sys.servers table similar to #18542. This would provide a SQL-friendly way to verify that clusters are running the intended commit, version, etc.

Comment on lines +200 to +216
private static Map<String, String> loadGitProperties()
{
try (InputStream is = EmitterModule.class.getClassLoader().getResourceAsStream("git.properties")) {
if (is != null) {
Properties props = new Properties();
props.load(is);

// Convert Properties to Map<String, String>
Map<String, String> gitProperties = new HashMap<>();
for (String key : props.stringPropertyNames()) {
String value = props.getProperty(key);
if (value != null && !value.trim().isEmpty()) {
gitProperties.put(key, value.trim());
}
}

return gitProperties;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

On the approach, I'm wondering whether using git.properties from the class loader vs using META-INF/MANIFEST.MF (produced by the JAR build) would be better.

Is the former coming from git-commit-id-maven-plugin: https://github.com/apache/druid/blob/master/pom.xml#L1878-L1903?

The latter should be available through https://github.com/apache/druid/blob/master/pom.xml#L1870:

Build-Revision: 1c2eb65...
Build-Version: 37.0.0-SNAPSHOT

Looks like version internally reads from the manifest as well: String version = getClass().getPackage().getImplementationVersion()

But those are standard properties, so we may want a small utility to read the Git SHA / build revision from the manifest, such as the Build-Revision property. I’ll also give it some thought.

Comment thread server/src/main/java/org/apache/druid/server/emitter/EmitterModule.java Outdated
@razinbouzar razinbouzar changed the title Git commit sha metric feat: Git commit sha metric Mar 21, 2026
@razinbouzar
Copy link
Copy Markdown
Contributor Author

Thanks @razinbouzar! It’s useful to have this to track service health across rolling deployments with the same version. Left some high-level thoughts.

  1. Please document the new dimension in metrics.md: https://druid.apache.org/docs/latest/operations/metrics/ (something like a high level info note would suffice)
  2. Once the new dimension is in, we can also add the same info to sys.servers table similar to Add version to sys server #18542. This would provide a SQL-friendly way to verify that clusters are running the intended commit, version, etc.

I included 2 in this PR as well since. Can break it out if preferred.

SHA gets flagged by spellcheck. Using git commit ID in its place.
changing to git commit hash.
spellcheck doesn't like jar. replacing it with binary to be consistent.

also complained about build_revision
@razinbouzar razinbouzar changed the title feat: Git commit sha metric feat: Emit git commit metric and add a commit version to sys.servers for validations Mar 21, 2026
Copy link
Copy Markdown
Contributor

@abhishekrb19 abhishekrb19 left a comment

Choose a reason for hiding this comment

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

Looks good to me overall. Left some suggestions. Thanks!

Comment on lines +287 to +303
private static String readBuildRevisionFromManifest()
{
try {
URL classUrl = DruidNode.class.getResource(DruidNode.class.getSimpleName() + ".class");
if (classUrl != null && "jar".equals(classUrl.getProtocol())) {
String classPath = classUrl.toString();
String manifestPath = classPath.substring(0, classPath.lastIndexOf('!') + 1) + "/META-INF/MANIFEST.MF";
try (InputStream is = new URL(manifestPath).openStream()) {
return new Manifest(is).getMainAttributes().getValue("Build-Revision");
}
}
}
catch (IOException e) {
// Fall through and return null
}
return null;
}
Copy link
Copy Markdown
Contributor

@abhishekrb19 abhishekrb19 Mar 24, 2026

Choose a reason for hiding this comment

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

We can create a class BuildInfo and move this utility to it so both EmitterModule and the DruidNode code here can share it. We can also add more build-related utilities to this class in the future.

}
}
catch (IOException e) {
// Fall through and return null
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Log the exception so it doesn't mask a legitimate issue

catch (IOException e) {
// Fall through and return null
}
return null;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Since both EmitterModule and DruidNode converts null to empty with nullToEmptyNonDruidDataString(), I think it'd be good to have this method directly return "" (for tests)

Comment thread docs/operations/metrics.md Outdated
* `service`: the service name that emitted the metric
* `host`: the host name that emitted the metric
* `version`: the Druid version of the service that emitted the metric
* `buildRevision`: the git commit of the build that produced the service binary. Useful for verifying that all nodes in a cluster are running the intended revision during rolling deployments. Empty string when running outside a packaged binary (e.g., during `mvn test`).
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

These are user-facing docs, so I think we can exclude the note about mvn test that's already captured in the javadocs for devs:

Suggested change
* `buildRevision`: the git commit of the build that produced the service binary. Useful for verifying that all nodes in a cluster are running the intended revision during rolling deployments. Empty string when running outside a packaged binary (e.g., during `mvn test`).
* `buildRevision`: the git commit of the build that produced the service binary. Useful for verifying that all nodes in a cluster are running the intended revision during rolling deployments.

Comment thread docs/querying/sql-metadata-tables.md Outdated
|is_leader|BIGINT|1 if the server is currently the 'leader' (for services which have the concept of leadership), otherwise 0 if the server is not the leader, or null if the server type does not have the concept of leadership|
|start_time|STRING|Timestamp in ISO8601 format when the server was announced in the cluster|
|version|VARCHAR|Druid version running on the server|
|build_revision|VARCHAR|The git commit of the build that produced the server binary. Empty string when running outside a packaged binary (e.g., during `mvn test`)|
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
|build_revision|VARCHAR|The git commit of the build that produced the server binary. Empty string when running outside a packaged binary (e.g., during `mvn test`)|
|build_revision|VARCHAR|The git commit of the build that produced the server binary.|

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Optionally we could also wire this to the console's services view by default in web-console/src/views/services-view/services-view.tsx and web-console/src/views/services-view/__snapshots__/services-view.spec.tsx.snap: https://github.com/apache/druid/pull/18542/changes#diff-07dc2b09eeb1fc84b83d5ec80b95e4cda9fb235200e26b37271cc73d8d62b883

Comment thread pom.xml Outdated
added build revision services view, created a buildinfo class for extending further
@abhishekrb19 abhishekrb19 merged commit 9a70797 into apache:master Mar 30, 2026
63 of 64 checks passed
@github-actions github-actions Bot added this to the 37.0.0 milestone Mar 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants