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 +