[Heartbeat] Add version to fe heartbeat and system page (#4521)

This commit adds git commit message of fe to the system page, just like be.
To achieve this, fe heartbeat message has now been carrying git commit message.
diff --git a/fe/src/main/java/org/apache/doris/common/proc/FrontendsProcNode.java b/fe/src/main/java/org/apache/doris/common/proc/FrontendsProcNode.java
index 6d12be3..ec520b2 100644
--- a/fe/src/main/java/org/apache/doris/common/proc/FrontendsProcNode.java
+++ b/fe/src/main/java/org/apache/doris/common/proc/FrontendsProcNode.java
@@ -44,22 +44,22 @@
     public static final ImmutableList<String> TITLE_NAMES = new ImmutableList.Builder<String>()
             .add("Name").add("IP").add("HostName").add("EditLogPort").add("HttpPort").add("QueryPort").add("RpcPort")
             .add("Role").add("IsMaster").add("ClusterId").add("Join").add("Alive")
-            .add("ReplayedJournalId").add("LastHeartbeat").add("IsHelper").add("ErrMsg")
+            .add("ReplayedJournalId").add("LastHeartbeat").add("IsHelper").add("ErrMsg").add("Version")
             .build();
-    
+
     public static final int HOSTNAME_INDEX = 2;
 
     private Catalog catalog;
-    
+
     public FrontendsProcNode(Catalog catalog) {
         this.catalog = catalog;
     }
-    
+
     @Override
     public ProcResult fetchResult() {
         BaseProcResult result = new BaseProcResult();
         result.setNames(TITLE_NAMES);
-        
+
         List<List<String>> infos = Lists.newArrayList();
 
         getFrontendsInfo(catalog, infos);
@@ -82,13 +82,13 @@
             // this may happen when majority of FOLLOWERS are down and no MASTER right now.
             LOG.warn("failed to get leader: {}", e.getMessage());
         }
-        
+
         // get all node which are joined in bdb group
         List<InetSocketAddress> allFe = catalog.getHaProtocol().getElectableNodes(true /* include leader */);
         allFe.addAll(catalog.getHaProtocol().getObserverNodes());
         List<Pair<String, Integer>> allFeHosts = convertToHostPortPair(allFe);
         List<Pair<String, Integer>> helperNodes = catalog.getHelperNodes();
-        
+
         for (Frontend fe : catalog.getFrontends(null /* all */)) {
 
             List<String> info = new ArrayList<String>();
@@ -112,7 +112,7 @@
 
             info.add(Integer.toString(catalog.getClusterId()));
             info.add(String.valueOf(isJoin(allFeHosts, fe)));
-            
+
             if (fe.getHost().equals(catalog.getSelfNode().first)) {
                 info.add("true");
                 info.add(Long.toString(catalog.getEditLog().getMaxJournalId()));
@@ -121,15 +121,17 @@
                 info.add(Long.toString(fe.getReplayedJournalId()));
             }
             info.add(TimeUtils.longToTimeString(fe.getLastUpdateTime()));
-            
+
             info.add(String.valueOf(isHelperNode(helperNodes, fe)));
 
             info.add(fe.getHeartbeatErrMsg());
 
+            info.add(fe.getVersion());
+
             infos.add(info);
         }
     }
-    
+
     private static boolean isHelperNode(List<Pair<String, Integer>> helperNodes, Frontend fe) {
         return helperNodes.stream().anyMatch(p -> p.first.equals(fe.getHost()) && p.second == fe.getEditLogPort());
     }
@@ -142,7 +144,7 @@
         }
         return false;
     }
