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

commit 298aff8b4cd0fe3d3c432d569eb29c47a8da2a6e
Author: kezhenxu94 <kezhenx...@163.com>
AuthorDate: Thu Nov 7 19:05:13 2019 +0800

    Motivation:
    
    Set up the graphql client, schema and implement a service command
    for reference
    
    Modifications:
    
    - Set up GraphQL client
    - Implement service ls command
    
    Result:
    
    GraphQL client can be reused by other commands
---
 .asf.yaml                   |  17 +
 .github/workflows/go.yml    |  32 +-
 Makefile                    |  24 +-
 cmd/main.go                 |  32 --
 cmd/service.go              |  24 --
 commands/interceptor.go     |  71 +++++
 commands/model.go           |  49 +++
 commands/service/list.go    |  73 +++++
 commands/service/service.go |  32 ++
 config/config.go            |  25 ++
 go.mod                      |   3 +-
 go.sum                      |   5 +
 graphql/client/client.go    |  51 +++
 graphql/schema/schema.go    | 750 ++++++++++++++++++++++++++++++++++++++++++++
 logger/log.go               |  18 ++
 scripts/build               |  19 +-
 swctl/main.go               |  86 +++++
 swctl/service/list.go       |   5 -
 swctl/service/service.go    |  24 --
 19 files changed, 1233 insertions(+), 107 deletions(-)

diff --git a/.asf.yaml b/.asf.yaml
index 3f2645a..c1f6dfa 100644
--- a/.asf.yaml
+++ b/.asf.yaml
@@ -1,3 +1,20 @@
+#
+# 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.
+#
+
 github:
   description: Apache SkyWalking CLI
   homepage: https://skywalking.apache.org/
diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml
index bdc008c..1abc12e 100644
--- a/.github/workflows/go.yml
+++ b/.github/workflows/go.yml
@@ -23,22 +23,22 @@ jobs:
     runs-on: ubuntu-latest
     steps:
 
-    - name: Set up Go 1.13
-      uses: actions/setup-go@v1
-      with:
-        go-version: 1.13
-      id: go
+      - name: Set up Go 1.13
+        uses: actions/setup-go@v1
+        with:
+          go-version: 1.13
+        id: go
 
-    - name: Check out code into the Go module directory
-      uses: actions/checkout@v1
+      - name: Check out code into the Go module directory
+        uses: actions/checkout@v1
 
-    - 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
+      - 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
 
-    - name: Build
-      run: make
+      - name: Build
+        run: make
diff --git a/Makefile b/Makefile
index aa368e7..3273175 100644
--- a/Makefile
+++ b/Makefile
@@ -1,9 +1,25 @@
-# Example:
-#   make build
-#   make install
+#
+# 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.
+#
 
 .PHONY: build install
 
 build:
        GO_BUILD_FLAGS="-v" ./scripts/build
