From 98ef399410437b097c417930ea9b4f02c2af8acf Mon Sep 17 00:00:00 2001 From: Wan Kai Date: Thu, 4 Jul 2024 15:09:53 +0800 Subject: [PATCH] Support tracing topology query for debugging (#12413) --- docs/en/api/query-protocol.md | 13 +- docs/en/changes/changes.md | 1 + docs/en/debugging/query-tracing.md | 403 +++++++++++++++--- .../core/query/EndpointTopologyBuilder.java | 87 ++++ .../core/query/ProcessTopologyBuilder.java | 18 + .../query/ServiceInstanceTopologyBuilder.java | 18 + .../core/query/ServiceTopologyBuilder.java | 18 + .../core/query/TopologyQueryService.java | 149 ++++--- .../core/query/type/EndpointTopology.java | 4 + .../core/query/type/ProcessTopology.java | 6 +- .../query/type/ServiceInstanceTopology.java | 4 + .../oap/server/core/query/type/Topology.java | 4 + .../core/storage/query/ITopologyQueryDAO.java | 155 +++++++ .../oap/query/debug/DebuggingHTTPHandler.java | 111 +++++ .../debug/DebuggingQueryExceptionHandler.java | 45 ++ .../DebuggingQueryEndpointTopologyRsp.java | 34 ++ .../DebuggingQueryInstanceTopologyRsp.java | 34 ++ .../DebuggingQueryProcessTopologyRsp.java | 34 ++ .../DebuggingQueryServiceTopologyRsp.java | 34 ++ .../query/graphql/resolver/TopologyQuery.java | 133 +++++- .../src/main/resources/query-protocol | 2 +- .../measure/BanyanDBTopologyQueryDAO.java | 10 +- .../plugin/elasticsearch/base/EsDAO.java | 4 + .../query/RecordsQueryEsDAO.java | 2 +- .../query/TopologyQueryEsDAO.java | 8 +- 25 files changed, 1188 insertions(+), 143 deletions(-) create mode 100644 oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/EndpointTopologyBuilder.java create mode 100644 oap-server/server-query-plugin/debugging-query-plugin/src/main/java/org/apache/skywalking/oap/query/debug/DebuggingQueryExceptionHandler.java create mode 100644 oap-server/server-query-plugin/debugging-query-plugin/src/main/java/org/apache/skywalking/oap/query/debug/topology/DebuggingQueryEndpointTopologyRsp.java create mode 100644 oap-server/server-query-plugin/debugging-query-plugin/src/main/java/org/apache/skywalking/oap/query/debug/topology/DebuggingQueryInstanceTopologyRsp.java create mode 100644 oap-server/server-query-plugin/debugging-query-plugin/src/main/java/org/apache/skywalking/oap/query/debug/topology/DebuggingQueryProcessTopologyRsp.java create mode 100644 oap-server/server-query-plugin/debugging-query-plugin/src/main/java/org/apache/skywalking/oap/query/debug/topology/DebuggingQueryServiceTopologyRsp.java diff --git a/docs/en/api/query-protocol.md b/docs/en/api/query-protocol.md index 346cb839b76b..8f5936ea2b6c 100644 --- a/docs/en/api/query-protocol.md +++ b/docs/en/api/query-protocol.md @@ -55,23 +55,24 @@ extend type Query { The topology and dependency graphs among services, instances and endpoints. Includes direct relationships or global maps. ```graphql +# Param, if debug is true will enable the query tracing and return DebuggingTrace in the result. extend type Query { # Query the global topology # When layer is specified, the topology of this layer would be queried - getGlobalTopology(duration: Duration!, layer: String): Topology + getGlobalTopology(duration: Duration!, layer: String, debug: Boolean): Topology # Query the topology, based on the given service - getServiceTopology(serviceId: ID!, duration: Duration!): Topology + getServiceTopology(serviceId: ID!, duration: Duration!, debug: Boolean): Topology # Query the topology, based on the given services. # `#getServiceTopology` could be replaced by this. - getServicesTopology(serviceIds: [ID!]!, duration: Duration!): Topology + getServicesTopology(serviceIds: [ID!]!, duration: Duration!, debug: Boolean): Topology # Query the instance topology, based on the given clientServiceId and serverServiceId - getServiceInstanceTopology(clientServiceId: ID!, serverServiceId: ID!, duration: Duration!): ServiceInstanceTopology + getServiceInstanceTopology(clientServiceId: ID!, serverServiceId: ID!, duration: Duration!, debug: Boolean): ServiceInstanceTopology # Query the topology, based on the given endpoint getEndpointTopology(endpointId: ID!, duration: Duration!): Topology # v2 of getEndpointTopology - getEndpointDependencies(endpointId: ID!, duration: Duration!): EndpointTopology + getEndpointDependencies(endpointId: ID!, duration: Duration!, debug: Boolean): EndpointTopology # Query the topology, based on the given instance - getProcessTopology(serviceInstanceId: ID!, duration: Duration!): ProcessTopology + getProcessTopology(serviceInstanceId: ID!, duration: Duration!, debug: Boolean): ProcessTopology } ``` diff --git a/docs/en/changes/changes.md b/docs/en/changes/changes.md index dd5f0275d92a..82222b25eeea 100644 --- a/docs/en/changes/changes.md +++ b/docs/en/changes/changes.md @@ -27,6 +27,7 @@ * Support BanyanDB internal metrics query execution tracing. * BanyanDB client config: rise the default `maxBulkSize` to 10000, add `flushTimeout` and set default to 10s. * Polish BanyanDB group and schema creation logic to fix the schema creation failure issue in distributed race conditions. +* Support tracing topology query for debugging. #### UI * Highlight search log keywords. diff --git a/docs/en/debugging/query-tracing.md b/docs/en/debugging/query-tracing.md index 55668a9f0a04..065ec0285312 100644 --- a/docs/en/debugging/query-tracing.md +++ b/docs/en/debugging/query-tracing.md @@ -15,16 +15,16 @@ SkyWalking OAP provides the metrics/trace/log/topology query tracing to help use - Span -| Field | Description | -|--------------|------------------------------------------------------------------------------------------------------------------| -| spanId | The unique ID of the span | -| parentSpanId | The parent span ID of the span | -| operation | The operation name of the span | -| startTime | The start time of the span. In nanoseconds | -| endTime | The end time of the span. In nanoseconds | -| duration | The duration of the span. In nanoseconds | -| msg | The message of the span, could include additional info such as request condition and response from the Database | -| error | The error message of the span, if the span has an error. | +| Field | Description | +|--------------|----------------------------------------------------------------------------------------------------------------------------------------------------| +| spanId | The unique ID of the span | +| parentSpanId | The parent span ID of the span | +| operation | The operation name of the span | +| startTime | The start time of the span. In nanoseconds, this is a relative time based on different env and implementation | +| endTime | The end time of the span. In nanoseconds, this is a relative time based on different env and implementation | +| duration | The duration of the span. In nanoseconds | +| msg | The message of the span, could include additional info such as request condition and response from the Database or Tags from BanyanDB internal trace | +| error | The error message of the span, if the span has an error. | ## Debugging through HTTP APIs @@ -57,10 +57,10 @@ The time and step parameters are follow the [Duration](../api/query-protocol.md# - Example -Tracing an avg query with the MQE query expression `avg(service_sla)` from 2024-06-18 11 to 2024-06-18 12 with the step HOUR for the service `mock_a_service` and the service layer `GENERAL`. +Tracing an avg query with the MQE query expression `avg(service_sla)` from 2024-07-03 to 2024-07-03 with the step DAY for the service `mock_a_service` and the service layer `GENERAL`. ```shell -curl -X GET 'http://127.0.0.1:12800/debugging/query/mqe?dumpDBRsp=true&expression=avg(service_sla)&startTime=2024-06-18%2011&endTime=2024-06-18%2012&step=HOUR&service=mock_a_service&serviceLayer=GENERAL' +curl -X GET 'http://127.0.0.1:12800/debugging/query/mqe?dumpDBRsp=true&expression=avg(service_sla)&startTime=2024-07-03&endTime=2024-07-03&step=DAY&service=mock_a_service&serviceLayer=GENERAL' ``` Response will include query result and the debuggingTrace information: @@ -78,55 +78,103 @@ results: emptyValue: false error: null debuggingTrace: - traceId: "a50910fe-c966-4249-87f9-e471e55cf92f" + traceId: "4f972417-c543-4f7d-a3f1-f5e694cfeb2b" condition: "Expression: avg(service_sla), Entity: Entity(scope=null, serviceName=mock_a_service,\ \ normal=true, serviceInstanceName=null, endpointName=null, processName=null,\ \ destServiceName=null, destNormal=null, destServiceInstanceName=null, destEndpointName=null,\ - \ destProcessName=null), Duration: Duration(start=2024-06-18 11, end=2024-06-18\ - \ 12, step=HOUR)" - startTime: 61636369350002 - endTime: 61636374541189 - duration: 5191187 + \ destProcessName=null), Duration: Duration(start=2024-07-03, end=2024-07-03,\ + \ step=DAY)" + startTime: 115828803080350 + endTime: 115828877400237 + duration: 74319887 rootSpan: spanId: 0 parentSpanId: -1 operation: "MQE query" - startTime: 61636369352761 - endTime: 61636374539893 - duration: 5187132 + startTime: 115828803110686 + endTime: 115828877396756 + duration: 74286070 msg: null error: null childSpans: - spanId: 1 parentSpanId: 0 operation: "MQE syntax analysis" - startTime: 61636369357437 - endTime: 61636369443631 - duration: 86194 + startTime: 115828803699331 + endTime: 115828805015745 + duration: 1316414 msg: null error: null childSpans: [] - spanId: 2 parentSpanId: 0 operation: "MQE Aggregation OP: avg(service_sla)" - startTime: 61636369458018 - endTime: 61636374440560 - duration: 4982542 + startTime: 115828805052267 + endTime: 115828876877134 + duration: 71824867 msg: null error: null childSpans: - spanId: 3 parentSpanId: 2 operation: "MQE Metric OP: service_sla" - startTime: 61636369468839 - endTime: 61636374373771 - duration: 4904932 + startTime: 115828805209453 + endTime: 115828875634953 + duration: 70425500 msg: null error: null childSpans: ... ``` +**Note:** if using the SkyWalking native storage [BanyanDB](../setup/backend/storages/banyandb.md), +the debuggingTrace will include the BanyanDB internal execution trace info, such as: +```yaml +... +childSpans: + - spanId: 7 + parentSpanId: 6 + operation: "BanyanDB: measure-grpc" + startTime: 1720059017222584700 + endTime: 1720059017223492400 + duration: 907700 + msg: "[Tag(key=request, value={\"groups\":[\"measure-default\"], \"\ + name\":\"service_sla_day\", \"timeRange\":{\"begin\":\"2024-07-02T16:00:00Z\"\ + , \"end\":\"2024-07-03T16:00:00Z\"}, \"criteria\":{\"condition\"\ + :{\"name\":\"entity_id\", \"op\":\"BINARY_OP_EQ\", \"value\":{\"\ + str\":{\"value\":\"bW9ja19hX3NlcnZpY2U=.1\"}}}}, \"tagProjection\"\ + :{\"tagFamilies\":[{\"name\":\"storage-only\", \"tags\":[\"entity_id\"\ + ]}]}, \"fieldProjection\":{\"names\":[\"percentage\"]}, \"trace\"\ + :true})]" + error: null + childSpans: + - spanId: 8 + parentSpanId: 7 + operation: "BanyanDB: data-0ebf3a27de83:17912" + startTime: 1720059017222821600 + endTime: 1720059017223473500 + duration: 651900 + msg: "[Tag(key=plan, value=IndexScan: startTime=1719936000,endTime=1720022400,Metadata{group=measure-default,name=service_sla_day},conditions=%!s();\ + \ projection=#storage-only:entity_id; order=OrderBy:\ + \ [], sort=SORT_UNSPECIFIED; limit=100 Limit: 0, 100)]" + error: null + childSpans: + - spanId: 9 + parentSpanId: 8 + operation: "BanyanDB: indexScan-group:\"measure-default\" name:\"\ + service_sla_day\"" + startTime: 1720059017222879200 + endTime: 1720059017223293300 + duration: 414100 + msg: "[Tag(key=orderBy, value=time SORT_UNSPECIFIED), Tag(key=details,\ + \ value=IndexScan: startTime=1719936000,endTime=1720022400,Metadata{group=measure-default,name=service_sla_day},conditions=%!s();\ + \ projection=#storage-only:entity_id; order=OrderBy:\ + \ [], sort=SORT_UNSPECIFIED; limit=100)]" + error: null + childSpans: +... +``` + ### Tracing SkyWalking Trace Query #### Tracing SkyWalking API queryBasicTraces @@ -245,6 +293,153 @@ debuggingTrace: ... ``` +### Tracing Topology Query + +#### Tracing SkyWalking API getGlobalTopology +- URL: HTTP GET `http://{core restHost}:{core restPort}/debugging/query/topology/getGlobalTopology?{parameters}`. +- Parameters + + | Field | Description | Required | + |-------------------|---------------------------------------------------------------|----------| + | startTime | The start time of the query | Yes | + | endTime | The end time of the query | Yes | + | step | The query step | Yes | + | serviceLayer | The service layer name | No | + +- Example +```shell +curl -X GET 'http://127.0.0.1:12800/debugging/query/topology/getGlobalTopology?startTime=2024-07-03&endTime=2024-07-03&step=DAY&serviceLayer=GENERAL' +``` + +Response will include query result and the debuggingTrace information, the debuggingTrace information is the same as the MQE query tracing: + +```yaml +nodes: +... +calls: +... +debuggingTrace: +... +``` + +#### Tracing SkyWalking API getServicesTopology +- URL: HTTP GET `http://{core restHost}:{core restPort}/debugging/query/topology/getServicesTopology?{parameters}`. +- Parameters + + | Field | Description | Required | + |--------------|-----------------------------------------------------------------------------|----------| + | startTime | The start time of the query | Yes | + | endTime | The end time of the query | Yes | + | step | The query step | Yes | + | serviceLayer | The service layer name | Yes | + | services | The services names list, separate by comma `mock_a_service, mock_b_service` | Yes | + +- Example +```shell +curl -X GET 'http://127.0.0.1:12800/debugging/query/topology/getServicesTopology?startTime=2024-07-03&endTime=2024-07-03&step=DAY&serviceLayer=GENERAL&services=mock_a_service%2Cmock_b_service' +``` + +Response will include query result and the debuggingTrace information, the debuggingTrace information is the same as the MQE query tracing: + +```yaml +nodes: +... +calls: +... +debuggingTrace: +... +``` + +#### Tracing SkyWalking API getServiceInstanceTopology +- URL: HTTP GET `http://{core restHost}:{core restPort}/debugging/query/topology/getServiceInstanceTopology?{parameters}`. +- Parameters + + | Field | Description | Required | + |--------------------|------------------------------------|----------| + | startTime | The start time of the query | Yes | + | endTime | The end time of the query | Yes | + | step | The query step | Yes | + | clientService | The client side service name | Yes | + | serverService | The server side service name | Yes | + | clientServiceLayer | The client side service layer name | Yes | + | serverServiceLayer | The server side service layer name | Yes | + +- Example +```shell +curl -X GET 'http://127.0.0.1:12800/debugging/query/topology/getServiceInstanceTopology?startTime=2024-07-03&endTime=2024-07-03&step=DAY&clientService=mock_a_service&serverService=mock_b_service&clientServiceLayer=GENERAL&serverServiceLayer=GENERAL' +``` + +Response will include query result and the debuggingTrace information, the debuggingTrace information is the same as the MQE query tracing: + +```yaml +nodes: +... +calls: +... +debuggingTrace: +... +``` + +#### Tracing SkyWalking API getEndpointDependencies +- URL: HTTP GET `http://{core restHost}:{core restPort}/debugging/query/topology/getEndpointDependencies?{parameters}`. +- Parameters + + | Field | Description | Required | + |--------------|-----------------------------------------------------------------------------|----------| + | startTime | The start time of the query | Yes | + | endTime | The end time of the query | Yes | + | step | The query step | Yes | + | service | The service name | Yes | + | serviceLayer | The service layer name | Yes | + | endpoint | The endpoint name | Yes | + +- Example +- Example +```shell +curl -X GET 'http://127.0.0.1:12800/debugging/query/topology/getEndpointDependencies?startTime=2024-07-03&endTime=2024-07-03&step=DAY&service=mock_a_service&serviceLayer=GENERAL&endpoint=%2Fdubbox-case%2Fcase%2Fdubbox-rest%2F404-test' +``` + +Response will include query result and the debuggingTrace information, the debuggingTrace information is the same as the MQE query tracing: + +```yaml +nodes: +... +calls: +... +debuggingTrace: +... +``` + +#### Tracing SkyWalking API getProcessTopology +- URL: HTTP GET `http://{core restHost}:{core restPort}/debugging/query/topology/getProcessTopology?{parameters}`. +- Parameters + + | Field | Description | Required | + |---------------|-----------------------------------------------------------------------------|----------| + | startTime | The start time of the query | Yes | + | endTime | The end time of the query | Yes | + | step | The query step | Yes | + | service | The service name | Yes | + | serviceLayer | The service layer name | Yes | + | instance | The instance name | Yes | + +- Example +```shell + +curl -X GET 'http://127.0.0.1:12800/debugging/query/topology/getProcessTopology?startTime=2024-07-03&endTime=2024-07-03&step=DAY&service=mock_a_service&serviceLayer=GENERAL&instance=mock_a_service_instance' +``` + +Response will include query result and the debuggingTrace information, the debuggingTrace information is the same as the MQE query tracing: + +```yaml +nodes: +... +calls: +... +debuggingTrace: +... +``` + ## Debugging with GraphQL bundled When querying the metrics though the [GraphQL APIs](../api/query-protocol.md), the query tracing service is also provided within the GraphQL bundled. @@ -277,7 +472,7 @@ http://127.0.0.1:12800/graphql ```graphql { - execExpression(expression: "avg(service_sla)", entity: {serviceName: "mock_a_service", normal: true}, duration: {start: "2024-06-18 11", end: "2024-06-18 12", step: HOUR}, debug: true, dumpDBRsp: true) { + execExpression(expression: "avg(service_sla)", entity: {serviceName: "mock_a_service", normal: true}, duration: {start: "2024-07-03", end: "2024-07-03", step: DAY}, debug: true, dumpDBRsp: true) { type error results { @@ -338,19 +533,19 @@ Response will include query result and the execTrace information: } ], "debuggingTrace": { - "traceId": "7caa6529-9a72-4878-ab82-7a9ca032a97b", - "condition": "Expression: avg(service_sla), Entity: Entity(scope=null, serviceName=mock_a_service, normal=true, serviceInstanceName=null, endpointName=null, processName=null, destServiceName=null, destNormal=null, destServiceInstanceName=null, destEndpointName=null, destProcessName=null), Duration: Duration(start=2024-06-18 11, end=2024-06-18 12, step=HOUR)", - "startTime": 73040673584523, - "endTime": 73040678525541, - "duration": 4941018, + "traceId": "3116ffe3-ee9c-4047-9f22-c135c237aad5", + "condition": "Expression: avg(service_sla), Entity: Entity(scope=null, serviceName=mock_a_service, normal=true, serviceInstanceName=null, endpointName=null, processName=null, destServiceName=null, destNormal=null, destServiceInstanceName=null, destEndpointName=null, destProcessName=null), Duration: Duration(start=2024-07-03, end=2024-07-03, step=DAY)", + "startTime": 117259274324665, + "endTime": 117259279847720, + "duration": 5523055, "spans": [ { "spanId": 0, "parentSpanId": -1, "operation": "MQE query", - "startTime": 73040673586770, - "endTime": 73040678523624, - "duration": 4936854, + "startTime": 117259274328719, + "endTime": 117259279846559, + "duration": 5517840, "msg": null, "error": null }, @@ -358,9 +553,9 @@ Response will include query result and the execTrace information: "spanId": 1, "parentSpanId": 0, "operation": "MQE syntax analysis", - "startTime": 73040673591566, - "endTime": 73040673677579, - "duration": 86013, + "startTime": 117259274333084, + "endTime": 117259274420159, + "duration": 87075, "msg": null, "error": null }, @@ -368,9 +563,9 @@ Response will include query result and the execTrace information: "spanId": 2, "parentSpanId": 0, "operation": "MQE Aggregation OP: avg(service_sla)", - "startTime": 73040673691700, - "endTime": 73040678270159, - "duration": 4578459, + "startTime": 117259274433533, + "endTime": 117259279812549, + "duration": 5379016, "msg": null, "error": null }, @@ -381,6 +576,53 @@ Response will include query result and the execTrace information: } } ``` +**Note:** if using the SkyWalking native storage [BanyanDB](../setup/backend/storages/banyandb.md), +the debuggingTrace will include the BanyanDB internal execution trace info, such as: +```json +... +{ + "spanId": 7, + "parentSpanId": 6, + "operation": "BanyanDB: measure-grpc", + "startTime": 1720060447687765300, + "endTime": 1720060447688830200, + "duration": 1064900, + "msg": "[Tag(key=request, value={\"groups\":[\"measure-default\"], \"name\":\"service_sla_day\", \"timeRange\":{\"begin\":\"2024-07-02T16:00:00Z\", \"end\":\"2024-07-03T16:00:00Z\"}, \"criteria\":{\"condition\":{\"name\":\"entity_id\", \"op\":\"BINARY_OP_EQ\", \"value\":{\"str\":{\"value\":\"bW9ja19hX3NlcnZpY2U=.1\"}}}}, \"tagProjection\":{\"tagFamilies\":[{\"name\":\"storage-only\", \"tags\":[\"entity_id\"]}]}, \"fieldProjection\":{\"names\":[\"percentage\"]}, \"trace\":true})]", + "error": null +}, +{ +"spanId": 8, +"parentSpanId": 7, +"operation": "BanyanDB: data-0ebf3a27de83:17912", +"startTime": 1720060447687956700, +"endTime": 1720060447688810000, +"duration": 853300, +"msg": "[Tag(key=plan, value=IndexScan: startTime=1719936000,endTime=1720022400,Metadata{group=measure-default,name=service_sla_day},conditions=%!s(); projection=#storage-only:entity_id; order=OrderBy: [], sort=SORT_UNSPECIFIED; limit=100 Limit: 0, 100)]", +"error": null +}, +{ +"spanId": 9, +"parentSpanId": 8, +"operation": "BanyanDB: indexScan-group:\"measure-default\" name:\"service_sla_day\"", +"startTime": 1720060447687997400, +"endTime": 1720060447688664700, +"duration": 667300, +"msg": "[Tag(key=orderBy, value=time SORT_UNSPECIFIED), Tag(key=details, value=IndexScan: startTime=1719936000,endTime=1720022400,Metadata{group=measure-default,name=service_sla_day},conditions=%!s(); projection=#storage-only:entity_id; order=OrderBy: [], sort=SORT_UNSPECIFIED; limit=100)]", +"error": null +}, +{ +"spanId": 10, +"parentSpanId": 9, +"operation": "BanyanDB: seriesIndex.Search", +"startTime": 1720060447688023800, +"endTime": 1720060447688101800, +"duration": 78000, +"msg": "[]", +"error": null +}, +... +``` + ### Tracing SkyWalking Trace Query #### Tracing SkyWalking API queryBasicTraces @@ -389,8 +631,10 @@ Response will include query result and the execTrace information: ```graphql # Param, if debug is true will enable the query tracing and return DebuggingTrace in the result. extend type Query { - # Search segment list with given conditions - queryBasicTraces(condition: TraceQueryCondition, debug: Boolean): TraceBrief + # Search segment list with given conditions + queryBasicTraces(condition: TraceQueryCondition, debug: Boolean): TraceBrief + # Read the specific trace ID with given trace ID + queryTrace(traceId: ID!, debug: Boolean): Trace ... } ``` @@ -402,35 +646,74 @@ type TraceBrief { #For OAP internal query debugging debuggingTrace: DebuggingTrace } + +# The trace represents a distributed trace, includes all segments and spans. +type Trace { +... + #For OAP internal query debugging + debuggingTrace: DebuggingTrace +} ``` - Example -Same as the MQE query tracing, follow the GraphQL protocol and grammar to query the result and get debuggingTrace information, +Same as the MQE query tracing, follow the GraphQL protocol and grammar to query the result and get debuggingTrace information, just enable the debug parameter to true. -#### Tracing SkyWalking API queryTrace -- Bundle API: [Trace](../api/query-protocol.md#trace) +### Tracing Topology Query +- Bundle API: [Topology](../api/query-protocol.md#topology) -```graphql +```graphql # Param, if debug is true will enable the query tracing and return DebuggingTrace in the result. extend type Query { - # Read the specific trace ID with given trace ID - queryTrace(traceId: ID!, debug: Boolean): Trace - ... + # Query the global topology + # When layer is specified, the topology of this layer would be queried + getGlobalTopology(duration: Duration!, layer: String, debug: Boolean): Topology + # Query the topology, based on the given service + getServiceTopology(serviceId: ID!, duration: Duration!, debug: Boolean): Topology + # Query the topology, based on the given services. + # `#getServiceTopology` could be replaced by this. + getServicesTopology(serviceIds: [ID!]!, duration: Duration!, debug: Boolean): Topology + # Query the instance topology, based on the given clientServiceId and serverServiceId + getServiceInstanceTopology(clientServiceId: ID!, serverServiceId: ID!, duration: Duration!, debug: Boolean): ServiceInstanceTopology +... + # v2 of getEndpointTopology + getEndpointDependencies(endpointId: ID!, duration: Duration!, debug: Boolean): EndpointTopology + # Query the topology, based on the given instance + getProcessTopology(serviceInstanceId: ID!, duration: Duration!, debug: Boolean): ProcessTopology } ``` ```graphql -# The trace represents a distributed trace, includes all segments and spans. -type Trace { -... - #For OAP internal query debugging - debuggingTrace: DebuggingTrace +# The overview topology of the whole application cluster or services, +type Topology { + nodes: [Node!]! + calls: [Call!]! + debuggingTrace: DebuggingTrace +} + +# The instance topology based on the given serviceIds +type ServiceInstanceTopology { + nodes: [ServiceInstanceNode!]! + calls: [Call!]! + debuggingTrace: DebuggingTrace +} + +# The endpoint topology +type EndpointTopology { + nodes: [EndpointNode!]! + calls: [Call!]! + debuggingTrace: DebuggingTrace +} + +# The process topology +type ProcessTopology { + nodes: [ProcessNode!]! + calls: [Call!]! + debuggingTrace: DebuggingTrace } ``` - Example - Same as the MQE query tracing, follow the GraphQL protocol and grammar to query the result and get debuggingTrace information, just enable the debug parameter to true. diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/EndpointTopologyBuilder.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/EndpointTopologyBuilder.java new file mode 100644 index 000000000000..dc391ca0239d --- /dev/null +++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/EndpointTopologyBuilder.java @@ -0,0 +1,87 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.skywalking.oap.server.core.query; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import org.apache.skywalking.oap.server.core.analysis.IDManager; +import org.apache.skywalking.oap.server.core.query.type.Call; +import org.apache.skywalking.oap.server.core.query.type.EndpointNode; +import org.apache.skywalking.oap.server.core.query.type.EndpointTopology; +import org.apache.skywalking.oap.server.core.query.type.debugging.DebuggingSpan; +import org.apache.skywalking.oap.server.core.query.type.debugging.DebuggingTraceContext; +import org.apache.skywalking.oap.server.core.source.DetectPoint; + +public class EndpointTopologyBuilder { + + EndpointTopology buildDebuggable(List serverSideCalls) { + DebuggingTraceContext traceContext = DebuggingTraceContext.TRACE_CONTEXT.get(); + DebuggingSpan span = null; + try { + if (traceContext != null) { + span = traceContext.createSpan("Build endpoint topology"); + } + return build(serverSideCalls); + } finally { + if (traceContext != null && span != null) { + traceContext.stopSpan(span); + } + } + } + + EndpointTopology build(List serverSideCalls) { + EndpointTopology topology = new EndpointTopology(); + serverSideCalls.forEach(callDetail -> { + Call call = new Call(); + call.setId(callDetail.getId()); + call.setSource(callDetail.getSource()); + call.setTarget(callDetail.getTarget()); + call.addDetectPoint(DetectPoint.SERVER); + topology.getCalls().add(call); + }); + + Set nodeIds = new HashSet<>(); + serverSideCalls.forEach(call -> { + if (!nodeIds.contains(call.getSource())) { + topology.getNodes().add(buildEndpointDependencyNode(call.getSource())); + nodeIds.add(call.getSource()); + } + if (!nodeIds.contains(call.getTarget())) { + topology.getNodes().add(buildEndpointDependencyNode(call.getTarget())); + nodeIds.add(call.getTarget()); + } + }); + return topology; + } + + private EndpointNode buildEndpointDependencyNode(String endpointId) { + final IDManager.EndpointID.EndpointIDDefinition endpointIDDefinition = IDManager.EndpointID.analysisId( + endpointId); + EndpointNode instanceNode = new EndpointNode(); + instanceNode.setId(endpointId); + instanceNode.setName(endpointIDDefinition.getEndpointName()); + instanceNode.setServiceId(endpointIDDefinition.getServiceId()); + final IDManager.ServiceID.ServiceIDDefinition serviceIDDefinition = IDManager.ServiceID.analysisId( + endpointIDDefinition.getServiceId()); + instanceNode.setServiceName(serviceIDDefinition.getName()); + instanceNode.setReal(serviceIDDefinition.isReal()); + return instanceNode; + } +} diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/ProcessTopologyBuilder.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/ProcessTopologyBuilder.java index 1b79dcd24ad4..8cdf6e0cdc1f 100644 --- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/ProcessTopologyBuilder.java +++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/ProcessTopologyBuilder.java @@ -27,6 +27,8 @@ import org.apache.skywalking.oap.server.core.query.type.Call; import org.apache.skywalking.oap.server.core.query.type.ProcessNode; import org.apache.skywalking.oap.server.core.query.type.ProcessTopology; +import org.apache.skywalking.oap.server.core.query.type.debugging.DebuggingSpan; +import org.apache.skywalking.oap.server.core.query.type.debugging.DebuggingTraceContext; import org.apache.skywalking.oap.server.core.source.DetectPoint; import org.apache.skywalking.oap.server.core.storage.IMetricsDAO; import org.apache.skywalking.oap.server.core.storage.StorageDAO; @@ -68,6 +70,22 @@ public ProcessTopologyBuilder(ModuleManager moduleManager, StorageModels storage .getService(IComponentLibraryCatalogService.class); } + ProcessTopology buildDebuggable(List clientCalls, + List serverCalls) throws Exception { + DebuggingTraceContext traceContext = DebuggingTraceContext.TRACE_CONTEXT.get(); + DebuggingSpan span = null; + try { + if (traceContext != null) { + span = traceContext.createSpan("Build process topology"); + } + return build(clientCalls, serverCalls); + } finally { + if (traceContext != null && span != null) { + traceContext.stopSpan(span); + } + } + } + ProcessTopology build(List clientCalls, List serverCalls) throws Exception { log.debug("building process topology, total found client calls: {}, total found server calls: {}", diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/ServiceInstanceTopologyBuilder.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/ServiceInstanceTopologyBuilder.java index bf8ae8f6c315..3466c7d32730 100644 --- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/ServiceInstanceTopologyBuilder.java +++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/ServiceInstanceTopologyBuilder.java @@ -28,6 +28,8 @@ import org.apache.skywalking.oap.server.core.query.type.Call; import org.apache.skywalking.oap.server.core.query.type.ServiceInstanceNode; import org.apache.skywalking.oap.server.core.query.type.ServiceInstanceTopology; +import org.apache.skywalking.oap.server.core.query.type.debugging.DebuggingSpan; +import org.apache.skywalking.oap.server.core.query.type.debugging.DebuggingTraceContext; import org.apache.skywalking.oap.server.core.source.DetectPoint; import org.apache.skywalking.oap.server.library.module.ModuleManager; @@ -37,6 +39,22 @@ public class ServiceInstanceTopologyBuilder { public ServiceInstanceTopologyBuilder(ModuleManager moduleManager) { } + ServiceInstanceTopology buildDebuggable(List serviceInstanceRelationClientCalls, + List serviceInstanceRelationServerCalls) { + DebuggingTraceContext traceContext = DebuggingTraceContext.TRACE_CONTEXT.get(); + DebuggingSpan span = null; + try { + if (traceContext != null) { + span = traceContext.createSpan("Build service instance topology"); + } + return build(serviceInstanceRelationClientCalls, serviceInstanceRelationServerCalls); + } finally { + if (traceContext != null && span != null) { + traceContext.stopSpan(span); + } + } + } + ServiceInstanceTopology build(List serviceInstanceRelationClientCalls, List serviceInstanceRelationServerCalls) { diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/ServiceTopologyBuilder.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/ServiceTopologyBuilder.java index ba48400f740b..e953d7c6c35d 100644 --- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/ServiceTopologyBuilder.java +++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/ServiceTopologyBuilder.java @@ -35,6 +35,8 @@ import org.apache.skywalking.oap.server.core.query.type.Node; import org.apache.skywalking.oap.server.core.query.type.Service; import org.apache.skywalking.oap.server.core.query.type.Topology; +import org.apache.skywalking.oap.server.core.query.type.debugging.DebuggingSpan; +import org.apache.skywalking.oap.server.core.query.type.debugging.DebuggingTraceContext; import org.apache.skywalking.oap.server.core.source.DetectPoint; import org.apache.skywalking.oap.server.library.module.ModuleManager; import org.apache.skywalking.oap.server.library.util.StringUtil; @@ -67,6 +69,22 @@ private MetadataQueryService getMetadataQueryService() { return metadataQueryService; } + Topology buildDebuggable(List serviceRelationClientCalls, + List serviceRelationServerCalls) { + DebuggingTraceContext traceContext = DebuggingTraceContext.TRACE_CONTEXT.get(); + DebuggingSpan span = null; + try { + if (traceContext != null) { + span = traceContext.createSpan("Build service topology"); + } + return build(serviceRelationClientCalls, serviceRelationServerCalls); + } finally { + if (traceContext != null && span != null) { + traceContext.stopSpan(span); + } + } + } + Topology build(List serviceRelationClientCalls, List serviceRelationServerCalls) { Map nodes = new HashMap<>(); diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/TopologyQueryService.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/TopologyQueryService.java index 449428f4346c..f4a37f517703 100644 --- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/TopologyQueryService.java +++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/TopologyQueryService.java @@ -26,12 +26,13 @@ import org.apache.skywalking.oap.server.core.config.IComponentLibraryCatalogService; import org.apache.skywalking.oap.server.core.query.input.Duration; import org.apache.skywalking.oap.server.core.query.type.Call; -import org.apache.skywalking.oap.server.core.query.type.EndpointNode; import org.apache.skywalking.oap.server.core.query.type.EndpointTopology; import org.apache.skywalking.oap.server.core.query.type.Node; import org.apache.skywalking.oap.server.core.query.type.ProcessTopology; import org.apache.skywalking.oap.server.core.query.type.ServiceInstanceTopology; import org.apache.skywalking.oap.server.core.query.type.Topology; +import org.apache.skywalking.oap.server.core.query.type.debugging.DebuggingSpan; +import org.apache.skywalking.oap.server.core.query.type.debugging.DebuggingTraceContext; import org.apache.skywalking.oap.server.core.source.DetectPoint; import org.apache.skywalking.oap.server.core.storage.StorageModule; import org.apache.skywalking.oap.server.core.storage.model.StorageModels; @@ -50,6 +51,8 @@ import java.util.Set; import java.util.stream.Collectors; +import static org.apache.skywalking.oap.server.core.query.type.debugging.DebuggingTraceContext.TRACE_CONTEXT; + @Slf4j public class TopologyQueryService implements Service { private final ModuleManager moduleManager; @@ -87,30 +90,63 @@ private IComponentLibraryCatalogService getComponentLibraryCatalogService() { } public Topology getGlobalTopology(final Duration duration, final String layer) throws IOException { + DebuggingTraceContext traceContext = TRACE_CONTEXT.get(); + DebuggingSpan span = null; + try { + if (traceContext != null) { + span = traceContext.createSpan("Query Service: getGlobalTopology"); + span.setMsg("Duration: " + duration + ", Layer: " + layer); + } + return invokeGetGlobalTopology(duration, layer); + } finally { + if (traceContext != null && span != null) { + traceContext.stopSpan(span); + } + } + } + + private Topology invokeGetGlobalTopology(final Duration duration, final String layer) throws IOException { if (StringUtil.isNotEmpty(layer)) { final List serviceIdList = Optional.ofNullable(getMetadataQueryService().listServices(layer, null)) .map(list -> list.stream().map(s -> s.getId()).collect(Collectors.toList())) .orElse(Collections.emptyList()); return getServiceTopology(duration, serviceIdList); } - List serviceRelationServerCalls = getTopologyQueryDAO().loadServiceRelationsDetectedAtServerSide( + List serviceRelationServerCalls = getTopologyQueryDAO().loadServiceRelationsDetectedAtServerSideDebuggable( duration); - List serviceRelationClientCalls = getTopologyQueryDAO().loadServiceRelationDetectedAtClientSide( + List serviceRelationClientCalls = getTopologyQueryDAO().loadServiceRelationDetectedAtClientSideDebuggable( duration); ServiceTopologyBuilder builder = new ServiceTopologyBuilder(moduleManager); - return builder.build(serviceRelationClientCalls, serviceRelationServerCalls); + return builder.buildDebuggable(serviceRelationClientCalls, serviceRelationServerCalls); } public Topology getServiceTopology(final Duration duration, + final List serviceIds) throws IOException { + DebuggingTraceContext traceContext = TRACE_CONTEXT.get(); + DebuggingSpan span = null; + try { + if (traceContext != null) { + span = traceContext.createSpan("Query Service: getServiceTopology"); + span.setMsg("Duration: " + duration + ", ServiceIds: " + serviceIds); + } + return invokeGetServiceTopology(duration, serviceIds); + } finally { + if (traceContext != null && span != null) { + traceContext.stopSpan(span); + } + } + } + + private Topology invokeGetServiceTopology(final Duration duration, final List serviceIds) throws IOException { - List serviceRelationClientCalls = getTopologyQueryDAO().loadServiceRelationDetectedAtClientSide( + List serviceRelationClientCalls = getTopologyQueryDAO().loadServiceRelationDetectedAtClientSideDebuggable( duration, serviceIds); - List serviceRelationServerCalls = getTopologyQueryDAO().loadServiceRelationsDetectedAtServerSide( + List serviceRelationServerCalls = getTopologyQueryDAO().loadServiceRelationsDetectedAtServerSideDebuggable( duration, serviceIds); ServiceTopologyBuilder builder = new ServiceTopologyBuilder(moduleManager); - Topology topology = builder.build(serviceRelationClientCalls, serviceRelationServerCalls); + Topology topology = builder.buildDebuggable(serviceRelationClientCalls, serviceRelationServerCalls); /** * The topology built above is complete. @@ -127,7 +163,7 @@ public Topology getServiceTopology(final Duration duration, }); if (CollectionUtils.isNotEmpty(outScopeSourceServiceIds)) { // If exist, query them as the server side to get the target's component. - List sourceCalls = getTopologyQueryDAO().loadServiceRelationsDetectedAtServerSide( + List sourceCalls = getTopologyQueryDAO().loadServiceRelationsDetectedAtServerSideDebuggable( duration, outScopeSourceServiceIds); topology.getNodes().forEach(node -> { if (Strings.isNullOrEmpty(node.getType())) { @@ -147,9 +183,27 @@ public Topology getServiceTopology(final Duration duration, public ServiceInstanceTopology getServiceInstanceTopology(final String clientServiceId, final String serverServiceId, final Duration duration) throws IOException { - List serviceInstanceRelationClientCalls = getTopologyQueryDAO().loadInstanceRelationDetectedAtClientSide( + DebuggingTraceContext traceContext = TRACE_CONTEXT.get(); + DebuggingSpan span = null; + try { + if (traceContext != null) { + span = traceContext.createSpan("Query Service: getServiceInstanceTopology"); + span.setMsg("ClientServiceId: " + clientServiceId + ", ServerServiceId: " + serverServiceId + ", Duration: " + duration); + } + return invokeGetServiceInstanceTopology(clientServiceId, serverServiceId, duration); + } finally { + if (traceContext != null && span != null) { + traceContext.stopSpan(span); + } + } + } + + private ServiceInstanceTopology invokeGetServiceInstanceTopology(final String clientServiceId, + final String serverServiceId, + final Duration duration) throws IOException { + List serviceInstanceRelationClientCalls = getTopologyQueryDAO().loadInstanceRelationDetectedAtClientSideDebuggable( clientServiceId, serverServiceId, duration); - List serviceInstanceRelationServerCalls = getTopologyQueryDAO().loadInstanceRelationDetectedAtServerSide( + List serviceInstanceRelationServerCalls = getTopologyQueryDAO().loadInstanceRelationDetectedAtServerSideDebuggable( clientServiceId, serverServiceId, duration); ServiceInstanceTopologyBuilder builder = new ServiceInstanceTopologyBuilder(moduleManager); @@ -189,37 +243,48 @@ public Topology getEndpointTopology(final Duration duration, public EndpointTopology getEndpointDependencies(final Duration duration, final String endpointId) throws IOException { - List serverSideCalls = getTopologyQueryDAO().loadEndpointRelation( - duration, endpointId); - - EndpointTopology topology = new EndpointTopology(); - serverSideCalls.forEach(callDetail -> { - Call call = new Call(); - call.setId(callDetail.getId()); - call.setSource(callDetail.getSource()); - call.setTarget(callDetail.getTarget()); - call.addDetectPoint(DetectPoint.SERVER); - topology.getCalls().add(call); - }); - - Set nodeIds = new HashSet<>(); - serverSideCalls.forEach(call -> { - if (!nodeIds.contains(call.getSource())) { - topology.getNodes().add(buildEndpointDependencyNode(call.getSource())); - nodeIds.add(call.getSource()); + DebuggingTraceContext traceContext = TRACE_CONTEXT.get(); + DebuggingSpan span = null; + try { + if (traceContext != null) { + span = traceContext.createSpan("Query Service: getEndpointDependencies"); + span.setMsg("Duration: " + duration + ", EndpointId: " + endpointId); } - if (!nodeIds.contains(call.getTarget())) { - topology.getNodes().add(buildEndpointDependencyNode(call.getTarget())); - nodeIds.add(call.getTarget()); + return invokeGetEndpointDependencies(duration, endpointId); + } finally { + if (traceContext != null && span != null) { + traceContext.stopSpan(span); } - }); + } + } - return topology; + private EndpointTopology invokeGetEndpointDependencies(final Duration duration, + final String endpointId) throws IOException { + List serverSideCalls = getTopologyQueryDAO().loadEndpointRelationDebuggable( + duration, endpointId); + EndpointTopologyBuilder builder = new EndpointTopologyBuilder(); + return builder.build(serverSideCalls); } public ProcessTopology getProcessTopology(final String instanceId, final Duration duration) throws Exception { - final List clientCalls = getTopologyQueryDAO().loadProcessRelationDetectedAtClientSide(instanceId, duration); - final List serverCalls = getTopologyQueryDAO().loadProcessRelationDetectedAtServerSide(instanceId, duration); + DebuggingTraceContext traceContext = TRACE_CONTEXT.get(); + DebuggingSpan span = null; + try { + if (traceContext != null) { + span = traceContext.createSpan("Query Service: getProcessTopology"); + span.setMsg("InstanceId: " + instanceId + ", Duration: " + duration); + } + return invokeGetProcessTopology(instanceId, duration); + } finally { + if (traceContext != null && span != null) { + traceContext.stopSpan(span); + } + } + } + + private ProcessTopology invokeGetProcessTopology(final String instanceId, final Duration duration) throws Exception { + final List clientCalls = getTopologyQueryDAO().loadProcessRelationDetectedAtClientSideDebuggable(instanceId, duration); + final List serverCalls = getTopologyQueryDAO().loadProcessRelationDetectedAtServerSideDebuggable(instanceId, duration); final ProcessTopologyBuilder topologyBuilder = new ProcessTopologyBuilder(moduleManager, storageModels); return topologyBuilder.build(clientCalls, serverCalls); @@ -236,18 +301,4 @@ private Node buildEndpointNode(String endpointId) { node.setReal(true); return node; } - - private EndpointNode buildEndpointDependencyNode(String endpointId) { - final IDManager.EndpointID.EndpointIDDefinition endpointIDDefinition = IDManager.EndpointID.analysisId( - endpointId); - EndpointNode instanceNode = new EndpointNode(); - instanceNode.setId(endpointId); - instanceNode.setName(endpointIDDefinition.getEndpointName()); - instanceNode.setServiceId(endpointIDDefinition.getServiceId()); - final IDManager.ServiceID.ServiceIDDefinition serviceIDDefinition = IDManager.ServiceID.analysisId( - endpointIDDefinition.getServiceId()); - instanceNode.setServiceName(serviceIDDefinition.getName()); - instanceNode.setReal(serviceIDDefinition.isReal()); - return instanceNode; - } } diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/type/EndpointTopology.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/type/EndpointTopology.java index 2510d9117fb3..4267c7596f8f 100644 --- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/type/EndpointTopology.java +++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/type/EndpointTopology.java @@ -21,11 +21,15 @@ import java.util.ArrayList; import java.util.List; import lombok.Getter; +import lombok.Setter; +import org.apache.skywalking.oap.server.core.query.type.debugging.DebuggingTrace; @Getter public class EndpointTopology { private final List nodes; private final List calls; + @Setter + private DebuggingTrace debuggingTrace; public EndpointTopology() { this.nodes = new ArrayList<>(); diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/type/ProcessTopology.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/type/ProcessTopology.java index 79518aa05ede..1ae63b937117 100644 --- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/type/ProcessTopology.java +++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/type/ProcessTopology.java @@ -22,14 +22,18 @@ import java.util.ArrayList; import java.util.List; +import lombok.Setter; +import org.apache.skywalking.oap.server.core.query.type.debugging.DebuggingTrace; @Getter public class ProcessTopology { private final List nodes; private final List calls; + @Setter + private DebuggingTrace debuggingTrace; public ProcessTopology() { this.nodes = new ArrayList<>(); this.calls = new ArrayList<>(); } -} \ No newline at end of file +} diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/type/ServiceInstanceTopology.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/type/ServiceInstanceTopology.java index 30070d13353a..2b38bd95b768 100644 --- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/type/ServiceInstanceTopology.java +++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/type/ServiceInstanceTopology.java @@ -21,12 +21,16 @@ import java.util.ArrayList; import java.util.List; import lombok.Getter; +import lombok.Setter; +import org.apache.skywalking.oap.server.core.query.type.debugging.DebuggingTrace; @Getter public class ServiceInstanceTopology { private final List nodes; private final List calls; + @Setter + private DebuggingTrace debuggingTrace; public ServiceInstanceTopology() { this.nodes = new ArrayList<>(); diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/type/Topology.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/type/Topology.java index 7b571157db25..274cb8dfb678 100644 --- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/type/Topology.java +++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/type/Topology.java @@ -21,11 +21,15 @@ import java.util.ArrayList; import java.util.List; import lombok.Getter; +import lombok.Setter; +import org.apache.skywalking.oap.server.core.query.type.debugging.DebuggingTrace; @Getter public class Topology { private final List nodes; private final List calls; + @Setter + private DebuggingTrace debuggingTrace; public Topology() { this.nodes = new ArrayList<>(); diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/query/ITopologyQueryDAO.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/query/ITopologyQueryDAO.java index 241591128324..f55d10c5a002 100644 --- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/query/ITopologyQueryDAO.java +++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/query/ITopologyQueryDAO.java @@ -26,9 +26,164 @@ import org.apache.skywalking.oap.server.core.analysis.manual.relation.service.ServiceRelationServerSideMetrics; import org.apache.skywalking.oap.server.core.query.input.Duration; import org.apache.skywalking.oap.server.core.query.type.Call; +import org.apache.skywalking.oap.server.core.query.type.debugging.DebuggingSpan; +import org.apache.skywalking.oap.server.core.query.type.debugging.DebuggingTraceContext; import org.apache.skywalking.oap.server.library.module.Service; public interface ITopologyQueryDAO extends Service { + default List loadServiceRelationsDetectedAtServerSideDebuggable(Duration duration) throws IOException { + DebuggingTraceContext traceContext = DebuggingTraceContext.TRACE_CONTEXT.get(); + DebuggingSpan span = null; + try { + if (traceContext != null) { + span = traceContext.createSpan("Query Dao: loadServiceRelationsDetectedAtServerSide"); + span.setMsg("Duration: " + duration); + } + return loadServiceRelationsDetectedAtServerSide(duration); + } finally { + if (traceContext != null && span != null) { + traceContext.stopSpan(span); + } + } + } + + default List loadServiceRelationDetectedAtClientSideDebuggable(Duration duration) throws IOException { + DebuggingTraceContext traceContext = DebuggingTraceContext.TRACE_CONTEXT.get(); + DebuggingSpan span = null; + try { + if (traceContext != null) { + span = traceContext.createSpan("Query Dao: loadServiceRelationDetectedAtClientSide"); + span.setMsg("Duration: " + duration); + } + return loadServiceRelationDetectedAtClientSide(duration); + } finally { + if (traceContext != null && span != null) { + traceContext.stopSpan(span); + } + } + } + + default List loadServiceRelationsDetectedAtServerSideDebuggable(Duration duration, + List serviceIds) throws IOException { + DebuggingTraceContext traceContext = DebuggingTraceContext.TRACE_CONTEXT.get(); + DebuggingSpan span = null; + try { + if (traceContext != null) { + span = traceContext.createSpan("Query Dao: loadServiceRelationsDetectedAtServerSide"); + span.setMsg("Duration: " + duration + ", ServiceIds: " + serviceIds); + } + return loadServiceRelationsDetectedAtServerSide(duration, serviceIds); + } finally { + if (traceContext != null && span != null) { + traceContext.stopSpan(span); + } + } + } + + default List loadServiceRelationDetectedAtClientSideDebuggable(Duration duration, + List serviceIds) throws IOException { + DebuggingTraceContext traceContext = DebuggingTraceContext.TRACE_CONTEXT.get(); + DebuggingSpan span = null; + try { + if (traceContext != null) { + span = traceContext.createSpan("Query Dao: loadServiceRelationDetectedAtClientSide"); + span.setMsg("Duration: " + duration + ", ServiceIds: " + serviceIds); + } + return loadServiceRelationDetectedAtClientSide(duration, serviceIds); + } finally { + if (traceContext != null && span != null) { + traceContext.stopSpan(span); + } + } + } + + default List loadInstanceRelationDetectedAtServerSideDebuggable(String clientServiceId, + String serverServiceId, + Duration duration) throws IOException { + DebuggingTraceContext traceContext = DebuggingTraceContext.TRACE_CONTEXT.get(); + DebuggingSpan span = null; + try { + if (traceContext != null) { + span = traceContext.createSpan("Query Dao: loadInstanceRelationDetectedAtServerSide"); + span.setMsg("ClientServiceId: " + clientServiceId + ", ServerServiceId: " + serverServiceId + ", Duration: " + duration); + } + return loadInstanceRelationDetectedAtServerSide(clientServiceId, serverServiceId, duration); + } finally { + if (traceContext != null && span != null) { + traceContext.stopSpan(span); + } + } + } + + default List loadInstanceRelationDetectedAtClientSideDebuggable(String clientServiceId, + String serverServiceId, + Duration duration) throws IOException { + DebuggingTraceContext traceContext = DebuggingTraceContext.TRACE_CONTEXT.get(); + DebuggingSpan span = null; + try { + if (traceContext != null) { + span = traceContext.createSpan("Query Dao: loadInstanceRelationDetectedAtClientSide"); + span.setMsg("ClientServiceId: " + clientServiceId + ", ServerServiceId: " + serverServiceId + ", Duration: " + duration); + } + return loadInstanceRelationDetectedAtClientSide(clientServiceId, serverServiceId, duration); + } finally { + if (traceContext != null && span != null) { + traceContext.stopSpan(span); + } + } + } + + default List loadEndpointRelationDebuggable(Duration duration, + String destEndpointId) throws IOException { + DebuggingTraceContext traceContext = DebuggingTraceContext.TRACE_CONTEXT.get(); + DebuggingSpan span = null; + try { + if (traceContext != null) { + span = traceContext.createSpan("Query Dao: loadEndpointRelation"); + span.setMsg("Duration: " + duration + ", DestEndpointId: " + destEndpointId); + } + return loadEndpointRelation(duration, destEndpointId); + } finally { + if (traceContext != null && span != null) { + traceContext.stopSpan(span); + } + } + } + + default List loadProcessRelationDetectedAtClientSideDebuggable(String serviceInstanceId, + Duration duration) throws IOException { + DebuggingTraceContext traceContext = DebuggingTraceContext.TRACE_CONTEXT.get(); + DebuggingSpan span = null; + try { + if (traceContext != null) { + span = traceContext.createSpan("Query Dao: loadProcessRelationDetectedAtClientSide"); + span.setMsg("ServiceInstanceId: " + serviceInstanceId + ", Duration: " + duration); + } + return loadProcessRelationDetectedAtClientSide(serviceInstanceId, duration); + } finally { + if (traceContext != null && span != null) { + traceContext.stopSpan(span); + } + } + } + + default List loadProcessRelationDetectedAtServerSideDebuggable(String serviceInstanceId, + Duration duration) throws IOException { + DebuggingTraceContext traceContext = DebuggingTraceContext.TRACE_CONTEXT.get(); + DebuggingSpan span = null; + try { + if (traceContext != null) { + span = traceContext.createSpan("Query Dao: loadProcessRelationDetectedAtServerSide"); + span.setMsg("ServiceInstanceId: " + serviceInstanceId + ", Duration: " + duration); + } + return loadProcessRelationDetectedAtServerSide(serviceInstanceId, duration); + } finally { + if (traceContext != null && span != null) { + traceContext.stopSpan(span); + } + } + } + /** * Query {@link ServiceRelationServerSideMetrics} through the given conditions */ diff --git a/oap-server/server-query-plugin/debugging-query-plugin/src/main/java/org/apache/skywalking/oap/query/debug/DebuggingHTTPHandler.java b/oap-server/server-query-plugin/debugging-query-plugin/src/main/java/org/apache/skywalking/oap/query/debug/DebuggingHTTPHandler.java index db761b08b686..4e8b8c19828c 100644 --- a/oap-server/server-query-plugin/debugging-query-plugin/src/main/java/org/apache/skywalking/oap/query/debug/DebuggingHTTPHandler.java +++ b/oap-server/server-query-plugin/debugging-query-plugin/src/main/java/org/apache/skywalking/oap/query/debug/DebuggingHTTPHandler.java @@ -27,6 +27,7 @@ import com.google.gson.Gson; import com.linecorp.armeria.common.AggregatedHttpResponse; import com.linecorp.armeria.server.annotation.Default; +import com.linecorp.armeria.server.annotation.ExceptionHandler; import com.linecorp.armeria.server.annotation.Get; import com.linecorp.armeria.server.annotation.Param; import java.util.ArrayList; @@ -39,11 +40,16 @@ import lombok.extern.slf4j.Slf4j; import org.apache.skywalking.mqe.rt.type.ExpressionResult; import org.apache.skywalking.oap.query.debug.mqe.DebuggingMQERsp; +import org.apache.skywalking.oap.query.debug.topology.DebuggingQueryEndpointTopologyRsp; +import org.apache.skywalking.oap.query.debug.topology.DebuggingQueryInstanceTopologyRsp; +import org.apache.skywalking.oap.query.debug.topology.DebuggingQueryProcessTopologyRsp; +import org.apache.skywalking.oap.query.debug.topology.DebuggingQueryServiceTopologyRsp; import org.apache.skywalking.oap.query.debug.trace.DebuggingQueryTraceBriefRsp; import org.apache.skywalking.oap.query.debug.trace.DebuggingQueryTraceRsp; import org.apache.skywalking.oap.query.debug.trace.zipkin.DebuggingZipkinQueryTraceRsp; import org.apache.skywalking.oap.query.debug.trace.zipkin.DebuggingZipkinQueryTracesRsp; import org.apache.skywalking.oap.query.graphql.resolver.MetricsExpressionQuery; +import org.apache.skywalking.oap.query.graphql.resolver.TopologyQuery; import org.apache.skywalking.oap.query.graphql.resolver.TraceQuery; import org.apache.skywalking.oap.query.zipkin.ZipkinQueryConfig; import org.apache.skywalking.oap.query.zipkin.handler.ZipkinQueryHandler; @@ -56,8 +62,12 @@ import org.apache.skywalking.oap.server.core.query.input.Duration; import org.apache.skywalking.oap.server.core.query.input.Entity; import org.apache.skywalking.oap.server.core.query.input.TraceQueryCondition; +import org.apache.skywalking.oap.server.core.query.type.EndpointTopology; import org.apache.skywalking.oap.server.core.query.type.Pagination; +import org.apache.skywalking.oap.server.core.query.type.ProcessTopology; import org.apache.skywalking.oap.server.core.query.type.QueryOrder; +import org.apache.skywalking.oap.server.core.query.type.ServiceInstanceTopology; +import org.apache.skywalking.oap.server.core.query.type.Topology; import org.apache.skywalking.oap.server.core.query.type.Trace; import org.apache.skywalking.oap.server.core.query.type.TraceBrief; import org.apache.skywalking.oap.server.core.query.type.TraceState; @@ -69,11 +79,13 @@ import zipkin2.Span; @Slf4j +@ExceptionHandler(DebuggingQueryExceptionHandler.class) public class DebuggingHTTPHandler { private final ServerStatusService serverStatusService; private final MetricsExpressionQuery mqeQuery; private final TraceQuery traceQuery; private final ZipkinQueryHandler zipkinQueryHandler; + private final TopologyQuery topologyQuery; final DebuggingQueryConfig config; public DebuggingHTTPHandler(final ModuleManager manager, final DebuggingQueryConfig config) { @@ -85,6 +97,7 @@ public DebuggingHTTPHandler(final ModuleManager manager, final DebuggingQueryCon this.traceQuery = new TraceQuery(manager); //use zipkin default config for debugging this.zipkinQueryHandler = new ZipkinQueryHandler(new ZipkinQueryConfig(), manager); + this.topologyQuery = new TopologyQuery(manager); } @Get("/debugging/config/dump") @@ -266,6 +279,104 @@ public String getZipkinTraceById(@Param("traceId") String traceId) { } } + @SneakyThrows + @Get("/debugging/query/topology/getGlobalTopology") + public String getGlobalTopology(@Param("startTime") String startTime, + @Param("endTime") String endTime, + @Param("step") String step, + @Param("serviceLayer") Optional serviceLayer) { + Duration duration = new Duration(); + duration.setStart(startTime); + duration.setEnd(endTime); + duration.setStep(Step.valueOf(step)); + Topology topology = topologyQuery.getGlobalTopology(duration, serviceLayer.orElse(null), true); + DebuggingQueryServiceTopologyRsp result = new DebuggingQueryServiceTopologyRsp( + topology.getNodes(), topology.getCalls(), transformTrace(topology.getDebuggingTrace())); + return transToYAMLString(result); + } + + @SneakyThrows + @Get("/debugging/query/topology/getServicesTopology") + public String getServicesTopology(@Param("startTime") String startTime, + @Param("endTime") String endTime, + @Param("step") String step, + @Param("serviceLayer") String serviceLayer, + @Param("services") String services) { + Duration duration = new Duration(); + duration.setStart(startTime); + duration.setEnd(endTime); + duration.setStep(Step.valueOf(step)); + + List ids = Arrays.stream(services.split(Const.COMMA)) + .map(name -> IDManager.ServiceID.buildId(name, Layer.nameOf(serviceLayer).isNormal())) + .collect(Collectors.toList()); + Topology topology = topologyQuery.getServicesTopology(ids, duration, true); + DebuggingQueryServiceTopologyRsp result = new DebuggingQueryServiceTopologyRsp( + topology.getNodes(), topology.getCalls(), transformTrace(topology.getDebuggingTrace())); + return transToYAMLString(result); + } + + @SneakyThrows + @Get("/debugging/query/topology/getServiceInstanceTopology") + public String getServiceInstanceTopology(@Param("startTime") String startTime, + @Param("endTime") String endTime, + @Param("step") String step, + @Param("clientService") String clientService, + @Param("serverService") String serverService, + @Param("clientServiceLayer") String clientServiceLayer, + @Param("serverServiceLayer") String serverServiceLayer) { + Duration duration = new Duration(); + duration.setStart(startTime); + duration.setEnd(endTime); + duration.setStep(Step.valueOf(step)); + String clientServiceId = IDManager.ServiceID.buildId(clientService, Layer.nameOf(clientServiceLayer).isNormal()); + String serverServiceId = IDManager.ServiceID.buildId(serverService, Layer.nameOf(serverServiceLayer).isNormal()); + ServiceInstanceTopology topology = topologyQuery.getServiceInstanceTopology(clientServiceId, serverServiceId, duration, true); + DebuggingQueryInstanceTopologyRsp result = new DebuggingQueryInstanceTopologyRsp( + topology.getNodes(), topology.getCalls(), transformTrace(topology.getDebuggingTrace())); + return transToYAMLString(result); + } + + @SneakyThrows + @Get("/debugging/query/topology/getEndpointDependencies") + public String getEndpointDependencies(@Param("startTime") String startTime, + @Param("endTime") String endTime, + @Param("step") String step, + @Param("service") String service, + @Param("serviceLayer") String serviceLayer, + @Param("endpoint") String endpoint) { + Duration duration = new Duration(); + duration.setStart(startTime); + duration.setEnd(endTime); + duration.setStep(Step.valueOf(step)); + String endpointId = IDManager.EndpointID.buildId( + IDManager.ServiceID.buildId(service, Layer.nameOf(serviceLayer).isNormal()), endpoint); + EndpointTopology topology = topologyQuery.getEndpointDependencies(endpointId, duration, true); + DebuggingQueryEndpointTopologyRsp result = new DebuggingQueryEndpointTopologyRsp( + topology.getNodes(), topology.getCalls(), transformTrace(topology.getDebuggingTrace())); + return transToYAMLString(result); + } + + @SneakyThrows + @Get("/debugging/query/topology/getProcessTopology") + public String getProcessTopology(@Param("startTime") String startTime, + @Param("endTime") String endTime, + @Param("step") String step, + @Param("service") String service, + @Param("serviceLayer") String serviceLayer, + @Param("instance") String process) { + Duration duration = new Duration(); + duration.setStart(startTime); + duration.setEnd(endTime); + duration.setStep(Step.valueOf(step)); + String instanceId = IDManager.ServiceInstanceID.buildId( + IDManager.ServiceID.buildId(service, Layer.nameOf(serviceLayer).isNormal()), process); + ProcessTopology topology = topologyQuery.getProcessTopology(instanceId, duration, true); + DebuggingQueryProcessTopologyRsp result = new DebuggingQueryProcessTopologyRsp( + topology.getNodes(), topology.getCalls(), transformTrace(topology.getDebuggingTrace())); + return transToYAMLString(result); + } + private DebuggingTraceRsp transformTrace(DebuggingTrace trace) { Map spanMap = trace.getSpans().stream() .collect(Collectors.toMap( diff --git a/oap-server/server-query-plugin/debugging-query-plugin/src/main/java/org/apache/skywalking/oap/query/debug/DebuggingQueryExceptionHandler.java b/oap-server/server-query-plugin/debugging-query-plugin/src/main/java/org/apache/skywalking/oap/query/debug/DebuggingQueryExceptionHandler.java new file mode 100644 index 000000000000..5bede1f43020 --- /dev/null +++ b/oap-server/server-query-plugin/debugging-query-plugin/src/main/java/org/apache/skywalking/oap/query/debug/DebuggingQueryExceptionHandler.java @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.skywalking.oap.query.debug; + +import com.linecorp.armeria.common.HttpRequest; +import com.linecorp.armeria.common.HttpResponse; +import com.linecorp.armeria.server.ServiceRequestContext; +import com.linecorp.armeria.server.annotation.ExceptionHandlerFunction; +import lombok.extern.slf4j.Slf4j; + +import static com.linecorp.armeria.common.HttpStatus.BAD_REQUEST; +import static com.linecorp.armeria.common.HttpStatus.INTERNAL_SERVER_ERROR; +import static com.linecorp.armeria.common.MediaType.ANY_TEXT_TYPE; + +@Slf4j +public class DebuggingQueryExceptionHandler implements ExceptionHandlerFunction { + @Override + public HttpResponse handleException(final ServiceRequestContext ctx, final HttpRequest req, final Throwable cause) { + String rspMsg = cause.getMessage() != null ? cause.getMessage() : cause.getClass().getSimpleName(); + // Response msg for illegal query args. + if (cause instanceof IllegalArgumentException) { + log.error(cause.getMessage(), cause); + return HttpResponse.of(BAD_REQUEST, ANY_TEXT_TYPE, rspMsg); + } else { + log.error(cause.getMessage(), cause); + return HttpResponse.of(INTERNAL_SERVER_ERROR, ANY_TEXT_TYPE, rspMsg); + } + } +} diff --git a/oap-server/server-query-plugin/debugging-query-plugin/src/main/java/org/apache/skywalking/oap/query/debug/topology/DebuggingQueryEndpointTopologyRsp.java b/oap-server/server-query-plugin/debugging-query-plugin/src/main/java/org/apache/skywalking/oap/query/debug/topology/DebuggingQueryEndpointTopologyRsp.java new file mode 100644 index 000000000000..483ca7fbf3d4 --- /dev/null +++ b/oap-server/server-query-plugin/debugging-query-plugin/src/main/java/org/apache/skywalking/oap/query/debug/topology/DebuggingQueryEndpointTopologyRsp.java @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.skywalking.oap.query.debug.topology; + +import java.util.List; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import org.apache.skywalking.oap.query.debug.DebuggingTraceRsp; +import org.apache.skywalking.oap.server.core.query.type.Call; +import org.apache.skywalking.oap.server.core.query.type.EndpointNode; + +@RequiredArgsConstructor +@Getter +public class DebuggingQueryEndpointTopologyRsp { + private final List nodes; + private final List calls; + private final DebuggingTraceRsp debuggingTrace; +} diff --git a/oap-server/server-query-plugin/debugging-query-plugin/src/main/java/org/apache/skywalking/oap/query/debug/topology/DebuggingQueryInstanceTopologyRsp.java b/oap-server/server-query-plugin/debugging-query-plugin/src/main/java/org/apache/skywalking/oap/query/debug/topology/DebuggingQueryInstanceTopologyRsp.java new file mode 100644 index 000000000000..a7d1c1db90cf --- /dev/null +++ b/oap-server/server-query-plugin/debugging-query-plugin/src/main/java/org/apache/skywalking/oap/query/debug/topology/DebuggingQueryInstanceTopologyRsp.java @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.skywalking.oap.query.debug.topology; + +import java.util.List; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import org.apache.skywalking.oap.query.debug.DebuggingTraceRsp; +import org.apache.skywalking.oap.server.core.query.type.Call; +import org.apache.skywalking.oap.server.core.query.type.ServiceInstanceNode; + +@RequiredArgsConstructor +@Getter +public class DebuggingQueryInstanceTopologyRsp { + private final List nodes; + private final List calls; + private final DebuggingTraceRsp debuggingTrace; +} diff --git a/oap-server/server-query-plugin/debugging-query-plugin/src/main/java/org/apache/skywalking/oap/query/debug/topology/DebuggingQueryProcessTopologyRsp.java b/oap-server/server-query-plugin/debugging-query-plugin/src/main/java/org/apache/skywalking/oap/query/debug/topology/DebuggingQueryProcessTopologyRsp.java new file mode 100644 index 000000000000..eb0e5bf8be11 --- /dev/null +++ b/oap-server/server-query-plugin/debugging-query-plugin/src/main/java/org/apache/skywalking/oap/query/debug/topology/DebuggingQueryProcessTopologyRsp.java @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.skywalking.oap.query.debug.topology; + +import java.util.List; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import org.apache.skywalking.oap.query.debug.DebuggingTraceRsp; +import org.apache.skywalking.oap.server.core.query.type.Call; +import org.apache.skywalking.oap.server.core.query.type.ProcessNode; + +@RequiredArgsConstructor +@Getter +public class DebuggingQueryProcessTopologyRsp { + private final List nodes; + private final List calls; + private final DebuggingTraceRsp debuggingTrace; +} diff --git a/oap-server/server-query-plugin/debugging-query-plugin/src/main/java/org/apache/skywalking/oap/query/debug/topology/DebuggingQueryServiceTopologyRsp.java b/oap-server/server-query-plugin/debugging-query-plugin/src/main/java/org/apache/skywalking/oap/query/debug/topology/DebuggingQueryServiceTopologyRsp.java new file mode 100644 index 000000000000..c421787c3835 --- /dev/null +++ b/oap-server/server-query-plugin/debugging-query-plugin/src/main/java/org/apache/skywalking/oap/query/debug/topology/DebuggingQueryServiceTopologyRsp.java @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.skywalking.oap.query.debug.topology; + +import java.util.List; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import org.apache.skywalking.oap.query.debug.DebuggingTraceRsp; +import org.apache.skywalking.oap.server.core.query.type.Call; +import org.apache.skywalking.oap.server.core.query.type.Node; + +@RequiredArgsConstructor +@Getter +public class DebuggingQueryServiceTopologyRsp { + private final List nodes; + private final List calls; + private final DebuggingTraceRsp debuggingTrace; +} diff --git a/oap-server/server-query-plugin/query-graphql-plugin/src/main/java/org/apache/skywalking/oap/query/graphql/resolver/TopologyQuery.java b/oap-server/server-query-plugin/query-graphql-plugin/src/main/java/org/apache/skywalking/oap/query/graphql/resolver/TopologyQuery.java index 7328a272af59..b161b4cbb3f4 100644 --- a/oap-server/server-query-plugin/query-graphql-plugin/src/main/java/org/apache/skywalking/oap/query/graphql/resolver/TopologyQuery.java +++ b/oap-server/server-query-plugin/query-graphql-plugin/src/main/java/org/apache/skywalking/oap/query/graphql/resolver/TopologyQuery.java @@ -29,8 +29,12 @@ import org.apache.skywalking.oap.server.core.query.type.ProcessTopology; import org.apache.skywalking.oap.server.core.query.type.ServiceInstanceTopology; import org.apache.skywalking.oap.server.core.query.type.Topology; +import org.apache.skywalking.oap.server.core.query.type.debugging.DebuggingSpan; +import org.apache.skywalking.oap.server.core.query.type.debugging.DebuggingTraceContext; import org.apache.skywalking.oap.server.library.module.ModuleManager; +import static org.apache.skywalking.oap.server.core.query.type.debugging.DebuggingTraceContext.TRACE_CONTEXT; + public class TopologyQuery implements GraphQLQueryResolver { private final ModuleManager moduleManager; @@ -47,31 +51,97 @@ private TopologyQueryService getQueryService() { return queryService; } - public Topology getGlobalTopology(final Duration duration, final String layer) throws IOException { - return getQueryService().getGlobalTopology(duration, layer); + public Topology getGlobalTopology(final Duration duration, + final String layer, + final boolean debug) throws IOException { + DebuggingTraceContext traceContext = new DebuggingTraceContext( + "Duration: " + duration + ", Layer: " + layer, debug, false); + DebuggingTraceContext.TRACE_CONTEXT.set(traceContext); + DebuggingSpan span = traceContext.createSpan("Query global topology"); + try { + Topology topology = getQueryService().getGlobalTopology(duration, layer); + if (debug) { + topology.setDebuggingTrace(traceContext.getExecTrace()); + } + return topology; + } finally { + traceContext.stopSpan(span); + traceContext.stopTrace(); + TRACE_CONTEXT.remove(); + } } - public Topology getServiceTopology(final String serviceId, final Duration duration) throws IOException { - List selectedServiceList = new ArrayList<>(1); - selectedServiceList.add(serviceId); - return this.getServicesTopology(selectedServiceList, duration); + public Topology getServiceTopology(final String serviceId, + final Duration duration, + final boolean debug) throws IOException { + DebuggingTraceContext traceContext = new DebuggingTraceContext( + "ServiceId: " + serviceId + "Duration: " + duration, debug, false); + DebuggingTraceContext.TRACE_CONTEXT.set(traceContext); + DebuggingSpan span = traceContext.createSpan("Query service topology"); + try { + List selectedServiceList = new ArrayList<>(1); + selectedServiceList.add(serviceId); + Topology topology = this.getServicesTopology(selectedServiceList, duration, debug); + if (debug) { + topology.setDebuggingTrace(traceContext.getExecTrace()); + } + return topology; + } finally { + + traceContext.stopSpan(span); + traceContext.stopTrace(); + TRACE_CONTEXT.remove(); + } } - public Topology getServicesTopology(final List serviceIds, final Duration duration) throws IOException { - return getQueryService().getServiceTopology(duration, serviceIds); + public Topology getServicesTopology(final List serviceIds, + final Duration duration, + final boolean debug) throws IOException { + DebuggingTraceContext traceContext = new DebuggingTraceContext( + "ServiceIds: " + serviceIds + "Duration: " + duration, debug, false); + DebuggingTraceContext.TRACE_CONTEXT.set(traceContext); + DebuggingSpan span = traceContext.createSpan("Query service topology"); + try { + Topology topology = getQueryService().getServiceTopology(duration, serviceIds); + if (debug) { + topology.setDebuggingTrace(traceContext.getExecTrace()); + } + return topology; + } finally { + traceContext.stopSpan(span); + traceContext.stopTrace(); + TRACE_CONTEXT.remove(); + } } public ServiceInstanceTopology getServiceInstanceTopology(final String clientServiceId, final String serverServiceId, - final Duration duration) throws IOException { - return getQueryService().getServiceInstanceTopology( - clientServiceId, serverServiceId, - duration + final Duration duration, + final boolean debug) throws IOException { + DebuggingTraceContext traceContext = new DebuggingTraceContext( + "ClientServiceId: " + clientServiceId + ", ServerServiceId: " + serverServiceId + ", Duration: " + duration, + debug, false ); + DebuggingTraceContext.TRACE_CONTEXT.set(traceContext); + DebuggingSpan span = traceContext.createSpan("Query service instance topology"); + try { + ServiceInstanceTopology topology = getQueryService().getServiceInstanceTopology( + clientServiceId, serverServiceId, + duration + ); + if (debug) { + topology.setDebuggingTrace(traceContext.getExecTrace()); + } + return topology; + } finally { + traceContext.stopSpan(span); + traceContext.stopTrace(); + TRACE_CONTEXT.remove(); + } } /** - * Replaced by {@link #getEndpointDependencies(String, Duration)} + * Replaced by {@link #getEndpointDependencies(String, Duration, boolean)} */ @Deprecated public Topology getEndpointTopology(final String endpointId, final Duration duration) throws IOException { @@ -79,11 +149,40 @@ public Topology getEndpointTopology(final String endpointId, final Duration dura } public EndpointTopology getEndpointDependencies(final String endpointId, - final Duration duration) throws IOException { - return getQueryService().getEndpointDependencies(duration, endpointId); + final Duration duration, + final boolean debug) throws IOException { + DebuggingTraceContext traceContext = new DebuggingTraceContext( + "EndpointId: " + endpointId + ", Duration: " + duration, debug, false); + DebuggingTraceContext.TRACE_CONTEXT.set(traceContext); + DebuggingSpan span = traceContext.createSpan("Query endpoint dependencies"); + try { + EndpointTopology topology = getQueryService().getEndpointDependencies(duration, endpointId); + if (debug) { + topology.setDebuggingTrace(traceContext.getExecTrace()); + } + return topology; + } finally { + traceContext.stopSpan(span); + traceContext.stopTrace(); + TRACE_CONTEXT.remove(); + } } - public ProcessTopology getProcessTopology(final String instanceId, final Duration duration) throws Exception { - return getQueryService().getProcessTopology(instanceId, duration); + public ProcessTopology getProcessTopology(final String instanceId, final Duration duration, final boolean debug) throws Exception { + DebuggingTraceContext traceContext = new DebuggingTraceContext( + "InstanceId: " + instanceId + ", Duration: " + duration, debug, false); + DebuggingTraceContext.TRACE_CONTEXT.set(traceContext); + DebuggingSpan span = traceContext.createSpan("Query process topology"); + try { + ProcessTopology topology = getQueryService().getProcessTopology(instanceId, duration); + if (debug) { + topology.setDebuggingTrace(traceContext.getExecTrace()); + } + return topology; + } finally { + traceContext.stopSpan(span); + traceContext.stopTrace(); + TRACE_CONTEXT.remove(); + } } } 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 ee577ac283c1..e93484a89c9d 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 ee577ac283c1e0b418d9da502deba41dfbcb28c3 +Subproject commit e93484a89c9d59fda8303f1dc3cac78e64f56bf7 diff --git a/oap-server/server-storage-plugin/storage-banyandb-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/banyandb/measure/BanyanDBTopologyQueryDAO.java b/oap-server/server-storage-plugin/storage-banyandb-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/banyandb/measure/BanyanDBTopologyQueryDAO.java index e1cd297ee378..e91fe30d4393 100644 --- a/oap-server/server-storage-plugin/storage-banyandb-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/banyandb/measure/BanyanDBTopologyQueryDAO.java +++ b/oap-server/server-storage-plugin/storage-banyandb-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/banyandb/measure/BanyanDBTopologyQueryDAO.java @@ -34,6 +34,7 @@ import org.apache.skywalking.banyandb.v1.client.MeasureQueryResponse; import org.apache.skywalking.banyandb.v1.client.TimestampRange; import org.apache.skywalking.oap.server.core.UnexpectedException; +import org.apache.skywalking.oap.server.core.analysis.DownSampling; import org.apache.skywalking.oap.server.core.analysis.TimeBucket; import org.apache.skywalking.oap.server.core.analysis.manual.relation.endpoint.EndpointRelationServerSideMetrics; import org.apache.skywalking.oap.server.core.analysis.manual.relation.instance.ServiceInstanceRelationClientSideMetrics; @@ -205,7 +206,7 @@ List queryInstanceRelation(Duration duration, final String modelName = detectPoint == DetectPoint.SERVER ? ServiceInstanceRelationServerSideMetrics.INDEX_NAME : ServiceInstanceRelationClientSideMetrics.INDEX_NAME; MetadataRegistry.Schema schema = MetadataRegistry.INSTANCE.findMetadata(modelName, duration.getStep()); - MeasureQueryResponse resp = query(schema, + MeasureQueryResponse resp = queryDebuggable(schema, ImmutableSet.of( Metrics.ENTITY_ID ), @@ -269,7 +270,7 @@ List queryEndpointRelation(Duration duration, timestampRange = new TimestampRange(TimeBucket.getTimestamp(startTB), TimeBucket.getTimestamp(endTB)); } MetadataRegistry.Schema schema = MetadataRegistry.INSTANCE.findMetadata(EndpointRelationServerSideMetrics.INDEX_NAME, duration.getStep()); - MeasureQueryResponse resp = query(schema, + MeasureQueryResponse resp = queryDebuggable(schema, ImmutableSet.of( Metrics.ENTITY_ID ), @@ -303,8 +304,9 @@ List queryProcessRelation(Duration duration, } final String modelName = detectPoint == DetectPoint.SERVER ? ProcessRelationServerSideMetrics.INDEX_NAME : ProcessRelationClientSideMetrics.INDEX_NAME; - MetadataRegistry.Schema schema = MetadataRegistry.INSTANCE.findMetadata(modelName, duration.getStep()); - MeasureQueryResponse resp = query(schema, + // process relation only has minute data + MetadataRegistry.Schema schema = MetadataRegistry.INSTANCE.findMetadata(modelName, DownSampling.Minute); + MeasureQueryResponse resp = queryDebuggable(schema, ImmutableSet.of(Metrics.ENTITY_ID, ProcessRelationClientSideMetrics.COMPONENT_ID), Collections.emptySet(), timestampRange, new QueryBuilder() { @Override diff --git a/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/base/EsDAO.java b/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/base/EsDAO.java index 4af0614790e1..e070eccb6b72 100644 --- a/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/base/EsDAO.java +++ b/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/base/EsDAO.java @@ -65,6 +65,10 @@ protected SearchResponse searchDebuggable(Supplier indices, Search sea } } + protected SearchResponse searchDebuggable(String indexName, Search search) { + return searchDebuggable(indexName, search, null); + } + protected SearchResponse searchDebuggable(String indexName, Search search, SearchParams params) { DebuggingTraceContext traceContext = DebuggingTraceContext.TRACE_CONTEXT.get(); DebuggingSpan span = null; diff --git a/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/query/RecordsQueryEsDAO.java b/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/query/RecordsQueryEsDAO.java index 65023469ebeb..ce6663f927ea 100644 --- a/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/query/RecordsQueryEsDAO.java +++ b/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/query/RecordsQueryEsDAO.java @@ -71,7 +71,7 @@ public List readRecords(final RecordCondition condition, ); final SearchResponse response = searchDebuggable( IndexController.LogicIndicesRegister.getPhysicalTableName(condition.getName()), - search.build(), null + search.build() ); List results = new ArrayList<>(condition.getTopN()); diff --git a/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/query/TopologyQueryEsDAO.java b/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/query/TopologyQueryEsDAO.java index 0d4f47a1f00b..a226c265bbf4 100644 --- a/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/query/TopologyQueryEsDAO.java +++ b/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/query/TopologyQueryEsDAO.java @@ -260,7 +260,7 @@ private List buildProcessRelation(String serviceInstanceId, if (IndexController.LogicIndicesRegister.isMergedTable(indexName)) { query.must(Query.term(IndexController.LogicIndicesRegister.METRIC_TABLE_NAME, indexName)); } - final SearchResponse response = getClient().search(index, sourceBuilder.build()); + final SearchResponse response = searchDebuggable(index, sourceBuilder.build()); final List calls = new ArrayList<>(); final Map entityTerms = @@ -300,7 +300,7 @@ private List buildServiceRelation(SearchBuilder sourceBuilder, final String index = IndexController.LogicIndicesRegister.getPhysicalTableName(indexName); - final SearchResponse response = getClient().search(index, sourceBuilder.build()); + final SearchResponse response = searchDebuggable(index, sourceBuilder.build()); final List calls = new ArrayList<>(); final Map entityTerms = @@ -337,7 +337,7 @@ private List buildInstanceRelation(SearchBuilder sourceBuilder, final String index = IndexController.LogicIndicesRegister.getPhysicalTableName(indexName); - SearchResponse response = getClient().search(index, sourceBuilder.build()); + SearchResponse response = searchDebuggable(index, sourceBuilder.build()); List calls = new ArrayList<>(); final Map entityTerms = @@ -365,7 +365,7 @@ private List loadEndpoint(SearchBuilder sourceBuilder, String i final String index = IndexController.LogicIndicesRegister.getPhysicalTableName(indexName); - final SearchResponse response = getClient().search(index, sourceBuilder.build()); + final SearchResponse response = searchDebuggable(index, sourceBuilder.build()); final List calls = new ArrayList<>(); final Map entityTerms =