This is an automated email from the ASF dual-hosted git repository.

wusheng pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/skywalking.git


The following commit(s) were added to refs/heads/master by this push:
     new da0205bc58 Add layer level query and more fields for Hierarchy, and 
docs. (#11756)
da0205bc58 is described below

commit da0205bc588bf6d70d5f2851300567ae6ca9b063
Author: Wan Kai <wankai...@foxmail.com>
AuthorDate: Fri Jan 12 16:17:15 2024 +0800

    Add layer level query and more fields for Hierarchy, and docs. (#11756)
---
 docs/en/concepts-and-designs/overview.md           |  2 +-
 .../service-hierarchy-configuration.md             | 63 ++++++++++++++++++++++
 docs/en/concepts-and-designs/service-hierarchy.md  | 39 ++++++++++++++
 docs/en/swip/SWIP-1.md                             | 40 ++++++++++----
 docs/menu.yml                                      |  4 ++
 .../core/config/HierarchyDefinitionService.java    | 40 ++++++++------
 .../server/core/hierarchy/HierarchyService.java    |  2 +-
 .../server/core/query/HierarchyQueryService.java   | 60 +++++++++++++++++++--
 .../core/query/type/HierarchyRelatedInstance.java  |  5 +-
 .../core/query/type/HierarchyRelatedService.java   |  1 +
 ...erarchyRelatedInstance.java => LayerLevel.java} | 17 +++---
 .../oap/query/graphql/resolver/HierarchyQuery.java |  6 +++
 .../src/main/resources/query-protocol              |  2 +-
 .../src/main/resources/hierarchy-definition.yml    | 17 +++++-
 14 files changed, 252 insertions(+), 46 deletions(-)

diff --git a/docs/en/concepts-and-designs/overview.md 
b/docs/en/concepts-and-designs/overview.md
index 0699a412db..568e2869a2 100644
--- a/docs/en/concepts-and-designs/overview.md
+++ b/docs/en/concepts-and-designs/overview.md
@@ -45,7 +45,7 @@ Instance and Endpoint are used everywhere today, so it is 
worth defining their s
 SkyWalking allows users to understand the topology relationship between 
Services and Endpoints, also detect API dependencies
 in the distributed environment if you use our native agents.,
 
-Besides topology map, SkyWalking provides Service Hierarchy Relationship, 
which defines the relationships of existing 
+Besides topology map, SkyWalking provides **Service Hierarchy Relationship**, 
which defines the relationships of existing 
 logically same services in various layers. For example, a service could be 
deployed in a Kubernetes cluster with Istio mesh, 
 services are detected by k8s monitoring and Istio mesh, this hierarchy 
relationship could connect the services in k8s layer and mesh layer.
 
diff --git a/docs/en/concepts-and-designs/service-hierarchy-configuration.md 
b/docs/en/concepts-and-designs/service-hierarchy-configuration.md
new file mode 100644
index 0000000000..9080d663e8
--- /dev/null
+++ b/docs/en/concepts-and-designs/service-hierarchy-configuration.md
@@ -0,0 +1,63 @@
+# Define Service Hierarchy
+SkyWalking v10 introduces a new concept `Service Hierarchy` which defines the 
relationships of existing logically same services in various layers.
+The concept and design could be found [here](service-hierarchy.md).
+
+## Service Hierarchy Configuration
+All the relationships defined in the `config/hierarchy-definition.yml` file. 
You can customize it according to your own needs.
+Here is an example:
+
+```yaml
+hierarchy:
+  MESH:
+    MESH_DP: name
+    K8S_SERVICE: short-name
+
+  MESH_DP:
+    K8S_SERVICE: short-name
+
+  GENERAL:
+    K8S_SERVICE: lower-short-name-remove-ns
+
+  MYSQL:
+    K8S_SERVICE: ~
+
+  VIRTUAL_DATABASE:
+    MYSQL: ~
+
+auto-matching-rules:
+  # the name of the upper service is equal to the name of the lower service
+  name: "{ (u, l) -> u.name == l.name }"
+  # the short name of the upper service is equal to the short name of the 
lower service
+  short-name: "{ (u, l) -> u.shortName == l.shortName }"
+  # remove the namespace from the lower service short name
+  lower-short-name-remove-ns: "{ (u, l) -> u.shortName == 
l.shortName.substring(0, l.shortName.lastIndexOf('.')) }"
+
+layer-levels:
+  # The hierarchy level of the service layer, the level is used to define the 
order of the service layer for UI presentation.
+  # The level of the upper service should greater than the level of the lower 
service in `hierarchy` section.
+  MESH: 3
+  GENERAL: 3
+  VIRTUAL_DATABASE: 3
+  MYSQL: 2
+  MESH_DP: 1
+  K8S_SERVICE: 0
+```
+
+### Hierarchy
+- The hierarchy of service layers are defined in the `hierarchy` section.
+- The layers under the specific layer are related lower of the layer.
+- The relation could have a matching rule for auto matching, which are defined 
in the `auto-matching-rules` section.
+- The relation without a matching rule should be built through the internal 
API.
+- All the layers are defined in the file 
`org.apache.skywalking.oap.server.core.analysis.Layers.java`.
+- If the hierarchy is not defined, the service hierarchy relationship will not 
be built.
+- If you want to add a new relationship, you should certainly know they can be 
matched automatically by [Auto Matching Rules](#auto-matching-rules).
+
+### Auto Matching Rules
+- The auto matching rules are defined in the `auto-matching-rules` section.
+- Use Groovy script to define the matching rules, the input parameters are the 
upper service(u) and the lower service(l) and the return value is a boolean, 
+which are used to match the relation between the upper service(u) and the 
lower service(l) on the different layers.
+
+### Layer Levels
+- Define the hierarchy level of the service layer in the `layer-levels` 
section.
+- The level is used to define the order of the service layer for UI 
presentation.
+- The level of the upper service should greater than the level of the lower 
service in `hierarchy` section.
diff --git a/docs/en/concepts-and-designs/service-hierarchy.md 
b/docs/en/concepts-and-designs/service-hierarchy.md
new file mode 100644
index 0000000000..27ea733416
--- /dev/null
+++ b/docs/en/concepts-and-designs/service-hierarchy.md
@@ -0,0 +1,39 @@
+# Service Hierarchy
+SkyWalking v10 introduces a new concept `Service Hierarchy` which defines the 
relationships of existing logically same services in various layers.
+OAP will detect the services from different layers, and try to build the 
connections.
+
+## Detect Service Hierarchy Connections
+There 2 ways to detect the connections:
+1. Automatically matching through OAP internal mechanism, no extra work is 
required.
+2. Build the connections through specific agents.
+
+**Note:** All the relationships should be defined in the 
`config/hierarchy-definition.yml` file.
+
+### Automatically Matching 
+
+| Upper layer | Lower layer  | Matching rule                                   
                      |
+|-------------|--------------|-----------------------------------------------------------------------|
+| MESH        | MESH_DP      | upper service name equals lower service name    
                      |
+| MESH        | K8S_SERVICE  | upper service short name equals lower service 
short name              |
+| MESH_DP     | K8S_SERVICE  | upper service short name equals lower service 
short name              |
+| GENERAL     | K8S_SERVICE  | upper service short name equals lower service 
name without namespace  |
+
+### Build Through Specific Agents
+Use agent tech involved(such as eBPF) and deployment tools(such as operator 
and agent injector) detect the service hierarchy relations.
+
+| Upper layer | Lower layer  | Agent |
+|-------------|--------------|-------|
+
+
+# Instance Hierarchy
+Instance Hierarchy relationship follows the same definition as Service 
Hierarchy.
+
+### Automatically Matching
+If the service hierarchy is built, the instance hierarchy relationship could 
be detected automatically through 
+the following rules:
+1. The upper instance name equals the lower instance name.
+2. The upper instance attribute `pod/hostname` equals the lower instance 
attribute `pod/hostname`.
+3. The upper instance attribute `pod/hostname` equals the lower instance name.
+4. The upper instance name equals the lower instance attribute `pod/hostname`.
+
+### Build Through Specific Agents
diff --git a/docs/en/swip/SWIP-1.md b/docs/en/swip/SWIP-1.md
index 1f0ad51280..568375f34c 100644
--- a/docs/en/swip/SWIP-1.md
+++ b/docs/en/swip/SWIP-1.md
@@ -72,6 +72,7 @@ type HierarchyRelatedService {
   name: String!
   # The related service's Layer name.
   layer: String!
+  normal: Boolean!
 }
 
 type HierarchyRelatedInstance {
@@ -79,8 +80,14 @@ type HierarchyRelatedInstance {
   id: ID!
   # The literal name of the #id. Instance Name.
   name: String!
-  # The related instance service's Layer name.
+  # Service id
+  serviceId: ID!
+  # The literal name of the #serviceId.
+  serviceName: String!
+  # The service's Layer name.
+  # Service could have multiple layers, this is the layer of the service that 
the instance belongs to.
   layer: String!
+  normal: Boolean!
 }
 
 type HierarchyServiceRelation {
@@ -101,20 +108,21 @@ type InstanceHierarchy {
   relations: [HierarchyInstanceRelation!]!
 }
 
+type LayerLevel {
+  # The layer name.
+  layer: String!
+  # The layer level.
+  # The level of the upper service should greater than the level of the lower 
service.
+  level: Int!
+}
+
 extend type Query {
   # Query the service hierarchy, based on the given service. Will recursively 
return all related layers services in the hierarchy.
   getServiceHierarchy(serviceId: ID!, layer: String!): ServiceHierarchy!
   # Query the instance hierarchy, based on the given instance. Will return all 
direct related layers instances in the hierarchy, no recursive.
   getInstanceHierarchy(instanceId: ID!, layer: String!): InstanceHierarchy!
-}
-```
-New fields are going to be added to the `topology.graphqls`.
-```graphql
-# Node in Topology
-type Node {
-  ...
-  # The service hierarchy of the node.
-  serviceHierarchy: ServiceHierarchy!
+  # List layer hierarchy levels. The layer levels are defined in the 
`hierarchy-definition.yml`.
+  listLayerLevels: [LayerLevel!]!
 }
 ```
 
@@ -169,7 +177,7 @@ hierarchy:
     K8S_SERVICE: lower-short-name-remove-ns
 
   MYSQL:
-    K8S_SERVICE: lower-short-name-remove-ns
+    K8S_SERVICE: ~
 
   VIRTUAL_DATABASE:
     MYSQL: ~
@@ -183,6 +191,16 @@ auto-matching-rules:
   short-name: "{ (u, l) -> u.shortName == l.shortName }"
   # remove the namespace from the lower service short name
   lower-short-name-remove-ns: "{ (u, l) -> u.shortName == 
l.shortName.substring(0, l.shortName.lastIndexOf('.')) }"
+
+# The hierarchy level of the service layer, the level is used to define the 
order of the service layer for UI presentation,
+# The level of the upper service should greater than the level of the lower 
service in `hierarchy` section.
+layer-levels:
+  MESH: 3
+  GENERAL: 3
+  VIRTUAL_DATABASE: 3
+  MYSQL: 2
+  MESH_DP: 1
+  K8S_SERVICE: 0
 ```
 
 ## General usage docs
diff --git a/docs/menu.yml b/docs/menu.yml
index 02fe826fd3..5c04054e29 100644
--- a/docs/menu.yml
+++ b/docs/menu.yml
@@ -32,6 +32,8 @@ catalog:
             path: "/en/concepts-and-designs/service-agent"
           - name: "Manual Instrument SDK"
             path: "/en/concepts-and-designs/manual-sdk"
+      - name: "Service Hierarchy"
+        path: "/en/concepts-and-designs/service-hierarchy"
   - name: "Setup"
     catalog:
       - name: "Quick Start"
@@ -318,6 +320,8 @@ catalog:
         path: "/en/concepts-and-designs/lal"
       - name: "Profiling"
         path: "/en/concepts-and-designs/profiling"
+      - name : "Service Hierarchy Configuration"
+        path: "/en/concepts-and-designs/service-hierarchy-configuration"
   - name: "Security Notice"
     path: "/en/security/readme"
   - name: "Debugging"
diff --git 
a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/config/HierarchyDefinitionService.java
 
b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/config/HierarchyDefinitionService.java
index 2d6a9ce11d..fbec34cf6c 100644
--- 
a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/config/HierarchyDefinitionService.java
+++ 
b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/config/HierarchyDefinitionService.java
@@ -28,6 +28,7 @@ import lombok.Getter;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.skywalking.oap.server.core.CoreModuleConfig;
 import org.apache.skywalking.oap.server.core.UnexpectedException;
+import org.apache.skywalking.oap.server.core.analysis.Layer;
 import org.apache.skywalking.oap.server.library.util.ResourceUtils;
 import org.yaml.snakeyaml.Yaml;
 
@@ -38,10 +39,13 @@ public class HierarchyDefinitionService implements 
org.apache.skywalking.oap.ser
 
     @Getter
     private final Map<String, Map<String, MatchingRule>> hierarchyDefinition;
+    @Getter
+    private Map<String, Integer> layerLevels;
     private Map<String, MatchingRule> matchingRules;
 
     public HierarchyDefinitionService(CoreModuleConfig moduleConfig) {
         this.hierarchyDefinition = new HashMap<>();
+        this.layerLevels = new HashMap<>();
         if (moduleConfig.isEnableHierarchy()) {
             this.init();
             this.checkLayers();
@@ -56,6 +60,7 @@ public class HierarchyDefinitionService implements 
org.apache.skywalking.oap.ser
             Map<String, Map> config = yaml.loadAs(applicationReader, 
Map.class);
             Map<String, Map<String, String>> hierarchy = (Map<String, 
Map<String, String>>) config.get("hierarchy");
             Map<String, String> matchingRules = (Map<String, String>) 
config.get("auto-matching-rules");
+            this.layerLevels = (Map<String, Integer>) 
config.get("layer-levels");
             this.matchingRules = matchingRules.entrySet().stream().map(entry 
-> {
                 MatchingRule matchingRule = new MatchingRule(entry.getKey(), 
entry.getValue());
                 return Map.entry(entry.getKey(), matchingRule);
@@ -73,26 +78,31 @@ public class HierarchyDefinitionService implements 
org.apache.skywalking.oap.ser
     }
 
     private void checkLayers() {
-        this.hierarchyDefinition.forEach((layer, lowerLayers) -> {
-            if (lowerLayers.containsKey(layer)) {
+        this.layerLevels.keySet().forEach(layer -> {
+            if (Layer.nameOf(layer).equals(Layer.UNDEFINED)) {
                 throw new IllegalArgumentException(
-                    "hierarchy-definition.yml " + layer + " contains recursive 
hierarchy relation.");
+                    "hierarchy-definition.yml " + layer + " is not a valid 
layer name.");
             }
-            checkRecursive(layer);
         });
-    }
+        this.hierarchyDefinition.forEach((layer, lowerLayers) -> {
+            Integer layerLevel = this.layerLevels.get(layer);
+            if (this.layerLevels.get(layer) == null) {
+                throw new IllegalArgumentException(
+                    "hierarchy-definition.yml  layer-levels: " + layer + " is 
not defined");
+            }
 
-    private void checkRecursive(String layerName) {
-        try {
-            Map<String, MatchingRule> lowerLayers = 
this.hierarchyDefinition.get(layerName);
-            if (lowerLayers == null) {
-                return;
+            for (String lowerLayer : lowerLayers.keySet()) {
+                Integer lowerLayerLevel = this.layerLevels.get(lowerLayer);
+                if (lowerLayerLevel == null) {
+                    throw new IllegalArgumentException(
+                        "hierarchy-definition.yml  layer-levels: " + 
lowerLayer + " is not defined.");
+                }
+                if (layerLevel <= lowerLayerLevel) {
+                    throw new IllegalArgumentException(
+                        "hierarchy-definition.yml hierarchy: " + layer + " 
layer-level should be greater than " + lowerLayer + " layer-level.");
+                }
             }
-            lowerLayers.keySet().forEach(this::checkRecursive);
-        } catch (Throwable e) {
-            throw new IllegalArgumentException(
-                "hierarchy-definition.yml " + layerName + " contains recursive 
hierarchy relation.");
-        }
+        });
     }
 
     @Getter
diff --git 
a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/hierarchy/HierarchyService.java
 
b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/hierarchy/HierarchyService.java
index c7261a2392..2d8e268676 100644
--- 
a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/hierarchy/HierarchyService.java
+++ 
b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/hierarchy/HierarchyService.java
@@ -139,7 +139,7 @@ public class HierarchyService implements 
org.apache.skywalking.oap.server.librar
         Executors.newSingleThreadScheduledExecutor()
                  .scheduleWithFixedDelay(
                      new 
RunnableWithExceptionProtection(this::autoMatchingServiceRelation, t -> 
log.error(
-                         "Scheduled auto matching service hierarchy from 
service traffic failure.", t)), 1, 20, TimeUnit.SECONDS);
+                         "Scheduled auto matching service hierarchy from 
service traffic failure.", t)), 30, 20, TimeUnit.SECONDS);
     }
 
     private void autoMatchingServiceRelation(String upperServiceName,
diff --git 
a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/HierarchyQueryService.java
 
b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/HierarchyQueryService.java
index 6af1c4ab0f..a669ca5b8d 100644
--- 
a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/HierarchyQueryService.java
+++ 
b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/HierarchyQueryService.java
@@ -35,6 +35,7 @@ import lombok.extern.slf4j.Slf4j;
 import org.apache.skywalking.oap.server.core.CoreModule;
 import org.apache.skywalking.oap.server.core.CoreModuleConfig;
 import org.apache.skywalking.oap.server.core.analysis.IDManager;
+import org.apache.skywalking.oap.server.core.analysis.Layer;
 import org.apache.skywalking.oap.server.core.config.HierarchyDefinitionService;
 import 
org.apache.skywalking.oap.server.core.hierarchy.instance.InstanceHierarchyRelationTraffic;
 import 
org.apache.skywalking.oap.server.core.hierarchy.service.ServiceHierarchyRelationTraffic;
@@ -44,6 +45,7 @@ import 
org.apache.skywalking.oap.server.core.query.type.HierarchyRelatedInstance
 import 
org.apache.skywalking.oap.server.core.query.type.HierarchyRelatedService;
 import 
org.apache.skywalking.oap.server.core.query.type.HierarchyServiceRelation;
 import org.apache.skywalking.oap.server.core.query.type.InstanceHierarchy;
+import org.apache.skywalking.oap.server.core.query.type.LayerLevel;
 import org.apache.skywalking.oap.server.core.query.type.ServiceHierarchy;
 import org.apache.skywalking.oap.server.core.query.type.ServiceInstance;
 import org.apache.skywalking.oap.server.core.storage.StorageModule;
@@ -59,6 +61,7 @@ public class HierarchyQueryService implements Service {
     private IHierarchyQueryDAO hierarchyQueryDAO;
     private IMetadataQueryDAO metadataQueryDAO;
     private Map<String, Map<String, HierarchyDefinitionService.MatchingRule>> 
hierarchyDefinition;
+    private Map<String, Integer> layerLevels;
     private LoadingCache<Boolean, Map<HierarchyRelatedService, 
ServiceRelations>> serviceHierarchyCache;
 
     public HierarchyQueryService(ModuleManager moduleManager, CoreModuleConfig 
moduleConfig) {
@@ -106,19 +109,34 @@ public class HierarchyQueryService implements Service {
         return hierarchyDefinition;
     }
 
+    private Map<String, Integer> getLayerLevels() {
+        if (layerLevels == null) {
+            layerLevels = moduleManager.find(CoreModule.NAME)
+                                               .provider()
+                                               
.getService(HierarchyDefinitionService.class).getLayerLevels();
+        }
+        return layerLevels;
+    }
+
     private Map<HierarchyRelatedService, ServiceRelations> 
mapServiceHierarchy() throws Exception {
         List<ServiceHierarchyRelationTraffic> traffics = 
getHierarchyQueryDAO().readAllServiceHierarchyRelations();
         Map<HierarchyRelatedService, ServiceRelations> serviceRelationsMap = 
new HashMap<>();
 
         for (ServiceHierarchyRelationTraffic traffic : traffics) {
             HierarchyRelatedService service = new HierarchyRelatedService();
+            IDManager.ServiceID.ServiceIDDefinition serviceIdDef = 
IDManager.ServiceID.analysisId(
+                traffic.getServiceId());
             service.setId(traffic.getServiceId());
-            
service.setName(IDManager.ServiceID.analysisId(traffic.getServiceId()).getName());
+            service.setName(serviceIdDef.getName());
             service.setLayer(traffic.getServiceLayer().name());
+            service.setNormal(serviceIdDef.isReal());
             HierarchyRelatedService relatedService = new 
HierarchyRelatedService();
+            IDManager.ServiceID.ServiceIDDefinition relatedServiceIdDef = 
IDManager.ServiceID.analysisId(
+                traffic.getRelatedServiceId());
             relatedService.setId(traffic.getRelatedServiceId());
-            
relatedService.setName(IDManager.ServiceID.analysisId(traffic.getRelatedServiceId()).getName());
+            relatedService.setName(relatedServiceIdDef.getName());
             relatedService.setLayer(traffic.getRelatedServiceLayer().name());
+            relatedService.setNormal(relatedServiceIdDef.isReal());
 
             ServiceRelations serviceRelations = 
serviceRelationsMap.computeIfAbsent(
                 service, k -> new ServiceRelations());
@@ -172,8 +190,8 @@ public class HierarchyQueryService implements Service {
         self.setId(serviceId);
         self.setName(IDManager.ServiceID.analysisId(serviceId).getName());
         self.setLayer(layer);
+        self.setNormal(Layer.nameOf(layer).isNormal());
         buildServiceRelation(hierarchy, self, maxDepth, direction);
-
         return hierarchy;
     }
 
@@ -203,6 +221,8 @@ public class HierarchyQueryService implements Service {
         //build from service hierarchy and instance traffic
         IDManager.ServiceInstanceID.InstanceIDDefinition idDefinition = 
IDManager.ServiceInstanceID.analysisId(
             instanceId);
+        IDManager.ServiceID.ServiceIDDefinition serviceIdDefinition = 
IDManager.ServiceID.analysisId(
+            idDefinition.getServiceId());
         //instance is only query 1 depth of service hierarchy, set max depth 
to 1
         ServiceHierarchy serviceHierarchy = 
getServiceHierarchy(idDefinition.getServiceId(), layer, 1, 
HierarchyDirection.All);
 
@@ -234,13 +254,19 @@ public class HierarchyQueryService implements Service {
             HierarchyRelatedInstance instance = new HierarchyRelatedInstance();
             instance.setId(self.getId());
             instance.setName(self.getName());
+            instance.setServiceId(idDefinition.getServiceId());
+            instance.setServiceName(serviceIdDefinition.getName());
+            instance.setNormal(serviceIdDefinition.isReal());
             instance.setLayer(layer);
             //The instances could be same but the service layer is different
             if (lower.isPresent() && 
!layer.equals(serviceRelation.getLowerService().getLayer())) {
                 HierarchyRelatedInstance relatedInstance = new 
HierarchyRelatedInstance();
                 relatedInstance.setId(lower.get().getId());
                 relatedInstance.setName(lower.get().getName());
+                
relatedInstance.setServiceId(serviceRelation.getLowerService().getId());
+                
relatedInstance.setServiceName(serviceRelation.getLowerService().getName());
                 
relatedInstance.setLayer(serviceRelation.getLowerService().getLayer());
+                
relatedInstance.setNormal(serviceRelation.getLowerService().isNormal());
                 relations.add(new HierarchyInstanceRelation(instance, 
relatedInstance));
             }
 
@@ -248,7 +274,10 @@ public class HierarchyQueryService implements Service {
                 HierarchyRelatedInstance relatedInstance = new 
HierarchyRelatedInstance();
                 relatedInstance.setId(upper.get().getId());
                 relatedInstance.setName(upper.get().getName());
+                
relatedInstance.setServiceId(serviceRelation.getUpperService().getId());
+                
relatedInstance.setServiceName(serviceRelation.getUpperService().getName());
                 
relatedInstance.setLayer(serviceRelation.getUpperService().getLayer());
+                
relatedInstance.setNormal(serviceRelation.getUpperService().isNormal());
                 relations.add(new HierarchyInstanceRelation(relatedInstance, 
instance));
             }
         }
@@ -259,13 +288,27 @@ public class HierarchyQueryService implements Service {
 
         for (InstanceHierarchyRelationTraffic traffic : traffics) {
             HierarchyRelatedInstance instance = new HierarchyRelatedInstance();
+            IDManager.ServiceInstanceID.InstanceIDDefinition idDef = 
IDManager.ServiceInstanceID.analysisId(
+                instanceId);
+            IDManager.ServiceID.ServiceIDDefinition serviceIdDef = 
IDManager.ServiceID.analysisId(
+                idDefinition.getServiceId());
             instance.setId(traffic.getInstanceId());
-            
instance.setName(IDManager.ServiceInstanceID.analysisId(traffic.getInstanceId()).getName());
+            instance.setName(idDef.getName());
+            instance.setServiceId(idDef.getServiceId());
+            instance.setServiceName(serviceIdDef.getName());
             instance.setLayer(traffic.getServiceLayer().name());
+            instance.setNormal(serviceIdDef.isReal());
             HierarchyRelatedInstance relatedInstance = new 
HierarchyRelatedInstance();
+            IDManager.ServiceInstanceID.InstanceIDDefinition relatedIdDef = 
IDManager.ServiceInstanceID.analysisId(
+                traffic.getRelatedInstanceId());
+            IDManager.ServiceID.ServiceIDDefinition relatedServiceIdDef = 
IDManager.ServiceID.analysisId(
+                relatedIdDef.getServiceId());
             relatedInstance.setId(traffic.getRelatedInstanceId());
-            
relatedInstance.setName(IDManager.ServiceInstanceID.analysisId(traffic.getRelatedInstanceId()).getName());
+            relatedInstance.setName(relatedIdDef.getName());
+            relatedInstance.setServiceId(relatedIdDef.getServiceId());
+            relatedInstance.setServiceName(relatedServiceIdDef.getName());
             relatedInstance.setLayer(traffic.getRelatedServiceLayer().name());
+            relatedInstance.setNormal(relatedServiceIdDef.isReal());
             Map<String, HierarchyDefinitionService.MatchingRule> lowerLayers = 
getHierarchyDefinition().get(
                 traffic.getServiceLayer().name());
             if (lowerLayers != null && 
lowerLayers.containsKey(traffic.getRelatedServiceLayer().name())) {
@@ -277,6 +320,13 @@ public class HierarchyQueryService implements Service {
         return hierarchy;
     }
 
+    public List<LayerLevel> listLayerLevels() {
+        return getLayerLevels().entrySet()
+                               .stream()
+                               .map(entry -> new LayerLevel(entry.getKey(), 
entry.getValue()))
+                               .collect(Collectors.toList());
+    }
+
     private Predicate<Attribute> hostAttrFilter() {
         return attribute -> attribute.getName().equalsIgnoreCase("pod")
             || attribute.getName().equalsIgnoreCase("hostname");
diff --git 
a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/type/HierarchyRelatedInstance.java
 
b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/type/HierarchyRelatedInstance.java
index 62fae29f28..eecbca9f22 100644
--- 
a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/type/HierarchyRelatedInstance.java
+++ 
b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/type/HierarchyRelatedInstance.java
@@ -24,9 +24,12 @@ import lombok.Setter;
 
 @Getter
 @Setter
-@EqualsAndHashCode
+@EqualsAndHashCode(of = {"id", "serviceId", "layer"})
 public class HierarchyRelatedInstance {
     private String id;
     private String name;
+    private String serviceId;
+    private String serviceName;
     private String layer;
+    private boolean normal;
 }
diff --git 
a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/type/HierarchyRelatedService.java
 
b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/type/HierarchyRelatedService.java
index ab65a98dd6..b56eb3252c 100644
--- 
a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/type/HierarchyRelatedService.java
+++ 
b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/type/HierarchyRelatedService.java
@@ -29,4 +29,5 @@ public class HierarchyRelatedService {
     private String id;
     private String name;
     private String layer;
+    private boolean normal;
 }
diff --git 
a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/type/HierarchyRelatedInstance.java
 
b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/type/LayerLevel.java
similarity index 81%
copy from 
oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/type/HierarchyRelatedInstance.java
copy to 
oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/type/LayerLevel.java
index 62fae29f28..38f06e9f94 100644
--- 
a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/type/HierarchyRelatedInstance.java
+++ 
b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/type/LayerLevel.java
@@ -18,15 +18,14 @@
 
 package org.apache.skywalking.oap.server.core.query.type;
 
-import lombok.EqualsAndHashCode;
-import lombok.Getter;
-import lombok.Setter;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
 
-@Getter
-@Setter
-@EqualsAndHashCode
-public class HierarchyRelatedInstance {
-    private String id;
-    private String name;
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class LayerLevel {
     private String layer;
+    private int level;
 }
diff --git 
a/oap-server/server-query-plugin/query-graphql-plugin/src/main/java/org/apache/skywalking/oap/query/graphql/resolver/HierarchyQuery.java
 
b/oap-server/server-query-plugin/query-graphql-plugin/src/main/java/org/apache/skywalking/oap/query/graphql/resolver/HierarchyQuery.java
index 57241ee7d0..083941ed50 100644
--- 
a/oap-server/server-query-plugin/query-graphql-plugin/src/main/java/org/apache/skywalking/oap/query/graphql/resolver/HierarchyQuery.java
+++ 
b/oap-server/server-query-plugin/query-graphql-plugin/src/main/java/org/apache/skywalking/oap/query/graphql/resolver/HierarchyQuery.java
@@ -19,9 +19,11 @@
 package org.apache.skywalking.oap.query.graphql.resolver;
 
 import graphql.kickstart.tools.GraphQLQueryResolver;
+import java.util.List;
 import org.apache.skywalking.oap.server.core.CoreModule;
 import org.apache.skywalking.oap.server.core.query.HierarchyQueryService;
 import org.apache.skywalking.oap.server.core.query.type.InstanceHierarchy;
+import org.apache.skywalking.oap.server.core.query.type.LayerLevel;
 import org.apache.skywalking.oap.server.core.query.type.ServiceHierarchy;
 import org.apache.skywalking.oap.server.library.module.ModuleManager;
 
@@ -49,4 +51,8 @@ public class HierarchyQuery implements GraphQLQueryResolver {
     public InstanceHierarchy getInstanceHierarchy(String instanceId, String 
layer) throws Exception {
         return getHierarchyQueryService().getInstanceHierarchy(instanceId, 
layer);
     }
+
+    public List<LayerLevel> listLayerLevels() throws Exception {
+        return getHierarchyQueryService().listLayerLevels();
+    }
 }
diff --git 
a/oap-server/server-query-plugin/query-graphql-plugin/src/main/resources/query-protocol
 
b/oap-server/server-query-plugin/query-graphql-plugin/src/main/resources/query-protocol
index b5fe539bce..72fdfe5660 160000
--- 
a/oap-server/server-query-plugin/query-graphql-plugin/src/main/resources/query-protocol
+++ 
b/oap-server/server-query-plugin/query-graphql-plugin/src/main/resources/query-protocol
@@ -1 +1 @@
-Subproject commit b5fe539bce21d464e5dff360a691b79729bf065b
+Subproject commit 72fdfe56603c6a6135f932fb402c0890bb78b4e7
diff --git 
a/oap-server/server-starter/src/main/resources/hierarchy-definition.yml 
b/oap-server/server-starter/src/main/resources/hierarchy-definition.yml
index 7cf1042783..eeffbb0e3a 100644
--- a/oap-server/server-starter/src/main/resources/hierarchy-definition.yml
+++ b/oap-server/server-starter/src/main/resources/hierarchy-definition.yml
@@ -29,12 +29,12 @@ hierarchy:
     K8S_SERVICE: lower-short-name-remove-ns
 
   MYSQL:
-    K8S_SERVICE: lower-short-name-remove-ns
+    K8S_SERVICE: ~
 
   VIRTUAL_DATABASE:
     MYSQL: ~
 
-# Use Groovy script to define the matching rules, the input parameters are the 
upper service(u) and the lower service(l) and the return value is a boolean.
+# Use Groovy script to define the matching rules, the input parameters are the 
upper service(u) and the lower service(l) and the return value is a boolean,
 # which are used to match the relation between the upper service(u) and the 
lower service(l) on the different layers.
 auto-matching-rules:
   # the name of the upper service is equal to the name of the lower service
@@ -44,3 +44,16 @@ auto-matching-rules:
   # remove the namespace from the lower service short name
   lower-short-name-remove-ns: "{ (u, l) -> u.shortName == 
l.shortName.substring(0, l.shortName.lastIndexOf('.')) }"
 
+# The hierarchy level of the service layer, the level is used to define the 
order of the service layer for UI presentation.
+# The level of the upper service should greater than the level of the lower 
service in `hierarchy` section.
+layer-levels:
+  MESH: 3
+  GENERAL: 3
+  VIRTUAL_DATABASE: 3
+
+  MYSQL: 2
+
+  MESH_DP: 1
+
+  K8S_SERVICE: 0
+

Reply via email to