From 298aff8b4cd0fe3d3c432d569eb29c47a8da2a6e Mon Sep 17 00:00:00 2001 From: kezhenxu94 Date: Thu, 7 Nov 2019 19:05:13 +0800 Subject: [PATCH] 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(-) delete mode 100644 cmd/main.go delete mode 100644 cmd/service.go create mode 100644 commands/interceptor.go create mode 100644 commands/model.go create mode 100644 commands/service/list.go create mode 100644 commands/service/service.go create mode 100644 config/config.go create mode 100644 graphql/client/client.go create mode 100644 graphql/schema/schema.go create mode 100644 swctl/main.go delete mode 100644 swctl/service/list.go delete mode 100644 swctl/service/service.go 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 -} -- GitLab