-    
+
     private static List<Pair<String, Integer>> convertToHostPortPair(List<InetSocketAddress> addrs) {
         List<Pair<String, Integer>> hostPortPair = Lists.newArrayList();
         for (InetSocketAddress addr : addrs) {
diff --git a/fe/src/main/java/org/apache/doris/http/rest/BootstrapFinishAction.java b/fe/src/main/java/org/apache/doris/http/rest/BootstrapFinishAction.java
index 1ebfa61..8e99e7a 100644
--- a/fe/src/main/java/org/apache/doris/http/rest/BootstrapFinishAction.java
+++ b/fe/src/main/java/org/apache/doris/http/rest/BootstrapFinishAction.java
@@ -20,6 +20,7 @@
 import org.apache.doris.catalog.Catalog;
 import org.apache.doris.common.Config;
 import org.apache.doris.common.DdlException;
+import org.apache.doris.common.Version;
 import org.apache.doris.http.ActionController;
 import org.apache.doris.http.BaseRequest;
 import org.apache.doris.http.BaseResponse;
@@ -43,6 +44,7 @@
     public static final String REPLAYED_JOURNAL_ID = "replayedJournalId";
     public static final String QUERY_PORT = "queryPort";
     public static final String RPC_PORT = "rpcPort";
+    public static final String VERSION = "version";
 
     public BootstrapFinishAction(ActionController controller) {
         super(controller);
@@ -92,6 +94,7 @@
                     result.setMaxReplayedJournal(replayedJournalId);
                     result.setQueryPort(Config.query_port);
                     result.setRpcPort(Config.rpc_port);
+                    result.setVersion(Version.DORIS_BUILD_VERSION + "-" + Version.DORIS_BUILD_SHORT_HASH);
                 }
             }
         } else {
@@ -108,6 +111,7 @@
         private long replayedJournalId = 0;
         private int queryPort = 0;
         private int rpcPort = 0;
+        private String version = "";
 
         public BootstrapResult() {
             super();
@@ -141,6 +145,14 @@
             return rpcPort;
         }
 
+        public String getVersion() {
+            return version;
+        }
+
+        public void setVersion(String version) {
+            this.version = version;
+        }
+
         @Override
         public String toJson() {
             Gson gson = new Gson();
diff --git a/fe/src/main/java/org/apache/doris/system/Frontend.java b/fe/src/main/java/org/apache/doris/system/Frontend.java
index feb123c..daae304 100644
--- a/fe/src/main/java/org/apache/doris/system/Frontend.java
+++ b/fe/src/main/java/org/apache/doris/system/Frontend.java
@@ -33,7 +33,8 @@
     private String nodeName;
     private String host;
     private int editLogPort;
-    
+    private String version;
+
     private int queryPort;
     private int rpcPort;
 
@@ -45,7 +46,7 @@
 
     public Frontend() {
     }
-    
+
     public Frontend(FrontendNodeType role, String nodeName, String host, int editLogPort) {
         this.role = role;
         this.nodeName = nodeName;
@@ -56,11 +57,15 @@
     public FrontendNodeType getRole() {
         return this.role;
     }
-    
+
     public String getHost() {
         return this.host;
     }
-    
+
+    public String getVersion() {
+        return version;
+    }
+
     public String getNodeName() {
         return nodeName;
     }
@@ -76,7 +81,7 @@
     public boolean isAlive() {
         return isAlive;
     }
-    
+
     public int getEditLogPort() {
         return this.editLogPort;
     }
@@ -103,6 +108,7 @@
         boolean isChanged = false;
         if (hbResponse.getStatus() == HbStatus.OK) {
             isAlive = true;
+            version = hbResponse.getVersion();
             queryPort = hbResponse.getQueryPort();
             rpcPort = hbResponse.getRpcPort();
             replayedJournalId = hbResponse.getReplayedJournalId();
diff --git a/fe/src/main/java/org/apache/doris/system/FrontendHbResponse.java b/fe/src/main/java/org/apache/doris/system/FrontendHbResponse.java
index 2b4cf5f..3774b6c 100644
--- a/fe/src/main/java/org/apache/doris/system/FrontendHbResponse.java
+++ b/fe/src/main/java/org/apache/doris/system/FrontendHbResponse.java
@@ -34,12 +34,13 @@
     private int queryPort;
     private int rpcPort;
     private long replayedJournalId;
+    private String version;
 
     public FrontendHbResponse() {
         super(HeartbeatResponse.Type.FRONTEND);
     }
 
-    public FrontendHbResponse(String name, int queryPort, int rpcPort, long replayedJournalId, long hbTime) {
+    public FrontendHbResponse(String name, int queryPort, int rpcPort, long replayedJournalId, long hbTime, String version) {
         super(HeartbeatResponse.Type.FRONTEND);
         this.status = HbStatus.OK;
         this.name = name;
@@ -47,6 +48,7 @@
         this.rpcPort = rpcPort;
         this.replayedJournalId = replayedJournalId;
         this.hbTime = hbTime;
+        this.version = version;
     }
 
     public FrontendHbResponse(String name, String errMsg) {
@@ -72,6 +74,10 @@
         return replayedJournalId;
     }
 
+    public String getVersion() {
+        return version;
+    }
+
     public static FrontendHbResponse read(DataInput in) throws IOException {
         FrontendHbResponse result = new FrontendHbResponse();
         result.readFields(in);
@@ -100,6 +106,7 @@
         StringBuilder sb = new StringBuilder();
         sb.append(super.toString());
         sb.append(", name: ").append(name);
+        sb.append(", version: ").append(version);
         sb.append(", queryPort: ").append(queryPort);
         sb.append(", rpcPort: ").append(rpcPort);
         sb.append(", replayedJournalId: ").append(replayedJournalId);
diff --git a/fe/src/main/java/org/apache/doris/system/HeartbeatMgr.java b/fe/src/main/java/org/apache/doris/system/HeartbeatMgr.java
index ad16535..d74613e 100644
--- a/fe/src/main/java/org/apache/doris/system/HeartbeatMgr.java
+++ b/fe/src/main/java/org/apache/doris/system/HeartbeatMgr.java
@@ -22,6 +22,7 @@
 import org.apache.doris.common.ClientPool;
 import org.apache.doris.common.Config;
 import org.apache.doris.common.FeConstants;
+import org.apache.doris.common.Version;
 import org.apache.doris.common.util.MasterDaemon;
 import org.apache.doris.common.util.Util;
 import org.apache.doris.http.rest.BootstrapFinishAction;
@@ -95,7 +96,7 @@
     @Override
     protected void runAfterCatalogReady() {
         List<Future<HeartbeatResponse>> hbResponses = Lists.newArrayList();
-        
+
         // send backend heartbeat
         for (Backend backend : nodeMgr.getIdToBackend().values()) {
             BackendHeartbeatHandler handler = new BackendHeartbeatHandler(backend);
@@ -152,7 +153,7 @@
         // we also add a 'mocked' master Frontends heartbeat response to synchronize master info to other Frontends.
         hbPackage.addHbResponse(new FrontendHbResponse(masterFeNodeName,
                 Config.query_port, Config.rpc_port, Catalog.getCurrentCatalog().getEditLog().getMaxJournalId(),
-                System.currentTimeMillis()));
+                System.currentTimeMillis(), Version.DORIS_BUILD_VERSION + "-" + Version.DORIS_BUILD_SHORT_HASH));
 
         // write edit log
         Catalog.getCurrentCatalog().getEditLog().logHeartbeat(hbPackage);
@@ -186,7 +187,7 @@
                 FsBroker broker = Catalog.getCurrentCatalog().getBrokerMgr().getBroker(
                         hbResponse.getName(), hbResponse.getHost(), hbResponse.getPort());
                 if (broker != null) {
-                    boolean isChanged =  broker.handleHbResponse(hbResponse);
+                    boolean isChanged = broker.handleHbResponse(hbResponse);
                     if (hbResponse.getStatus() != HbStatus.OK) {
                         // invalid all connections cached in ClientPool
                         ClientPool.brokerPool.clearPool(new TNetworkAddress(broker.ip, broker.port));
@@ -276,7 +277,8 @@
                 // heartbeat to self
                 if (Catalog.getInstance().isReady()) {
                     return new FrontendHbResponse(fe.getNodeName(), Config.query_port, Config.rpc_port,
-                            Catalog.getInstance().getReplayedJournalId(), System.currentTimeMillis());
+                            Catalog.getInstance().getReplayedJournalId(), System.currentTimeMillis(),
+                            Version.DORIS_BUILD_VERSION + "-" + Version.DORIS_BUILD_SHORT_HASH);
                 } else {
                     return new FrontendHbResponse(fe.getNodeName(), "not ready");
                 }
@@ -299,8 +301,9 @@
                     long replayedJournalId = root.getLong(BootstrapFinishAction.REPLAYED_JOURNAL_ID);
                     int queryPort = root.getInt(BootstrapFinishAction.QUERY_PORT);
                     int rpcPort = root.getInt(BootstrapFinishAction.RPC_PORT);
+                    String version = root.getString(BootstrapFinishAction.VERSION);
                     return new FrontendHbResponse(fe.getNodeName(), queryPort, rpcPort, replayedJournalId,
-                            System.currentTimeMillis());
+                            System.currentTimeMillis(), version == null ? "unknown" : version);
                 }
             } catch (Exception e) {
                 return new FrontendHbResponse(fe.getNodeName(),
diff --git a/gensrc/script/gen_build_version.sh b/gensrc/script/gen_build_version.sh
index 0b3550b..8075d87 100755
--- a/gensrc/script/gen_build_version.sh
+++ b/gensrc/script/gen_build_version.sh
@@ -121,6 +121,7 @@
 
   public static final String DORIS_BUILD_VERSION = "${build_version}";
   public static final String DORIS_BUILD_HASH = "${build_hash}";
+  public static final String DORIS_BUILD_SHORT_HASH = "${build_short_hash}";
   public static final String DORIS_BUILD_TIME = "${build_time}";
   public static final String DORIS_BUILD_INFO = "${build_info}";
   public static final String DORIS_JAVA_COMPILE_VERSION = "${java_version_str}";
@@ -128,6 +129,7 @@
   public static void main(String[] args) {
     System.out.println("doris_build_version: " + DORIS_BUILD_VERSION);
     System.out.println("doris_build_hash: " + DORIS_BUILD_HASH);
+    System.out.println("doris_build_short_hash: " + DORIS_BUILD_SHORT_HASH);
     System.out.println("doris_build_time: " + DORIS_BUILD_TIME);
     System.out.println("doris_build_info: " + DORIS_BUILD_INFO);
     System.out.println("doris_java_compile_version: " + DORIS_JAVA_COMPILE_VERSION);