diff --git a/README.md b/README.md
index ae0945a1..95c1dfdd 100644
--- a/README.md
+++ b/README.md
@@ -4,7 +4,7 @@ Apache SkyWalking CLI


-
+
The CLI (Command Line Interface) for [Apache SkyWalking](https://github.com/apache/skywalking).
@@ -103,314 +103,16 @@ command to create `$profile` file:
New-Item -Type file -Force $profile
```
-After reloading your shell, swctl auto-completion should be working.
-
-### `metrics`
-
-#### `metrics linear`
-
-
-
-metrics linear [--start=start-time] [--end=end-time] --name=metrics-name [--service=service-name] [--instance=instance-name] [--endpoint=endpoint-name] [--destService=dest-service-name] [--destInstance=dest-instance-name] [--destEndpoint=dest-endpoint-name] [--isDestNormal=true/false]
-
-| option | description | default |
-| :--- | :--- | :--- |
-| `--name` | Metrics name, defined in [OAL](https://github.com/apache/skywalking/blob/master/oap-server/server-bootstrap/src/main/resources/oal/core.oal). |
-| `--service` | The name of the service. | "" |
-| `--instance` | The name of the service instance. | "" |
-| `--endpoint` | The name of the endpoint. | "" |
-| `--destService` | The name of the destination service. | "" |
-| `--destInstance` | The name of the destination instance. | "" |
-| `--destEndpoint` | The name of the destination endpoint. | "" |
-| `--isDestNormal` | Set the destination service to normal or unnormal. | `true` |
-| `--start` | See [Common options](#common-options) | See [Common options](#common-options) |
-| `--end` | See [Common options](#common-options) | See [Common options](#common-options) |
-
-
-
-#### `metrics multiple-linear`
-
-
-
-metrics multiple-linear [--start=start-time] [--end=end-time] --name=metrics-name [--service=service-name] [--num=number-of-linear-metrics] [--instance=instance-name] [--endpoint=endpoint-name] [--isNormal=true/false] [--destService=dest-service-name] [--destInstance=dest-instance-name] [--destEndpoint=dest-endpoint-name] [--isDestNormal=true/false]
-
-| option | description | default |
-| :--- | :--- | :--- |
-| `--name` | Metrics name that ends with `_percentile`, defined in [OAL](https://github.com/apache/skywalking/blob/master/oap-server/server-bootstrap/src/main/resources/oal/core.oal), such as `all_percentile`, etc. |
-| `--service` | The name of the service, when scope is `All`, no name is required. | "" |
-| `--labels` | The labels you need to query | `0,1,2,3,4` |
-| `--instance` | The name of the service instance. | "" |
-| `--endpoint` | The name of the endpoint. | "" |
-| `--isNormal` | Set the service to normal or unnormal. | `true` |
-| `--destService` | The name of the destination service. | "" |
-| `--destInstance` | The name of the destination instance. | "" |
-| `--destEndpoint` | The name of the destination endpoint. | "" |
-| `--isDestNormal` | Set the destination service to normal or unnormal. | `true` |
-| `--start` | See [Common options](#common-options) | See [Common options](#common-options) |
-| `--end` | See [Common options](#common-options) | See [Common options](#common-options) |
-
-
-
-#### `metrics single`
-
-
-
-metrics single [--start=start-time] [--end=end-time] --name=metrics-name --service=service-name [--instance=instance-name] [--endpoint=endpoint-name] [--isNormal=true/false] [--destService=dest-service-name] [--destInstance=dest-instance-name] [--destEndpoint=dest-endpoint-name] [--isDestNormal=true/false]
-
-| option | description | default |
-| :--- | :--- | :--- |
-| `--name` | Metrics name, defined in [OAL](https://github.com/apache/skywalking/blob/master/oap-server/server-bootstrap/src/main/resources/oal/core.oal), such as `service_sla`, etc. |
-| `--service` | The name of the service. | "" |
-| `--instance` | The name of the service instance. | "" |
-| `--endpoint` | The name of the endpoint. | "" |
-| `--isNormal` | Set the service to normal or unnormal. | `true` |
-| `--destService` | The name of the destination service. | "" |
-| `--destInstance` | The name of the destination instance. | "" |
-| `--destEndpoint` | The name of the destination endpoint. | "" |
-| `--isDestNormal` | Set the destination service to normal or unnormal. | `true` |
-| `--start` | See [Common options](#common-options) | See [Common options](#common-options) |
-| `--end` | See [Common options](#common-options) | See [Common options](#common-options) |
-
-
-
-### `dashboard`
-
-#### `dashboard global-metrics`
-
-
-
-dashboard global-metrics [--template=template]
-
-`dashboard global-metrics` displays global metrics in the form of a dashboard.
-
-| argument | description | default |
-| :--- | :--- | :--- |
-| `--template` | The template file to customize how to display information | `templates/Dashboard.Global.json` |
-| `--start` | See [Common options](#common-options) | See [Common options](#common-options) |
-| `--end` | See [Common options](#common-options) | See [Common options](#common-options) |
-
-You can imitate the content of [the default template file](examples/global.yml) to customize the dashboard.
-
-
-
-#### `dashboard global`
-
-
-
-dashboard global [--template=template]
-
-`dashboard global` displays global metrics, global response latency and global heat map in the form of a dashboard.
-
-| argument | description | default |
-| :--- | :--- | :--- |
-| `--template` | The template file to customize how to display information | `templates/dashboard/global.yml` |
-| `--refresh` | The interval of auto-refresh (s). When `start` and `end` are both present, auto-refresh is disabled. | `6` |
-| `--start` | See [Common options](#common-options) | See [Common options](#common-options) |
-| `--end` | See [Common options](#common-options) | See [Common options](#common-options) |
-
-You can imitate the content of [the default template file](examples/global.yml) to customize the dashboard.
-
-
-
-### `install`
-
-#### `manifest`
-
-
-
-install manifest oap|ui [--name=string] [--namespace=string] [-f=filepath/-]
-
-| argument | description | default |
-| :--- | :--- | :--- |
-| `--name` | The name of prefix of generated resources | `skywalking` |
-| `--namespace` | The namespace where resource will be deployed | `skywalking-system` |
-| `-f` | The custom resource file describing custom resources defined by swck | |
-
-
-
-### `event`
-
-#### `report`
-
-
-
-event report [--uuid=uuid] [--service=service] [--name=name] [--message=message] [--startTime=startTime] [--endTime=endTime] [--instance=instance] [--endpoint=endpoint] [--type=type] [parameters...]
-
-`event report` reports an event to OAP server via gRPC.
-
-| argument | description | default |
-| :--- | :--- | :--- |
-| `uuid` | The unique ID of the event. | |
-| `service` | The service of the event occurred on. | |
-| `instance` | The service instance of the event occurred on. | |
-| `endpoint` | The endpoint of the event occurred on. | |
-| `name` | The name of the event. For example, 'Reboot' and 'Upgrade' etc. | |
-| `type` | The type of the event, could be `Normal` or `Error`. | `Normal` |
-| `message` | The detail of the event. This should be a one-line message that briefly describes why the event is reported. | |
-| `startTime` | The start time (in milliseconds) of the event, measured between the current time and midnight, January 1, 1970 UTC. | |
-| `endTime` | The end time (in milliseconds) of the event, measured between the current time and midnight, January 1, 1970 UTC. | |
-
-
-
-#### `list`
-
-
-
-event list [--service=service] [--instance=instance] [--endpoint=endpoint] [--name=name] [--type=type] [--start=start-time] [--end=end-time]
-
-| argument | description | default |
-| :--- | :--- | :--- |
-| `service` | The service name whose events are to displayed. | |
-| `instance` | The service instance name whose events are to displayed. | |
-| `endpoint` | The endpoint name whose logs are to displayed. | |
-| `name` | The name of the event. | |
-| `type` | The type of the event, could be `Normal` or `Error`. | `Normal` |
-
-
-
-### `logs`
-
-#### `list`
+After reloading your shell, `swctl` auto-completion should be working.
-
-
-logs list [--service-id=service-id] [--instance-id=instance-id] [--endpoint-id=endpoint-id] [--trace-id=trace-id] [--tags=tags] [--start=start-time] [--end=end-time]
-
-| argument | description | default |
-| :--- | :--- | :--- |
-| `service-id` | The service id whose logs are to displayed. | |
-| `instance-id` | The service instance id whose logs are to displayed. | |
-| `endpoint-id` | The service endpoint id whose logs are to displayed. | |
-| `trace-id` | The trace id whose logs are to displayed. | |
-| `tags` | Only tags defined in the core/default/searchableLogsTags are searchable. Check more details on the Configuration Vocabulary page | See [Configuration Vocabulary page](https://github.com/apache/skywalking/blob/master/docs/en/setup/backend/configuration-vocabulary.md) |
-
-
-
-### `profile`
-
-#### `create`
-
-
-
-profile create [--service-id=service-id] [--service-name=service-name] [--endpoint=endpoint] [--start-time=start-time] [--duration=duration] [--min-duration-threshold=min-duration-threshold] [--dump-period=dump-period] [--max-sampling-count=max-sampling-count]
-
-| argument | description | default |
-| :--- | :--- | :--- |
-| `service-id` | whose endpoints are to be profile. | |
-| `service-name` | whose endpoints are to be profile. | |
-| `endpoint` | which endpoint should profile. | |
-| `start-time` | profile task start time(millisecond). | |
-| `duration` | profile task continuous time(minute). | |
-| `min-duration-threshold` | profiled endpoint must greater duration(millisecond). | |
-| `dump-period` | profiled endpoint dump period(millisecond). | |
-| `max-sampling-count` | profile task max sampling count. | |
-
-
-
-#### `list`
-
-
-
-profile list [--service-id=service-id] [--service-name=service-name] [--endpoint=endpoint]
+## Help / Manual
-| argument | description | default |
-| :--- | :--- | :--- |
-| `service-id` | `` whose profile task are to be searched. | |
-| `service-name` | `` whose profile task are to be searched. | |
-| `endpoint` | `` whose profile task are to be searched | |
-
-
-
-#### `segment-list`
-
-
-
-profile segment-list [--task-id=task-id]
-
-| argument | description | default |
-| :--- | :--- | :--- |
-| `task-id` | `` whose profiled segment are to be searched. | |
-
-
-
-#### `profiled-segment`
-
-
-
-profile profiled-segment [--segment-id=segment-id]
-
-| argument | description | default |
-| :--- | :--- | :--- |
-| `segment-id` | profiled segment id. | |
-
-
-
-#### `profiled-analyze`
-
-
-
-profile profiled-analyze [--segment-id=segment-id] [--time-ranges=time-ranges]
-
-| argument | description | default |
-| :--- | :--- | :--- |
-| `segment-id` | profiled segment id. | |
-| `time-ranges` | need to analyze time ranges in the segment: start-end,start-end. | |
-
-
-
-### `dependency`
-
-#### `service`
-
-
-
-dependency service [service-id] [--start=start-time] [--end=end-time]
-
-`dependency service` shows all the dependencies of given `[service-id]` in the time range of `[start, end]`.
-
-| argument | description | default |
-| :--- | :--- | :--- |
-| `service-id` | The service id whose dependencies are to displayed. |
-| `--start` | See [Common options](#common-options) | See [Common options](#common-options) |
-| `--end` | See [Common options](#common-options) | See [Common options](#common-options) |
-
-
-
-#### `endpoint`
-
-
-
-dependency endpoint [endpoint-id] [--start=start-time] [--end=end-time]
-
-`dependency endpoint` shows all the dependencies of given `[endpoint-id]` in the time range of `[start, end]`.
-
-| argument | description | default |
-| :--- | :--- | :--- |
-| `endpoint-id` | The service endpoint id whose dependencies are to displayed. | |
-| `--start` | See [Common options](#common-options) | See [Common options](#common-options) |
-| `--end` | See [Common options](#common-options) | See [Common options](#common-options) |
-
-
-
-#### `instance`
-
-
-
-dependency instance [clientService-id] [serverService-id] [--start=start-time] [--end=end-time]
-
-`dependency instance` shows the instance topology of given `[clientService-id]` and `[serverService-id]` in the time
-range of `[start, end]`.
-
-| argument | description | default |
-| :--- | :--- | :--- |
-| `clientService-id` | The service id of the client. | |
-| `serverService-id` | The service id of the server. | |
-| `--start` | See [Common options](#common-options) | See [Common options](#common-options) |
-| `--end` | See [Common options](#common-options) | See [Common options](#common-options) |
-
-
+`swctl` builds the help manual inside the command itself with some useful example commands, please type `swctl help`
+after installation. If you want to look up detail manual for a specific sub-command, insert `help` before the last
+sub-command, for example, `swctl service help list` shows the manual for command `swctl service list`,
+and `swctl install manifest help oap` shows the manual for `swctl install manifest oap`.
-# Use Cases
+# More Use Cases
Report events in CD workflows - GitHub Actions
diff --git a/internal/commands/interceptor/endpoint.go b/internal/commands/interceptor/endpoint.go
index d4c42d1c..5131ef85 100644
--- a/internal/commands/interceptor/endpoint.go
+++ b/internal/commands/interceptor/endpoint.go
@@ -49,7 +49,7 @@ func ParseEndpoint(required bool) func(*cli.Context) error {
// See flags.EndpointRelationFlags.
func ParseEndpointRelation(required bool) func(*cli.Context) error {
return func(ctx *cli.Context) error {
- if err := ParseService(required)(ctx); err != nil {
+ if err := ParseServiceRelation(required)(ctx); err != nil {
return err
}
if err := ParseEndpoint(required)(ctx); err != nil {
@@ -72,12 +72,7 @@ func parseEndpoint(required bool, idFlagName, nameFlagName, serviceIDFlagName st
return nil
}
- if name != "" {
- if serviceID == "" {
- return fmt.Errorf(`"--%s" is specified but its related service name or id is not given`, nameFlagName)
- }
- id = serviceID + "_" + b64enc(name)
- } else if id != "" {
+ if id != "" {
parts := strings.Split(id, "_")
if len(parts) != 2 {
return fmt.Errorf("invalid endpoint id, cannot be splitted into 2 parts. %v", id)
@@ -87,6 +82,11 @@ func parseEndpoint(required bool, idFlagName, nameFlagName, serviceIDFlagName st
return err
}
name = string(s)
+ } else if name != "" {
+ if serviceID == "" {
+ return fmt.Errorf(`"--%s" is specified but its related service name or id is not given`, nameFlagName)
+ }
+ id = serviceID + "_" + b64enc(name)
}
if err := ctx.Set(idFlagName, id); err != nil {
diff --git a/internal/commands/interceptor/entity.go b/internal/commands/interceptor/entity.go
index d8a40e73..8b110a6a 100644
--- a/internal/commands/interceptor/entity.go
+++ b/internal/commands/interceptor/entity.go
@@ -19,11 +19,14 @@ package interceptor
import (
"encoding/base64"
+ "encoding/json"
"fmt"
"strings"
+ "github.com/sirupsen/logrus"
"github.com/urfave/cli/v2"
+ "github.com/apache/skywalking-cli/internal/logger"
"github.com/apache/skywalking-cli/pkg/graphql/utils"
api "skywalking.apache.org/repo/goapi/query"
@@ -60,6 +63,11 @@ func ParseEntity(ctx *cli.Context) (*api.Entity, error) {
}
entity.Scope = utils.ParseScope(entity)
+ if logger.Log.GetLevel() <= logrus.DebugLevel {
+ s, _ := json.Marshal(&entity)
+ logger.Log.Debugf("entity: %+v", string(s))
+ }
+
return entity, nil
}
diff --git a/internal/commands/interceptor/instance.go b/internal/commands/interceptor/instance.go
index a33ff11d..78f5ad15 100644
--- a/internal/commands/interceptor/instance.go
+++ b/internal/commands/interceptor/instance.go
@@ -72,12 +72,7 @@ func parseInstance(required bool, idFlagName, nameFlagName, serviceIDFlagName st
return nil
}
- if name != "" {
- if serviceID == "" {
- return fmt.Errorf(`"--%s" is specified but its related service name or id is not given`, nameFlagName)
- }
- id = serviceID + "_" + b64enc(name)
- } else if id != "" {
+ if id != "" {
parts := strings.Split(id, "_")
if len(parts) != 2 {
return fmt.Errorf("invalid instance id, cannot be splitted into 2 parts. %v", id)
@@ -87,6 +82,11 @@ func parseInstance(required bool, idFlagName, nameFlagName, serviceIDFlagName st
return err
}
name = string(s)
+ } else if name != "" {
+ if serviceID == "" {
+ return fmt.Errorf(`"--%s" is specified but its related service name or id is not given`, nameFlagName)
+ }
+ id = serviceID + "_" + b64enc(name)
}
if err := ctx.Set(idFlagName, id); err != nil {
diff --git a/internal/commands/interceptor/service.go b/internal/commands/interceptor/service.go
index f1b7036c..f87fd884 100644
--- a/internal/commands/interceptor/service.go
+++ b/internal/commands/interceptor/service.go
@@ -66,13 +66,7 @@ func parseService(required bool, idFlagName, nameFlagName string) func(*cli.Cont
return nil
}
- if name != "" {
- service, err := metadata.SearchService(ctx, name)
- if err != nil {
- return err
- }
- id = service.ID
- } else if id != "" {
+ if id != "" {
parts := strings.Split(id, ".")
if len(parts) != 2 {
return fmt.Errorf("invalid service id, cannot be splitted into 2 parts. %v", id)
@@ -82,6 +76,12 @@ func parseService(required bool, idFlagName, nameFlagName string) func(*cli.Cont
return err
}
name = string(s)
+ } else if name != "" {
+ service, err := metadata.SearchService(ctx, name)
+ if err != nil {
+ return err
+ }
+ id = service.ID
}
if err := ctx.Set(idFlagName, id); err != nil {
diff --git a/internal/commands/metrics/linear/linear-metrics.go b/internal/commands/metrics/linear/linear-metrics.go
index a89a33a1..25930c40 100644
--- a/internal/commands/metrics/linear/linear-metrics.go
+++ b/internal/commands/metrics/linear/linear-metrics.go
@@ -43,6 +43,9 @@ $ swctl metrics linear --name=service_resp_time --service-name business-zone::pr
2. Query the response time of service instance
$ swctl metrics linear --name=service_instance_resp_time --service-name business-zone::projectB \
--instance-name d708c6bfea9f4d50902d1743302a6f50@10.170.0.12
+
+3. Query the traffic (calls per minutes) between service "consumer" to service "provider"
+$ swctl metrics linear --name=service_relation_client_cpm --service-name consumer --dest-service-name provider
`,
Flags: flags.Flags(
flags.DurationFlags,
@@ -52,8 +55,8 @@ $ swctl metrics linear --name=service_instance_resp_time --service-name business
),
Before: interceptor.BeforeChain(
interceptor.DurationInterceptor,
- interceptor.ParseInstanceRelation(false),
interceptor.ParseEndpointRelation(false),
+ interceptor.ParseInstanceRelation(false),
),
Action: func(ctx *cli.Context) error {
end := ctx.String("end")
diff --git a/internal/commands/metrics/linear/multiple-linear-metrics.go b/internal/commands/metrics/linear/multiple-linear-metrics.go
index 72e7ffd4..af4a4078 100644
--- a/internal/commands/metrics/linear/multiple-linear-metrics.go
+++ b/internal/commands/metrics/linear/multiple-linear-metrics.go
@@ -58,8 +58,8 @@ $ swctl metrics multiple-linear --name all_percentile`,
),
Before: interceptor.BeforeChain(
interceptor.DurationInterceptor,
- interceptor.ParseInstanceRelation(false),
interceptor.ParseEndpointRelation(false),
+ interceptor.ParseInstanceRelation(false),
),
Action: func(ctx *cli.Context) error {
end := ctx.String("end")
diff --git a/internal/commands/metrics/single/single-metrics.go b/internal/commands/metrics/single/single-metrics.go
index 5c9afa7b..98764853 100644
--- a/internal/commands/metrics/single/single-metrics.go
+++ b/internal/commands/metrics/single/single-metrics.go
@@ -49,8 +49,8 @@ $ swctl metrics single --name endpoint_cpm --service-name business-zone::project
),
Before: interceptor.BeforeChain(
interceptor.DurationInterceptor,
- interceptor.ParseInstanceRelation(false),
interceptor.ParseEndpointRelation(false),
+ interceptor.ParseInstanceRelation(false),
),
Action: func(ctx *cli.Context) error {
end := ctx.String("end")
diff --git a/internal/commands/metrics/thermodynamic/thermodynamic.go b/internal/commands/metrics/thermodynamic/thermodynamic.go
index 52d6b1ed..a34199b1 100644
--- a/internal/commands/metrics/thermodynamic/thermodynamic.go
+++ b/internal/commands/metrics/thermodynamic/thermodynamic.go
@@ -48,8 +48,8 @@ $ swctl metrics thermodynamic --scope all --name all_heatmap
),
Before: interceptor.BeforeChain(
interceptor.DurationInterceptor,
- interceptor.ParseInstanceRelation(false),
interceptor.ParseEndpointRelation(false),
+ interceptor.ParseInstanceRelation(false),
),
Action: func(ctx *cli.Context) error {
end := ctx.String("end")
diff --git a/internal/flags/endpoint.go b/internal/flags/endpoint.go
index 06b83676..ac91e49c 100644
--- a/internal/flags/endpoint.go
+++ b/internal/flags/endpoint.go
@@ -41,7 +41,7 @@ var EndpointFlags = append(
// EndpointRelationFlags take either destination endpoint id or destination endpoint name as input,
// and transform to the other one.
var EndpointRelationFlags = append(
- EndpointFlags,
+ append(EndpointFlags[len(ServiceFlags):], ServiceRelationFlags...),
&cli.StringFlag{
Name: "dest-endpoint-id",
diff --git a/test/test.yaml b/test/test.yaml
index 75bbbbe1..4cfc28c7 100644
--- a/test/test.yaml
+++ b/test/test.yaml
@@ -70,6 +70,10 @@ verify:
expected: expected/metrics-has-value.yml
- query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics linear --name=endpoint_sla --service-name provider --endpoint-name /users | yq e 'to_entries' -
expected: expected/metrics-has-value.yml
+ - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics linear --name=service_relation_client_cpm --service-name consumer --dest-service-name provider | yq e 'to_entries' -
+ expected: expected/metrics-has-value.yml
+ - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics linear --name=service_instance_relation_client_cpm --service-name consumer --instance-name consumer1 --dest-service-name provider --dest-instance-name provider1 | yq e 'to_entries' -
+ expected: expected/metrics-has-value.yml
- query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics single --name endpoint_cpm --service-name provider --endpoint-name /users
expected: expected/value.yml