cmd/geth: add attach and rows flags to the monitor command

This commit is contained in:
Péter Szilágyi 2015-06-25 10:36:47 +03:00
parent 1ce40d7581
commit b98b444179
2 changed files with 43 additions and 33 deletions

View File

@ -72,6 +72,7 @@ func init() {
upgradedbCommand, upgradedbCommand,
removedbCommand, removedbCommand,
dumpCommand, dumpCommand,
monitorCommand,
{ {
Action: makedag, Action: makedag,
Name: "makedag", Name: "makedag",
@ -214,16 +215,6 @@ The Geth console is an interactive shell for the JavaScript runtime environment
which exposes a node admin interface as well as the Ðapp JavaScript API. which exposes a node admin interface as well as the Ðapp JavaScript API.
See https://github.com/ethereum/go-ethereum/wiki/Javascipt-Console. See https://github.com/ethereum/go-ethereum/wiki/Javascipt-Console.
This command allows to open a console on a running geth node. This command allows to open a console on a running geth node.
`,
},
{
Action: monitor,
Name: "monitor",
Usage: `Geth Monitor: node metrics monitoring and visualization`,
Description: `
The Geth monitor is a tool to collect and visualize various internal metrics
gathered by the node, supporting different chart types as well as the capacity
to display multiple metrics simultaneously.
`, `,
}, },
{ {

View File

@ -9,48 +9,61 @@ import (
"github.com/codegangsta/cli" "github.com/codegangsta/cli"
"github.com/ethereum/go-ethereum/cmd/utils" "github.com/ethereum/go-ethereum/cmd/utils"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/rpc"
"github.com/ethereum/go-ethereum/rpc/codec" "github.com/ethereum/go-ethereum/rpc/codec"
"github.com/ethereum/go-ethereum/rpc/comms" "github.com/ethereum/go-ethereum/rpc/comms"
"github.com/gizak/termui" "github.com/gizak/termui"
) )
var (
monitorCommandAttachFlag = cli.StringFlag{
Name: "attach",
Value: "ipc:" + common.DefaultIpcPath(),
Usage: "IPC or RPC API endpoint to attach to",
}
monitorCommandRowsFlag = cli.IntFlag{
Name: "rows",
Value: 5,
Usage: "Rows (maximum) to display the charts in",
}
monitorCommand = cli.Command{
Action: monitor,
Name: "monitor",
Usage: `Geth Monitor: node metrics monitoring and visualization`,
Description: `
The Geth monitor is a tool to collect and visualize various internal metrics
gathered by the node, supporting different chart types as well as the capacity
to display multiple metrics simultaneously.
`,
Flags: []cli.Flag{
monitorCommandAttachFlag,
monitorCommandRowsFlag,
},
}
)
// monitor starts a terminal UI based monitoring tool for the requested metrics. // monitor starts a terminal UI based monitoring tool for the requested metrics.
func monitor(ctx *cli.Context) { func monitor(ctx *cli.Context) {
var ( var (
client comms.EthereumClient client comms.EthereumClient
args []string
err error err error
) )
// Attach to an Ethereum node over IPC or RPC // Attach to an Ethereum node over IPC or RPC
if ctx.Args().Present() { endpoint := ctx.String(monitorCommandAttachFlag.Name)
// Try to interpret the first parameter as an endpoint if client, err = comms.ClientFromEndpoint(endpoint, codec.JSON); err != nil {
client, err = comms.ClientFromEndpoint(ctx.Args().First(), codec.JSON) utils.Fatalf("Unable to attach to geth node: %v", err)
if err == nil {
args = ctx.Args().Tail()
}
}
if !ctx.Args().Present() || err != nil {
// Either no args were given, or not endpoint, use defaults
cfg := comms.IpcConfig{
Endpoint: ctx.GlobalString(utils.IPCPathFlag.Name),
}
args = ctx.Args()
client, err = comms.NewIpcClient(cfg, codec.JSON)
}
if err != nil {
utils.Fatalf("Unable to attach to geth node - %v", err)
} }
defer client.Close() defer client.Close()
xeth := rpc.NewXeth(client) xeth := rpc.NewXeth(client)
// Retrieve all the available metrics and resolve the user pattens // Retrieve all the available metrics and resolve the user pattens
metrics, err := xeth.Call("debug_metrics", []interface{}{true}) metrics, err := retrieveMetrics(xeth)
if err != nil { if err != nil {
utils.Fatalf("Failed to retrieve system metrics: %v", err) utils.Fatalf("Failed to retrieve system metrics: %v", err)
} }
monitored := resolveMetrics(metrics, args) monitored := resolveMetrics(metrics, ctx.Args())
sort.Strings(monitored) sort.Strings(monitored)
// Create the access function and check that the metric exists // Create the access function and check that the metric exists
@ -77,8 +90,8 @@ func monitor(ctx *cli.Context) {
termui.UseTheme("helloworld") termui.UseTheme("helloworld")
rows := len(monitored) rows := len(monitored)
if rows > 5 { if max := ctx.Int(monitorCommandRowsFlag.Name); rows > max {
rows = 5 rows = max
} }
cols := (len(monitored) + rows - 1) / rows cols := (len(monitored) + rows - 1) / rows
for i := 0; i < rows; i++ { for i := 0; i < rows; i++ {
@ -126,7 +139,7 @@ func monitor(ctx *cli.Context) {
termui.Render(termui.Body) termui.Render(termui.Body)
} }
case <-refresh: case <-refresh:
metrics, err := xeth.Call("debug_metrics", []interface{}{true}) metrics, err := retrieveMetrics(xeth)
if err != nil { if err != nil {
utils.Fatalf("Failed to retrieve system metrics: %v", err) utils.Fatalf("Failed to retrieve system metrics: %v", err)
} }
@ -139,6 +152,12 @@ func monitor(ctx *cli.Context) {
} }
} }
// retrieveMetrics contacts the attached geth node and retrieves the entire set
// of collected system metrics.
func retrieveMetrics(xeth *rpc.Xeth) (map[string]interface{}, error) {
return xeth.Call("debug_metrics", []interface{}{true})
}
// resolveMetrics takes a list of input metric patterns, and resolves each to one // resolveMetrics takes a list of input metric patterns, and resolves each to one
// or more canonical metric names. // or more canonical metric names.
func resolveMetrics(metrics map[string]interface{}, patterns []string) []string { func resolveMetrics(metrics map[string]interface{}, patterns []string) []string {