func attach(ctx *cli.Context) { utils.CheckLegalese(ctx.GlobalString(utils.DataDirFlag.Name)) var client comms.EthereumClient var err error if ctx.Args().Present() { client, err = comms.ClientFromEndpoint(ctx.Args().First(), codec.JSON) } else { cfg := comms.IpcConfig{ Endpoint: ctx.GlobalString(utils.IPCPathFlag.Name), } client, err = comms.NewIpcClient(cfg, codec.JSON) } if err != nil { utils.Fatalf("Unable to attach to geth node - %v", err) } repl := newLightweightJSRE( ctx.GlobalString(utils.JSpathFlag.Name), client, true, ) if ctx.GlobalString(utils.ExecFlag.Name) != "" { repl.batch(ctx.GlobalString(utils.ExecFlag.Name)) } else { repl.welcome() repl.interactive() } }
func attach(ctx *cli.Context) { utils.CheckLegalese(ctx.GlobalString(utils.DataDirFlag.Name)) // Wrap the standard output with a colorified stream (windows) if isatty.IsTerminal(os.Stdout.Fd()) { if pr, pw, err := os.Pipe(); err == nil { go io.Copy(colorable.NewColorableStdout(), pr) os.Stdout = pw } } var client comms.EthereumClient var err error if ctx.Args().Present() { client, err = comms.ClientFromEndpoint(ctx.Args().First(), codec.JSON) } else { cfg := comms.IpcConfig{ Endpoint: ctx.GlobalString(utils.IPCPathFlag.Name), } client, err = comms.NewIpcClient(cfg, codec.JSON) } if err != nil { utils.Fatalf("Unable to attach to geth node - %v", err) } repl := newLightweightJSRE( ctx.GlobalString(utils.JSpathFlag.Name), client, true, nil) if ctx.GlobalString(utils.ExecFlag.Name) != "" { repl.batch(ctx.GlobalString(utils.ExecFlag.Name)) } else { repl.welcome() repl.interactive() } }
// monitor starts a terminal UI based monitoring tool for the requested metrics. func monitor(ctx *cli.Context) { var ( client comms.EthereumClient err error ) // Attach to an Ethereum node over IPC or RPC endpoint := ctx.String(monitorCommandAttachFlag.Name) if client, err = comms.ClientFromEndpoint(endpoint, codec.JSON); err != nil { utils.Fatalf("Unable to attach to geth node: %v", err) } defer client.Close() xeth := rpc.NewXeth(client) // Retrieve all the available metrics and resolve the user pattens metrics, err := retrieveMetrics(xeth) if err != nil { utils.Fatalf("Failed to retrieve system metrics: %v", err) } monitored := resolveMetrics(metrics, ctx.Args()) if len(monitored) == 0 { list := expandMetrics(metrics, "") sort.Strings(list) if len(list) > 0 { utils.Fatalf("No metrics specified.\n\nAvailable:\n - %s", strings.Join(list, "\n - ")) } else { utils.Fatalf("No metrics collected by geth (--%s).\n", utils.MetricsEnabledFlag.Name) } } sort.Strings(monitored) if cols := len(monitored) / ctx.Int(monitorCommandRowsFlag.Name); cols > 6 { utils.Fatalf("Requested metrics (%d) spans more that 6 columns:\n - %s", len(monitored), strings.Join(monitored, "\n - ")) } // Create and configure the chart UI defaults if err := termui.Init(); err != nil { utils.Fatalf("Unable to initialize terminal UI: %v", err) } defer termui.Close() termui.UseTheme("helloworld") rows := len(monitored) if max := ctx.Int(monitorCommandRowsFlag.Name); rows > max { rows = max } cols := (len(monitored) + rows - 1) / rows for i := 0; i < rows; i++ { termui.Body.AddRows(termui.NewRow()) } // Create each individual data chart footer := termui.NewPar("") footer.HasBorder = true footer.Height = 3 charts := make([]*termui.LineChart, len(monitored)) units := make([]int, len(monitored)) data := make([][]float64, len(monitored)) for i := 0; i < len(monitored); i++ { charts[i] = createChart((termui.TermHeight() - footer.Height) / rows) row := termui.Body.Rows[i%rows] row.Cols = append(row.Cols, termui.NewCol(12/cols, 0, charts[i])) } termui.Body.AddRows(termui.NewRow(termui.NewCol(12, 0, footer))) refreshCharts(xeth, monitored, data, units, charts, ctx, footer) termui.Body.Align() termui.Render(termui.Body) // Watch for various system events, and periodically refresh the charts refresh := time.Tick(time.Duration(ctx.Int(monitorCommandRefreshFlag.Name)) * time.Second) for { select { case event := <-termui.EventCh(): if event.Type == termui.EventKey && event.Key == termui.KeyCtrlC { return } if event.Type == termui.EventResize { termui.Body.Width = termui.TermWidth() for _, chart := range charts { chart.Height = (termui.TermHeight() - footer.Height) / rows } termui.Body.Align() termui.Render(termui.Body) } case <-refresh: if refreshCharts(xeth, monitored, data, units, charts, ctx, footer) { termui.Body.Align() } termui.Render(termui.Body) } } }