-       ./bin/swctl --version
\ No newline at end of file
+       ./bin/swctl --version
+
+clean:
+       -rm -rf ./bin
\ No newline at end of file
diff --git a/cmd/main.go b/cmd/main.go
deleted file mode 100644
index e4969db..0000000
--- a/cmd/main.go
+++ /dev/null
@@ -1,32 +0,0 @@
-package main
-
-import (
-       "os"
-
-       "github.com/sirupsen/logrus"
-       "github.com/urfave/cli"
-
-       "github.com/apache/skywalking-cli/logger"
-)
-
-var log *logrus.Logger
-
-func init() {
-       log = logger.Log
-}
-
-func main() {
-       app := cli.NewApp()
-       app.Flags = []cli.Flag{
-               cli.StringFlag{
-                       Name:  "config, c",
-                       Usage: "path of settings.yml config. Use the file in 
the same folder as default.",
-               },
-       }
-       app.Commands = []cli.Command{serviceCmd}
-
-       err := app.Run(os.Args)
-       if err != nil {
-               log.Fatal(err)
-       }
-}
diff --git a/cmd/service.go b/cmd/service.go
deleted file mode 100644
index 36c9e5e..0000000
--- a/cmd/service.go
+++ /dev/null
@@ -1,24 +0,0 @@
-package main
-
-import (
-       "github.com/apache/skywalking-cli/swctl/service"
-       "github.com/urfave/cli"
-)
-
-var serviceCmd = cli.Command{
-       Name: "service",
-       Flags: []cli.Flag{
-               cli.BoolFlag{
-                       Name:  "list",
-                       Usage: "list all available services.",
-               },
-       },
-       Action: func(c *cli.Context) {
-               ctl := service.NewService(c)
-
-               err := ctl.Exec()
-               if err != nil {
-                       log.Fatal(err)
-               }
-       },
-}
diff --git a/commands/interceptor.go b/commands/interceptor.go
new file mode 100644
index 0000000..6837529
--- /dev/null
+++ b/commands/interceptor.go
@@ -0,0 +1,71 @@
+/*
+ * 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 commands
+
+import (
+       "github.com/apache/skywalking-cli/graphql/schema"
+       "github.com/apache/skywalking-cli/logger"
+       "github.com/urfave/cli"
+       "time"
+)
+
+// Convenient function to chain up multiple cli.BeforeFunc
+func BeforeChain(beforeFunctions []cli.BeforeFunc) cli.BeforeFunc {
+       return func(ctx *cli.Context) error {
+               for _, beforeFunc := range beforeFunctions {
+                       if err := beforeFunc(ctx); err != nil {
+                               return err
+                       }
+               }
+               return nil
+       }
+}
+
+var StepFormats = map[schema.Step]string{
+       schema.StepMonth:  "2006-01-02",
+       schema.StepDay:    "2006-01-02",
+       schema.StepHour:   "2006-01-02 15",
+       schema.StepMinute: "2006-01-02 1504",
+       schema.StepSecond: "2006-01-02 1504",
+}
+
+// Set the duration if not set, and format it according to
+// the given step
+func SetUpDuration(ctx *cli.Context) error {
+       step := ctx.Generic("step").(*StepEnumValue).Selected
+       end := ctx.String("end")
+       if len(end) == 0 {
+               end = time.Now().Format(StepFormats[step])
+               logger.Log.Debugln("Missing --end, defaults to", end)
+               if err := ctx.Set("end", end); err != nil {
+                       return err
+               }
+       }
+
+       start := ctx.String("start")
+       if len(start) == 0 {
+               start = time.Now().Add(-15 * 
time.Minute).Format(StepFormats[step])
+               logger.Log.Debugln("Missing --start, defaults to", start)
+               if err := ctx.Set("start", start); err != nil {
+                       return err
+               }
+       }
+
+       return nil
+}
diff --git a/commands/model.go b/commands/model.go
new file mode 100644
index 0000000..9da2fba
--- /dev/null
+++ b/commands/model.go
@@ -0,0 +1,49 @@
+/*
+ * 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 commands
+
+import (
+       "fmt"
+       "github.com/apache/skywalking-cli/graphql/schema"
+       "strings"
+)
+
+type StepEnumValue struct {
+       Enum     []schema.Step
+       Default  schema.Step
+       Selected schema.Step
+}
+
+func (s *StepEnumValue) Set(value string) error {
+       for _, enum := range s.Enum {
+               if enum.String() == value {
+                       s.Selected = enum
+                       return nil
+               }
+       }
+       steps := make([]string, len(schema.AllStep))
+       for i, step := range schema.AllStep {
+               steps[i] = step.String()
+       }
+       return fmt.Errorf("allowed steps are %s", strings.Join(steps, ", "))
+}
+
+func (s StepEnumValue) String() string {
+       return s.Selected.String()
+}
diff --git a/commands/service/list.go b/commands/service/list.go
new file mode 100644
index 0000000..e2c91af
--- /dev/null
+++ b/commands/service/list.go
@@ -0,0 +1,73 @@
+/*
+ * 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 service
+
+import (
+       "encoding/json"
+       "fmt"
+       "github.com/apache/skywalking-cli/commands"
+       "github.com/apache/skywalking-cli/graphql/client"
+       "github.com/apache/skywalking-cli/graphql/schema"
+       "github.com/urfave/cli"
+)
+
+var ListCommand = cli.Command{
+       Name:      "list",
+       ShortName: "ls",
+       Usage:     "List all available services",
+       Flags: []cli.Flag{
+               cli.StringFlag{
+                       Name:  "start",
+                       Usage: "Query start time",
+               },
+               cli.StringFlag{
+                       Name:  "end",
+                       Usage: "Query end time",
+               },
+               cli.GenericFlag{
+                       Name: "step",
+                       Value: &commands.StepEnumValue{
+                               Enum:     schema.AllStep,
+                               Default:  schema.StepMinute,
+                               Selected: schema.StepMinute,
+                       },
+               },
+       },
+       Before: commands.BeforeChain([]cli.BeforeFunc{
+               commands.SetUpDuration,
+       }),
+       Action: func(ctx *cli.Context) error {
+               end := ctx.String("end")
+               start := ctx.String("start")
+               step := ctx.Generic("step")
+               services := client.Services(schema.Duration{
+                       Start: start,
+                       End:   end,
+                       Step:  step.(*commands.StepEnumValue).Selected,
+               })
+
+               if bytes, e := json.Marshal(services); e != nil {
+                       return e
+               } else {
+                       fmt.Printf("%v\n", string(bytes))
+               }
+
+               return nil
+       },
+}
diff --git a/commands/service/service.go b/commands/service/service.go
new file mode 100644
index 0000000..5760adf
--- /dev/null
+++ b/commands/service/service.go
@@ -0,0 +1,32 @@
+/*
+ * 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 service
+
+import (
+       "github.com/urfave/cli"
+)
+
+var Command = cli.Command{
+       Name:      "service",
+       ShortName: "s",
+       Usage:     "Service related sub-command",
+       Subcommands: cli.Commands{
+               ListCommand,
+       },
+}
diff --git a/config/config.go b/config/config.go
new file mode 100644
index 0000000..bc33da2
--- /dev/null
+++ b/config/config.go
@@ -0,0 +1,25 @@
+/*
+ * 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 config
+
+var Config struct {
+       Global struct {
+               BaseUrl string `yaml:"base-url"`
+       }
+}
diff --git a/go.mod b/go.mod
index 8d79e73..062d750 100644
--- a/go.mod
+++ b/go.mod
@@ -3,7 +3,8 @@ module github.com/apache/skywalking-cli
 go 1.13
 
 require (
-       github.com/lytics/logrus v0.0.0-20170528191427-4389a17ed024 // indirect
+       github.com/machinebox/graphql v0.2.2
+       github.com/pkg/errors v0.8.1 // indirect
        github.com/sirupsen/logrus v1.4.2
        github.com/urfave/cli v1.22.1
 )
diff --git a/go.sum b/go.sum
index 7860264..7627702 100644
--- a/go.sum
+++ b/go.sum
@@ -5,6 +5,10 @@ github.com/davecgh/go-spew v1.1.1/go.mod 
h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
 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=
+github.com/machinebox/graphql v0.2.2 
h1:dWKpJligYKhYKO5A2gvNhkJdQMNZeChZYyBbrZkBZfo=
+github.com/machinebox/graphql v0.2.2/go.mod 
h1:F+kbVMHuwrQ5tYgU9JXlnskM8nOaFxCAEolaQybkjWA=
+github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
+github.com/pkg/errors v0.8.1/go.mod 
h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pmezard/go-difflib v1.0.0/go.mod 
h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/russross/blackfriday/v2 v2.0.1 
h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
 github.com/russross/blackfriday/v2 v2.0.1/go.mod 
h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
@@ -19,4 +23,5 @@ github.com/urfave/cli v1.22.1/go.mod 
h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtX
 golang.org/x/sys v0.0.0-20190422165155-953cdadca894 
h1:Cz4ceDQGXuKRnVBDTS23GTn/pU5OE2C0WrNTOYK1Uuc=
 golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod 
h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod 
h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
 gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
diff --git a/graphql/client/client.go b/graphql/client/client.go
new file mode 100644
index 0000000..10a680a
--- /dev/null
+++ b/graphql/client/client.go
@@ -0,0 +1,51 @@
+/*
+ * 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 client
+
+import (
+       "context"
+       "github.com/apache/skywalking-cli/config"
+       "github.com/apache/skywalking-cli/graphql/schema"
+       "github.com/apache/skywalking-cli/logger"
+       "github.com/machinebox/graphql"
+)
+
+func Services(duration schema.Duration) []schema.Service {
+       ctx := context.Background()
+       client := graphql.NewClient(config.Config.Global.BaseUrl)
+       client.Log = func(msg string) {
+               logger.Log.Debugln(msg)
+       }
+
+       var services map[string][]schema.Service
+       request := graphql.NewRequest(`
+               query ($duration: Duration!) {
+                       services: getAllServices(duration: $duration) {
+                               id name
+                       }
+               }
+       `)
+       request.Var("duration", duration)
+       if err := client.Run(ctx, request, &services); err != nil {
+               logger.Log.Fatalln(err)
+               panic(err)
+       }
+
+       return services["services"]
+}
diff --git a/graphql/schema/schema.go b/graphql/schema/schema.go
new file mode 100644
index 0000000..d3848d5
--- /dev/null
+++ b/graphql/schema/schema.go
@@ -0,0 +1,750 @@
+/*
+ * 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 schema
+
+import (
+       "fmt"
+       "io"
+       "strconv"
+)
+
+type AlarmMessage struct {
+       StartTime int64  `json:"startTime"`
+       Scope     *Scope `json:"scope"`
+       ID        string `json:"id"`
+       Message   string `json:"message"`
+}
+
+type AlarmTrend struct {
+       NumOfAlarm []*int `json:"numOfAlarm"`
+}
+
+type Alarms struct {
+       Msgs  []*AlarmMessage `json:"msgs"`
+       Total int             `json:"total"`
+}
+
+type Attribute struct {
+       Name  string `json:"name"`
+       Value string `json:"value"`
+}
+
+type BasicTrace struct {
+       SegmentID     string   `json:"segmentId"`
+       EndpointNames []string `json:"endpointNames"`
+       Duration      int      `json:"duration"`
+       Start         string   `json:"start"`
+       IsError       *bool    `json:"isError"`
+       TraceIds      []string `json:"traceIds"`
+}
+
+type BatchMetricConditions struct {
+       Name string   `json:"name"`
+       Ids  []string `json:"ids"`
+}
+
+type Call struct {
+       Source           string        `json:"source"`
+       SourceComponents []string      `json:"sourceComponents"`
+       Target           string        `json:"target"`
+       TargetComponents []string      `json:"targetComponents"`
+       ID               string        `json:"id"`
+       DetectPoints     []DetectPoint `json:"detectPoints"`
+}
+
+type ClusterBrief struct {
+       NumOfService  int `json:"numOfService"`
+       NumOfEndpoint int `json:"numOfEndpoint"`
+       NumOfDatabase int `json:"numOfDatabase"`
+       NumOfCache    int `json:"numOfCache"`
+       NumOfMq       int `json:"numOfMQ"`
+}
+
+type Database struct {
+       ID   string `json:"id"`
+       Name string `json:"name"`
+       Type string `json:"type"`
+}
+
+type Duration struct {
+       Start string `json:"start"`
+       End   string `json:"end"`
+       Step  Step   `json:"step"`
+}
+
+type Endpoint struct {
+       ID   string `json:"id"`
+       Name string `json:"name"`
+}
+
+type EndpointInfo struct {
+       ID          string `json:"id"`
+       Name        string `json:"name"`
+       ServiceID   string `json:"serviceId"`
+       ServiceName string `json:"serviceName"`
+}
+
+type IntValues struct {
+       Values []*KVInt `json:"values"`
+}
+
+type KVInt struct {
+       ID    string `json:"id"`
+       Value int64  `json:"value"`
+}
+
+type KeyValue struct {
+       Key   string  `json:"key"`
+       Value *string `json:"value"`
+}
+
+type Log struct {
+       ServiceName         *string     `json:"serviceName"`
+       ServiceID           *string     `json:"serviceId"`
+       ServiceInstanceName *string     `json:"serviceInstanceName"`
+       ServiceInstanceID   *string     `json:"serviceInstanceId"`
+       EndpointName        *string     `json:"endpointName"`
+       EndpointID          *string     `json:"endpointId"`
+       TraceID             *string     `json:"traceId"`
+       Timestamp           string      `json:"timestamp"`
+       IsError             *bool       `json:"isError"`
+       StatusCode          *string     `json:"statusCode"`
+       ContentType         ContentType `json:"contentType"`
+       Content             *string     `json:"content"`
+}
+
+type LogEntity struct {
+       Time int64       `json:"time"`
+       Data []*KeyValue `json:"data"`
+}
+
+type LogQueryCondition struct {
+       MetricName        *string     `json:"metricName"`
+       ServiceID         *string     `json:"serviceId"`
+       ServiceInstanceID *string     `json:"serviceInstanceId"`
+       EndpointID        *string     `json:"endpointId"`
+       TraceID           *string     `json:"traceId"`
+       QueryDuration     *Duration   `json:"queryDuration"`
+       State             LogState    `json:"state"`
+       StateCode         *string     `json:"stateCode"`
+       Paging            *Pagination `json:"paging"`
+}
+
+type Logs struct {
+       Logs  []*Log `json:"logs"`
+       Total int    `json:"total"`
+}
+
+type MetricCondition struct {
+       Name string  `json:"name"`
+       ID   *string `json:"id"`
+}
+
+type Node struct {
+       ID     string  `json:"id"`
+       Name   string  `json:"name"`
+       Type   *string `json:"type"`
+       IsReal bool    `json:"isReal"`
+}
+
+type Pagination struct {
+       PageNum   *int  `json:"pageNum"`
+       PageSize  int   `json:"pageSize"`
+       NeedTotal *bool `json:"needTotal"`
+}
+
+type Ref struct {
+       TraceID         string  `json:"traceId"`
+       ParentSegmentID string  `json:"parentSegmentId"`
+       ParentSpanID    int     `json:"parentSpanId"`
+       Type            RefType `json:"type"`
+}
+
+type Service struct {
+       ID   string `json:"id"`
+       Name string `json:"name"`
+}
+
+type ServiceInstance struct {
+       ID           string       `json:"id"`
+       Name         string       `json:"name"`
+       Attributes   []*Attribute `json:"attributes"`
+       Language     Language     `json:"language"`
+       InstanceUUID string       `json:"instanceUUID"`
+}
+
+type Span struct {
+       TraceID      string       `json:"traceId"`
+       SegmentID    string       `json:"segmentId"`
+       SpanID       int          `json:"spanId"`
+       ParentSpanID int          `json:"parentSpanId"`
+       Refs         []*Ref       `json:"refs"`
+       ServiceCode  string       `json:"serviceCode"`
+       StartTime    int64        `json:"startTime"`
+       EndTime      int64        `json:"endTime"`
+       EndpointName *string      `json:"endpointName"`
+       Type         string       `json:"type"`
+       Peer         *string      `json:"peer"`
+       Component    *string      `json:"component"`
+       IsError      *bool        `json:"isError"`
+       Layer        *string      `json:"layer"`
+       Tags         []*KeyValue  `json:"tags"`
+       Logs         []*LogEntity `json:"logs"`
+}
+
+type Thermodynamic struct {
+       Nodes     [][]*int `json:"nodes"`
+       AxisYStep int      `json:"axisYStep"`
+}
+
+type TimeInfo struct {
+       Timezone         *string `json:"timezone"`
+       CurrentTimestamp *int64  `json:"currentTimestamp"`
+}
+
+type TopNEntity struct {
+       Name  string `json:"name"`
+       ID    string `json:"id"`
+       Value int64  `json:"value"`
+}
+
+type TopNRecord struct {
+       Statement *string `json:"statement"`
+       Latency   int64   `json:"latency"`
+       TraceID   *string `json:"traceId"`
+}
+
+type TopNRecordsCondition struct {
+       ServiceID  string    `json:"serviceId"`
+       MetricName string    `json:"metricName"`
+       TopN       int       `json:"topN"`
+       Order      Order     `json:"order"`
+       Duration   *Duration `json:"duration"`
+}
+
+type Topology struct {
+       Nodes []*Node `json:"nodes"`
+       Calls []*Call `json:"calls"`
+}
+
+type Trace struct {
+       Spans []*Span `json:"spans"`
+}
+
+type TraceBrief struct {
+       Traces []*BasicTrace `json:"traces"`
+       Total  int           `json:"total"`
+}
+
+type TraceQueryCondition struct {
+       ServiceID         *string     `json:"serviceId"`
+       ServiceInstanceID *string     `json:"serviceInstanceId"`
+       TraceID           *string     `json:"traceId"`
+       EndpointID        *string     `json:"endpointId"`
+       EndpointName      *string     `json:"endpointName"`
+       QueryDuration     *Duration   `json:"queryDuration"`
+       MinTraceDuration  *int        `json:"minTraceDuration"`
+       MaxTraceDuration  *int        `json:"maxTraceDuration"`
+       TraceState        TraceState  `json:"traceState"`
+       QueryOrder        QueryOrder  `json:"queryOrder"`
+       Paging            *Pagination `json:"paging"`
+}
+
+type ContentType string
+
+const (
+       ContentTypeText ContentType = "TEXT"
+       ContentTypeJSON ContentType = "JSON"
+       ContentTypeNone ContentType = "NONE"
+)
+
+var AllContentType = []ContentType{
+       ContentTypeText,
+       ContentTypeJSON,
+       ContentTypeNone,
+}
+
+func (e ContentType) IsValid() bool {
+       switch e {
+       case ContentTypeText, ContentTypeJSON, ContentTypeNone:
+               return true
+       }
+       return false
+}
+
+func (e ContentType) String() string {
+       return string(e)
+}
+
+func (e *ContentType) UnmarshalGQL(v interface{}) error {
+       str, ok := v.(string)
+       if !ok {
+               return fmt.Errorf("enums must be strings")
+       }
+
+       *e = ContentType(str)
+       if !e.IsValid() {
+               return fmt.Errorf("%s is not a valid ContentType", str)
+       }
+       return nil
+}
+
+func (e ContentType) MarshalGQL(w io.Writer) {
+       fmt.Fprint(w, strconv.Quote(e.String()))
+}
+
+type DetectPoint string
+
+const (
+       DetectPointClient DetectPoint = "CLIENT"
+       DetectPointServer DetectPoint = "SERVER"
+       DetectPointProxy  DetectPoint = "PROXY"
+)
+
+var AllDetectPoint = []DetectPoint{
+       DetectPointClient,
+       DetectPointServer,
+       DetectPointProxy,
+}
+
+func (e DetectPoint) IsValid() bool {
+       switch e {
+       case DetectPointClient, DetectPointServer, DetectPointProxy:
+               return true
+       }
+       return false
+}
+
+func (e DetectPoint) String() string {
+       return string(e)
+}
+
+func (e *DetectPoint) UnmarshalGQL(v interface{}) error {
+       str, ok := v.(string)
+       if !ok {
+               return fmt.Errorf("enums must be strings")
+       }
+
+       *e = DetectPoint(str)
+       if !e.IsValid() {
+               return fmt.Errorf("%s is not a valid DetectPoint", str)
+       }
+       return nil
+}
+
+func (e DetectPoint) MarshalGQL(w io.Writer) {
+       fmt.Fprint(w, strconv.Quote(e.String()))
+}
+
+type Language string
+
+const (
+       LanguageUnknown Language = "UNKNOWN"
+       LanguageJava    Language = "JAVA"
+       LanguageDotnet  Language = "DOTNET"
+       LanguageNodejs  Language = "NODEJS"
+       LanguagePython  Language = "PYTHON"
+       LanguageRuby    Language = "RUBY"
+)
+
+var AllLanguage = []Language{
+       LanguageUnknown,
+       LanguageJava,
+       LanguageDotnet,
+       LanguageNodejs,
+       LanguagePython,
+       LanguageRuby,
+}
+
+func (e Language) IsValid() bool {
+       switch e {
+       case LanguageUnknown, LanguageJava, LanguageDotnet, LanguageNodejs, 
LanguagePython, LanguageRuby:
+               return true
+       }
+       return false
+}
+
+func (e Language) String() string {
+       return string(e)
+}
+
+func (e *Language) UnmarshalGQL(v interface{}) error {
+       str, ok := v.(string)
+       if !ok {
+               return fmt.Errorf("enums must be strings")
+       }
+
+       *e = Language(str)
+       if !e.IsValid() {
+               return fmt.Errorf("%s is not a valid Language", str)
+       }
+       return nil
+}
+
+func (e Language) MarshalGQL(w io.Writer) {
+       fmt.Fprint(w, strconv.Quote(e.String()))
+}
+
+type LogState string
+
+const (
+       LogStateAll     LogState = "ALL"
+       LogStateSuccess LogState = "SUCCESS"
+       LogStateError   LogState = "ERROR"
+)
+
+var AllLogState = []LogState{
+       LogStateAll,
+       LogStateSuccess,
+       LogStateError,
+}
+
+func (e LogState) IsValid() bool {
+       switch e {
+       case LogStateAll, LogStateSuccess, LogStateError:
+               return true
+       }
+       return false
+}
+
+func (e LogState) String() string {
+       return string(e)
+}
+
+func (e *LogState) UnmarshalGQL(v interface{}) error {
+       str, ok := v.(string)
+       if !ok {
+               return fmt.Errorf("enums must be strings")
+       }
+
+       *e = LogState(str)
+       if !e.IsValid() {
+               return fmt.Errorf("%s is not a valid LogState", str)
+       }
+       return nil
+}
+
+func (e LogState) MarshalGQL(w io.Writer) {
+       fmt.Fprint(w, strconv.Quote(e.String()))
+}
+
+type NodeType string
+
+const (
+       NodeTypeService  NodeType = "SERVICE"
+       NodeTypeEndpoint NodeType = "ENDPOINT"
+       NodeTypeUser     NodeType = "USER"
+)
+
+var AllNodeType = []NodeType{
+       NodeTypeService,
+       NodeTypeEndpoint,
+       NodeTypeUser,
+}
+
+func (e NodeType) IsValid() bool {
+       switch e {
+       case NodeTypeService, NodeTypeEndpoint, NodeTypeUser:
+               return true
+       }
+       return false
+}
+
+func (e NodeType) String() string {
+       return string(e)
+}
+
+func (e *NodeType) UnmarshalGQL(v interface{}) error {
+       str, ok := v.(string)
+       if !ok {
+               return fmt.Errorf("enums must be strings")
+       }
+
+       *e = NodeType(str)
+       if !e.IsValid() {
+               return fmt.Errorf("%s is not a valid NodeType", str)
+       }
+       return nil
+}
+
+func (e NodeType) MarshalGQL(w io.Writer) {
+       fmt.Fprint(w, strconv.Quote(e.String()))
+}
+
+type Order string
+
+const (
+       OrderAsc Order = "ASC"
+       OrderDes Order = "DES"
+)
+
+var AllOrder = []Order{
+       OrderAsc,
+       OrderDes,
+}
+
+func (e Order) IsValid() bool {
+       switch e {
+       case OrderAsc, OrderDes:
+               return true
+       }
+       return false
+}
+
+func (e Order) String() string {
+       return string(e)
+}
+
+func (e *Order) UnmarshalGQL(v interface{}) error {
+       str, ok := v.(string)
+       if !ok {
+               return fmt.Errorf("enums must be strings")
+       }
+
+       *e = Order(str)
+       if !e.IsValid() {
+               return fmt.Errorf("%s is not a valid Order", str)
+       }
+       return nil
+}
+
+func (e Order) MarshalGQL(w io.Writer) {
+       fmt.Fprint(w, strconv.Quote(e.String()))
+}
+
+type QueryOrder string
+
+const (
+       QueryOrderByStartTime QueryOrder = "BY_START_TIME"
+       QueryOrderByDuration  QueryOrder = "BY_DURATION"
+)
+
+var AllQueryOrder = []QueryOrder{
+       QueryOrderByStartTime,
+       QueryOrderByDuration,
+}
+
+func (e QueryOrder) IsValid() bool {
+       switch e {
+       case QueryOrderByStartTime, QueryOrderByDuration:
+               return true
+       }
+       return false
+}
+
+func (e QueryOrder) String() string {
+       return string(e)
+}
+
+func (e *QueryOrder) UnmarshalGQL(v interface{}) error {
+       str, ok := v.(string)
+       if !ok {
+               return fmt.Errorf("enums must be strings")
+       }
+
+       *e = QueryOrder(str)
+       if !e.IsValid() {
+               return fmt.Errorf("%s is not a valid QueryOrder", str)
+       }
+       return nil
+}
+
+func (e QueryOrder) MarshalGQL(w io.Writer) {
+       fmt.Fprint(w, strconv.Quote(e.String()))
+}
+
+type RefType string
+
+const (
+       RefTypeCrossProcess RefType = "CROSS_PROCESS"
+       RefTypeCrossThread  RefType = "CROSS_THREAD"
+)
+
+var AllRefType = []RefType{
+       RefTypeCrossProcess,
+       RefTypeCrossThread,
+}
+
+func (e RefType) IsValid() bool {
+       switch e {
+       case RefTypeCrossProcess, RefTypeCrossThread:
+               return true
+       }
+       return false
+}
+
+func (e RefType) String() string {
+       return string(e)
+}
+
+func (e *RefType) UnmarshalGQL(v interface{}) error {
+       str, ok := v.(string)
+       if !ok {
+               return fmt.Errorf("enums must be strings")
+       }
+
+       *e = RefType(str)
+       if !e.IsValid() {
+               return fmt.Errorf("%s is not a valid RefType", str)
+       }
+       return nil
+}
+
+func (e RefType) MarshalGQL(w io.Writer) {
+       fmt.Fprint(w, strconv.Quote(e.String()))
+}
+
+type Scope string
+
+const (
+       ScopeService                 Scope = "Service"
+       ScopeServiceInstance         Scope = "ServiceInstance"
+       ScopeEndpoint                Scope = "Endpoint"
+       ScopeServiceRelation         Scope = "ServiceRelation"
+       ScopeServiceInstanceRelation Scope = "ServiceInstanceRelation"
+       ScopeEndpointRelation        Scope = "EndpointRelation"
+)
+
+var AllScope = []Scope{
+       ScopeService,
+       ScopeServiceInstance,
+       ScopeEndpoint,
+       ScopeServiceRelation,
+       ScopeServiceInstanceRelation,
+       ScopeEndpointRelation,
+}
+
+func (e Scope) IsValid() bool {
+       switch e {
+       case ScopeService, ScopeServiceInstance, ScopeEndpoint, 
ScopeServiceRelation, ScopeServiceInstanceRelation, ScopeEndpointRelation:
+               return true
+       }
+       return false
+}
+
+func (e Scope) String() string {
+       return string(e)
+}
+
+func (e *Scope) UnmarshalGQL(v interface{}) error {
+       str, ok := v.(string)
+       if !ok {
+               return fmt.Errorf("enums must be strings")
+       }
+
+       *e = Scope(str)
+       if !e.IsValid() {
+               return fmt.Errorf("%s is not a valid Scope", str)
+       }
+       return nil
+}
+
+func (e Scope) MarshalGQL(w io.Writer) {
+       fmt.Fprint(w, strconv.Quote(e.String()))
+}
+
+type Step string
+
+const (
+       StepMonth  Step = "MONTH"
+       StepDay    Step = "DAY"
+       StepHour   Step = "HOUR"
+       StepMinute Step = "MINUTE"
+       StepSecond Step = "SECOND"
+)
+
+var AllStep = []Step{
+       StepMonth,
+       StepDay,
+       StepHour,
+       StepMinute,
+       StepSecond,
+}
+
+func (e Step) IsValid() bool {
+       switch e {
+       case StepMonth, StepDay, StepHour, StepMinute, StepSecond:
+               return true
+       }
+       return false
+}
+
+func (e Step) String() string {
+       return string(e)
+}
+
+func (e *Step) UnmarshalGQL(v interface{}) error {
+       str, ok := v.(string)
+       if !ok {
+               return fmt.Errorf("enums must be strings")
+       }
+
+       *e = Step(str)
+       if !e.IsValid() {
+               return fmt.Errorf("%s is not a valid Step", str)
+       }
+       return nil
+}
+
+func (e Step) MarshalGQL(w io.Writer) {
+       fmt.Fprint(w, strconv.Quote(e.String()))
+}
+
+type TraceState string
+
+const (
+       TraceStateAll     TraceState = "ALL"
+       TraceStateSuccess TraceState = "SUCCESS"
+       TraceStateError   TraceState = "ERROR"
+)
+
+var AllTraceState = []TraceState{
+       TraceStateAll,
+       TraceStateSuccess,
+       TraceStateError,
+}
+
+func (e TraceState) IsValid() bool {
+       switch e {
+       case TraceStateAll, TraceStateSuccess, TraceStateError:
+               return true
+       }
+       return false
+}
+
+func (e TraceState) String() string {
+       return string(e)
+}
+
+func (e *TraceState) UnmarshalGQL(v interface{}) error {
+       str, ok := v.(string)
+       if !ok {
+               return fmt.Errorf("enums must be strings")
+       }
+
+       *e = TraceState(str)
+       if !e.IsValid() {
+               return fmt.Errorf("%s is not a valid TraceState", str)
+       }
+       return nil
+}
+
+func (e TraceState) MarshalGQL(w io.Writer) {
+       fmt.Fprint(w, strconv.Quote(e.String()))
+}
diff --git a/logger/log.go b/logger/log.go
index 039bdec..4a5d482 100644
--- a/logger/log.go
+++ b/logger/log.go
@@ -1,3 +1,21 @@
+/*
+ * 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 logger
 
 import (
diff --git a/scripts/build b/scripts/build
index a60a9cf..7a20563 100755
--- a/scripts/build
+++ b/scripts/build
@@ -1,9 +1,26 @@
 #!/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" cmd/* || return
+  -o "${out}/swctl" swctl/* || return
 }
 
 if echo "$0" | grep "build$" > /dev/null; then
diff --git a/swctl/main.go b/swctl/main.go
new file mode 100644
index 0000000..5619a28
--- /dev/null
+++ b/swctl/main.go
@@ -0,0 +1,86 @@
+/*
+ * 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 main
+
+import (
+       "encoding/json"
+       "github.com/apache/skywalking-cli/commands/service"
+       "github.com/apache/skywalking-cli/config"
+       "github.com/sirupsen/logrus"
+       "github.com/urfave/cli"
+       "gopkg.in/yaml.v2"
+       "io/ioutil"
+       "os"
+
+       "github.com/apache/skywalking-cli/logger"
+)
+
+var log *logrus.Logger
+
+func init() {
+       log = logger.Log
+}
+
+func main() {
+       app := cli.NewApp()
+       app.Usage = "The CLI (Command Line Interface) for Apache SkyWalking."
+       app.Flags = []cli.Flag{
+               cli.StringFlag{
+                       Name:  "config",
+                       Value: "./settings.yml",
+                       Usage: "load configuration `FILE`, default to 
./settings.yml",
+               },
+               cli.BoolFlag{
+                       Name:     "debug",
+                       Required: false,
+                       Usage:    "enable debug mode, will print more detailed 
logs",
+               },
+       }
+       app.Commands = []cli.Command{
+               service.Command,
+       }
+
+       app.Before = BeforeCommand
+
+       if err := app.Run(os.Args); err != nil {
+               log.Fatalln(err)
+       }
+}
+
+func BeforeCommand(c *cli.Context) error {
+       if c.Bool("debug") {
+               log.SetLevel(logrus.DebugLevel)
+               log.Debugln("Debug mode is enabled")
+       }
+
+       configFile := c.String("config")
+       log.Debugln("Using configuration file:", configFile)
+
+       if bytes, err := ioutil.ReadFile(configFile); err != nil {
+               return err
+       } else if err := yaml.Unmarshal(bytes, &config.Config); err != nil {
+               return err
+       }
+
+       if bytes, err := json.Marshal(config.Config); err == nil {
+               log.Debugln("Configurations: ", string(bytes))
+       }
+
+       return nil
+}
diff --git a/swctl/service/list.go b/swctl/service/list.go
deleted file mode 100644
index 73784f5..0000000
--- a/swctl/service/list.go
+++ /dev/null
@@ -1,5 +0,0 @@
-package service
-
-func (s *service) showList() error {
-       return nil
-}
diff --git a/swctl/service/service.go b/swctl/service/service.go
deleted file mode 100644
index f67edf5..0000000
--- a/swctl/service/service.go
+++ /dev/null
@@ -1,24 +0,0 @@
-package service
-
-import (
-       "github.com/urfave/cli"
-)
-
-type service struct {
-       flag *cli.Context
-       list bool
-}
-
-func NewService(flag *cli.Context) *service {
-       return &service{
-               flag: flag,
-               list: flag.Bool("list"),
-       }
-}
-
-func (s *service) Exec() (err error) {
-       if s.list {
-               err = s.showList()
-       }
-       return
-}

Reply via email to