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

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


The following commit(s) were added to refs/heads/master by this push:
     new f6aad1f  [Feature] Add endpoint command, refactor Makefile to cross 
build target (#17)
f6aad1f is described below

commit f6aad1fde8b945e6f4c17a9c6ade6e9f3728c8a8
Author: kezhenxu94 <[email protected]>
AuthorDate: Mon Dec 2 23:30:46 2019 +0800

    [Feature] Add endpoint command, refactor Makefile to cross build target 
(#17)
    
    * [Feature] Add endpoint command, refactor Makefile to cross build target
    
    * Add missing documentation and polish
    
    * Fix bug
    
    * Polish
    
    * Re-organize documentations and collapse details for simplicity
    
    * Add some common use cases
    
    * Polish
    
    * Add ascii graph
---
 .github/workflows/go.yml                           |  31 ++-
 CONTRIBUTING.md                                    |  84 +++++++
 Makefile                                           |  68 +++++-
 README.md                                          | 243 ++++++++++++++++-----
 .../table.go => commands/endpoint/endpoint.go      |  46 +---
 .../linear-metrics.go => endpoint/list.go}         |  61 +++---
 commands/metrics/{ => linear}/linear-metrics.go    |  14 +-
 .../single-metrics.go}                             |  25 ++-
 display/table/table.go                             |  14 +-
 go.sum                                             |   1 +
 graphql/client/client.go                           |  50 +++++
 scripts/build                                      |  28 ---
 swctl/main.go                                      |   8 +-
 13 files changed, 490 insertions(+), 183 deletions(-)

diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml
index f9485ab..0b6646e 100644
--- a/.github/workflows/go.yml
+++ b/.github/workflows/go.yml
@@ -15,7 +15,13 @@
 # limitations under the License.
 
 name: Build
-on: [push, pull_request]
+
+on:
+  pull_request:
+  push:
+    branches:
+      - master
+
 jobs:
 
   build:
@@ -33,27 +39,16 @@ jobs:
         uses: actions/checkout@v1
 
       - name: Check License
-        run: |
-          GO111MODULE=off go get -u github.com/elastic/go-licenser
-          $(go env GOPATH)/bin/go-licenser -d -licensor='Apache Software 
Foundation (ASF)' .
+        run: make license
 
       - name: Get dependencies
-        run: |
-          go get -v -t -d ./...
-          if [ -f Gopkg.toml ]; then
-              curl 
https://raw.githubusercontent.com/golang/dep/master/install.sh | sh
-              dep ensure
-          fi
+        run: make deps
 
       - name: Lint
-        run: |
-          curl -sfL 
https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh| sh 
-s -- -b $(go env GOPATH)/bin v1.21.0
-          $(go env GOPATH)/bin/golangci-lint run -v ./...
+        run: make lint
 
