mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-18 02:40:45 +00:00
cmd/XDC, internal, node: nuke XDC monitor (#19399)
This commit is contained in:
parent
68d9dcbee4
commit
d3c023ed37
4 changed files with 0 additions and 478 deletions
|
|
@ -1,351 +0,0 @@
|
||||||
// Copyright 2015 The go-ethereum Authors
|
|
||||||
// This file is part of go-ethereum.
|
|
||||||
//
|
|
||||||
// go-ethereum is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// go-ethereum is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"math"
|
|
||||||
"reflect"
|
|
||||||
"runtime"
|
|
||||||
"sort"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/XinFinOrg/XDPoSChain/cmd/utils"
|
|
||||||
"github.com/XinFinOrg/XDPoSChain/node"
|
|
||||||
"github.com/XinFinOrg/XDPoSChain/rpc"
|
|
||||||
"github.com/gizak/termui"
|
|
||||||
"gopkg.in/urfave/cli.v1"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
monitorCommandAttachFlag = cli.StringFlag{
|
|
||||||
Name: "attach",
|
|
||||||
Value: node.DefaultIPCEndpoint(clientIdentifier),
|
|
||||||
Usage: "API endpoint to attach to",
|
|
||||||
}
|
|
||||||
monitorCommandRowsFlag = cli.IntFlag{
|
|
||||||
Name: "rows",
|
|
||||||
Value: 5,
|
|
||||||
Usage: "Maximum rows in the chart grid",
|
|
||||||
}
|
|
||||||
monitorCommandRefreshFlag = cli.IntFlag{
|
|
||||||
Name: "refresh",
|
|
||||||
Value: 3,
|
|
||||||
Usage: "Refresh interval in seconds",
|
|
||||||
}
|
|
||||||
monitorCommand = cli.Command{
|
|
||||||
Action: utils.MigrateFlags(monitor), // keep track of migration progress
|
|
||||||
Name: "monitor",
|
|
||||||
Usage: "Monitor and visualize node metrics",
|
|
||||||
ArgsUsage: " ",
|
|
||||||
Category: "MONITOR COMMANDS",
|
|
||||||
Description: `
|
|
||||||
The XDC 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,
|
|
||||||
monitorCommandRefreshFlag,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
// monitor starts a terminal UI based monitoring tool for the requested metrics.
|
|
||||||
func monitor(ctx *cli.Context) error {
|
|
||||||
var (
|
|
||||||
client *rpc.Client
|
|
||||||
err error
|
|
||||||
)
|
|
||||||
// Attach to an Ethereum node over IPC or RPC
|
|
||||||
endpoint := ctx.String(monitorCommandAttachFlag.Name)
|
|
||||||
if client, err = dialRPC(endpoint); err != nil {
|
|
||||||
utils.Fatalf("Unable to attach to XDC node: %v", err)
|
|
||||||
}
|
|
||||||
defer client.Close()
|
|
||||||
|
|
||||||
// Retrieve all the available metrics and resolve the user pattens
|
|
||||||
metrics, err := retrieveMetrics(client)
|
|
||||||
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 XDC (--%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()
|
|
||||||
|
|
||||||
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.Block.Border = 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(client, monitored, data, units, charts, ctx, footer)
|
|
||||||
termui.Body.Align()
|
|
||||||
termui.Render(termui.Body)
|
|
||||||
|
|
||||||
// Watch for various system events, and periodically refresh the charts
|
|
||||||
termui.Handle("/sys/kbd/C-c", func(termui.Event) {
|
|
||||||
termui.StopLoop()
|
|
||||||
})
|
|
||||||
termui.Handle("/sys/wnd/resize", func(termui.Event) {
|
|
||||||
termui.Body.Width = termui.TermWidth()
|
|
||||||
for _, chart := range charts {
|
|
||||||
chart.Height = (termui.TermHeight() - footer.Height) / rows
|
|
||||||
}
|
|
||||||
termui.Body.Align()
|
|
||||||
termui.Render(termui.Body)
|
|
||||||
})
|
|
||||||
go func() {
|
|
||||||
tick := time.NewTicker(time.Duration(ctx.Int(monitorCommandRefreshFlag.Name)) * time.Second)
|
|
||||||
for range tick.C {
|
|
||||||
if refreshCharts(client, monitored, data, units, charts, ctx, footer) {
|
|
||||||
termui.Body.Align()
|
|
||||||
}
|
|
||||||
termui.Render(termui.Body)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
termui.Loop()
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// retrieveMetrics contacts the attached XDC node and retrieves the entire set
|
|
||||||
// of collected system metrics.
|
|
||||||
func retrieveMetrics(client *rpc.Client) (map[string]interface{}, error) {
|
|
||||||
var metrics map[string]interface{}
|
|
||||||
err := client.Call(&metrics, "debug_metrics", true)
|
|
||||||
return metrics, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// resolveMetrics takes a list of input metric patterns, and resolves each to one
|
|
||||||
// or more canonical metric names.
|
|
||||||
func resolveMetrics(metrics map[string]interface{}, patterns []string) []string {
|
|
||||||
res := []string{}
|
|
||||||
for _, pattern := range patterns {
|
|
||||||
res = append(res, resolveMetric(metrics, pattern, "")...)
|
|
||||||
}
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
|
|
||||||
// resolveMetrics takes a single of input metric pattern, and resolves it to one
|
|
||||||
// or more canonical metric names.
|
|
||||||
func resolveMetric(metrics map[string]interface{}, pattern string, path string) []string {
|
|
||||||
results := []string{}
|
|
||||||
|
|
||||||
// If a nested metric was requested, recurse optionally branching (via comma)
|
|
||||||
parts := strings.SplitN(pattern, "/", 2)
|
|
||||||
if len(parts) > 1 {
|
|
||||||
for _, variation := range strings.Split(parts[0], ",") {
|
|
||||||
if submetrics, ok := metrics[variation].(map[string]interface{}); !ok {
|
|
||||||
utils.Fatalf("Failed to retrieve system metrics: %s", path+variation)
|
|
||||||
return nil
|
|
||||||
} else {
|
|
||||||
results = append(results, resolveMetric(submetrics, parts[1], path+variation+"/")...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return results
|
|
||||||
}
|
|
||||||
// Depending what the last link is, return or expand
|
|
||||||
for _, variation := range strings.Split(pattern, ",") {
|
|
||||||
switch metric := metrics[variation].(type) {
|
|
||||||
case float64:
|
|
||||||
// Final metric value found, return as singleton
|
|
||||||
results = append(results, path+variation)
|
|
||||||
|
|
||||||
case map[string]interface{}:
|
|
||||||
results = append(results, expandMetrics(metric, path+variation+"/")...)
|
|
||||||
|
|
||||||
default:
|
|
||||||
utils.Fatalf("Metric pattern resolved to unexpected type: %v", reflect.TypeOf(metric))
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return results
|
|
||||||
}
|
|
||||||
|
|
||||||
// expandMetrics expands the entire tree of metrics into a flat list of paths.
|
|
||||||
func expandMetrics(metrics map[string]interface{}, path string) []string {
|
|
||||||
// Iterate over all fields and expand individually
|
|
||||||
list := []string{}
|
|
||||||
for name, metric := range metrics {
|
|
||||||
switch metric := metric.(type) {
|
|
||||||
case float64:
|
|
||||||
// Final metric value found, append to list
|
|
||||||
list = append(list, path+name)
|
|
||||||
|
|
||||||
case map[string]interface{}:
|
|
||||||
// Tree of metrics found, expand recursively
|
|
||||||
list = append(list, expandMetrics(metric, path+name+"/")...)
|
|
||||||
|
|
||||||
default:
|
|
||||||
utils.Fatalf("Metric pattern %s resolved to unexpected type: %v", path+name, reflect.TypeOf(metric))
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return list
|
|
||||||
}
|
|
||||||
|
|
||||||
// fetchMetric iterates over the metrics map and retrieves a specific one.
|
|
||||||
func fetchMetric(metrics map[string]interface{}, metric string) float64 {
|
|
||||||
parts := strings.Split(metric, "/")
|
|
||||||
for _, part := range parts[:len(parts)-1] {
|
|
||||||
var found bool
|
|
||||||
metrics, found = metrics[part].(map[string]interface{})
|
|
||||||
if !found {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if v, ok := metrics[parts[len(parts)-1]].(float64); ok {
|
|
||||||
return v
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// refreshCharts retrieves a next batch of metrics, and inserts all the new
|
|
||||||
// values into the active datasets and charts
|
|
||||||
func refreshCharts(client *rpc.Client, metrics []string, data [][]float64, units []int, charts []*termui.LineChart, ctx *cli.Context, footer *termui.Par) (realign bool) {
|
|
||||||
values, err := retrieveMetrics(client)
|
|
||||||
for i, metric := range metrics {
|
|
||||||
if len(data) < 512 {
|
|
||||||
data[i] = append([]float64{fetchMetric(values, metric)}, data[i]...)
|
|
||||||
} else {
|
|
||||||
data[i] = append([]float64{fetchMetric(values, metric)}, data[i][:len(data[i])-1]...)
|
|
||||||
}
|
|
||||||
if updateChart(metric, data[i], &units[i], charts[i], err) {
|
|
||||||
realign = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
updateFooter(ctx, err, footer)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// updateChart inserts a dataset into a line chart, scaling appropriately as to
|
|
||||||
// not display weird labels, also updating the chart label accordingly.
|
|
||||||
func updateChart(metric string, data []float64, base *int, chart *termui.LineChart, err error) (realign bool) {
|
|
||||||
dataUnits := []string{"", "K", "M", "G", "T", "E"}
|
|
||||||
timeUnits := []string{"ns", "µs", "ms", "s", "ks", "ms"}
|
|
||||||
colors := []termui.Attribute{termui.ColorBlue, termui.ColorCyan, termui.ColorGreen, termui.ColorYellow, termui.ColorRed, termui.ColorRed}
|
|
||||||
|
|
||||||
// Extract only part of the data that's actually visible
|
|
||||||
if chart.Width*2 < len(data) {
|
|
||||||
data = data[:chart.Width*2]
|
|
||||||
}
|
|
||||||
// Find the maximum value and scale under 1K
|
|
||||||
high := 0.0
|
|
||||||
if len(data) > 0 {
|
|
||||||
high = data[0]
|
|
||||||
for _, value := range data[1:] {
|
|
||||||
high = math.Max(high, value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
unit, scale := 0, 1.0
|
|
||||||
for high >= 1000 && unit+1 < len(dataUnits) {
|
|
||||||
high, unit, scale = high/1000, unit+1, scale*1000
|
|
||||||
}
|
|
||||||
// If the unit changes, re-create the chart (hack to set max height...)
|
|
||||||
if unit != *base {
|
|
||||||
realign, *base, *chart = true, unit, *createChart(chart.Height)
|
|
||||||
}
|
|
||||||
// Update the chart's data points with the scaled values
|
|
||||||
if cap(chart.Data) < len(data) {
|
|
||||||
chart.Data = make([]float64, len(data))
|
|
||||||
}
|
|
||||||
chart.Data = chart.Data[:len(data)]
|
|
||||||
for i, value := range data {
|
|
||||||
chart.Data[i] = value / scale
|
|
||||||
}
|
|
||||||
// Update the chart's label with the scale units
|
|
||||||
units := dataUnits
|
|
||||||
if strings.Contains(metric, "/Percentiles/") || strings.Contains(metric, "/pauses/") || strings.Contains(metric, "/time/") {
|
|
||||||
units = timeUnits
|
|
||||||
}
|
|
||||||
chart.BorderLabel = metric
|
|
||||||
if len(units[unit]) > 0 {
|
|
||||||
chart.BorderLabel += " [" + units[unit] + "]"
|
|
||||||
}
|
|
||||||
chart.LineColor = colors[unit] | termui.AttrBold
|
|
||||||
if err != nil {
|
|
||||||
chart.LineColor = termui.ColorRed | termui.AttrBold
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// createChart creates an empty line chart with the default configs.
|
|
||||||
func createChart(height int) *termui.LineChart {
|
|
||||||
chart := termui.NewLineChart()
|
|
||||||
if runtime.GOOS == "windows" {
|
|
||||||
chart.Mode = "dot"
|
|
||||||
}
|
|
||||||
chart.DataLabels = []string{""}
|
|
||||||
chart.Height = height
|
|
||||||
chart.AxesColor = termui.ColorWhite
|
|
||||||
chart.PaddingBottom = -2
|
|
||||||
|
|
||||||
chart.BorderLabelFg = chart.BorderFg | termui.AttrBold
|
|
||||||
chart.BorderFg = chart.BorderBg
|
|
||||||
|
|
||||||
return chart
|
|
||||||
}
|
|
||||||
|
|
||||||
// updateFooter updates the footer contents based on any encountered errors.
|
|
||||||
func updateFooter(ctx *cli.Context, err error, footer *termui.Par) {
|
|
||||||
// Generate the basic footer
|
|
||||||
refresh := time.Duration(ctx.Int(monitorCommandRefreshFlag.Name)) * time.Second
|
|
||||||
footer.Text = fmt.Sprintf("Press Ctrl+C to quit. Refresh interval: %v.", refresh)
|
|
||||||
footer.TextFgColor = termui.ThemeAttr("par.fg") | termui.AttrBold
|
|
||||||
|
|
||||||
// Append any encountered errors
|
|
||||||
if err != nil {
|
|
||||||
footer.Text = fmt.Sprintf("Error: %v.", err)
|
|
||||||
footer.TextFgColor = termui.ColorRed | termui.AttrBold
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -300,11 +300,6 @@ web3._extend({
|
||||||
name: 'chaindbCompact',
|
name: 'chaindbCompact',
|
||||||
call: 'debug_chaindbCompact',
|
call: 'debug_chaindbCompact',
|
||||||
}),
|
}),
|
||||||
new web3._extend.Method({
|
|
||||||
name: 'metrics',
|
|
||||||
call: 'debug_metrics',
|
|
||||||
params: 1
|
|
||||||
}),
|
|
||||||
new web3._extend.Method({
|
new web3._extend.Method({
|
||||||
name: 'verbosity',
|
name: 'verbosity',
|
||||||
call: 'debug_verbosity',
|
call: 'debug_verbosity',
|
||||||
|
|
|
||||||
117
node/api.go
117
node/api.go
|
|
@ -21,11 +21,9 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/XinFinOrg/XDPoSChain/common/hexutil"
|
"github.com/XinFinOrg/XDPoSChain/common/hexutil"
|
||||||
"github.com/XinFinOrg/XDPoSChain/crypto"
|
"github.com/XinFinOrg/XDPoSChain/crypto"
|
||||||
"github.com/XinFinOrg/XDPoSChain/metrics"
|
|
||||||
"github.com/XinFinOrg/XDPoSChain/p2p"
|
"github.com/XinFinOrg/XDPoSChain/p2p"
|
||||||
"github.com/XinFinOrg/XDPoSChain/p2p/discover"
|
"github.com/XinFinOrg/XDPoSChain/p2p/discover"
|
||||||
"github.com/XinFinOrg/XDPoSChain/rpc"
|
"github.com/XinFinOrg/XDPoSChain/rpc"
|
||||||
|
|
@ -298,121 +296,6 @@ func (api *PublicAdminAPI) Datadir() string {
|
||||||
return api.node.DataDir()
|
return api.node.DataDir()
|
||||||
}
|
}
|
||||||
|
|
||||||
// PublicDebugAPI is the collection of debugging related API methods exposed over
|
|
||||||
// both secure and unsecure RPC channels.
|
|
||||||
type PublicDebugAPI struct {
|
|
||||||
node *Node // Node interfaced by this API
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewPublicDebugAPI creates a new API definition for the public debug methods
|
|
||||||
// of the node itself.
|
|
||||||
func NewPublicDebugAPI(node *Node) *PublicDebugAPI {
|
|
||||||
return &PublicDebugAPI{node: node}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Metrics retrieves all the known system metric collected by the node.
|
|
||||||
func (api *PublicDebugAPI) Metrics(raw bool) (map[string]interface{}, error) {
|
|
||||||
// Create a rate formatter
|
|
||||||
units := []string{"", "K", "M", "G", "T", "E", "P"}
|
|
||||||
round := func(value float64, prec int) string {
|
|
||||||
unit := 0
|
|
||||||
for value >= 1000 {
|
|
||||||
unit, value, prec = unit+1, value/1000, 2
|
|
||||||
}
|
|
||||||
return fmt.Sprintf(fmt.Sprintf("%%.%df%s", prec, units[unit]), value)
|
|
||||||
}
|
|
||||||
format := func(total float64, rate float64) string {
|
|
||||||
return fmt.Sprintf("%s (%s/s)", round(total, 0), round(rate, 2))
|
|
||||||
}
|
|
||||||
// Iterate over all the metrics, and just dump for now
|
|
||||||
counters := make(map[string]interface{})
|
|
||||||
metrics.DefaultRegistry.Each(func(name string, metric interface{}) {
|
|
||||||
// Create or retrieve the counter hierarchy for this metric
|
|
||||||
root, parts := counters, strings.Split(name, "/")
|
|
||||||
for _, part := range parts[:len(parts)-1] {
|
|
||||||
if _, ok := root[part]; !ok {
|
|
||||||
root[part] = make(map[string]interface{})
|
|
||||||
}
|
|
||||||
root = root[part].(map[string]interface{})
|
|
||||||
}
|
|
||||||
name = parts[len(parts)-1]
|
|
||||||
|
|
||||||
// Fill the counter with the metric details, formatting if requested
|
|
||||||
if raw {
|
|
||||||
switch metric := metric.(type) {
|
|
||||||
case metrics.Counter:
|
|
||||||
root[name] = map[string]interface{}{
|
|
||||||
"Overall": float64(metric.Count()),
|
|
||||||
}
|
|
||||||
|
|
||||||
case metrics.Meter:
|
|
||||||
root[name] = map[string]interface{}{
|
|
||||||
"AvgRate01Min": metric.Rate1(),
|
|
||||||
"AvgRate05Min": metric.Rate5(),
|
|
||||||
"AvgRate15Min": metric.Rate15(),
|
|
||||||
"MeanRate": metric.RateMean(),
|
|
||||||
"Overall": float64(metric.Count()),
|
|
||||||
}
|
|
||||||
|
|
||||||
case metrics.Timer:
|
|
||||||
root[name] = map[string]interface{}{
|
|
||||||
"AvgRate01Min": metric.Rate1(),
|
|
||||||
"AvgRate05Min": metric.Rate5(),
|
|
||||||
"AvgRate15Min": metric.Rate15(),
|
|
||||||
"MeanRate": metric.RateMean(),
|
|
||||||
"Overall": float64(metric.Count()),
|
|
||||||
"Percentiles": map[string]interface{}{
|
|
||||||
"5": metric.Percentile(0.05),
|
|
||||||
"20": metric.Percentile(0.2),
|
|
||||||
"50": metric.Percentile(0.5),
|
|
||||||
"80": metric.Percentile(0.8),
|
|
||||||
"95": metric.Percentile(0.95),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
root[name] = "Unknown metric type"
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
switch metric := metric.(type) {
|
|
||||||
case metrics.Counter:
|
|
||||||
root[name] = map[string]interface{}{
|
|
||||||
"Overall": float64(metric.Count()),
|
|
||||||
}
|
|
||||||
|
|
||||||
case metrics.Meter:
|
|
||||||
root[name] = map[string]interface{}{
|
|
||||||
"Avg01Min": format(metric.Rate1()*60, metric.Rate1()),
|
|
||||||
"Avg05Min": format(metric.Rate5()*300, metric.Rate5()),
|
|
||||||
"Avg15Min": format(metric.Rate15()*900, metric.Rate15()),
|
|
||||||
"Overall": format(float64(metric.Count()), metric.RateMean()),
|
|
||||||
}
|
|
||||||
|
|
||||||
case metrics.Timer:
|
|
||||||
root[name] = map[string]interface{}{
|
|
||||||
"Avg01Min": format(metric.Rate1()*60, metric.Rate1()),
|
|
||||||
"Avg05Min": format(metric.Rate5()*300, metric.Rate5()),
|
|
||||||
"Avg15Min": format(metric.Rate15()*900, metric.Rate15()),
|
|
||||||
"Overall": format(float64(metric.Count()), metric.RateMean()),
|
|
||||||
"Maximum": time.Duration(metric.Max()).String(),
|
|
||||||
"Minimum": time.Duration(metric.Min()).String(),
|
|
||||||
"Percentiles": map[string]interface{}{
|
|
||||||
"5": time.Duration(metric.Percentile(0.05)).String(),
|
|
||||||
"20": time.Duration(metric.Percentile(0.2)).String(),
|
|
||||||
"50": time.Duration(metric.Percentile(0.5)).String(),
|
|
||||||
"80": time.Duration(metric.Percentile(0.8)).String(),
|
|
||||||
"95": time.Duration(metric.Percentile(0.95)).String(),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
root[name] = "Unknown metric type"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
return counters, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// PublicWeb3API offers helper utils
|
// PublicWeb3API offers helper utils
|
||||||
type PublicWeb3API struct {
|
type PublicWeb3API struct {
|
||||||
stack *Node
|
stack *Node
|
||||||
|
|
|
||||||
|
|
@ -628,11 +628,6 @@ func (n *Node) apis() []rpc.API {
|
||||||
Namespace: "debug",
|
Namespace: "debug",
|
||||||
Version: "1.0",
|
Version: "1.0",
|
||||||
Service: debug.Handler,
|
Service: debug.Handler,
|
||||||
}, {
|
|
||||||
Namespace: "debug",
|
|
||||||
Version: "1.0",
|
|
||||||
Service: NewPublicDebugAPI(n),
|
|
||||||
Public: true,
|
|
||||||
}, {
|
}, {
|
||||||
Namespace: "web3",
|
Namespace: "web3",
|
||||||
Version: "1.0",
|
Version: "1.0",
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue