未验证 提交 d2bac718 编写于 作者: wu-sheng's avatar wu-sheng 提交者: GitHub

Merge pull request #9 from kezhenxu94/feature/display-styles

[Feature] Support multiple display styles, JSON, YAML, ASCII Table
/*
* 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 flags
import (
"github.com/apache/skywalking-cli/commands/model"
"github.com/apache/skywalking-cli/graphql/schema"
"github.com/urfave/cli"
)
// DurationFlags are common flags that involves a duration, composed
// by a start time, an end time, and a step, which is commonly used
// in most of the commands
var DurationFlags = []cli.Flag{
cli.StringFlag{
Name: "start",
Usage: "query start `TIME`",
},
cli.StringFlag{
Name: "end",
Usage: "query end `TIME`",
},
cli.GenericFlag{
Name: "step",
Hidden: true,
Value: &model.StepEnumValue{
Enum: schema.AllStep,
Default: schema.StepMinute,
Selected: schema.StepMinute,
},
},
}
......@@ -19,10 +19,10 @@
package service
import (
"encoding/json"
"fmt"
"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"
"github.com/urfave/cli"
......@@ -32,25 +32,7 @@ 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",
Hidden: true,
Value: &model.StepEnumValue{
Enum: schema.AllStep,
Default: schema.StepMinute,
Selected: schema.StepMinute,
},
},
},
Flags: flags.DurationFlags,
Before: interceptor.BeforeChain([]cli.BeforeFunc{
interceptor.DurationInterceptor,
}),
......@@ -58,18 +40,12 @@ var ListCommand = cli.Command{
end := ctx.String("end")
start := ctx.String("start")
step := ctx.Generic("step")
services := client.Services(schema.Duration{
services := client.Services(ctx, schema.Duration{
Start: start,
End: end,
Step: step.(*model.StepEnumValue).Selected,
})
if bytes, e := json.Marshal(services); e == nil {
fmt.Printf("%v\n", string(bytes))
} else {
return e
}
return nil
return display.Display(ctx, services)
},
}
/*
* 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 display
import (
"fmt"
"github.com/apache/skywalking-cli/display/json"
"github.com/apache/skywalking-cli/display/table"
"github.com/apache/skywalking-cli/display/yaml"
"github.com/urfave/cli"
"strings"
)
const (
Json string = "json"
Yaml string = "yaml"
Table string = "table"
)
// Display the object in the style specified in flag --display
func Display(ctx *cli.Context, object interface{}) error {
displayStyle := ctx.GlobalString("display")
switch strings.ToLower(displayStyle) {
case Json:
return json.Display(object)
case Yaml:
return yaml.Display(object)
case Table:
return table.Display(object)
default:
return fmt.Errorf("unsupported display style: %s", displayStyle)
}
}
......@@ -16,10 +16,19 @@
*
*/
package config
package json
var Config struct {
Global struct {
BaseURL string `yaml:"base-url"`
import (
"encoding/json"
"fmt"
)
func Display(object interface{}) error {
if bytes, e := json.Marshal(object); e == nil {
fmt.Printf("%v\n", string(bytes))
} else {
return e
}
return nil
}
/*
* 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 table
import (
"encoding/json"
"github.com/olekukonko/tablewriter"
"os"
)
func Display(object interface{}) error {
var objMaps []map[string]string
bytes, _ := json.Marshal(object)
_ = json.Unmarshal(bytes, &objMaps)
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
}
/*
* 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 yaml
import (
"fmt"
"gopkg.in/yaml.v2"
)
func Display(object interface{}) error {
if bytes, e := yaml.Marshal(object); e == nil {
fmt.Printf("%v", string(bytes))
} else {
return e
}
return nil
}
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
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=
......@@ -7,6 +8,11 @@ github.com/lytics/logrus v0.0.0-20170528191427-4389a17ed024 h1:QaKVrqyQRNPbdBNCp
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/mattn/go-runewidth v0.0.4 h1:2BvfKmzob6Bmd4YsL0zygOqfdFnK7GR4QL06Do4/p7Y=
github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
github.com/olekukonko/tablewriter v0.0.2 h1:sq53g+DWf0J6/ceFUHpQ0nAEb6WgM++fq16MZ91cS6o=
github.com/olekukonko/tablewriter v0.0.2/go.mod h1:rSAaSIOAGT9odnlyGlUfAJaoc5w2fSBUmeGDbRWPxyQ=
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=
......
......@@ -20,15 +20,14 @@ 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"
"github.com/urfave/cli"
)
func Services(duration schema.Duration) []schema.Service {
ctx := context.Background()
client := graphql.NewClient(config.Config.Global.BaseURL)
func Services(cliCtx *cli.Context, duration schema.Duration) []schema.Service {
client := graphql.NewClient(cliCtx.GlobalString("base-url"))
client.Log = func(msg string) {
logger.Log.Debugln(msg)
}
......@@ -42,6 +41,8 @@ func Services(duration schema.Duration) []schema.Service {
}
`)
request.Var("duration", duration)
ctx := context.Background()
if err := client.Run(ctx, request, &response); err != nil {
logger.Log.Fatalln(err)
panic(err)
......
......@@ -19,14 +19,13 @@
package main
import (
"encoding/json"
"github.com/apache/skywalking-cli/commands/interceptor"
"github.com/apache/skywalking-cli/commands/service"
"github.com/apache/skywalking-cli/config"
"github.com/apache/skywalking-cli/logger"
"github.com/apache/skywalking-cli/util"
"github.com/sirupsen/logrus"
"github.com/urfave/cli"
"gopkg.in/yaml.v2"
"github.com/urfave/cli/altsrc"
"io/ioutil"
"os"
)
......@@ -40,46 +39,64 @@ func init() {
func main() {
app := cli.NewApp()
app.Usage = "The CLI (Command Line Interface) for Apache SkyWalking."
app.Flags = []cli.Flag{
cli.StringFlag{
flags := []cli.Flag{
altsrc.NewStringFlag(cli.StringFlag{
Name: "config",
Value: "~/.skywalking.yml",
Usage: "load configuration `FILE`",
},
cli.BoolFlag{
}),
altsrc.NewStringFlag(cli.StringFlag{
Name: "base-url",
Required: false,
Usage: "base `url` of the OAP backend graphql",
Value: "http://127.0.0.1:12800/graphql",
}),
altsrc.NewBoolFlag(cli.BoolFlag{
Name: "debug",
Required: false,
Usage: "enable debug mode, will print more detailed logs",
},
}),
altsrc.NewStringFlag(cli.StringFlag{
Name: "display",
Required: false,
Usage: "display `style` of the result, supported styles are: json, yaml",
}),
}
app.Commands = []cli.Command{
service.Command,
}
app.Before = beforeCommand
app.Before = interceptor.BeforeChain([]cli.BeforeFunc{
expandConfigFile,
altsrc.InitInputSourceWithContext(flags, altsrc.NewYamlSourceFromFlagFunc("config")),
setUpCommandLineContext,
})
app.Flags = flags
if err := app.Run(os.Args); err != nil {
log.Fatalln(err)
}
}
func beforeCommand(c *cli.Context) error {
func expandConfigFile(c *cli.Context) error {
return c.Set("config", util.ExpandFilePath(c.String("config")))
}
func setUpCommandLineContext(c *cli.Context) error {
if c.Bool("debug") {
log.SetLevel(logrus.DebugLevel)
log.Debugln("Debug mode is enabled")
}
configFile := util.ExpandFilePath(c.String("config"))
log.Debugln("Using configuration file:", configFile)
configFile := c.String("config")
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))
} else {
log.Debug("Using configurations:\n", string(bytes))
}
return nil
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册