-      - name: Test
-        run: |
-          go test ./... -coverprofile=coverage.txt -covermode=atomic
-          CODECOV_TOKEN="a5af28a3-92a2-4b35-9a77-54ad99b1ae00" bash <(curl -s 
https://codecov.io/bash)
+      - name: Test and report coverage
+        run: make coverage
 
       - name: Build
-        run: make clean && make
+        run: make build -j3
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000..bf0f7a0
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,84 @@
+# Contributing to Apache SkyWalking CLI
+
+Firstly, thanks for your interest in contributing! We hope that this will be a
+pleasant first experience for you, and that you will return to continue
+contributing.
+
+## Code of Conduct
+
+This project and everyone participating in it is governed by the Apache
+software Foundation's [Code of 
Conduct](http://www.apache.org/foundation/policies/conduct.html).
+By participating, you are expected to adhere to this code. If you are aware of 
unacceptable behavior, please visit the
+[Reporting Guidelines 
page](http://www.apache.org/foundation/policies/conduct.html#reporting-guidelines)
+and follow the instructions there.
+
+## How to contribute?
+
+Most of the contributions that we receive are code contributions, but you can
+also contribute to the documentation or simply report solid bugs
+for us to fix.
+
+## How to report a bug?
+
+* **Ensure the bug was not already reported** by searching on GitHub under 
[Issues](https://github.com/apache/skywalking/issues).
+
+* If you're unable to find an open issue addressing the problem, [open a new 
one](https://github.com/apache/skywalking/issues/new).
+Be sure to include a **title and clear description**, as much relevant 
information as possible,
+and a **code sample** or an **executable test case** demonstrating the 
expected behavior that is not occurring.
+
+## How to add a new feature or change an existing one
+
+_Before making any significant changes, please [open an 
issue](https://github.com/apache/skywalking/issues)._
+Discussing your proposed changes ahead of time will make the contribution 
process smooth for everyone.
+
+Once we've discussed your changes and you've got your code ready, make sure 
that tests are passing and open your pull request. Your PR is most likely to be 
accepted if it:
+
+* Update the README.md with details of changes to the interface.
+* Includes tests for new functionality.
+* References the original issue in description, e.g. "Resolves #123".
+* Has a [good commit 
message](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html).
+
+## Compiling and building
+Clone the source code and simply run `make` in the source directory,
+this will download all necessary dependencies and run tests, lint, and build 
three binary files in `./bin/`, for Windows, Linux, MacOS respectively.
+
+```shell
+make
+```
+
+## Writing a new command
+All commands files locate in directory [`commands`](commands), and an 
individual directory for each second-level command,
+an individual `go` file for each third-level command, for example, there is a 
directory [`service`](commands/service) for command `swctl service`, 
+and a [`list.go`](commands/service/list.go) file for `swctl service list` 
command.
+
+Determine what entity your command will operate on, and put your command `go` 
file into that directory, or create one if it doesn't exist,
+for example, if you want to create a command to `list` all the `instance`s of 
a service, create a directory `commands/instance`,
+and a `go` file `commands/instance/list.go`.
+
+## Reusing common options
+There're some [common options](#common-options) that can be shared by multiple 
commands, check [`commands/flags`](commands/flags)
+to get all the shared options, and reuse them when possible, an example shares 
the options is [`commands/service/list.go`](commands/service/list.go#L35)
+
+## Linting your codes
+We have some rules for the code style and please lint your codes locally 
before opening a pull request
+
+```shell
+make lint
+```
+
+if you found some errors in the output of the above command, try `make fix` to 
fix some obvious style issues, as for the complicated errors, please fix them 
manually.
+
+## Checking license
+The Apache Software Foundation requires every source file to contain a license 
header, run `make license` to check that there is license header in every 
source file.
+
+```shell
+make license
+``` 
+
+## Running tests
+Before submitting a pull request, add some test code to test the 
added/modified codes,
+and run the tests locally, make sure all tests passed.
+
+```shell
+make test
+```
\ No newline at end of file
diff --git a/Makefile b/Makefile
index 3273175..a8ad5c4 100644
--- a/Makefile
+++ b/Makefile
@@ -15,11 +15,69 @@
 # limitations under the License.
 #
 
-.PHONY: build install
+VERSION ?= latest
+OUT_DIR = bin
+BINARY = swctl
 
-build:
-       GO_BUILD_FLAGS="-v" ./scripts/build
-       ./bin/swctl --version
+OS = $(shell uname)
 
+GO = go
+GO_PATH = $$($(GO) env GOPATH)
+GO_BUILD = $(GO) build
+GO_GET = $(GO) get
+GO_CLEAN = $(GO) clean
+GO_TEST = $(GO) test
+GO_LINT = $(GO_PATH)/bin/golangci-lint
+GO_LICENSER = $(GO_PATH)/bin/go-licenser
+GO_BUILD_FLAGS = -v
+
+PLATFORMS := windows linux darwin
+os = $(word 1, $@)
+ARCH = amd64
+
+SHELL = /bin/bash
+
+all: clean deps lint test license build
+
+deps:
+       $(GO_GET) -v -t -d ./...
+
+.PHONY: $(PLATFORMS)
+$(PLATFORMS):
+       mkdir -p $(OUT_DIR)
+       GOOS=$(os) GOARCH=$(ARCH) $(GO_BUILD) $(GO_BUILD_FLAGS) -o 
$(OUT_DIR)/$(BINARY)-$(VERSION)-$(os)-$(ARCH) swctl/main.go
+
+.PHONY: lint
+lint:
+       $(GO_LINT) version || curl -sfL 
https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh 
-s -- -b $(GO_PATH)/bin v1.21.0
+       $(GO_LINT) run -v ./...
+
+.PHONE: test
+test: clean lint
+       $(GO_TEST) ./... -coverprofile=coverage.txt -covermode=atomic
+
+.PHONY: build
+build: deps windows linux darwin
+
+.PHONY: license
+license: clean
+       $(GO_LICENSER) -version || GO111MODULE=off $(GO_GET) -u 
github.com/elastic/go-licenser
+       $(GO_LICENSER) -d -licensor='Apache Software Foundation (ASF)' .
+
+.PHONY: verify
+verify: clean lint test license
+
+.PHONY: fix
+fix:
+       $(GO_LINT) run -v --fix ./...
+       $(GO_LICENSER) -licensor='Apache Software Foundation (ASF)' .
+
+.PHONY: coverage
+coverage: test
+       bash <(curl -s https://codecov.io/bash) -t 
a5af28a3-92a2-4b35-9a77-54ad99b1ae00
+
+.PHONY: clean
 clean:
-       -rm -rf ./bin
\ No newline at end of file
+       $(GO_CLEAN) ./...
+       -rm -rf ./bin
+       -rm -rf coverage.txt
diff --git a/README.md b/README.md
index 8d8ff70..ad81bed 100644
--- a/README.md
+++ b/README.md
@@ -17,11 +17,12 @@ As SkyWalking CLI is using `Makefile`, compiling the 
project is as easy as execu
 ```shell
 git clone https://github.com/apache/skywalking-cli
 cd skywalking-cli
-make clean && make
+make
 ```
 
-and copy the `./bin/swctl` to your `PATH` directory, usually `/usr/bin/` or 
`/usr/local/bin`, or you can copy it to any directory you like,
-and add that directory to `PATH`.
+and copy the `./bin/swctl-latest-(darwin|linux|windows)-amd64` to your `PATH` 
directory according to your OS,
+usually `/usr/bin/` or `/usr/local/bin`, or you can copy it to any directory 
you like,
+and add that directory to `PATH`, we recommend you to rename the 
`swctl-latest-(darwin|linux|windows)-amd64` to `swctl`.
 
 # Commands
 Commands in SkyWalking CLI are organized into two levels, in the form of 
`swctl --option <level1> --option <level2> --option`,
@@ -41,7 +42,10 @@ will list all the `service`s, `service instance`s, etc.
 ## Common options
 There're some common options that are shared by multiple commands, and they 
follow the same rules in different commands,
 
-### `--start`, `--end`
+<details>
+
+<summary>--start, --end</summary>
+
 `--start` and `--end` specify a time range during which the query is preformed,
 they are both optional and their default values follow the rules below:
 
@@ -56,18 +60,12 @@ and if `end = 2019-11-09 12`, the precision is `HOUR`, so 
`start = end - 30HOUR
 e.g. `start = 2019-11-09 1204`, the precision is `MINUTE`, so `end = start + 
30 minutes = 2019-11-09 1234`,
 and if `start = 2019-11-08 06`, the precision is `HOUR`, so `end = start + 
30HOUR = 2019-11-09 12`;
 
+</details>
 
 ## All available commands
 This section covers all the available commands in SkyWalking CLI and their 
usages.
 
-- [`swctl`](#swctl-top-level-command)
-- [`service`](#service-second-level-command) (second level command)
-  - [`list`, `ls`](#service-list---startstart-time---endend-time)
-- [`instance`](#instance-second-level-command) (second level command)
-  - [`list`, 
`ls`](#instance-list---service-idservice-id---service-nameservice-name---startstart-time---endend-time)
-  - 
[`search`](#instance-search---regexinstance-name-regex---service-idservice-id---service-nameservice-name---startstart-time---endend-time)
-
-### `swctl` top-level command
+### `swctl`
 `swctl` is the top-level command, which has some options that will take 
effects globally.
 
 | option | description | default |
@@ -77,83 +75,228 @@ This section covers all the available commands in 
SkyWalking CLI and their usage
 | `--base-url` | base url of GraphQL backend | 
`http://127.0.0.1:12800/graphql` |
 | `--display` | display style when printing the query result, supported styles 
are: `json`, `yaml`, `table` | `json` |
 
-### `service` second-level command
-`service` second-level command is an entry for all operations related to 
services,
-and it also has some options and third-level commands.
+### `service`
+
+<details>
+
+<summary>service list [--start=start-time] [--end=end-time]</summary>
 
-#### `service list [--start=<start time>] [--end=<end time>]`
-`service list` lists all the services in the time range of \[`start`, `end`\].
+`service list` lists all the services in the time range of `[start, end]`.
 
 | option | description | default |
 | :--- | :--- | :--- |
 | `--start` | See [Common options](#common-options) | See [Common 
options](#common-options) |
 | `--end` | See [Common options](#common-options) | See [Common 
options](#common-options) |
 
-### `instance` second-level command
-`instance` second-level command is an entry for all operations related to 
instances,
-and it also has some options and third-level commands.
+</details>
 
-#### `instance list [--service-id=<service id>] [--service-name=<service 
name>] [--start=<start time>] [--end=<end time>]`
-`instance list` lists all the instances in the time range of \[`start`, 
`end`\] and given --service-id or --service-name.
+### `instance`
+
+<details>
+
+<summary>instance list [--start=start-time] [--end=end-time] 
[--service-id=service-id] [--service-name=service-name]</summary>
+
+`instance list` lists all the instances in the time range of `[start, end]` 
and given `--service-id` or `--service-name`.
 
 | option | description | default |
 | :--- | :--- | :--- |
-| `--service-id` | Query service id (priority over --service-name)|  |
-| `--service-name` | Query service name |  |
+| `--service-id` | Query by service id (priority over `--service-name`)|  |
+| `--service-name` | Query by service name if `--service-id` is absent |  |
 | `--start` | See [Common options](#common-options) | See [Common 
options](#common-options) |
 | `--end` | See [Common options](#common-options) | See [Common 
options](#common-options) |
 
-#### `instance search [--regex=<instance name regex>] [--service-id=<service 
id>] [--service-name=<service name>] [--start=<start time>] [--end=<end time>]`
-`instance search` filter the instance in the time range of \[`start`, `end`\] 
and given --regex --service-id or --service-name.
+</details>
+
+<details>
+
+<summary>instance search [--start=start-time] [--end=end-time] 
[--regex=instance-name-regex] [--service-id=service-id] 
[--service-name=service-name]</summary>
+
+`instance search` filter the instance in the time range of `[start, end]` and 
given --regex --service-id or --service-name.
 
 | option | description | default |
 | :--- | :--- | :--- |
 | `--regex` | Query regex of instance name|  |
-| `--service-id` | Query service id (priority over --service-name)|  |
-| `--service-name` | Query service name |  |
+| `--service-id` | Query by service id (priority over `--service-name`)|  |
+| `--service-name` | Query by service name if `service-id` is absent |  |
 | `--start` | See [Common options](#common-options) | See [Common 
options](#common-options) |
 | `--end` | See [Common options](#common-options) | See [Common 
options](#common-options) |
 
-### `linear-metrics` second-level command
-`linear-metrics` second-level command is an entrance for all operations 
related to linear metrics,
-and it also has some options.
+</details>
+
+### `endpoint`
+
+<details>
+
+<summary>endpoint list [--start=start-time] [--end=end-time] 
--service-id=service-id [--limit=count] [--keyword=search-keyword]</summary>
+
+`endpoint list` lists all the endpoints of the given service id in the time 
range of `[start, end]`.
+
+| option | description | default |
+| :--- | :--- | :--- |
+| `--service-id` | <service id> whose endpoints are to be searched | |
+| `--limit` | returns at most <limit> endpoints (default: 100) | 100 |
+| `--keyword` | <keyword> of the endpoint name to search for, empty to search 
all | "" |
+
+</details>
+
+### `linear-metrics`
+
+<details>
+
+<summary>linear-metrics [--start=start-time] [--end=end-time] 
--name=metrics-name [--id=entity-id]</summary>
 
 | option | description | default |
 | :--- | :--- | :--- |
 | `--name` | Metrics name, defined in 
[OAL](https://github.com/apache/skywalking/blob/master/oap-server/server-bootstrap/src/main/resources/official_analysis.oal),
 such as `all_p99`, etc. |
+| `--id` | the related id if the metrics requires one, e.g. for metrics 
`service_p99`, the service `id` is required, use `--id` to specify the service 
id, the same for `instance`, `endpoint`, etc. |
+| `--start` | See [Common options](#common-options) | See [Common 
options](#common-options) |
+| `--end` | See [Common options](#common-options) | See [Common 
options](#common-options) |
+
+</details>
+
+### `single-metrics`
+
+<details>
+
+<summary>single-metrics [--start=start-time] [--end=end-time] 
--name=metrics-name [--ids=entity-ids]</summary>
+
+| option | description | default |
+| :--- | :--- | :--- |
+| `--name` | Metrics name, defined in 
[OAL](https://github.com/apache/skywalking/blob/master/oap-server/server-bootstrap/src/main/resources/official_analysis.oal),
 such as `service_sla`, etc. |
+| `--ids` | IDs that are required by the metric type, such as service IDs for 
`service_sla` |
 | `--start` | See [Common options](#common-options) | See [Common 
options](#common-options) |
 | `--end` | See [Common options](#common-options) | See [Common 
options](#common-options) |
 
-# Developer guide
+</details>
+
+# Use Cases
+
+<details>
+
+<summary>Query a specific service by name</summary>
+
+```shell
+# query the service named projectC
+$ ./bin/swctl service ls projectC
+[{"id":"4","name":"projectC"}]
+```
+
+</details>
+
+<details>
+
+<summary>Query instances of a specific service</summary>
+
+If you have already got the `id` of the service:
+
+```shell
+$ ./bin/swctl instance ls --service-id=3
+[{"id":"3","name":"projectD-pid:7909@skywalking-server-0001","attributes":[{"name":"os_name","value":"Linux"},{"name":"host_name","value":"skywalking-server-0001"},{"name":"process_no","value":"7909"},{"name":"ipv4s","value":"192.168.252.12"}],"language":"JAVA","instanceUUID":"ec8a79d7cb58447c978ee85846f6699a"}]
+```
+
+otherwise,
+
+```shell
+$ ./bin/swctl instance ls --service-name=projectC
+[{"id":"3","name":"projectD-pid:7909@skywalking-server-0001","attributes":[{"name":"os_name","value":"Linux"},{"name":"host_name","value":"skywalking-server-0001"},{"name":"process_no","value":"7909"},{"name":"ipv4s","value":"192.168.252.12"}],"language":"JAVA","instanceUUID":"ec8a79d7cb58447c978ee85846f6699a"}]
+```
+
+</details>
+
+<details>
+
+<summary>Query endpoints of a specific service</summary>
+
+If you have already got the `id` of the service:
+
+```shell
+$ ./bin/swctl endpoint ls --service-id=3
+```
+
+otherwise,
+
+```shell
+./bin/swctl service ls projectC | jq '.[].id' | xargs 
./bin/swctl-latest-darwin-amd64 endpoint ls --service-id 
+[{"id":"22","name":"/projectC/{value}"}]
+```
+
+</details>
+
+<details>
+
+<summary>Query a linear metrics graph for an instance</summary>
+
+If you have already got the `id` of the instance:
 
-## Compiling and building
-Clone the source code and simply run `make clean && make` in the source 
directory,
-this will download all necessary dependencies and build a binary file in 
`./bin/swctl`.
+```shell
+$ ./bin/swctl --display=graph linear-metrics --name=service_instance_resp_time 
--id 5
+┌─────────────────────────────────────────────────────────────────────────────────Press
 q to 
quit──────────────────────────────────────────────────────────────────────────────────┐
+│                                                                              
                                                                                
                    │
+│                                                                              
                                                                                
                    │
+│         │                                                                    
                                                                                
⡜⠢⡀                 │
+│  1181.80│                                      ⡰⡀                            
                             ⢀⡠⢢         ⡰⢣                                    
⡰⠁ ⠈⠢⡀               │
+│         │                                     ⢠⠃⠱⡀              ⡀            
                           ⢀⠔⠁  ⠱⡀     ⢀⠜  ⢣                        ⢀⠞⡄       
⢠⠃    ⠈⠢⡀             │
+│         │                                     ⡎  ⠱⡀          ⢀⠔⠊⠱⡀           
      ⢀⣀⣀⣀              ⢀⡠⠊⠁     ⠘⢄   ⢀⠎    ⢣                      ⡠⠃ ⠘⡄      ⡎ 
      ⠈⠑⠢⢄⡀  ⢀⡠⠔⠊⠁  │
+│         │          ⢀⠤⣀⡀       ⢀⡀             ⡸    ⢣        ⡠⠔⠁   ⠱⡀          
  ⡠⠊⠉⠉⠁   ⠉⠉⠒⠒⠤⠤⣀⣀⣀ ⢀⡠⠔⠊⠁          ⠣⡀⡠⠃      ⢣           ⢀⠔⠤⡀     ⡰⠁   ⠘⡄    ⡜  
          ⠈⠑⠊⠁      │
+│  1043.41│⡀       ⢀⠔⠁  ⠈⠑⠒⠤⠔⠒⠊⠉⠁⠈⠒⢄          ⢀⠇     ⢣    ⢀⠤⠊       ⠱⡀         
⢀⠔⠁                ⠉⠁               ⠑⠁        ⢣         ⡠⠃  ⠈⠒⢄ ⢀⠜      ⠘⡄  ⢰⠁  
                    │
+│         │⠈⠑⠤⣀   ⡠⠊                ⠑⠤⡀       ⡜       ⢣ ⣀⠔⠁          ⠱⡀       
⡰⠁                                              ⠣⢄⣀    ⢠⠊       ⠉⠊        ⠘⡄⢠⠃  
                     │
+│         │    ⠑⠢⠊                    ⠈⠢⡀    ⢰⠁        ⠋              ⠱⡀  ⣀⠤⠔⠊ 
                                                  ⠉⠒⠢⠔⠁                   ⠘⠎    
                    │
+│         │                             ⠈⠢⡀ ⢀⠇                         ⠑⠊⠉     
                                                                                
                    │
+│      905│                               ⠈⠢⡜                                  
                                                                                
                    │
+│         
└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
  │
+│          2019-12-02 2121   2019-12-02 2107   2019-12-02 2115   2019-12-02 
2119   2019-12-02 2137   2019-12-02 2126   2019-12-02 2118   2019-12-02 2128   
2019-12-02 2136         │
+│                                                                              
                                                                                
                    │
+│                                                                              
                                                                                
                    │
+└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
+```
+
+otherwise
 
 ```shell
-make clean && make
+$ ./bin/swctl instance ls --service-name=projectC | jq '.[] | select(.name == 
"projectC-pid:7895@skywalking-server-0001").id' | xargs ./bin/swctl 
--display=graph linear-metrics --name=service_instance_resp_time --id
+┌─────────────────────────────────────────────────────────────────────────────────Press
 q to 
quit──────────────────────────────────────────────────────────────────────────────────┐
+│                                                                              
                                                                                
                    │
+│                                                                              
                                                                                
                    │
+│         │                                                                    
       ⡠⠒⢣                                                                      
                    │
+│  1181.80│                          ⡠⠊⢢                                       
    ⣀⠔⠉   ⢣              ⡔⡄                               ⡔⡄                    
                    │
+│         │           ⣀            ⡠⠊   ⠑⡄                                    
⣀⡠⠔⠒⠉       ⢣            ⡜ ⠈⢆                            ⢀⠎ ⠈⢢              ⡀   
                     │
+│         │          ⡜ ⠉⠒⠤⣀   ⢀⣀⣀⡠⠊      ⠈⠢⡀               ⢀⡠⢄⣀⡀            ⡰⠉ 
            ⢣          ⡜    ⢣                          ⡠⠃    ⠑⡄        ⢀⡠⠔⠉⠘⢄   
                    │
+│         │        ⢀⠜      ⠉⠉⠉⠁            ⠑⢄          ⢀⡠⠔⠊⠁   ⠈⠉⠑⢢        ⡰⠁  
             ⢣       ⢀⠎      ⠱⡀          ⢀⠦⡀         ⢀⠜       ⠈⢢ ⢀⣀⣀⡠⠤⠒⠁     ⠣⡀ 
                 ⡀  │
+│  1043.41│       ⢀⠎                         ⠑⢄      ⢀⠔⠁           ⠱⡀     ⡰⠁   
              ⢣⣀    ⢀⠎        ⠘⢄        ⢀⠎ ⠈⢢      ⢀⠤⠊          ⠉⠁            
⠘⢄               ⡠⠊   │
+│         │      ⢠⠃                           ⠈⠢⡀  ⡠⠒⠁              ⠘⢄   ⡰⠁    
                ⠉⠉⠉⠒⠊          ⠈⢢      ⢀⠎    ⠑⢄  ⡠⠒⠁                            
⠣⠤⣀⣀⣀       ⢀⠔⠉     │
+│         │⠤⠤⠤⠤⠤⠤⠃                              ⠈⠢⠊                   ⠣⡀⡰⠁     
                                 ⠱⡀   ⢀⠎       ⠑⠉                               
     ⠉⠉⠉⠉⠒⠒⠒⠁       │
+│         │                                                            ⠑⠁      
                                  ⠑⡄ ⢀⠎                                         
                    │
+│      905│                                                                    
                                   ⠈⢆⠎                                          
                    │
+│         
└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
  │
+│          2019-12-02 2122   2019-12-02 2137   2019-12-02 2136   2019-12-02 
2128   2019-12-02 2108   2019-12-02 2130   2019-12-02 2129   2019-12-02 2115   
2019-12-02 2119         │
+│                                                                              
                                                                                
                    │
+│                                                                              
                                                                                
                    │
+└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
 ```
 
-## Writing a new command
-All commands files locate in directory [`commands`](commands), and an 
individual directory for each second-level command,
-an individual `go` file for each third-level command, for example, there is a 
directory [`service`](commands/service) for command `swctl service`, 
-and a [`list.go`](commands/service/list.go) file for `swctl service list` 
command.
+</details>
 
-Determine what entity your command will operate on, and put your command `go` 
file into that directory, or create one if it doesn't exist,
-for example, if you want to create a command to `list` all the `instance`s of 
a service, create a directory `commands/instance`,
-and a `go` file `commands/instance/list.go`.
+<details>
 
-## Reusing common options
-There're some [common options](#common-options) that can be shared by multiple 
commands, check [`commands/flags`](commands/flags)
-to get all the shared options, and reuse them when possible, an example shares 
the options is [`commands/service/list.go`](commands/service/list.go#L35)
+<summary>Query a single metrics value for a specific endpoint</summary>
 
-## Running tests
-Before submitting a pull request, add some test code to test the 
added/modified codes,
-and run the tests locally, make sure all tests passed.
+```shell
+$ ./bin/swctl service ls projectC | jq '.[0].id' | xargs ./bin/swctl endpoint 
ls --service-id | jq '.[] | [.id] | join(",")' | xargs ./bin/swctl 
single-metrics --name endpoint_cpm --ids
+[{"id":"22","value":116}]
+```
+
+</details>
+
+<details>
+
+<summary>Query metrics single values for all endpoints of service of id 
3</summary>
 
 ```shell
-go test -v ./...
+$ ./bin/swctl service ls projectC | jq '.[0].id' | xargs ./bin/swctl endpoint 
ls --service-id | jq '.[] | [.id] | join(",")' | xargs ./bin/swctl 
single-metrics --name endpoint_cpm --end='2019-12-02 2137' --ids
+[{"id":"3","value":116}]
 ```
 
+</details>
+
 # License
 [Apache 2.0 License.](/LICENSE)
diff --git a/display/table/table.go b/commands/endpoint/endpoint.go
similarity index 56%
copy from display/table/table.go
copy to commands/endpoint/endpoint.go
index d79f917..d357224 100644
--- a/display/table/table.go
+++ b/commands/endpoint/endpoint.go
@@ -15,45 +15,17 @@
 // specific language governing permissions and limitations
 // under the License.
 
-package table
+package endpoint
 
 import (
-       "encoding/json"
-       "os"
-
-       "github.com/olekukonko/tablewriter"
+       "github.com/urfave/cli"
 )
 
-func Display(object interface{}) error {
-       var objMaps []map[string]string
-
-       bytes, _ := json.Marshal(object)
-       _ = json.Unmarshal(bytes, &objMaps)
-
-       if len(objMaps) < 1 {
-               return nil
-       }
-
-       var header []string
-
-       for k := range objMaps[0] {
-               header = append(header, k)
-       }
-
-       var data [][]string
-
-       for _, objMap := range objMaps {
-               var datum []string
-               for _, key := range header {
-                       datum = append(datum, objMap[key])
-               }
-               data = append(data, datum)
-       }
-
-       table := tablewriter.NewWriter(os.Stdout)
-       table.SetHeader(header)
-       table.AppendBulk(data)
-       table.Render()
-
-       return nil
+var Command = cli.Command{
+       Name:      "endpoint",
+       ShortName: "e",
+       Usage:     "Endpoint related sub-command",
+       Subcommands: cli.Commands{
+               ListCommand,
+       },
 }
diff --git a/commands/metrics/linear-metrics.go b/commands/endpoint/list.go
similarity index 50%
copy from commands/metrics/linear-metrics.go
copy to commands/endpoint/list.go
index e3148fe..51ea320 100644
--- a/commands/metrics/linear-metrics.go
+++ b/commands/endpoint/list.go
@@ -15,49 +15,46 @@
 // specific language governing permissions and limitations
 // under the License.
 
-package metrics
+package endpoint
 
 import (
        "github.com/urfave/cli"
 
-       "github.com/apache/skywalking-cli/commands/flags"
-       "github.com/apache/skywalking-cli/commands/interceptor"
-       "github.com/apache/skywalking-cli/commands/model"
        "github.com/apache/skywalking-cli/display"
        "github.com/apache/skywalking-cli/graphql/client"
-       "github.com/apache/skywalking-cli/graphql/schema"
 )
 
-var Command = cli.Command{
-       Name:  "linear-metrics",
-       Usage: "Query linear metrics defined in backend OAL",
-       Flags: flags.Flags(
-               flags.DurationFlags,
-               []cli.Flag{
-                       cli.StringFlag{
-                               Name:     "name",
-                               Usage:    "metrics `NAME`, such as `all_p99`",
-                               Required: true,
-                       },
+var ListCommand = cli.Command{
+       Name:        "list",
+       ShortName:   "ls",
+       Usage:       "List endpoints",
+       Description: "list all endpoints if no <endpoint id> is given, 
otherwise, only list the given endpoint",
+       Flags: []cli.Flag{
+               cli.StringFlag{
+                       Name:     "service-id",
+                       Usage:    "`<service id>` whose endpoints are to be 
searched",
+                       Required: true,
                },
-       ),
-       Before: interceptor.BeforeChain([]cli.BeforeFunc{
-               interceptor.DurationInterceptor,
-       }),
+               cli.IntFlag{
+                       Name:     "limit",
+                       Usage:    "returns at most `<limit>` endpoints",
+                       Required: false,
+                       Value:    100,
+               },
+               cli.StringFlag{
+                       Name:     "keyword",
+                       Usage:    "`<keyword>` of the endpoint name to search 
for, empty to search all",
+                       Required: false,
+                       Value:    "",
+               },
+       },
        Action: func(ctx *cli.Context) error {
-               end := ctx.String("end")
-               start := ctx.String("start")
-               step := ctx.Generic("step")
-               metricsName := ctx.String("name")
+               serviceID := ctx.String("service-id")
+               limit := ctx.Int("limit")
+               keyword := ctx.String("keyword")
 
-               metricsValues := client.LinearIntValues(ctx, 
schema.MetricCondition{
-                       Name: metricsName,
-               }, schema.Duration{
-                       Start: start,
-                       End:   end,
-                       Step:  step.(*model.StepEnumValue).Selected,
-               })
+               endpoints := client.SearchEndpoints(ctx, serviceID, keyword, 
limit)
 
-               return display.Display(ctx, metricsValues)
+               return display.Display(ctx, endpoints)
        },
 }
diff --git a/commands/metrics/linear-metrics.go 
b/commands/metrics/linear/linear-metrics.go
similarity index 88%
copy from commands/metrics/linear-metrics.go
copy to commands/metrics/linear/linear-metrics.go
index e3148fe..f34289a 100644
--- a/commands/metrics/linear-metrics.go
+++ b/commands/metrics/linear/linear-metrics.go
@@ -15,7 +15,7 @@
 // specific language governing permissions and limitations
 // under the License.
 
-package metrics
+package linear
 
 import (
        "github.com/urfave/cli"
@@ -39,6 +39,11 @@ var Command = cli.Command{
                                Usage:    "metrics `NAME`, such as `all_p99`",
                                Required: true,
                        },
+                       cli.StringFlag{
+                               Name:     "id",
+                               Usage:    "`ID`, the related id if the metrics 
requires one",
+                               Required: false,
+                       },
                },
        ),
        Before: interceptor.BeforeChain([]cli.BeforeFunc{
@@ -50,8 +55,15 @@ var Command = cli.Command{
                step := ctx.Generic("step")
                metricsName := ctx.String("name")
 
+               var id *string = nil
+
+               if idString := ctx.String("id"); idString != "" {
+                       id = &idString
+               }
+
                metricsValues := client.LinearIntValues(ctx, 
schema.MetricCondition{
                        Name: metricsName,
+                       ID:   id,
                }, schema.Duration{
                        Start: start,
                        End:   end,
diff --git a/commands/metrics/linear-metrics.go 
b/commands/metrics/single/single-metrics.go
similarity index 76%
rename from commands/metrics/linear-metrics.go
rename to commands/metrics/single/single-metrics.go
index e3148fe..ded58ac 100644
--- a/commands/metrics/linear-metrics.go
+++ b/commands/metrics/single/single-metrics.go
@@ -15,9 +15,11 @@
 // specific language governing permissions and limitations
 // under the License.
 
-package metrics
+package single
 
 import (
+       "strings"
+
        "github.com/urfave/cli"
 
        "github.com/apache/skywalking-cli/commands/flags"
@@ -29,16 +31,21 @@ import (
 )
 
 var Command = cli.Command{
-       Name:  "linear-metrics",
-       Usage: "Query linear metrics defined in backend OAL",
+       Name:  "single-metrics",
+       Usage: "Query single metrics defined in backend OAL",
        Flags: flags.Flags(
                flags.DurationFlags,
                []cli.Flag{
                        cli.StringFlag{
                                Name:     "name",
-                               Usage:    "metrics `NAME`, such as `all_p99`",
+                               Usage:    "metrics `NAME`, which should be 
defined in OAL script",
                                Required: true,
                        },
+                       cli.StringSliceFlag{
+                               Name:     "ids",
+                               Usage:    "`IDs`, IDs that are required by the 
given metric type",
+                               Required: false,
+                       },
                },
        ),
        Before: interceptor.BeforeChain([]cli.BeforeFunc{
@@ -49,9 +56,17 @@ var Command = cli.Command{
                start := ctx.String("start")
                step := ctx.Generic("step")
                metricsName := ctx.String("name")
+               idsString := ctx.StringSlice("ids")
+
+               var ids []string
+
+               for _, id := range idsString {
+                       ids = append(ids, strings.Split(id, ",")...)
+               }
 
-               metricsValues := client.LinearIntValues(ctx, 
schema.MetricCondition{
+               metricsValues := client.IntValues(ctx, 
schema.BatchMetricConditions{
                        Name: metricsName,
+                       Ids:  ids,
                }, schema.Duration{
                        Start: start,
                        End:   end,
diff --git a/display/table/table.go b/display/table/table.go
index d79f917..ce2a5ea 100644
--- a/display/table/table.go
+++ b/display/table/table.go
@@ -21,28 +21,32 @@ import (
        "encoding/json"
        "os"
 
+       "github.com/apache/skywalking-cli/logger"
+
        "github.com/olekukonko/tablewriter"
 )
 
 func Display(object interface{}) error {
-       var objMaps []map[string]string
+       var stringMapArrays []map[string]string
 
        bytes, _ := json.Marshal(object)
-       _ = json.Unmarshal(bytes, &objMaps)
+       _ = json.Unmarshal(bytes, &stringMapArrays)
 
-       if len(objMaps) < 1 {
+       if len(stringMapArrays) < 1 {
                return nil
        }
 
        var header []string
 
-       for k := range objMaps[0] {
+       for k := range stringMapArrays[0] {
                header = append(header, k)
        }
 
+       logger.Log.Debugln("stringMapArrays = ", stringMapArrays, " Headers = 
", header)
+
        var data [][]string
 
-       for _, objMap := range objMaps {
+       for _, objMap := range stringMapArrays {
                var datum []string
                for _, key := range header {
                        datum = append(datum, objMap[key])
diff --git a/go.sum b/go.sum
index 0203faf..3d6e7a9 100644
--- a/go.sum
+++ b/go.sum
@@ -3,6 +3,7 @@ github.com/BurntSushi/toml v0.3.1/go.mod 
h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03
 github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d 
h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY=
 github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod 
h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
 github.com/davecgh/go-spew v1.1.1/go.mod 
h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/konsorten/go-windows-terminal-sequences v1.0.1 
h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
 github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod 
h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
 github.com/lytics/logrus v0.0.0-20170528191427-4389a17ed024 
h1:QaKVrqyQRNPbdBNCpiU0Ei3iDQko3qoiUUXMiTWhzZM=
 github.com/lytics/logrus v0.0.0-20170528191427-4389a17ed024/go.mod 
h1:SkQviJ2s7rFyzyuxdVp6osZceHOabU91ZhKsEXF0RWg=
diff --git a/graphql/client/client.go b/graphql/client/client.go
index 1f87a55..d33df92 100644
--- a/graphql/client/client.go
+++ b/graphql/client/client.go
@@ -60,6 +60,38 @@ func Services(cliCtx *cli.Context, duration schema.Duration) 
[]schema.Service {
        return response["services"]
 }
 
+func SearchEndpoints(cliCtx *cli.Context, serviceID, keyword string, limit 
int) []schema.Endpoint {
+       var response map[string][]schema.Endpoint
+       request := graphql.NewRequest(`
+               query ($keyword: String!, $serviceId: ID!, $limit: Int!) {
+                       endpoints: searchEndpoint(keyword: $keyword, serviceId: 
$serviceId, limit: $limit) {
+                               id name
+                       }
+               }
+       `)
+       request.Var("serviceId", serviceID)
+       request.Var("keyword", keyword)
+       request.Var("limit", limit)
+
+       executeQuery(cliCtx, request, &response)
+       return response["endpoints"]
+}
+
+func GetEndpointInfo(cliCtx *cli.Context, endpointID string) schema.Endpoint {
+       var response map[string]schema.Endpoint
+       request := graphql.NewRequest(`
+               query ($endpointId: ID!) {
+                       endpoint: getEndpointInfo(endpointId: $endpointId) {
+                               id name
+                       }
+               }
+       `)
+       request.Var("endpointId", endpointID)
+
+       executeQuery(cliCtx, request, &response)
+       return response["endpoint"]
+}
+
 func Instances(cliCtx *cli.Context, serviceID string, duration 
schema.Duration) []schema.ServiceInstance {
        var response map[string][]schema.ServiceInstance
        request := graphql.NewRequest(`
@@ -122,6 +154,24 @@ func LinearIntValues(ctx *cli.Context, condition 
schema.MetricCondition, duratio
        return values
 }
 
+func IntValues(ctx *cli.Context, condition schema.BatchMetricConditions, 
duration schema.Duration) []*schema.KVInt {
+       var response map[string]schema.IntValues
+
+       request := graphql.NewRequest(`
+               query ($metric: BatchMetricConditions!, $duration: Duration!) {
+                       metrics: getValues(metric: $metric, duration: 
$duration) {
+                               values { id value }
+                       }
+               }
+       `)
+       request.Var("metric", condition)
+       request.Var("duration", duration)
+
+       executeQuery(ctx, request, &response)
+
+       return response["metrics"].Values
+}
+
 func metricsToMap(duration schema.Duration, kvInts []*schema.KVInt) 
map[string]float64 {
        values := map[string]float64{}
        format := schema.StepFormats[duration.Step]
diff --git a/scripts/build b/scripts/build
deleted file mode 100755
index 7a20563..0000000
--- a/scripts/build
+++ /dev/null
@@ -1,28 +0,0 @@
-#!/usr/bin/env bash
-#
-# 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.
-#
-#
-
-cli_build() {
-  out="bin"
-  CGO_ENABLED=0 go build $GO_BUILD_FLAGS \
-  -o "${out}/swctl" swctl/* || return
-}
-
-if echo "$0" | grep "build$" > /dev/null; then
-  cli_build
-fi
\ No newline at end of file
diff --git a/swctl/main.go b/swctl/main.go
index f260fc2..20efced 100644
--- a/swctl/main.go
+++ b/swctl/main.go
@@ -21,7 +21,9 @@ import (
        "io/ioutil"
        "os"
 
-       "github.com/apache/skywalking-cli/commands/metrics"
+       "github.com/apache/skywalking-cli/commands/endpoint"
+       linearMetrics "github.com/apache/skywalking-cli/commands/metrics/linear"
+       singleMetrics "github.com/apache/skywalking-cli/commands/metrics/single"
 
        "github.com/apache/skywalking-cli/commands/instance"
 
@@ -73,7 +75,9 @@ func main() {
        app.Commands = []cli.Command{
                service.Command,
                instance.Command,
-               metrics.Command,
+               linearMetrics.Command,
+               singleMetrics.Command,
+               endpoint.Command,
        }
 
        app.Before = interceptor.BeforeChain([]cli.BeforeFunc{

Reply via email to