mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-20 10:52:25 +00:00
Merge branch 'ethereum:master' into main
This commit is contained in:
commit
4d8a45ac37
126 changed files with 2373 additions and 2778 deletions
|
|
@ -20,6 +20,7 @@
|
||||||
package keystore
|
package keystore
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"os"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
|
|
@ -77,7 +78,9 @@ func (w *watcher) loop() {
|
||||||
}
|
}
|
||||||
defer watcher.Close()
|
defer watcher.Close()
|
||||||
if err := watcher.Add(w.ac.keydir); err != nil {
|
if err := watcher.Add(w.ac.keydir); err != nil {
|
||||||
|
if !os.IsNotExist(err) {
|
||||||
logger.Warn("Failed to watch keystore folder", "err", err)
|
logger.Warn("Failed to watch keystore folder", "err", err)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,20 +4,20 @@
|
||||||
24bac679f3a2d8240d8e08e7f6a70b70c2dabf673317d924cf1d1887b9fe1f81 fixtures.tar.gz
|
24bac679f3a2d8240d8e08e7f6a70b70c2dabf673317d924cf1d1887b9fe1f81 fixtures.tar.gz
|
||||||
|
|
||||||
# https://go.dev/dl/
|
# https://go.dev/dl/
|
||||||
818d46ede85682dd551ad378ef37a4d247006f12ec59b5b755601d2ce114369a go1.21.0.src.tar.gz
|
bfa36bf75e9a1e9cbbdb9abcf9d1707e479bd3a07880a8ae3564caee5711cb99 go1.21.1.src.tar.gz
|
||||||
b314de9f704ab122c077d2ec8e67e3670affe8865479d1f01991e7ac55d65e70 go1.21.0.darwin-amd64.tar.gz
|
809f5b0ef4f7dcdd5f51e9630a5b2e5a1006f22a047126d61560cdc365678a19 go1.21.1.darwin-amd64.tar.gz
|
||||||
3aca44de55c5e098de2f406e98aba328898b05d509a2e2a356416faacf2c4566 go1.21.0.darwin-arm64.tar.gz
|
ffd40391a1e995855488b008ad9326ff8c2e81803a6e80894401003bae47fcf1 go1.21.1.darwin-arm64.tar.gz
|
||||||
312a0065714a50862af714e7a5b3fbbd70fe68f905ffb9bcc56d42eadf6bffab go1.21.0.freebsd-386.tar.gz
|
9919a9a4dc82371aba3da5b7c830bcb6249fc1502cd26d959eb340a60e41ee01 go1.21.1.freebsd-386.tar.gz
|
||||||
b8eaa36654625df799654f77f4af0ea7bd9e5e760ebe86e68fe7c484748ae995 go1.21.0.freebsd-amd64.tar.gz
|
2571f10f6047e04d87c1f5986a05e5e8f7b511faf98803ef12b66d563845d2a1 go1.21.1.freebsd-amd64.tar.gz
|
||||||
0e6f378d9b072fab0a3d9ff4d5e990d98487d47252dba8160015a61e6bd0bcba go1.21.0.linux-386.tar.gz
|
b93850666cdadbd696a986cf7b03111fe99db8c34a9aaa113d7c96d0081e1901 go1.21.1.linux-386.tar.gz
|
||||||
d0398903a16ba2232b389fb31032ddf57cac34efda306a0eebac34f0965a0742 go1.21.0.linux-amd64.tar.gz
|
b3075ae1ce5dab85f89bc7905d1632de23ca196bd8336afd93fa97434cfa55ae go1.21.1.linux-amd64.tar.gz
|
||||||
f3d4548edf9b22f26bbd49720350bbfe59d75b7090a1a2bff1afad8214febaf3 go1.21.0.linux-arm64.tar.gz
|
7da1a3936a928fd0b2602ed4f3ef535b8cd1990f1503b8d3e1acc0fa0759c967 go1.21.1.linux-arm64.tar.gz
|
||||||
e377a0004957c8c560a3ff99601bce612330a3d95ba3b0a2ae144165fc87deb1 go1.21.0.linux-armv6l.tar.gz
|
f3716a43f59ae69999841d6007b42c9e286e8d8ce470656fb3e70d7be2d7ca85 go1.21.1.linux-armv6l.tar.gz
|
||||||
e938ffc81d8ebe5efc179240960ba22da6a841ff05d5cab7ce2547112b14a47f go1.21.0.linux-ppc64le.tar.gz
|
eddf018206f8a5589bda75252b72716d26611efebabdca5d0083ec15e9e41ab7 go1.21.1.linux-ppc64le.tar.gz
|
||||||
be7338df8e5d5472dfa307b0df2b446d85d001b0a2a3cdb1a14048d751b70481 go1.21.0.linux-s390x.tar.gz
|
a83b3e8eb4dbf76294e773055eb51397510ff4d612a247bad9903560267bba6d go1.21.1.linux-s390x.tar.gz
|
||||||
af920fbb74fc3d173118dc3cc35f02a709c1de642700e92a91a7d16981df3fec go1.21.0.windows-386.zip
|
170256c820f466f29d64876f25f4dfa4029ed9902a0a9095d8bd603aecf4d83b go1.21.1.windows-386.zip
|
||||||
732121e64e0ecb07c77fdf6cc1bc5ce7b242c2d40d4ac29021ad4c64a08731f6 go1.21.0.windows-amd64.zip
|
10a4f5b63215d11d1770453733dbcbf024f3f74872f84e28d7ea59f0250316c6 go1.21.1.windows-amd64.zip
|
||||||
41342f5a0f8c083b14c68bde738ddcd313a4f53a5854bfdfab47f0e88247de12 go1.21.0.windows-arm64.zip
|
41135ce6e0ced4bc1e459cb96bd4090c9dc2062e24179c3f337d855af9b560ef go1.21.1.windows-arm64.zip
|
||||||
|
|
||||||
# https://github.com/golangci/golangci-lint/releases
|
# https://github.com/golangci/golangci-lint/releases
|
||||||
fba08acc4027f69f07cef48fbff70b8a7ecdfaa1c2aba9ad3fb31d60d9f5d4bc golangci-lint-1.51.1-darwin-amd64.tar.gz
|
fba08acc4027f69f07cef48fbff70b8a7ecdfaa1c2aba9ad3fb31d60d9f5d4bc golangci-lint-1.51.1-darwin-amd64.tar.gz
|
||||||
|
|
|
||||||
|
|
@ -139,7 +139,7 @@ var (
|
||||||
// This is the version of Go that will be downloaded by
|
// This is the version of Go that will be downloaded by
|
||||||
//
|
//
|
||||||
// go run ci.go install -dlgo
|
// go run ci.go install -dlgo
|
||||||
dlgoVersion = "1.21.0"
|
dlgoVersion = "1.21.1"
|
||||||
|
|
||||||
// This is the version of Go that will be used to bootstrap the PPA builder.
|
// This is the version of Go that will be used to bootstrap the PPA builder.
|
||||||
//
|
//
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
@ -51,7 +52,14 @@ type resolver interface {
|
||||||
RequestENR(*enode.Node) (*enode.Node, error)
|
RequestENR(*enode.Node) (*enode.Node, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func newCrawler(input nodeSet, disc resolver, iters ...enode.Iterator) *crawler {
|
func newCrawler(input nodeSet, bootnodes []*enode.Node, disc resolver, iters ...enode.Iterator) (*crawler, error) {
|
||||||
|
if len(input) == 0 {
|
||||||
|
input.add(bootnodes...)
|
||||||
|
}
|
||||||
|
if len(input) == 0 {
|
||||||
|
return nil, errors.New("no input nodes to start crawling")
|
||||||
|
}
|
||||||
|
|
||||||
c := &crawler{
|
c := &crawler{
|
||||||
input: input,
|
input: input,
|
||||||
output: make(nodeSet, len(input)),
|
output: make(nodeSet, len(input)),
|
||||||
|
|
@ -67,7 +75,7 @@ func newCrawler(input nodeSet, disc resolver, iters ...enode.Iterator) *crawler
|
||||||
for id, n := range input {
|
for id, n := range input {
|
||||||
c.output[id] = n
|
c.output[id] = n
|
||||||
}
|
}
|
||||||
return c
|
return c, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *crawler) run(timeout time.Duration, nthreads int) nodeSet {
|
func (c *crawler) run(timeout time.Duration, nthreads int) nodeSet {
|
||||||
|
|
|
||||||
|
|
@ -143,7 +143,7 @@ var discoveryNodeFlags = []cli.Flag{
|
||||||
|
|
||||||
func discv4Ping(ctx *cli.Context) error {
|
func discv4Ping(ctx *cli.Context) error {
|
||||||
n := getNodeArg(ctx)
|
n := getNodeArg(ctx)
|
||||||
disc := startV4(ctx)
|
disc, _ := startV4(ctx)
|
||||||
defer disc.Close()
|
defer disc.Close()
|
||||||
|
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
|
|
@ -156,7 +156,7 @@ func discv4Ping(ctx *cli.Context) error {
|
||||||
|
|
||||||
func discv4RequestRecord(ctx *cli.Context) error {
|
func discv4RequestRecord(ctx *cli.Context) error {
|
||||||
n := getNodeArg(ctx)
|
n := getNodeArg(ctx)
|
||||||
disc := startV4(ctx)
|
disc, _ := startV4(ctx)
|
||||||
defer disc.Close()
|
defer disc.Close()
|
||||||
|
|
||||||
respN, err := disc.RequestENR(n)
|
respN, err := disc.RequestENR(n)
|
||||||
|
|
@ -169,7 +169,7 @@ func discv4RequestRecord(ctx *cli.Context) error {
|
||||||
|
|
||||||
func discv4Resolve(ctx *cli.Context) error {
|
func discv4Resolve(ctx *cli.Context) error {
|
||||||
n := getNodeArg(ctx)
|
n := getNodeArg(ctx)
|
||||||
disc := startV4(ctx)
|
disc, _ := startV4(ctx)
|
||||||
defer disc.Close()
|
defer disc.Close()
|
||||||
|
|
||||||
fmt.Println(disc.Resolve(n).String())
|
fmt.Println(disc.Resolve(n).String())
|
||||||
|
|
@ -196,10 +196,13 @@ func discv4ResolveJSON(ctx *cli.Context) error {
|
||||||
nodeargs = append(nodeargs, n)
|
nodeargs = append(nodeargs, n)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run the crawler.
|
disc, config := startV4(ctx)
|
||||||
disc := startV4(ctx)
|
|
||||||
defer disc.Close()
|
defer disc.Close()
|
||||||
c := newCrawler(inputSet, disc, enode.IterNodes(nodeargs))
|
|
||||||
|
c, err := newCrawler(inputSet, config.Bootnodes, disc, enode.IterNodes(nodeargs))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
c.revalidateInterval = 0
|
c.revalidateInterval = 0
|
||||||
output := c.run(0, 1)
|
output := c.run(0, 1)
|
||||||
writeNodesJSON(nodesFile, output)
|
writeNodesJSON(nodesFile, output)
|
||||||
|
|
@ -211,14 +214,18 @@ func discv4Crawl(ctx *cli.Context) error {
|
||||||
return errors.New("need nodes file as argument")
|
return errors.New("need nodes file as argument")
|
||||||
}
|
}
|
||||||
nodesFile := ctx.Args().First()
|
nodesFile := ctx.Args().First()
|
||||||
var inputSet nodeSet
|
inputSet := make(nodeSet)
|
||||||
if common.FileExist(nodesFile) {
|
if common.FileExist(nodesFile) {
|
||||||
inputSet = loadNodesJSON(nodesFile)
|
inputSet = loadNodesJSON(nodesFile)
|
||||||
}
|
}
|
||||||
|
|
||||||
disc := startV4(ctx)
|
disc, config := startV4(ctx)
|
||||||
defer disc.Close()
|
defer disc.Close()
|
||||||
c := newCrawler(inputSet, disc, disc.RandomNodes())
|
|
||||||
|
c, err := newCrawler(inputSet, config.Bootnodes, disc, disc.RandomNodes())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
c.revalidateInterval = 10 * time.Minute
|
c.revalidateInterval = 10 * time.Minute
|
||||||
output := c.run(ctx.Duration(crawlTimeoutFlag.Name), ctx.Int(crawlParallelismFlag.Name))
|
output := c.run(ctx.Duration(crawlTimeoutFlag.Name), ctx.Int(crawlParallelismFlag.Name))
|
||||||
writeNodesJSON(nodesFile, output)
|
writeNodesJSON(nodesFile, output)
|
||||||
|
|
@ -238,14 +245,14 @@ func discv4Test(ctx *cli.Context) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// startV4 starts an ephemeral discovery V4 node.
|
// startV4 starts an ephemeral discovery V4 node.
|
||||||
func startV4(ctx *cli.Context) *discover.UDPv4 {
|
func startV4(ctx *cli.Context) (*discover.UDPv4, discover.Config) {
|
||||||
ln, config := makeDiscoveryConfig(ctx)
|
ln, config := makeDiscoveryConfig(ctx)
|
||||||
socket := listen(ctx, ln)
|
socket := listen(ctx, ln)
|
||||||
disc, err := discover.ListenV4(socket, ln, config)
|
disc, err := discover.ListenV4(socket, ln, config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
exit(err)
|
exit(err)
|
||||||
}
|
}
|
||||||
return disc
|
return disc, config
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeDiscoveryConfig(ctx *cli.Context) (*enode.LocalNode, discover.Config) {
|
func makeDiscoveryConfig(ctx *cli.Context) (*enode.LocalNode, discover.Config) {
|
||||||
|
|
|
||||||
|
|
@ -81,7 +81,7 @@ var (
|
||||||
|
|
||||||
func discv5Ping(ctx *cli.Context) error {
|
func discv5Ping(ctx *cli.Context) error {
|
||||||
n := getNodeArg(ctx)
|
n := getNodeArg(ctx)
|
||||||
disc := startV5(ctx)
|
disc, _ := startV5(ctx)
|
||||||
defer disc.Close()
|
defer disc.Close()
|
||||||
|
|
||||||
fmt.Println(disc.Ping(n))
|
fmt.Println(disc.Ping(n))
|
||||||
|
|
@ -90,7 +90,7 @@ func discv5Ping(ctx *cli.Context) error {
|
||||||
|
|
||||||
func discv5Resolve(ctx *cli.Context) error {
|
func discv5Resolve(ctx *cli.Context) error {
|
||||||
n := getNodeArg(ctx)
|
n := getNodeArg(ctx)
|
||||||
disc := startV5(ctx)
|
disc, _ := startV5(ctx)
|
||||||
defer disc.Close()
|
defer disc.Close()
|
||||||
|
|
||||||
fmt.Println(disc.Resolve(n))
|
fmt.Println(disc.Resolve(n))
|
||||||
|
|
@ -102,14 +102,18 @@ func discv5Crawl(ctx *cli.Context) error {
|
||||||
return errors.New("need nodes file as argument")
|
return errors.New("need nodes file as argument")
|
||||||
}
|
}
|
||||||
nodesFile := ctx.Args().First()
|
nodesFile := ctx.Args().First()
|
||||||
var inputSet nodeSet
|
inputSet := make(nodeSet)
|
||||||
if common.FileExist(nodesFile) {
|
if common.FileExist(nodesFile) {
|
||||||
inputSet = loadNodesJSON(nodesFile)
|
inputSet = loadNodesJSON(nodesFile)
|
||||||
}
|
}
|
||||||
|
|
||||||
disc := startV5(ctx)
|
disc, config := startV5(ctx)
|
||||||
defer disc.Close()
|
defer disc.Close()
|
||||||
c := newCrawler(inputSet, disc, disc.RandomNodes())
|
|
||||||
|
c, err := newCrawler(inputSet, config.Bootnodes, disc, disc.RandomNodes())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
c.revalidateInterval = 10 * time.Minute
|
c.revalidateInterval = 10 * time.Minute
|
||||||
output := c.run(ctx.Duration(crawlTimeoutFlag.Name), ctx.Int(crawlParallelismFlag.Name))
|
output := c.run(ctx.Duration(crawlTimeoutFlag.Name), ctx.Int(crawlParallelismFlag.Name))
|
||||||
writeNodesJSON(nodesFile, output)
|
writeNodesJSON(nodesFile, output)
|
||||||
|
|
@ -127,7 +131,7 @@ func discv5Test(ctx *cli.Context) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func discv5Listen(ctx *cli.Context) error {
|
func discv5Listen(ctx *cli.Context) error {
|
||||||
disc := startV5(ctx)
|
disc, _ := startV5(ctx)
|
||||||
defer disc.Close()
|
defer disc.Close()
|
||||||
|
|
||||||
fmt.Println(disc.Self())
|
fmt.Println(disc.Self())
|
||||||
|
|
@ -135,12 +139,12 @@ func discv5Listen(ctx *cli.Context) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// startV5 starts an ephemeral discovery v5 node.
|
// startV5 starts an ephemeral discovery v5 node.
|
||||||
func startV5(ctx *cli.Context) *discover.UDPv5 {
|
func startV5(ctx *cli.Context) (*discover.UDPv5, discover.Config) {
|
||||||
ln, config := makeDiscoveryConfig(ctx)
|
ln, config := makeDiscoveryConfig(ctx)
|
||||||
socket := listen(ctx, ln)
|
socket := listen(ctx, ln)
|
||||||
disc, err := discover.ListenV5(socket, ln, config)
|
disc, err := discover.ListenV5(socket, ln, config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
exit(err)
|
exit(err)
|
||||||
}
|
}
|
||||||
return disc
|
return disc, config
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,6 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
"github.com/ethereum/go-ethereum/eth/tracers/logger"
|
"github.com/ethereum/go-ethereum/eth/tracers/logger"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
|
||||||
"github.com/ethereum/go-ethereum/tests"
|
"github.com/ethereum/go-ethereum/tests"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
@ -41,10 +40,7 @@ func blockTestCmd(ctx *cli.Context) error {
|
||||||
if len(ctx.Args().First()) == 0 {
|
if len(ctx.Args().First()) == 0 {
|
||||||
return errors.New("path-to-test argument required")
|
return errors.New("path-to-test argument required")
|
||||||
}
|
}
|
||||||
// Configure the go-ethereum logger
|
|
||||||
glogger := log.NewGlogHandler(log.StreamHandler(os.Stderr, log.TerminalFormat(false)))
|
|
||||||
glogger.Verbosity(log.Lvl(ctx.Int(VerbosityFlag.Name)))
|
|
||||||
log.Root().SetHandler(glogger)
|
|
||||||
var tracer vm.EVMLogger
|
var tracer vm.EVMLogger
|
||||||
// Configure the EVM logger
|
// Configure the EVM logger
|
||||||
if ctx.Bool(MachineFlag.Name) {
|
if ctx.Bool(MachineFlag.Name) {
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ import (
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/cmd/evm/internal/t8ntool"
|
"github.com/ethereum/go-ethereum/cmd/evm/internal/t8ntool"
|
||||||
|
"github.com/ethereum/go-ethereum/internal/debug"
|
||||||
"github.com/ethereum/go-ethereum/internal/flags"
|
"github.com/ethereum/go-ethereum/internal/flags"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
@ -31,99 +32,107 @@ var (
|
||||||
DebugFlag = &cli.BoolFlag{
|
DebugFlag = &cli.BoolFlag{
|
||||||
Name: "debug",
|
Name: "debug",
|
||||||
Usage: "output full trace logs",
|
Usage: "output full trace logs",
|
||||||
}
|
Category: flags.VMCategory,
|
||||||
MemProfileFlag = &cli.StringFlag{
|
|
||||||
Name: "memprofile",
|
|
||||||
Usage: "creates a memory profile at the given path",
|
|
||||||
}
|
|
||||||
CPUProfileFlag = &cli.StringFlag{
|
|
||||||
Name: "cpuprofile",
|
|
||||||
Usage: "creates a CPU profile at the given path",
|
|
||||||
}
|
}
|
||||||
StatDumpFlag = &cli.BoolFlag{
|
StatDumpFlag = &cli.BoolFlag{
|
||||||
Name: "statdump",
|
Name: "statdump",
|
||||||
Usage: "displays stack and heap memory information",
|
Usage: "displays stack and heap memory information",
|
||||||
|
Category: flags.VMCategory,
|
||||||
}
|
}
|
||||||
CodeFlag = &cli.StringFlag{
|
CodeFlag = &cli.StringFlag{
|
||||||
Name: "code",
|
Name: "code",
|
||||||
Usage: "EVM code",
|
Usage: "EVM code",
|
||||||
|
Category: flags.VMCategory,
|
||||||
}
|
}
|
||||||
CodeFileFlag = &cli.StringFlag{
|
CodeFileFlag = &cli.StringFlag{
|
||||||
Name: "codefile",
|
Name: "codefile",
|
||||||
Usage: "File containing EVM code. If '-' is specified, code is read from stdin ",
|
Usage: "File containing EVM code. If '-' is specified, code is read from stdin ",
|
||||||
|
Category: flags.VMCategory,
|
||||||
}
|
}
|
||||||
GasFlag = &cli.Uint64Flag{
|
GasFlag = &cli.Uint64Flag{
|
||||||
Name: "gas",
|
Name: "gas",
|
||||||
Usage: "gas limit for the evm",
|
Usage: "gas limit for the evm",
|
||||||
Value: 10000000000,
|
Value: 10000000000,
|
||||||
|
Category: flags.VMCategory,
|
||||||
}
|
}
|
||||||
PriceFlag = &flags.BigFlag{
|
PriceFlag = &flags.BigFlag{
|
||||||
Name: "price",
|
Name: "price",
|
||||||
Usage: "price set for the evm",
|
Usage: "price set for the evm",
|
||||||
Value: new(big.Int),
|
Value: new(big.Int),
|
||||||
|
Category: flags.VMCategory,
|
||||||
}
|
}
|
||||||
ValueFlag = &flags.BigFlag{
|
ValueFlag = &flags.BigFlag{
|
||||||
Name: "value",
|
Name: "value",
|
||||||
Usage: "value set for the evm",
|
Usage: "value set for the evm",
|
||||||
Value: new(big.Int),
|
Value: new(big.Int),
|
||||||
|
Category: flags.VMCategory,
|
||||||
}
|
}
|
||||||
DumpFlag = &cli.BoolFlag{
|
DumpFlag = &cli.BoolFlag{
|
||||||
Name: "dump",
|
Name: "dump",
|
||||||
Usage: "dumps the state after the run",
|
Usage: "dumps the state after the run",
|
||||||
|
Category: flags.VMCategory,
|
||||||
}
|
}
|
||||||
InputFlag = &cli.StringFlag{
|
InputFlag = &cli.StringFlag{
|
||||||
Name: "input",
|
Name: "input",
|
||||||
Usage: "input for the EVM",
|
Usage: "input for the EVM",
|
||||||
|
Category: flags.VMCategory,
|
||||||
}
|
}
|
||||||
InputFileFlag = &cli.StringFlag{
|
InputFileFlag = &cli.StringFlag{
|
||||||
Name: "inputfile",
|
Name: "inputfile",
|
||||||
Usage: "file containing input for the EVM",
|
Usage: "file containing input for the EVM",
|
||||||
}
|
Category: flags.VMCategory,
|
||||||
VerbosityFlag = &cli.IntFlag{
|
|
||||||
Name: "verbosity",
|
|
||||||
Usage: "sets the verbosity level",
|
|
||||||
}
|
}
|
||||||
BenchFlag = &cli.BoolFlag{
|
BenchFlag = &cli.BoolFlag{
|
||||||
Name: "bench",
|
Name: "bench",
|
||||||
Usage: "benchmark the execution",
|
Usage: "benchmark the execution",
|
||||||
|
Category: flags.VMCategory,
|
||||||
}
|
}
|
||||||
CreateFlag = &cli.BoolFlag{
|
CreateFlag = &cli.BoolFlag{
|
||||||
Name: "create",
|
Name: "create",
|
||||||
Usage: "indicates the action should be create rather than call",
|
Usage: "indicates the action should be create rather than call",
|
||||||
|
Category: flags.VMCategory,
|
||||||
}
|
}
|
||||||
GenesisFlag = &cli.StringFlag{
|
GenesisFlag = &cli.StringFlag{
|
||||||
Name: "prestate",
|
Name: "prestate",
|
||||||
Usage: "JSON file with prestate (genesis) config",
|
Usage: "JSON file with prestate (genesis) config",
|
||||||
|
Category: flags.VMCategory,
|
||||||
}
|
}
|
||||||
MachineFlag = &cli.BoolFlag{
|
MachineFlag = &cli.BoolFlag{
|
||||||
Name: "json",
|
Name: "json",
|
||||||
Usage: "output trace logs in machine readable format (json)",
|
Usage: "output trace logs in machine readable format (json)",
|
||||||
|
Category: flags.VMCategory,
|
||||||
}
|
}
|
||||||
SenderFlag = &cli.StringFlag{
|
SenderFlag = &cli.StringFlag{
|
||||||
Name: "sender",
|
Name: "sender",
|
||||||
Usage: "The transaction origin",
|
Usage: "The transaction origin",
|
||||||
|
Category: flags.VMCategory,
|
||||||
}
|
}
|
||||||
ReceiverFlag = &cli.StringFlag{
|
ReceiverFlag = &cli.StringFlag{
|
||||||
Name: "receiver",
|
Name: "receiver",
|
||||||
Usage: "The transaction receiver (execution context)",
|
Usage: "The transaction receiver (execution context)",
|
||||||
|
Category: flags.VMCategory,
|
||||||
}
|
}
|
||||||
DisableMemoryFlag = &cli.BoolFlag{
|
DisableMemoryFlag = &cli.BoolFlag{
|
||||||
Name: "nomemory",
|
Name: "nomemory",
|
||||||
Value: true,
|
Value: true,
|
||||||
Usage: "disable memory output",
|
Usage: "disable memory output",
|
||||||
|
Category: flags.VMCategory,
|
||||||
}
|
}
|
||||||
DisableStackFlag = &cli.BoolFlag{
|
DisableStackFlag = &cli.BoolFlag{
|
||||||
Name: "nostack",
|
Name: "nostack",
|
||||||
Usage: "disable stack output",
|
Usage: "disable stack output",
|
||||||
|
Category: flags.VMCategory,
|
||||||
}
|
}
|
||||||
DisableStorageFlag = &cli.BoolFlag{
|
DisableStorageFlag = &cli.BoolFlag{
|
||||||
Name: "nostorage",
|
Name: "nostorage",
|
||||||
Usage: "disable storage output",
|
Usage: "disable storage output",
|
||||||
|
Category: flags.VMCategory,
|
||||||
}
|
}
|
||||||
DisableReturnDataFlag = &cli.BoolFlag{
|
DisableReturnDataFlag = &cli.BoolFlag{
|
||||||
Name: "noreturndata",
|
Name: "noreturndata",
|
||||||
Value: true,
|
Value: true,
|
||||||
Usage: "enable return data output",
|
Usage: "enable return data output",
|
||||||
|
Category: flags.VMCategory,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -183,34 +192,38 @@ var blockBuilderCommand = &cli.Command{
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
var app = flags.NewApp("the evm command line interface")
|
// vmFlags contains flags related to running the EVM.
|
||||||
|
var vmFlags = []cli.Flag{
|
||||||
func init() {
|
|
||||||
app.Flags = []cli.Flag{
|
|
||||||
BenchFlag,
|
|
||||||
CreateFlag,
|
|
||||||
DebugFlag,
|
|
||||||
VerbosityFlag,
|
|
||||||
CodeFlag,
|
CodeFlag,
|
||||||
CodeFileFlag,
|
CodeFileFlag,
|
||||||
|
CreateFlag,
|
||||||
GasFlag,
|
GasFlag,
|
||||||
PriceFlag,
|
PriceFlag,
|
||||||
ValueFlag,
|
ValueFlag,
|
||||||
DumpFlag,
|
|
||||||
InputFlag,
|
InputFlag,
|
||||||
InputFileFlag,
|
InputFileFlag,
|
||||||
MemProfileFlag,
|
|
||||||
CPUProfileFlag,
|
|
||||||
StatDumpFlag,
|
|
||||||
GenesisFlag,
|
GenesisFlag,
|
||||||
MachineFlag,
|
|
||||||
SenderFlag,
|
SenderFlag,
|
||||||
ReceiverFlag,
|
ReceiverFlag,
|
||||||
|
}
|
||||||
|
|
||||||
|
// traceFlags contains flags that configure tracing output.
|
||||||
|
var traceFlags = []cli.Flag{
|
||||||
|
BenchFlag,
|
||||||
|
DebugFlag,
|
||||||
|
DumpFlag,
|
||||||
|
MachineFlag,
|
||||||
|
StatDumpFlag,
|
||||||
DisableMemoryFlag,
|
DisableMemoryFlag,
|
||||||
DisableStackFlag,
|
DisableStackFlag,
|
||||||
DisableStorageFlag,
|
DisableStorageFlag,
|
||||||
DisableReturnDataFlag,
|
DisableReturnDataFlag,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var app = flags.NewApp("the evm command line interface")
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
app.Flags = flags.Merge(vmFlags, traceFlags, debug.Flags)
|
||||||
app.Commands = []*cli.Command{
|
app.Commands = []*cli.Command{
|
||||||
compileCommand,
|
compileCommand,
|
||||||
disasmCommand,
|
disasmCommand,
|
||||||
|
|
@ -221,6 +234,14 @@ func init() {
|
||||||
transactionCommand,
|
transactionCommand,
|
||||||
blockBuilderCommand,
|
blockBuilderCommand,
|
||||||
}
|
}
|
||||||
|
app.Before = func(ctx *cli.Context) error {
|
||||||
|
flags.MigrateGlobalFlags(ctx)
|
||||||
|
return debug.Setup(ctx)
|
||||||
|
}
|
||||||
|
app.After = func(ctx *cli.Context) error {
|
||||||
|
debug.Exit()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,6 @@ import (
|
||||||
"math/big"
|
"math/big"
|
||||||
"os"
|
"os"
|
||||||
goruntime "runtime"
|
goruntime "runtime"
|
||||||
"runtime/pprof"
|
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
|
@ -34,12 +33,10 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core"
|
||||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
"github.com/ethereum/go-ethereum/core/state"
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
"github.com/ethereum/go-ethereum/core/vm/runtime"
|
"github.com/ethereum/go-ethereum/core/vm/runtime"
|
||||||
"github.com/ethereum/go-ethereum/eth/tracers/logger"
|
"github.com/ethereum/go-ethereum/eth/tracers/logger"
|
||||||
"github.com/ethereum/go-ethereum/internal/flags"
|
"github.com/ethereum/go-ethereum/internal/flags"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/trie"
|
"github.com/ethereum/go-ethereum/trie"
|
||||||
"github.com/ethereum/go-ethereum/trie/triedb/hashdb"
|
"github.com/ethereum/go-ethereum/trie/triedb/hashdb"
|
||||||
|
|
@ -52,6 +49,7 @@ var runCommand = &cli.Command{
|
||||||
Usage: "run arbitrary evm binary",
|
Usage: "run arbitrary evm binary",
|
||||||
ArgsUsage: "<code>",
|
ArgsUsage: "<code>",
|
||||||
Description: `The run command runs arbitrary EVM code.`,
|
Description: `The run command runs arbitrary EVM code.`,
|
||||||
|
Flags: flags.Merge(vmFlags, traceFlags),
|
||||||
}
|
}
|
||||||
|
|
||||||
// readGenesis will read the given JSON format genesis file and return
|
// readGenesis will read the given JSON format genesis file and return
|
||||||
|
|
@ -109,9 +107,6 @@ func timedExec(bench bool, execFunc func() ([]byte, uint64, error)) (output []by
|
||||||
}
|
}
|
||||||
|
|
||||||
func runCmd(ctx *cli.Context) error {
|
func runCmd(ctx *cli.Context) error {
|
||||||
glogger := log.NewGlogHandler(log.StreamHandler(os.Stderr, log.TerminalFormat(false)))
|
|
||||||
glogger.Verbosity(log.Lvl(ctx.Int(VerbosityFlag.Name)))
|
|
||||||
log.Root().SetHandler(glogger)
|
|
||||||
logconfig := &logger.Config{
|
logconfig := &logger.Config{
|
||||||
EnableMemory: !ctx.Bool(DisableMemoryFlag.Name),
|
EnableMemory: !ctx.Bool(DisableMemoryFlag.Name),
|
||||||
DisableStack: ctx.Bool(DisableStackFlag.Name),
|
DisableStack: ctx.Bool(DisableStackFlag.Name),
|
||||||
|
|
@ -127,7 +122,6 @@ func runCmd(ctx *cli.Context) error {
|
||||||
chainConfig *params.ChainConfig
|
chainConfig *params.ChainConfig
|
||||||
sender = common.BytesToAddress([]byte("sender"))
|
sender = common.BytesToAddress([]byte("sender"))
|
||||||
receiver = common.BytesToAddress([]byte("receiver"))
|
receiver = common.BytesToAddress([]byte("receiver"))
|
||||||
genesisConfig *core.Genesis
|
|
||||||
preimages = ctx.Bool(DumpFlag.Name)
|
preimages = ctx.Bool(DumpFlag.Name)
|
||||||
blobHashes []common.Hash // TODO (MariusVanDerWijden) implement blob hashes in state tests
|
blobHashes []common.Hash // TODO (MariusVanDerWijden) implement blob hashes in state tests
|
||||||
)
|
)
|
||||||
|
|
@ -139,30 +133,30 @@ func runCmd(ctx *cli.Context) error {
|
||||||
} else {
|
} else {
|
||||||
debugLogger = logger.NewStructLogger(logconfig)
|
debugLogger = logger.NewStructLogger(logconfig)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
initialGas := ctx.Uint64(GasFlag.Name)
|
||||||
|
genesisConfig := new(core.Genesis)
|
||||||
|
genesisConfig.GasLimit = initialGas
|
||||||
if ctx.String(GenesisFlag.Name) != "" {
|
if ctx.String(GenesisFlag.Name) != "" {
|
||||||
gen := readGenesis(ctx.String(GenesisFlag.Name))
|
genesisConfig = readGenesis(ctx.String(GenesisFlag.Name))
|
||||||
genesisConfig = gen
|
if genesisConfig.GasLimit != 0 {
|
||||||
|
initialGas = genesisConfig.GasLimit
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
genesisConfig.Config = params.AllEthashProtocolChanges
|
||||||
|
}
|
||||||
|
|
||||||
db := rawdb.NewMemoryDatabase()
|
db := rawdb.NewMemoryDatabase()
|
||||||
triedb := trie.NewDatabase(db, &trie.Config{
|
triedb := trie.NewDatabase(db, &trie.Config{
|
||||||
Preimages: preimages,
|
Preimages: preimages,
|
||||||
HashDB: hashdb.Defaults,
|
HashDB: hashdb.Defaults,
|
||||||
})
|
})
|
||||||
defer triedb.Close()
|
defer triedb.Close()
|
||||||
genesis := gen.MustCommit(db, triedb)
|
genesis := genesisConfig.MustCommit(db, triedb)
|
||||||
sdb := state.NewDatabaseWithNodeDB(db, triedb)
|
sdb := state.NewDatabaseWithNodeDB(db, triedb)
|
||||||
statedb, _ = state.New(genesis.Root(), sdb, nil)
|
statedb, _ = state.New(genesis.Root(), sdb, nil)
|
||||||
chainConfig = gen.Config
|
chainConfig = genesisConfig.Config
|
||||||
} else {
|
|
||||||
db := rawdb.NewMemoryDatabase()
|
|
||||||
triedb := trie.NewDatabase(db, &trie.Config{
|
|
||||||
Preimages: preimages,
|
|
||||||
HashDB: hashdb.Defaults,
|
|
||||||
})
|
|
||||||
defer triedb.Close()
|
|
||||||
sdb := state.NewDatabaseWithNodeDB(db, triedb)
|
|
||||||
statedb, _ = state.New(types.EmptyRootHash, sdb, nil)
|
|
||||||
genesisConfig = new(core.Genesis)
|
|
||||||
}
|
|
||||||
if ctx.String(SenderFlag.Name) != "" {
|
if ctx.String(SenderFlag.Name) != "" {
|
||||||
sender = common.HexToAddress(ctx.String(SenderFlag.Name))
|
sender = common.HexToAddress(ctx.String(SenderFlag.Name))
|
||||||
}
|
}
|
||||||
|
|
@ -216,10 +210,6 @@ func runCmd(ctx *cli.Context) error {
|
||||||
}
|
}
|
||||||
code = common.Hex2Bytes(bin)
|
code = common.Hex2Bytes(bin)
|
||||||
}
|
}
|
||||||
initialGas := ctx.Uint64(GasFlag.Name)
|
|
||||||
if genesisConfig.GasLimit != 0 {
|
|
||||||
initialGas = genesisConfig.GasLimit
|
|
||||||
}
|
|
||||||
runtimeConfig := runtime.Config{
|
runtimeConfig := runtime.Config{
|
||||||
Origin: sender,
|
Origin: sender,
|
||||||
State: statedb,
|
State: statedb,
|
||||||
|
|
@ -236,19 +226,6 @@ func runCmd(ctx *cli.Context) error {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
if cpuProfilePath := ctx.String(CPUProfileFlag.Name); cpuProfilePath != "" {
|
|
||||||
f, err := os.Create(cpuProfilePath)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println("could not create CPU profile: ", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
if err := pprof.StartCPUProfile(f); err != nil {
|
|
||||||
fmt.Println("could not start CPU profile: ", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
defer pprof.StopCPUProfile()
|
|
||||||
}
|
|
||||||
|
|
||||||
if chainConfig != nil {
|
if chainConfig != nil {
|
||||||
runtimeConfig.ChainConfig = chainConfig
|
runtimeConfig.ChainConfig = chainConfig
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -296,19 +273,6 @@ func runCmd(ctx *cli.Context) error {
|
||||||
fmt.Println(string(statedb.Dump(nil)))
|
fmt.Println(string(statedb.Dump(nil)))
|
||||||
}
|
}
|
||||||
|
|
||||||
if memProfilePath := ctx.String(MemProfileFlag.Name); memProfilePath != "" {
|
|
||||||
f, err := os.Create(memProfilePath)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println("could not create memory profile: ", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
if err := pprof.WriteHeapProfile(f); err != nil {
|
|
||||||
fmt.Println("could not write memory profile: ", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
f.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
if ctx.Bool(DebugFlag.Name) {
|
if ctx.Bool(DebugFlag.Name) {
|
||||||
if debugLogger != nil {
|
if debugLogger != nil {
|
||||||
fmt.Fprintln(os.Stderr, "#### TRACE ####")
|
fmt.Fprintln(os.Stderr, "#### TRACE ####")
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,6 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/state/snapshot"
|
"github.com/ethereum/go-ethereum/core/state/snapshot"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
"github.com/ethereum/go-ethereum/eth/tracers/logger"
|
"github.com/ethereum/go-ethereum/eth/tracers/logger"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
|
||||||
"github.com/ethereum/go-ethereum/tests"
|
"github.com/ethereum/go-ethereum/tests"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
@ -52,11 +51,6 @@ type StatetestResult struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func stateTestCmd(ctx *cli.Context) error {
|
func stateTestCmd(ctx *cli.Context) error {
|
||||||
// Configure the go-ethereum logger
|
|
||||||
glogger := log.NewGlogHandler(log.StreamHandler(os.Stderr, log.TerminalFormat(false)))
|
|
||||||
glogger.Verbosity(log.Lvl(ctx.Int(VerbosityFlag.Name)))
|
|
||||||
log.Root().SetHandler(glogger)
|
|
||||||
|
|
||||||
// Configure the EVM logger
|
// Configure the EVM logger
|
||||||
config := &logger.Config{
|
config := &logger.Config{
|
||||||
EnableMemory: !ctx.Bool(DisableMemoryFlag.Name),
|
EnableMemory: !ctx.Bool(DisableMemoryFlag.Name),
|
||||||
|
|
|
||||||
|
|
@ -50,8 +50,7 @@ var (
|
||||||
ArgsUsage: "<genesisPath>",
|
ArgsUsage: "<genesisPath>",
|
||||||
Flags: flags.Merge([]cli.Flag{
|
Flags: flags.Merge([]cli.Flag{
|
||||||
utils.CachePreimagesFlag,
|
utils.CachePreimagesFlag,
|
||||||
utils.StateSchemeFlag,
|
}, utils.DatabaseFlags),
|
||||||
}, utils.DatabasePathFlags),
|
|
||||||
Description: `
|
Description: `
|
||||||
The init command initializes a new genesis block and definition for the network.
|
The init command initializes a new genesis block and definition for the network.
|
||||||
This is a destructive action and changes the network in which you will be
|
This is a destructive action and changes the network in which you will be
|
||||||
|
|
@ -97,9 +96,8 @@ if one is set. Otherwise it prints the genesis from the datadir.`,
|
||||||
utils.MetricsInfluxDBOrganizationFlag,
|
utils.MetricsInfluxDBOrganizationFlag,
|
||||||
utils.TxLookupLimitFlag,
|
utils.TxLookupLimitFlag,
|
||||||
utils.TransactionHistoryFlag,
|
utils.TransactionHistoryFlag,
|
||||||
utils.StateSchemeFlag,
|
|
||||||
utils.StateHistoryFlag,
|
utils.StateHistoryFlag,
|
||||||
}, utils.DatabasePathFlags),
|
}, utils.DatabaseFlags),
|
||||||
Description: `
|
Description: `
|
||||||
The import command imports blocks from an RLP-encoded form. The form can be one file
|
The import command imports blocks from an RLP-encoded form. The form can be one file
|
||||||
with several RLP-encoded blocks, or several files can be used.
|
with several RLP-encoded blocks, or several files can be used.
|
||||||
|
|
@ -115,8 +113,7 @@ processing will proceed even if an individual RLP-file import failure occurs.`,
|
||||||
Flags: flags.Merge([]cli.Flag{
|
Flags: flags.Merge([]cli.Flag{
|
||||||
utils.CacheFlag,
|
utils.CacheFlag,
|
||||||
utils.SyncModeFlag,
|
utils.SyncModeFlag,
|
||||||
utils.StateSchemeFlag,
|
}, utils.DatabaseFlags),
|
||||||
}, utils.DatabasePathFlags),
|
|
||||||
Description: `
|
Description: `
|
||||||
Requires a first argument of the file to write to.
|
Requires a first argument of the file to write to.
|
||||||
Optional second and third arguments control the first and
|
Optional second and third arguments control the first and
|
||||||
|
|
@ -132,7 +129,7 @@ be gzipped.`,
|
||||||
Flags: flags.Merge([]cli.Flag{
|
Flags: flags.Merge([]cli.Flag{
|
||||||
utils.CacheFlag,
|
utils.CacheFlag,
|
||||||
utils.SyncModeFlag,
|
utils.SyncModeFlag,
|
||||||
}, utils.DatabasePathFlags),
|
}, utils.DatabaseFlags),
|
||||||
Description: `
|
Description: `
|
||||||
The import-preimages command imports hash preimages from an RLP encoded stream.
|
The import-preimages command imports hash preimages from an RLP encoded stream.
|
||||||
It's deprecated, please use "geth db import" instead.
|
It's deprecated, please use "geth db import" instead.
|
||||||
|
|
@ -146,7 +143,7 @@ It's deprecated, please use "geth db import" instead.
|
||||||
Flags: flags.Merge([]cli.Flag{
|
Flags: flags.Merge([]cli.Flag{
|
||||||
utils.CacheFlag,
|
utils.CacheFlag,
|
||||||
utils.SyncModeFlag,
|
utils.SyncModeFlag,
|
||||||
}, utils.DatabasePathFlags),
|
}, utils.DatabaseFlags),
|
||||||
Description: `
|
Description: `
|
||||||
The export-preimages command exports hash preimages to an RLP encoded stream.
|
The export-preimages command exports hash preimages to an RLP encoded stream.
|
||||||
It's deprecated, please use "geth db export" instead.
|
It's deprecated, please use "geth db export" instead.
|
||||||
|
|
@ -165,8 +162,7 @@ It's deprecated, please use "geth db export" instead.
|
||||||
utils.IncludeIncompletesFlag,
|
utils.IncludeIncompletesFlag,
|
||||||
utils.StartKeyFlag,
|
utils.StartKeyFlag,
|
||||||
utils.DumpLimitFlag,
|
utils.DumpLimitFlag,
|
||||||
utils.StateSchemeFlag,
|
}, utils.DatabaseFlags),
|
||||||
}, utils.DatabasePathFlags),
|
|
||||||
Description: `
|
Description: `
|
||||||
This command dumps out the state for a given block (or latest, if none provided).
|
This command dumps out the state for a given block (or latest, if none provided).
|
||||||
`,
|
`,
|
||||||
|
|
|
||||||
|
|
@ -188,7 +188,7 @@ func makeFullNode(ctx *cli.Context) (*node.Node, ethapi.Backend) {
|
||||||
"arch": runtime.GOARCH,
|
"arch": runtime.GOARCH,
|
||||||
"os": runtime.GOOS,
|
"os": runtime.GOOS,
|
||||||
"version": cfg.Node.Version,
|
"version": cfg.Node.Version,
|
||||||
"eth_protocols": strings.Join(protos, ","),
|
"protocols": strings.Join(protos, ","),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,7 @@ var (
|
||||||
Name: "removedb",
|
Name: "removedb",
|
||||||
Usage: "Remove blockchain and state databases",
|
Usage: "Remove blockchain and state databases",
|
||||||
ArgsUsage: "",
|
ArgsUsage: "",
|
||||||
Flags: utils.DatabasePathFlags,
|
Flags: utils.DatabaseFlags,
|
||||||
Description: `
|
Description: `
|
||||||
Remove blockchain and state databases`,
|
Remove blockchain and state databases`,
|
||||||
}
|
}
|
||||||
|
|
@ -77,7 +77,7 @@ Remove blockchain and state databases`,
|
||||||
ArgsUsage: "<prefix> <start>",
|
ArgsUsage: "<prefix> <start>",
|
||||||
Flags: flags.Merge([]cli.Flag{
|
Flags: flags.Merge([]cli.Flag{
|
||||||
utils.SyncModeFlag,
|
utils.SyncModeFlag,
|
||||||
}, utils.NetworkFlags, utils.DatabasePathFlags),
|
}, utils.NetworkFlags, utils.DatabaseFlags),
|
||||||
Usage: "Inspect the storage size for each type of data in the database",
|
Usage: "Inspect the storage size for each type of data in the database",
|
||||||
Description: `This commands iterates the entire database. If the optional 'prefix' and 'start' arguments are provided, then the iteration is limited to the given subset of data.`,
|
Description: `This commands iterates the entire database. If the optional 'prefix' and 'start' arguments are provided, then the iteration is limited to the given subset of data.`,
|
||||||
}
|
}
|
||||||
|
|
@ -85,7 +85,7 @@ Remove blockchain and state databases`,
|
||||||
Action: checkStateContent,
|
Action: checkStateContent,
|
||||||
Name: "check-state-content",
|
Name: "check-state-content",
|
||||||
ArgsUsage: "<start (optional)>",
|
ArgsUsage: "<start (optional)>",
|
||||||
Flags: flags.Merge(utils.NetworkFlags, utils.DatabasePathFlags),
|
Flags: flags.Merge(utils.NetworkFlags, utils.DatabaseFlags),
|
||||||
Usage: "Verify that state data is cryptographically correct",
|
Usage: "Verify that state data is cryptographically correct",
|
||||||
Description: `This command iterates the entire database for 32-byte keys, looking for rlp-encoded trie nodes.
|
Description: `This command iterates the entire database for 32-byte keys, looking for rlp-encoded trie nodes.
|
||||||
For each trie node encountered, it checks that the key corresponds to the keccak256(value). If this is not true, this indicates
|
For each trie node encountered, it checks that the key corresponds to the keccak256(value). If this is not true, this indicates
|
||||||
|
|
@ -97,7 +97,7 @@ a data corruption.`,
|
||||||
Usage: "Print leveldb statistics",
|
Usage: "Print leveldb statistics",
|
||||||
Flags: flags.Merge([]cli.Flag{
|
Flags: flags.Merge([]cli.Flag{
|
||||||
utils.SyncModeFlag,
|
utils.SyncModeFlag,
|
||||||
}, utils.NetworkFlags, utils.DatabasePathFlags),
|
}, utils.NetworkFlags, utils.DatabaseFlags),
|
||||||
}
|
}
|
||||||
dbCompactCmd = &cli.Command{
|
dbCompactCmd = &cli.Command{
|
||||||
Action: dbCompact,
|
Action: dbCompact,
|
||||||
|
|
@ -107,7 +107,7 @@ a data corruption.`,
|
||||||
utils.SyncModeFlag,
|
utils.SyncModeFlag,
|
||||||
utils.CacheFlag,
|
utils.CacheFlag,
|
||||||
utils.CacheDatabaseFlag,
|
utils.CacheDatabaseFlag,
|
||||||
}, utils.NetworkFlags, utils.DatabasePathFlags),
|
}, utils.NetworkFlags, utils.DatabaseFlags),
|
||||||
Description: `This command performs a database compaction.
|
Description: `This command performs a database compaction.
|
||||||
WARNING: This operation may take a very long time to finish, and may cause database
|
WARNING: This operation may take a very long time to finish, and may cause database
|
||||||
corruption if it is aborted during execution'!`,
|
corruption if it is aborted during execution'!`,
|
||||||
|
|
@ -119,7 +119,7 @@ corruption if it is aborted during execution'!`,
|
||||||
ArgsUsage: "<hex-encoded key>",
|
ArgsUsage: "<hex-encoded key>",
|
||||||
Flags: flags.Merge([]cli.Flag{
|
Flags: flags.Merge([]cli.Flag{
|
||||||
utils.SyncModeFlag,
|
utils.SyncModeFlag,
|
||||||
}, utils.NetworkFlags, utils.DatabasePathFlags),
|
}, utils.NetworkFlags, utils.DatabaseFlags),
|
||||||
Description: "This command looks up the specified database key from the database.",
|
Description: "This command looks up the specified database key from the database.",
|
||||||
}
|
}
|
||||||
dbDeleteCmd = &cli.Command{
|
dbDeleteCmd = &cli.Command{
|
||||||
|
|
@ -129,7 +129,7 @@ corruption if it is aborted during execution'!`,
|
||||||
ArgsUsage: "<hex-encoded key>",
|
ArgsUsage: "<hex-encoded key>",
|
||||||
Flags: flags.Merge([]cli.Flag{
|
Flags: flags.Merge([]cli.Flag{
|
||||||
utils.SyncModeFlag,
|
utils.SyncModeFlag,
|
||||||
}, utils.NetworkFlags, utils.DatabasePathFlags),
|
}, utils.NetworkFlags, utils.DatabaseFlags),
|
||||||
Description: `This command deletes the specified database key from the database.
|
Description: `This command deletes the specified database key from the database.
|
||||||
WARNING: This is a low-level operation which may cause database corruption!`,
|
WARNING: This is a low-level operation which may cause database corruption!`,
|
||||||
}
|
}
|
||||||
|
|
@ -140,7 +140,7 @@ WARNING: This is a low-level operation which may cause database corruption!`,
|
||||||
ArgsUsage: "<hex-encoded key> <hex-encoded value>",
|
ArgsUsage: "<hex-encoded key> <hex-encoded value>",
|
||||||
Flags: flags.Merge([]cli.Flag{
|
Flags: flags.Merge([]cli.Flag{
|
||||||
utils.SyncModeFlag,
|
utils.SyncModeFlag,
|
||||||
}, utils.NetworkFlags, utils.DatabasePathFlags),
|
}, utils.NetworkFlags, utils.DatabaseFlags),
|
||||||
Description: `This command sets a given database key to the given value.
|
Description: `This command sets a given database key to the given value.
|
||||||
WARNING: This is a low-level operation which may cause database corruption!`,
|
WARNING: This is a low-level operation which may cause database corruption!`,
|
||||||
}
|
}
|
||||||
|
|
@ -151,8 +151,7 @@ WARNING: This is a low-level operation which may cause database corruption!`,
|
||||||
ArgsUsage: "<hex-encoded state root> <hex-encoded account hash> <hex-encoded storage trie root> <hex-encoded start (optional)> <int max elements (optional)>",
|
ArgsUsage: "<hex-encoded state root> <hex-encoded account hash> <hex-encoded storage trie root> <hex-encoded start (optional)> <int max elements (optional)>",
|
||||||
Flags: flags.Merge([]cli.Flag{
|
Flags: flags.Merge([]cli.Flag{
|
||||||
utils.SyncModeFlag,
|
utils.SyncModeFlag,
|
||||||
utils.StateSchemeFlag,
|
}, utils.NetworkFlags, utils.DatabaseFlags),
|
||||||
}, utils.NetworkFlags, utils.DatabasePathFlags),
|
|
||||||
Description: "This command looks up the specified database key from the database.",
|
Description: "This command looks up the specified database key from the database.",
|
||||||
}
|
}
|
||||||
dbDumpFreezerIndex = &cli.Command{
|
dbDumpFreezerIndex = &cli.Command{
|
||||||
|
|
@ -162,7 +161,7 @@ WARNING: This is a low-level operation which may cause database corruption!`,
|
||||||
ArgsUsage: "<freezer-type> <table-type> <start (int)> <end (int)>",
|
ArgsUsage: "<freezer-type> <table-type> <start (int)> <end (int)>",
|
||||||
Flags: flags.Merge([]cli.Flag{
|
Flags: flags.Merge([]cli.Flag{
|
||||||
utils.SyncModeFlag,
|
utils.SyncModeFlag,
|
||||||
}, utils.NetworkFlags, utils.DatabasePathFlags),
|
}, utils.NetworkFlags, utils.DatabaseFlags),
|
||||||
Description: "This command displays information about the freezer index.",
|
Description: "This command displays information about the freezer index.",
|
||||||
}
|
}
|
||||||
dbImportCmd = &cli.Command{
|
dbImportCmd = &cli.Command{
|
||||||
|
|
@ -172,7 +171,7 @@ WARNING: This is a low-level operation which may cause database corruption!`,
|
||||||
ArgsUsage: "<dumpfile> <start (optional)",
|
ArgsUsage: "<dumpfile> <start (optional)",
|
||||||
Flags: flags.Merge([]cli.Flag{
|
Flags: flags.Merge([]cli.Flag{
|
||||||
utils.SyncModeFlag,
|
utils.SyncModeFlag,
|
||||||
}, utils.NetworkFlags, utils.DatabasePathFlags),
|
}, utils.NetworkFlags, utils.DatabaseFlags),
|
||||||
Description: "The import command imports the specific chain data from an RLP encoded stream.",
|
Description: "The import command imports the specific chain data from an RLP encoded stream.",
|
||||||
}
|
}
|
||||||
dbExportCmd = &cli.Command{
|
dbExportCmd = &cli.Command{
|
||||||
|
|
@ -182,7 +181,7 @@ WARNING: This is a low-level operation which may cause database corruption!`,
|
||||||
ArgsUsage: "<type> <dumpfile>",
|
ArgsUsage: "<type> <dumpfile>",
|
||||||
Flags: flags.Merge([]cli.Flag{
|
Flags: flags.Merge([]cli.Flag{
|
||||||
utils.SyncModeFlag,
|
utils.SyncModeFlag,
|
||||||
}, utils.NetworkFlags, utils.DatabasePathFlags),
|
}, utils.NetworkFlags, utils.DatabaseFlags),
|
||||||
Description: "Exports the specified chain data to an RLP encoded stream, optionally gzip-compressed.",
|
Description: "Exports the specified chain data to an RLP encoded stream, optionally gzip-compressed.",
|
||||||
}
|
}
|
||||||
dbMetadataCmd = &cli.Command{
|
dbMetadataCmd = &cli.Command{
|
||||||
|
|
@ -191,7 +190,7 @@ WARNING: This is a low-level operation which may cause database corruption!`,
|
||||||
Usage: "Shows metadata about the chain status.",
|
Usage: "Shows metadata about the chain status.",
|
||||||
Flags: flags.Merge([]cli.Flag{
|
Flags: flags.Merge([]cli.Flag{
|
||||||
utils.SyncModeFlag,
|
utils.SyncModeFlag,
|
||||||
}, utils.NetworkFlags, utils.DatabasePathFlags),
|
}, utils.NetworkFlags, utils.DatabaseFlags),
|
||||||
Description: "Shows metadata about the chain status.",
|
Description: "Shows metadata about the chain status.",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -89,7 +89,6 @@ var (
|
||||||
utils.SnapshotFlag,
|
utils.SnapshotFlag,
|
||||||
utils.TxLookupLimitFlag,
|
utils.TxLookupLimitFlag,
|
||||||
utils.TransactionHistoryFlag,
|
utils.TransactionHistoryFlag,
|
||||||
utils.StateSchemeFlag,
|
|
||||||
utils.StateHistoryFlag,
|
utils.StateHistoryFlag,
|
||||||
utils.LightServeFlag,
|
utils.LightServeFlag,
|
||||||
utils.LightIngressFlag,
|
utils.LightIngressFlag,
|
||||||
|
|
@ -145,7 +144,7 @@ var (
|
||||||
utils.GpoMaxGasPriceFlag,
|
utils.GpoMaxGasPriceFlag,
|
||||||
utils.GpoIgnoreGasPriceFlag,
|
utils.GpoIgnoreGasPriceFlag,
|
||||||
configFileFlag,
|
configFileFlag,
|
||||||
}, utils.NetworkFlags, utils.DatabasePathFlags)
|
}, utils.NetworkFlags, utils.DatabaseFlags)
|
||||||
|
|
||||||
rpcFlags = []cli.Flag{
|
rpcFlags = []cli.Flag{
|
||||||
utils.HTTPEnabledFlag,
|
utils.HTTPEnabledFlag,
|
||||||
|
|
@ -244,11 +243,16 @@ func init() {
|
||||||
debug.Flags,
|
debug.Flags,
|
||||||
metricsFlags,
|
metricsFlags,
|
||||||
)
|
)
|
||||||
|
flags.AutoEnvVars(app.Flags, "GETH")
|
||||||
|
|
||||||
app.Before = func(ctx *cli.Context) error {
|
app.Before = func(ctx *cli.Context) error {
|
||||||
maxprocs.Set() // Automatically set GOMAXPROCS to match Linux container CPU quota.
|
maxprocs.Set() // Automatically set GOMAXPROCS to match Linux container CPU quota.
|
||||||
flags.MigrateGlobalFlags(ctx)
|
flags.MigrateGlobalFlags(ctx)
|
||||||
return debug.Setup(ctx)
|
if err := debug.Setup(ctx); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
flags.CheckEnvVars(ctx, app.Flags, "GETH")
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
app.After = func(ctx *cli.Context) error {
|
app.After = func(ctx *cli.Context) error {
|
||||||
debug.Exit()
|
debug.Exit()
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,7 @@ var (
|
||||||
Action: pruneState,
|
Action: pruneState,
|
||||||
Flags: flags.Merge([]cli.Flag{
|
Flags: flags.Merge([]cli.Flag{
|
||||||
utils.BloomFilterSizeFlag,
|
utils.BloomFilterSizeFlag,
|
||||||
}, utils.NetworkFlags, utils.DatabasePathFlags),
|
}, utils.NetworkFlags, utils.DatabaseFlags),
|
||||||
Description: `
|
Description: `
|
||||||
geth snapshot prune-state <state-root>
|
geth snapshot prune-state <state-root>
|
||||||
will prune historical state data with the help of the state snapshot.
|
will prune historical state data with the help of the state snapshot.
|
||||||
|
|
@ -69,9 +69,7 @@ WARNING: it's only supported in hash mode(--state.scheme=hash)".
|
||||||
Usage: "Recalculate state hash based on the snapshot for verification",
|
Usage: "Recalculate state hash based on the snapshot for verification",
|
||||||
ArgsUsage: "<root>",
|
ArgsUsage: "<root>",
|
||||||
Action: verifyState,
|
Action: verifyState,
|
||||||
Flags: flags.Merge([]cli.Flag{
|
Flags: flags.Merge(utils.NetworkFlags, utils.DatabaseFlags),
|
||||||
utils.StateSchemeFlag,
|
|
||||||
}, utils.NetworkFlags, utils.DatabasePathFlags),
|
|
||||||
Description: `
|
Description: `
|
||||||
geth snapshot verify-state <state-root>
|
geth snapshot verify-state <state-root>
|
||||||
will traverse the whole accounts and storages set based on the specified
|
will traverse the whole accounts and storages set based on the specified
|
||||||
|
|
@ -84,7 +82,7 @@ In other words, this command does the snapshot to trie conversion.
|
||||||
Usage: "Check that there is no 'dangling' snap storage",
|
Usage: "Check that there is no 'dangling' snap storage",
|
||||||
ArgsUsage: "<root>",
|
ArgsUsage: "<root>",
|
||||||
Action: checkDanglingStorage,
|
Action: checkDanglingStorage,
|
||||||
Flags: flags.Merge(utils.NetworkFlags, utils.DatabasePathFlags),
|
Flags: flags.Merge(utils.NetworkFlags, utils.DatabaseFlags),
|
||||||
Description: `
|
Description: `
|
||||||
geth snapshot check-dangling-storage <state-root> traverses the snap storage
|
geth snapshot check-dangling-storage <state-root> traverses the snap storage
|
||||||
data, and verifies that all snapshot storage data has a corresponding account.
|
data, and verifies that all snapshot storage data has a corresponding account.
|
||||||
|
|
@ -95,7 +93,7 @@ data, and verifies that all snapshot storage data has a corresponding account.
|
||||||
Usage: "Check all snapshot layers for the a specific account",
|
Usage: "Check all snapshot layers for the a specific account",
|
||||||
ArgsUsage: "<address | hash>",
|
ArgsUsage: "<address | hash>",
|
||||||
Action: checkAccount,
|
Action: checkAccount,
|
||||||
Flags: flags.Merge(utils.NetworkFlags, utils.DatabasePathFlags),
|
Flags: flags.Merge(utils.NetworkFlags, utils.DatabaseFlags),
|
||||||
Description: `
|
Description: `
|
||||||
geth snapshot inspect-account <address | hash> checks all snapshot layers and prints out
|
geth snapshot inspect-account <address | hash> checks all snapshot layers and prints out
|
||||||
information about the specified address.
|
information about the specified address.
|
||||||
|
|
@ -106,9 +104,7 @@ information about the specified address.
|
||||||
Usage: "Traverse the state with given root hash and perform quick verification",
|
Usage: "Traverse the state with given root hash and perform quick verification",
|
||||||
ArgsUsage: "<root>",
|
ArgsUsage: "<root>",
|
||||||
Action: traverseState,
|
Action: traverseState,
|
||||||
Flags: flags.Merge([]cli.Flag{
|
Flags: flags.Merge(utils.NetworkFlags, utils.DatabaseFlags),
|
||||||
utils.StateSchemeFlag,
|
|
||||||
}, utils.NetworkFlags, utils.DatabasePathFlags),
|
|
||||||
Description: `
|
Description: `
|
||||||
geth snapshot traverse-state <state-root>
|
geth snapshot traverse-state <state-root>
|
||||||
will traverse the whole state from the given state root and will abort if any
|
will traverse the whole state from the given state root and will abort if any
|
||||||
|
|
@ -123,9 +119,7 @@ It's also usable without snapshot enabled.
|
||||||
Usage: "Traverse the state with given root hash and perform detailed verification",
|
Usage: "Traverse the state with given root hash and perform detailed verification",
|
||||||
ArgsUsage: "<root>",
|
ArgsUsage: "<root>",
|
||||||
Action: traverseRawState,
|
Action: traverseRawState,
|
||||||
Flags: flags.Merge([]cli.Flag{
|
Flags: flags.Merge(utils.NetworkFlags, utils.DatabaseFlags),
|
||||||
utils.StateSchemeFlag,
|
|
||||||
}, utils.NetworkFlags, utils.DatabasePathFlags),
|
|
||||||
Description: `
|
Description: `
|
||||||
geth snapshot traverse-rawstate <state-root>
|
geth snapshot traverse-rawstate <state-root>
|
||||||
will traverse the whole state from the given root and will abort if any referenced
|
will traverse the whole state from the given root and will abort if any referenced
|
||||||
|
|
@ -146,8 +140,7 @@ It's also usable without snapshot enabled.
|
||||||
utils.ExcludeStorageFlag,
|
utils.ExcludeStorageFlag,
|
||||||
utils.StartKeyFlag,
|
utils.StartKeyFlag,
|
||||||
utils.DumpLimitFlag,
|
utils.DumpLimitFlag,
|
||||||
utils.StateSchemeFlag,
|
}, utils.NetworkFlags, utils.DatabaseFlags),
|
||||||
}, utils.NetworkFlags, utils.DatabasePathFlags),
|
|
||||||
Description: `
|
Description: `
|
||||||
This command is semantically equivalent to 'geth dump', but uses the snapshots
|
This command is semantically equivalent to 'geth dump', but uses the snapshots
|
||||||
as the backend data source, making this command a lot faster.
|
as the backend data source, making this command a lot faster.
|
||||||
|
|
@ -332,6 +325,11 @@ func traverseState(ctx *cli.Context) error {
|
||||||
storageIter := trie.NewIterator(storageIt)
|
storageIter := trie.NewIterator(storageIt)
|
||||||
for storageIter.Next() {
|
for storageIter.Next() {
|
||||||
slots += 1
|
slots += 1
|
||||||
|
|
||||||
|
if time.Since(lastReport) > time.Second*8 {
|
||||||
|
log.Info("Traversing state", "accounts", accounts, "slots", slots, "codes", codes, "elapsed", common.PrettyDuration(time.Since(start)))
|
||||||
|
lastReport = time.Now()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if storageIter.Err != nil {
|
if storageIter.Err != nil {
|
||||||
log.Error("Failed to traverse storage trie", "root", acc.Root, "err", storageIter.Err)
|
log.Error("Failed to traverse storage trie", "root", acc.Root, "err", storageIter.Err)
|
||||||
|
|
@ -486,6 +484,10 @@ func traverseRawState(ctx *cli.Context) error {
|
||||||
if storageIter.Leaf() {
|
if storageIter.Leaf() {
|
||||||
slots += 1
|
slots += 1
|
||||||
}
|
}
|
||||||
|
if time.Since(lastReport) > time.Second*8 {
|
||||||
|
log.Info("Traversing state", "nodes", nodes, "accounts", accounts, "slots", slots, "codes", codes, "elapsed", common.PrettyDuration(time.Since(start)))
|
||||||
|
lastReport = time.Now()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if storageIter.Error() != nil {
|
if storageIter.Error() != nil {
|
||||||
log.Error("Failed to traverse storage trie", "root", acc.Root, "err", storageIter.Error())
|
log.Error("Failed to traverse storage trie", "root", acc.Root, "err", storageIter.Error())
|
||||||
|
|
|
||||||
4
cmd/geth/testdata/vcheck/minisig-sigs-new/data.json.minisig
vendored
Normal file
4
cmd/geth/testdata/vcheck/minisig-sigs-new/data.json.minisig
vendored
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
untrusted comment: signature from minisign secret key
|
||||||
|
RUQkliYstQBOKLK05Sy5f3bVRMBqJT26ABo6Vbp3BNJAVjejoqYCu4GWE/+7qcDfHBqYIniDCbFIUvYEnOHxV6vZ93wO1xJWDQw=
|
||||||
|
trusted comment: timestamp:1693986492 file:data.json hashed
|
||||||
|
6Fdw2H+W1ZXK7QXSF77Z5AWC7+AEFAfDmTSxNGylU5HLT1AuSJQmxslj+VjtUBamYCvOuET7plbXza942AlWDw==
|
||||||
|
|
@ -45,7 +45,7 @@ var (
|
||||||
Usage: "verify the conversion of a MPT into a verkle tree",
|
Usage: "verify the conversion of a MPT into a verkle tree",
|
||||||
ArgsUsage: "<root>",
|
ArgsUsage: "<root>",
|
||||||
Action: verifyVerkle,
|
Action: verifyVerkle,
|
||||||
Flags: flags.Merge(utils.NetworkFlags, utils.DatabasePathFlags),
|
Flags: flags.Merge(utils.NetworkFlags, utils.DatabaseFlags),
|
||||||
Description: `
|
Description: `
|
||||||
geth verkle verify <state-root>
|
geth verkle verify <state-root>
|
||||||
This command takes a root commitment and attempts to rebuild the tree.
|
This command takes a root commitment and attempts to rebuild the tree.
|
||||||
|
|
@ -56,7 +56,7 @@ This command takes a root commitment and attempts to rebuild the tree.
|
||||||
Usage: "Dump a verkle tree to a DOT file",
|
Usage: "Dump a verkle tree to a DOT file",
|
||||||
ArgsUsage: "<root> <key1> [<key 2> ...]",
|
ArgsUsage: "<root> <key1> [<key 2> ...]",
|
||||||
Action: expandVerkle,
|
Action: expandVerkle,
|
||||||
Flags: flags.Merge(utils.NetworkFlags, utils.DatabasePathFlags),
|
Flags: flags.Merge(utils.NetworkFlags, utils.DatabaseFlags),
|
||||||
Description: `
|
Description: `
|
||||||
geth verkle dump <state-root> <key 1> [<key 2> ...]
|
geth verkle dump <state-root> <key 1> [<key 2> ...]
|
||||||
This command will produce a dot file representing the tree, rooted at <root>.
|
This command will produce a dot file representing the tree, rooted at <root>.
|
||||||
|
|
|
||||||
|
|
@ -30,17 +30,24 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestVerification(t *testing.T) {
|
func TestVerification(t *testing.T) {
|
||||||
// Signatures generated with `minisign`
|
// Signatures generated with `minisign`. Legacy format, not pre-hashed file.
|
||||||
t.Run("minisig", func(t *testing.T) {
|
t.Run("minisig-legacy", func(t *testing.T) {
|
||||||
// For this test, the pubkey is in testdata/minisign.pub
|
// For this test, the pubkey is in testdata/vcheck/minisign.pub
|
||||||
// (the privkey is `minisign.sec`, if we want to expand this test. Password 'test' )
|
// (the privkey is `minisign.sec`, if we want to expand this test. Password 'test' )
|
||||||
pub := "RWQkliYstQBOKOdtClfgC3IypIPX6TAmoEi7beZ4gyR3wsaezvqOMWsp"
|
pub := "RWQkliYstQBOKOdtClfgC3IypIPX6TAmoEi7beZ4gyR3wsaezvqOMWsp"
|
||||||
testVerification(t, pub, "./testdata/vcheck/minisig-sigs/")
|
testVerification(t, pub, "./testdata/vcheck/minisig-sigs/")
|
||||||
})
|
})
|
||||||
|
t.Run("minisig-new", func(t *testing.T) {
|
||||||
|
// For this test, the pubkey is in testdata/vcheck/minisign.pub
|
||||||
|
// (the privkey is `minisign.sec`, if we want to expand this test. Password 'test' )
|
||||||
|
// `minisign -S -s ./minisign.sec -m data.json -x ./minisig-sigs-new/data.json.minisig`
|
||||||
|
pub := "RWQkliYstQBOKOdtClfgC3IypIPX6TAmoEi7beZ4gyR3wsaezvqOMWsp"
|
||||||
|
testVerification(t, pub, "./testdata/vcheck/minisig-sigs-new/")
|
||||||
|
})
|
||||||
// Signatures generated with `signify-openbsd`
|
// Signatures generated with `signify-openbsd`
|
||||||
t.Run("signify-openbsd", func(t *testing.T) {
|
t.Run("signify-openbsd", func(t *testing.T) {
|
||||||
t.Skip("This currently fails, minisign expects 4 lines of data, signify provides only 2")
|
t.Skip("This currently fails, minisign expects 4 lines of data, signify provides only 2")
|
||||||
// For this test, the pubkey is in testdata/signifykey.pub
|
// For this test, the pubkey is in testdata/vcheck/signifykey.pub
|
||||||
// (the privkey is `signifykey.sec`, if we want to expand this test. Password 'test' )
|
// (the privkey is `signifykey.sec`, if we want to expand this test. Password 'test' )
|
||||||
pub := "RWSKLNhZb0KdATtRT7mZC/bybI3t3+Hv/O2i3ye04Dq9fnT9slpZ1a2/"
|
pub := "RWSKLNhZb0KdATtRT7mZC/bybI3t3+Hv/O2i3ye04Dq9fnT9slpZ1a2/"
|
||||||
testVerification(t, pub, "./testdata/vcheck/signify-sigs/")
|
testVerification(t, pub, "./testdata/vcheck/signify-sigs/")
|
||||||
|
|
@ -58,6 +65,9 @@ func testVerification(t *testing.T, pubkey, sigdir string) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
if len(files) == 0 {
|
||||||
|
t.Fatal("Missing tests")
|
||||||
|
}
|
||||||
for _, f := range files {
|
for _, f := range files {
|
||||||
sig, err := os.ReadFile(filepath.Join(sigdir, f.Name()))
|
sig, err := os.ReadFile(filepath.Join(sigdir, f.Name()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -961,18 +961,19 @@ var (
|
||||||
// NetworkFlags is the flag group of all built-in supported networks.
|
// NetworkFlags is the flag group of all built-in supported networks.
|
||||||
NetworkFlags = append([]cli.Flag{MainnetFlag}, TestnetFlags...)
|
NetworkFlags = append([]cli.Flag{MainnetFlag}, TestnetFlags...)
|
||||||
|
|
||||||
// DatabasePathFlags is the flag group of all database path flags.
|
// DatabaseFlags is the flag group of all database flags.
|
||||||
DatabasePathFlags = []cli.Flag{
|
DatabaseFlags = []cli.Flag{
|
||||||
DataDirFlag,
|
DataDirFlag,
|
||||||
AncientFlag,
|
AncientFlag,
|
||||||
RemoteDBFlag,
|
RemoteDBFlag,
|
||||||
|
StateSchemeFlag,
|
||||||
HttpHeaderFlag,
|
HttpHeaderFlag,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
if rawdb.PebbleEnabled {
|
if rawdb.PebbleEnabled {
|
||||||
DatabasePathFlags = append(DatabasePathFlags, DBEngineFlag)
|
DatabaseFlags = append(DatabaseFlags, DBEngineFlag)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -998,7 +999,7 @@ func MakeDataDir(ctx *cli.Context) string {
|
||||||
|
|
||||||
// setNodeKey creates a node key from set command line flags, either loading it
|
// setNodeKey creates a node key from set command line flags, either loading it
|
||||||
// from a file or as a specified hex value. If neither flags were provided, this
|
// from a file or as a specified hex value. If neither flags were provided, this
|
||||||
// method returns nil and an emphemeral key is to be generated.
|
// method returns nil and an ephemeral key is to be generated.
|
||||||
func setNodeKey(ctx *cli.Context, cfg *p2p.Config) {
|
func setNodeKey(ctx *cli.Context, cfg *p2p.Config) {
|
||||||
var (
|
var (
|
||||||
hex = ctx.String(NodeKeyHexFlag.Name)
|
hex = ctx.String(NodeKeyHexFlag.Name)
|
||||||
|
|
@ -2121,7 +2122,7 @@ func DialRPCWithHeaders(endpoint string, headers []string) (*rpc.Client, error)
|
||||||
}
|
}
|
||||||
var opts []rpc.ClientOption
|
var opts []rpc.ClientOption
|
||||||
if len(headers) > 0 {
|
if len(headers) > 0 {
|
||||||
var customHeaders = make(http.Header)
|
customHeaders := make(http.Header)
|
||||||
for _, h := range headers {
|
for _, h := range headers {
|
||||||
kv := strings.Split(h, ":")
|
kv := strings.Split(h, ":")
|
||||||
if len(kv) != 2 {
|
if len(kv) != 2 {
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ import (
|
||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestBytesConversion(t *testing.T) {
|
func TestBytesConversion(t *testing.T) {
|
||||||
|
|
@ -583,3 +584,14 @@ func TestAddressEIP55(t *testing.T) {
|
||||||
t.Fatal("Unexpected address after unmarshal")
|
t.Fatal("Unexpected address after unmarshal")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func BenchmarkPrettyDuration(b *testing.B) {
|
||||||
|
var x = PrettyDuration(time.Duration(int64(1203123912312)))
|
||||||
|
b.Logf("Pre %s", time.Duration(x).String())
|
||||||
|
var a string
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
a = x.String()
|
||||||
|
}
|
||||||
|
b.Logf("Post %s", a)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,6 @@
|
||||||
package misc
|
package misc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
|
|
@ -36,7 +35,7 @@ func VerifyGaslimit(parentGasLimit, headerGasLimit uint64) error {
|
||||||
return fmt.Errorf("invalid gas limit: have %d, want %d +-= %d", headerGasLimit, parentGasLimit, limit-1)
|
return fmt.Errorf("invalid gas limit: have %d, want %d +-= %d", headerGasLimit, parentGasLimit, limit-1)
|
||||||
}
|
}
|
||||||
if headerGasLimit < params.MinGasLimit {
|
if headerGasLimit < params.MinGasLimit {
|
||||||
return errors.New("invalid gas limit below 5000")
|
return fmt.Errorf("invalid gas limit below %d", params.MinGasLimit)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,8 @@
|
||||||
package asm
|
package asm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/hex"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
"os"
|
"os"
|
||||||
|
|
@ -30,7 +32,7 @@ import (
|
||||||
// and holds the tokens for the program.
|
// and holds the tokens for the program.
|
||||||
type Compiler struct {
|
type Compiler struct {
|
||||||
tokens []token
|
tokens []token
|
||||||
binary []interface{}
|
out []byte
|
||||||
|
|
||||||
labels map[string]int
|
labels map[string]int
|
||||||
|
|
||||||
|
|
@ -50,12 +52,10 @@ func NewCompiler(debug bool) *Compiler {
|
||||||
// Feed feeds tokens in to ch and are interpreted by
|
// Feed feeds tokens in to ch and are interpreted by
|
||||||
// the compiler.
|
// the compiler.
|
||||||
//
|
//
|
||||||
// feed is the first pass in the compile stage as it
|
// feed is the first pass in the compile stage as it collects the used labels in the
|
||||||
// collects the used labels in the program and keeps a
|
// program and keeps a program counter which is used to determine the locations of the
|
||||||
// program counter which is used to determine the locations
|
// jump dests. The labels can than be used in the second stage to push labels and
|
||||||
// of the jump dests. The labels can than be used in the
|
// determine the right position.
|
||||||
// second stage to push labels and determine the right
|
|
||||||
// position.
|
|
||||||
func (c *Compiler) Feed(ch <-chan token) {
|
func (c *Compiler) Feed(ch <-chan token) {
|
||||||
var prev token
|
var prev token
|
||||||
for i := range ch {
|
for i := range ch {
|
||||||
|
|
@ -79,7 +79,6 @@ func (c *Compiler) Feed(ch <-chan token) {
|
||||||
c.pc++
|
c.pc++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
c.tokens = append(c.tokens, i)
|
c.tokens = append(c.tokens, i)
|
||||||
prev = i
|
prev = i
|
||||||
}
|
}
|
||||||
|
|
@ -88,12 +87,11 @@ func (c *Compiler) Feed(ch <-chan token) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compile compiles the current tokens and returns a
|
// Compile compiles the current tokens and returns a binary string that can be interpreted
|
||||||
// binary string that can be interpreted by the EVM
|
// by the EVM and an error if it failed.
|
||||||
// and an error if it failed.
|
|
||||||
//
|
//
|
||||||
// compile is the second stage in the compile phase
|
// compile is the second stage in the compile phase which compiles the tokens to EVM
|
||||||
// which compiles the tokens to EVM instructions.
|
// instructions.
|
||||||
func (c *Compiler) Compile() (string, []error) {
|
func (c *Compiler) Compile() (string, []error) {
|
||||||
var errors []error
|
var errors []error
|
||||||
// continue looping over the tokens until
|
// continue looping over the tokens until
|
||||||
|
|
@ -105,16 +103,8 @@ func (c *Compiler) Compile() (string, []error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// turn the binary to hex
|
// turn the binary to hex
|
||||||
var bin strings.Builder
|
h := hex.EncodeToString(c.out)
|
||||||
for _, v := range c.binary {
|
return h, errors
|
||||||
switch v := v.(type) {
|
|
||||||
case vm.OpCode:
|
|
||||||
bin.WriteString(fmt.Sprintf("%x", []byte{byte(v)}))
|
|
||||||
case []byte:
|
|
||||||
bin.WriteString(fmt.Sprintf("%x", v))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return bin.String(), errors
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// next returns the next token and increments the
|
// next returns the next token and increments the
|
||||||
|
|
@ -156,47 +146,73 @@ func (c *Compiler) compileLine() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// compileNumber compiles the number to bytes
|
// parseNumber compiles the number to bytes
|
||||||
func (c *Compiler) compileNumber(element token) {
|
func parseNumber(tok token) ([]byte, error) {
|
||||||
num := math.MustParseBig256(element.text).Bytes()
|
if tok.typ != number {
|
||||||
if len(num) == 0 {
|
panic("parseNumber of non-number token")
|
||||||
num = []byte{0}
|
|
||||||
}
|
}
|
||||||
c.pushBin(num)
|
num, ok := math.ParseBig256(tok.text)
|
||||||
|
if !ok {
|
||||||
|
return nil, errors.New("invalid number")
|
||||||
|
}
|
||||||
|
bytes := num.Bytes()
|
||||||
|
if len(bytes) == 0 {
|
||||||
|
bytes = []byte{0}
|
||||||
|
}
|
||||||
|
return bytes, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// compileElement compiles the element (push & label or both)
|
// compileElement compiles the element (push & label or both)
|
||||||
// to a binary representation and may error if incorrect statements
|
// to a binary representation and may error if incorrect statements
|
||||||
// where fed.
|
// where fed.
|
||||||
func (c *Compiler) compileElement(element token) error {
|
func (c *Compiler) compileElement(element token) error {
|
||||||
// check for a jump. jumps must be read and compiled
|
switch {
|
||||||
// from right to left.
|
case isJump(element.text):
|
||||||
if isJump(element.text) {
|
return c.compileJump(element.text)
|
||||||
|
case isPush(element.text):
|
||||||
|
return c.compilePush()
|
||||||
|
default:
|
||||||
|
c.outputOpcode(toBinary(element.text))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Compiler) compileJump(jumpType string) error {
|
||||||
rvalue := c.next()
|
rvalue := c.next()
|
||||||
switch rvalue.typ {
|
switch rvalue.typ {
|
||||||
case number:
|
case number:
|
||||||
// TODO figure out how to return the error properly
|
numBytes, err := parseNumber(rvalue)
|
||||||
c.compileNumber(rvalue)
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
c.outputBytes(numBytes)
|
||||||
|
|
||||||
case stringValue:
|
case stringValue:
|
||||||
// strings are quoted, remove them.
|
// strings are quoted, remove them.
|
||||||
c.pushBin(rvalue.text[1 : len(rvalue.text)-2])
|
str := rvalue.text[1 : len(rvalue.text)-2]
|
||||||
|
c.outputBytes([]byte(str))
|
||||||
|
|
||||||
case label:
|
case label:
|
||||||
c.pushBin(vm.PUSH4)
|
c.outputOpcode(vm.PUSH4)
|
||||||
pos := big.NewInt(int64(c.labels[rvalue.text])).Bytes()
|
pos := big.NewInt(int64(c.labels[rvalue.text])).Bytes()
|
||||||
pos = append(make([]byte, 4-len(pos)), pos...)
|
pos = append(make([]byte, 4-len(pos)), pos...)
|
||||||
c.pushBin(pos)
|
c.outputBytes(pos)
|
||||||
|
|
||||||
case lineEnd:
|
case lineEnd:
|
||||||
|
// push without argument is supported, it just takes the destination from the stack.
|
||||||
c.pos--
|
c.pos--
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return compileErr(rvalue, rvalue.text, "number, string or label")
|
return compileErr(rvalue, rvalue.text, "number, string or label")
|
||||||
}
|
}
|
||||||
// push the operation
|
// push the operation
|
||||||
c.pushBin(toBinary(element.text))
|
c.outputOpcode(toBinary(jumpType))
|
||||||
return nil
|
return nil
|
||||||
} else if isPush(element.text) {
|
}
|
||||||
|
|
||||||
|
func (c *Compiler) compilePush() error {
|
||||||
// handle pushes. pushes are read from left to right.
|
// handle pushes. pushes are read from left to right.
|
||||||
var value []byte
|
var value []byte
|
||||||
|
|
||||||
rvalue := c.next()
|
rvalue := c.next()
|
||||||
switch rvalue.typ {
|
switch rvalue.typ {
|
||||||
case number:
|
case number:
|
||||||
|
|
@ -212,31 +228,32 @@ func (c *Compiler) compileElement(element token) error {
|
||||||
default:
|
default:
|
||||||
return compileErr(rvalue, rvalue.text, "number, string or label")
|
return compileErr(rvalue, rvalue.text, "number, string or label")
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(value) > 32 {
|
if len(value) > 32 {
|
||||||
return fmt.Errorf("%d type error: unsupported string or number with size > 32", rvalue.lineno)
|
return fmt.Errorf("%d: string or number size > 32 bytes", rvalue.lineno+1)
|
||||||
}
|
}
|
||||||
|
c.outputOpcode(vm.OpCode(int(vm.PUSH1) - 1 + len(value)))
|
||||||
c.pushBin(vm.OpCode(int(vm.PUSH1) - 1 + len(value)))
|
c.outputBytes(value)
|
||||||
c.pushBin(value)
|
|
||||||
} else {
|
|
||||||
c.pushBin(toBinary(element.text))
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// compileLabel pushes a jumpdest to the binary slice.
|
// compileLabel pushes a jumpdest to the binary slice.
|
||||||
func (c *Compiler) compileLabel() {
|
func (c *Compiler) compileLabel() {
|
||||||
c.pushBin(vm.JUMPDEST)
|
c.outputOpcode(vm.JUMPDEST)
|
||||||
}
|
}
|
||||||
|
|
||||||
// pushBin pushes the value v to the binary stack.
|
func (c *Compiler) outputOpcode(op vm.OpCode) {
|
||||||
func (c *Compiler) pushBin(v interface{}) {
|
|
||||||
if c.debug {
|
if c.debug {
|
||||||
fmt.Printf("%d: %v\n", len(c.binary), v)
|
fmt.Printf("%d: %v\n", len(c.out), op)
|
||||||
}
|
}
|
||||||
c.binary = append(c.binary, v)
|
c.out = append(c.out, byte(op))
|
||||||
|
}
|
||||||
|
|
||||||
|
// output pushes the value v to the binary stack.
|
||||||
|
func (c *Compiler) outputBytes(b []byte) {
|
||||||
|
if c.debug {
|
||||||
|
fmt.Printf("%d: %x\n", len(c.out), b)
|
||||||
|
}
|
||||||
|
c.out = append(c.out, b...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// isPush returns whether the string op is either any of
|
// isPush returns whether the string op is either any of
|
||||||
|
|
@ -263,13 +280,13 @@ type compileError struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (err compileError) Error() string {
|
func (err compileError) Error() string {
|
||||||
return fmt.Sprintf("%d syntax error: unexpected %v, expected %v", err.lineno, err.got, err.want)
|
return fmt.Sprintf("%d: syntax error: unexpected %v, expected %v", err.lineno, err.got, err.want)
|
||||||
}
|
}
|
||||||
|
|
||||||
func compileErr(c token, got, want string) error {
|
func compileErr(c token, got, want string) error {
|
||||||
return compileError{
|
return compileError{
|
||||||
got: got,
|
got: got,
|
||||||
want: want,
|
want: want,
|
||||||
lineno: c.lineno,
|
lineno: c.lineno + 1,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,14 @@ func TestCompiler(t *testing.T) {
|
||||||
`,
|
`,
|
||||||
output: "6300000006565b",
|
output: "6300000006565b",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
input: `
|
||||||
|
JUMP @label
|
||||||
|
label: ;; comment
|
||||||
|
ADD ;; comment
|
||||||
|
`,
|
||||||
|
output: "6300000006565b01",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
ch := Lex([]byte(test.input), false)
|
ch := Lex([]byte(test.input), false)
|
||||||
|
|
|
||||||
|
|
@ -72,6 +72,16 @@ func TestLexer(t *testing.T) {
|
||||||
input: "@label123",
|
input: "@label123",
|
||||||
tokens: []token{{typ: lineStart}, {typ: label, text: "label123"}, {typ: eof}},
|
tokens: []token{{typ: lineStart}, {typ: label, text: "label123"}, {typ: eof}},
|
||||||
},
|
},
|
||||||
|
// comment after label
|
||||||
|
{
|
||||||
|
input: "@label123 ;; comment",
|
||||||
|
tokens: []token{{typ: lineStart}, {typ: label, text: "label123"}, {typ: eof}},
|
||||||
|
},
|
||||||
|
// comment after instruction
|
||||||
|
{
|
||||||
|
input: "push 3 ;; comment\nadd",
|
||||||
|
tokens: []token{{typ: lineStart}, {typ: element, text: "push"}, {typ: number, text: "3"}, {typ: lineEnd, text: "\n"}, {typ: lineStart, lineno: 1}, {typ: element, lineno: 1, text: "add"}, {typ: eof, lineno: 1}},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,8 @@ type token struct {
|
||||||
// is able to parse and return.
|
// is able to parse and return.
|
||||||
type tokenType int
|
type tokenType int
|
||||||
|
|
||||||
|
//go:generate go run golang.org/x/tools/cmd/stringer -type tokenType
|
||||||
|
|
||||||
const (
|
const (
|
||||||
eof tokenType = iota // end of file
|
eof tokenType = iota // end of file
|
||||||
lineStart // emitted when a line starts
|
lineStart // emitted when a line starts
|
||||||
|
|
@ -52,31 +54,13 @@ const (
|
||||||
labelDef // label definition is emitted when a new label is found
|
labelDef // label definition is emitted when a new label is found
|
||||||
number // number is emitted when a number is found
|
number // number is emitted when a number is found
|
||||||
stringValue // stringValue is emitted when a string has been found
|
stringValue // stringValue is emitted when a string has been found
|
||||||
|
|
||||||
Numbers = "1234567890" // characters representing any decimal number
|
|
||||||
HexadecimalNumbers = Numbers + "aAbBcCdDeEfF" // characters representing any hexadecimal
|
|
||||||
Alpha = "abcdefghijklmnopqrstuwvxyzABCDEFGHIJKLMNOPQRSTUWVXYZ" // characters representing alphanumeric
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// String implements stringer
|
const (
|
||||||
func (it tokenType) String() string {
|
decimalNumbers = "1234567890" // characters representing any decimal number
|
||||||
if int(it) > len(stringtokenTypes) {
|
hexNumbers = decimalNumbers + "aAbBcCdDeEfF" // characters representing any hexadecimal
|
||||||
return "invalid"
|
alpha = "abcdefghijklmnopqrstuwvxyzABCDEFGHIJKLMNOPQRSTUWVXYZ" // characters representing alphanumeric
|
||||||
}
|
)
|
||||||
return stringtokenTypes[it]
|
|
||||||
}
|
|
||||||
|
|
||||||
var stringtokenTypes = []string{
|
|
||||||
eof: "EOF",
|
|
||||||
lineStart: "new line",
|
|
||||||
lineEnd: "end of line",
|
|
||||||
invalidStatement: "invalid statement",
|
|
||||||
element: "element",
|
|
||||||
label: "label",
|
|
||||||
labelDef: "label definition",
|
|
||||||
number: "number",
|
|
||||||
stringValue: "string",
|
|
||||||
}
|
|
||||||
|
|
||||||
// lexer is the basic construct for parsing
|
// lexer is the basic construct for parsing
|
||||||
// source code and turning them in to tokens.
|
// source code and turning them in to tokens.
|
||||||
|
|
@ -200,7 +184,6 @@ func lexLine(l *lexer) stateFn {
|
||||||
l.emit(lineEnd)
|
l.emit(lineEnd)
|
||||||
l.ignore()
|
l.ignore()
|
||||||
l.lineno++
|
l.lineno++
|
||||||
|
|
||||||
l.emit(lineStart)
|
l.emit(lineStart)
|
||||||
case r == ';' && l.peek() == ';':
|
case r == ';' && l.peek() == ';':
|
||||||
return lexComment
|
return lexComment
|
||||||
|
|
@ -225,6 +208,7 @@ func lexLine(l *lexer) stateFn {
|
||||||
// of the line and discards the text.
|
// of the line and discards the text.
|
||||||
func lexComment(l *lexer) stateFn {
|
func lexComment(l *lexer) stateFn {
|
||||||
l.acceptRunUntil('\n')
|
l.acceptRunUntil('\n')
|
||||||
|
l.backup()
|
||||||
l.ignore()
|
l.ignore()
|
||||||
|
|
||||||
return lexLine
|
return lexLine
|
||||||
|
|
@ -234,7 +218,7 @@ func lexComment(l *lexer) stateFn {
|
||||||
// the lex text state function to advance the parsing
|
// the lex text state function to advance the parsing
|
||||||
// process.
|
// process.
|
||||||
func lexLabel(l *lexer) stateFn {
|
func lexLabel(l *lexer) stateFn {
|
||||||
l.acceptRun(Alpha + "_" + Numbers)
|
l.acceptRun(alpha + "_" + decimalNumbers)
|
||||||
|
|
||||||
l.emit(label)
|
l.emit(label)
|
||||||
|
|
||||||
|
|
@ -253,9 +237,9 @@ func lexInsideString(l *lexer) stateFn {
|
||||||
}
|
}
|
||||||
|
|
||||||
func lexNumber(l *lexer) stateFn {
|
func lexNumber(l *lexer) stateFn {
|
||||||
acceptance := Numbers
|
acceptance := decimalNumbers
|
||||||
if l.accept("xX") {
|
if l.accept("xX") {
|
||||||
acceptance = HexadecimalNumbers
|
acceptance = hexNumbers
|
||||||
}
|
}
|
||||||
l.acceptRun(acceptance)
|
l.acceptRun(acceptance)
|
||||||
|
|
||||||
|
|
@ -265,7 +249,7 @@ func lexNumber(l *lexer) stateFn {
|
||||||
}
|
}
|
||||||
|
|
||||||
func lexElement(l *lexer) stateFn {
|
func lexElement(l *lexer) stateFn {
|
||||||
l.acceptRun(Alpha + "_" + Numbers)
|
l.acceptRun(alpha + "_" + decimalNumbers)
|
||||||
|
|
||||||
if l.peek() == ':' {
|
if l.peek() == ':' {
|
||||||
l.emit(labelDef)
|
l.emit(labelDef)
|
||||||
|
|
|
||||||
31
core/asm/tokentype_string.go
Normal file
31
core/asm/tokentype_string.go
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
// Code generated by "stringer -type tokenType"; DO NOT EDIT.
|
||||||
|
|
||||||
|
package asm
|
||||||
|
|
||||||
|
import "strconv"
|
||||||
|
|
||||||
|
func _() {
|
||||||
|
// An "invalid array index" compiler error signifies that the constant values have changed.
|
||||||
|
// Re-run the stringer command to generate them again.
|
||||||
|
var x [1]struct{}
|
||||||
|
_ = x[eof-0]
|
||||||
|
_ = x[lineStart-1]
|
||||||
|
_ = x[lineEnd-2]
|
||||||
|
_ = x[invalidStatement-3]
|
||||||
|
_ = x[element-4]
|
||||||
|
_ = x[label-5]
|
||||||
|
_ = x[labelDef-6]
|
||||||
|
_ = x[number-7]
|
||||||
|
_ = x[stringValue-8]
|
||||||
|
}
|
||||||
|
|
||||||
|
const _tokenType_name = "eoflineStartlineEndinvalidStatementelementlabellabelDefnumberstringValue"
|
||||||
|
|
||||||
|
var _tokenType_index = [...]uint8{0, 3, 12, 19, 35, 42, 47, 55, 61, 72}
|
||||||
|
|
||||||
|
func (i tokenType) String() string {
|
||||||
|
if i < 0 || i >= tokenType(len(_tokenType_index)-1) {
|
||||||
|
return "tokenType(" + strconv.FormatInt(int64(i), 10) + ")"
|
||||||
|
}
|
||||||
|
return _tokenType_name[_tokenType_index[i]:_tokenType_index[i+1]]
|
||||||
|
}
|
||||||
|
|
@ -340,6 +340,15 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
|
||||||
// Make sure the state associated with the block is available
|
// Make sure the state associated with the block is available
|
||||||
head := bc.CurrentBlock()
|
head := bc.CurrentBlock()
|
||||||
if !bc.HasState(head.Root) {
|
if !bc.HasState(head.Root) {
|
||||||
|
if head.Number.Uint64() == 0 {
|
||||||
|
// The genesis state is missing, which is only possible in the path-based
|
||||||
|
// scheme. This situation occurs when the state syncer overwrites it.
|
||||||
|
//
|
||||||
|
// The solution is to reset the state to the genesis state. Although it may not
|
||||||
|
// match the sync target, the state healer will later address and correct any
|
||||||
|
// inconsistencies.
|
||||||
|
bc.resetState()
|
||||||
|
} else {
|
||||||
// Head state is missing, before the state recovery, find out the
|
// Head state is missing, before the state recovery, find out the
|
||||||
// disk layer point of snapshot(if it's enabled). Make sure the
|
// disk layer point of snapshot(if it's enabled). Make sure the
|
||||||
// rewound point is lower than disk layer.
|
// rewound point is lower than disk layer.
|
||||||
|
|
@ -365,6 +374,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// Ensure that a previous crash in SetHead doesn't leave extra ancients
|
// Ensure that a previous crash in SetHead doesn't leave extra ancients
|
||||||
if frozen, err := bc.db.Ancients(); err == nil && frozen > 0 {
|
if frozen, err := bc.db.Ancients(); err == nil && frozen > 0 {
|
||||||
var (
|
var (
|
||||||
|
|
@ -620,6 +630,28 @@ func (bc *BlockChain) SetSafe(header *types.Header) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// resetState resets the persistent state to genesis state if it's not present.
|
||||||
|
func (bc *BlockChain) resetState() {
|
||||||
|
// Short circuit if the genesis state is already present.
|
||||||
|
root := bc.genesisBlock.Root()
|
||||||
|
if bc.HasState(root) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Reset the state database to empty for committing genesis state.
|
||||||
|
// Note, it should only happen in path-based scheme and Reset function
|
||||||
|
// is also only call-able in this mode.
|
||||||
|
if bc.triedb.Scheme() == rawdb.PathScheme {
|
||||||
|
if err := bc.triedb.Reset(types.EmptyRootHash); err != nil {
|
||||||
|
log.Crit("Failed to clean state", "err", err) // Shouldn't happen
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Write genesis state into database.
|
||||||
|
if err := CommitGenesisState(bc.db, bc.triedb, bc.genesisBlock.Hash()); err != nil {
|
||||||
|
log.Crit("Failed to commit genesis state", "err", err)
|
||||||
|
}
|
||||||
|
log.Info("Reset state to genesis", "root", root)
|
||||||
|
}
|
||||||
|
|
||||||
// setHeadBeyondRoot rewinds the local chain to a new head with the extra condition
|
// setHeadBeyondRoot rewinds the local chain to a new head with the extra condition
|
||||||
// that the rewind must pass the specified state root. This method is meant to be
|
// that the rewind must pass the specified state root. This method is meant to be
|
||||||
// used when rewinding with snapshots enabled to ensure that we go back further than
|
// used when rewinding with snapshots enabled to ensure that we go back further than
|
||||||
|
|
@ -646,25 +678,6 @@ func (bc *BlockChain) setHeadBeyondRoot(head uint64, time uint64, root common.Ha
|
||||||
pivot := rawdb.ReadLastPivotNumber(bc.db)
|
pivot := rawdb.ReadLastPivotNumber(bc.db)
|
||||||
frozen, _ := bc.db.Ancients()
|
frozen, _ := bc.db.Ancients()
|
||||||
|
|
||||||
// resetState resets the persistent state to genesis if it's not available.
|
|
||||||
resetState := func() {
|
|
||||||
// Short circuit if the genesis state is already present.
|
|
||||||
if bc.HasState(bc.genesisBlock.Root()) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// Reset the state database to empty for committing genesis state.
|
|
||||||
// Note, it should only happen in path-based scheme and Reset function
|
|
||||||
// is also only call-able in this mode.
|
|
||||||
if bc.triedb.Scheme() == rawdb.PathScheme {
|
|
||||||
if err := bc.triedb.Reset(types.EmptyRootHash); err != nil {
|
|
||||||
log.Crit("Failed to clean state", "err", err) // Shouldn't happen
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Write genesis state into database.
|
|
||||||
if err := CommitGenesisState(bc.db, bc.triedb, bc.genesisBlock.Hash()); err != nil {
|
|
||||||
log.Crit("Failed to commit genesis state", "err", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
updateFn := func(db ethdb.KeyValueWriter, header *types.Header) (*types.Header, bool) {
|
updateFn := func(db ethdb.KeyValueWriter, header *types.Header) (*types.Header, bool) {
|
||||||
// Rewind the blockchain, ensuring we don't end up with a stateless head
|
// Rewind the blockchain, ensuring we don't end up with a stateless head
|
||||||
// block. Note, depth equality is permitted to allow using SetHead as a
|
// block. Note, depth equality is permitted to allow using SetHead as a
|
||||||
|
|
@ -674,7 +687,7 @@ func (bc *BlockChain) setHeadBeyondRoot(head uint64, time uint64, root common.Ha
|
||||||
if newHeadBlock == nil {
|
if newHeadBlock == nil {
|
||||||
log.Error("Gap in the chain, rewinding to genesis", "number", header.Number, "hash", header.Hash())
|
log.Error("Gap in the chain, rewinding to genesis", "number", header.Number, "hash", header.Hash())
|
||||||
newHeadBlock = bc.genesisBlock
|
newHeadBlock = bc.genesisBlock
|
||||||
resetState()
|
bc.resetState()
|
||||||
} else {
|
} else {
|
||||||
// Block exists, keep rewinding until we find one with state,
|
// Block exists, keep rewinding until we find one with state,
|
||||||
// keeping rewinding until we exceed the optional threshold
|
// keeping rewinding until we exceed the optional threshold
|
||||||
|
|
@ -703,7 +716,7 @@ func (bc *BlockChain) setHeadBeyondRoot(head uint64, time uint64, root common.Ha
|
||||||
}
|
}
|
||||||
if beyondRoot || newHeadBlock.NumberU64() == 0 {
|
if beyondRoot || newHeadBlock.NumberU64() == 0 {
|
||||||
if newHeadBlock.NumberU64() == 0 {
|
if newHeadBlock.NumberU64() == 0 {
|
||||||
resetState()
|
bc.resetState()
|
||||||
} else if !bc.HasState(newHeadBlock.Root()) {
|
} else if !bc.HasState(newHeadBlock.Root()) {
|
||||||
// Rewind to a block with recoverable state. If the state is
|
// Rewind to a block with recoverable state. If the state is
|
||||||
// missing, run the state recovery here.
|
// missing, run the state recovery here.
|
||||||
|
|
|
||||||
|
|
@ -111,11 +111,11 @@ const crashesToKeep = 10
|
||||||
func PushUncleanShutdownMarker(db ethdb.KeyValueStore) ([]uint64, uint64, error) {
|
func PushUncleanShutdownMarker(db ethdb.KeyValueStore) ([]uint64, uint64, error) {
|
||||||
var uncleanShutdowns crashList
|
var uncleanShutdowns crashList
|
||||||
// Read old data
|
// Read old data
|
||||||
if data, err := db.Get(uncleanShutdownKey); err != nil {
|
if data, err := db.Get(uncleanShutdownKey); err == nil {
|
||||||
log.Warn("Error reading unclean shutdown markers", "error", err)
|
if err := rlp.DecodeBytes(data, &uncleanShutdowns); err != nil {
|
||||||
} else if err := rlp.DecodeBytes(data, &uncleanShutdowns); err != nil {
|
|
||||||
return nil, 0, err
|
return nil, 0, err
|
||||||
}
|
}
|
||||||
|
}
|
||||||
var discarded = uncleanShutdowns.Discarded
|
var discarded = uncleanShutdowns.Discarded
|
||||||
var previous = make([]uint64, len(uncleanShutdowns.Recent))
|
var previous = make([]uint64, len(uncleanShutdowns.Recent))
|
||||||
copy(previous, uncleanShutdowns.Recent)
|
copy(previous, uncleanShutdowns.Recent)
|
||||||
|
|
|
||||||
|
|
@ -89,6 +89,16 @@ func HasAccountTrieNode(db ethdb.KeyValueReader, path []byte, hash common.Hash)
|
||||||
return h.hash(data) == hash
|
return h.hash(data) == hash
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ExistsAccountTrieNode checks the presence of the account trie node with the
|
||||||
|
// specified node path, regardless of the node hash.
|
||||||
|
func ExistsAccountTrieNode(db ethdb.KeyValueReader, path []byte) bool {
|
||||||
|
has, err := db.Has(accountTrieNodeKey(path))
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return has
|
||||||
|
}
|
||||||
|
|
||||||
// WriteAccountTrieNode writes the provided account trie node into database.
|
// WriteAccountTrieNode writes the provided account trie node into database.
|
||||||
func WriteAccountTrieNode(db ethdb.KeyValueWriter, path []byte, node []byte) {
|
func WriteAccountTrieNode(db ethdb.KeyValueWriter, path []byte, node []byte) {
|
||||||
if err := db.Put(accountTrieNodeKey(path), node); err != nil {
|
if err := db.Put(accountTrieNodeKey(path), node); err != nil {
|
||||||
|
|
@ -127,6 +137,16 @@ func HasStorageTrieNode(db ethdb.KeyValueReader, accountHash common.Hash, path [
|
||||||
return h.hash(data) == hash
|
return h.hash(data) == hash
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ExistsStorageTrieNode checks the presence of the storage trie node with the
|
||||||
|
// specified account hash and node path, regardless of the node hash.
|
||||||
|
func ExistsStorageTrieNode(db ethdb.KeyValueReader, accountHash common.Hash, path []byte) bool {
|
||||||
|
has, err := db.Has(storageTrieNodeKey(accountHash, path))
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return has
|
||||||
|
}
|
||||||
|
|
||||||
// WriteStorageTrieNode writes the provided storage trie node into database.
|
// WriteStorageTrieNode writes the provided storage trie node into database.
|
||||||
func WriteStorageTrieNode(db ethdb.KeyValueWriter, accountHash common.Hash, path []byte, node []byte) {
|
func WriteStorageTrieNode(db ethdb.KeyValueWriter, accountHash common.Hash, path []byte, node []byte) {
|
||||||
if err := db.Put(storageTrieNodeKey(accountHash, path), node); err != nil {
|
if err := db.Put(storageTrieNodeKey(accountHash, path), node); err != nil {
|
||||||
|
|
|
||||||
|
|
@ -88,6 +88,9 @@ func inspectFreezers(db ethdb.Database) ([]freezerInfo, error) {
|
||||||
infos = append(infos, info)
|
infos = append(infos, info)
|
||||||
|
|
||||||
case stateFreezerName:
|
case stateFreezerName:
|
||||||
|
if ReadStateScheme(db) != PathScheme {
|
||||||
|
continue
|
||||||
|
}
|
||||||
datadir, err := db.AncientDatadir()
|
datadir, err := db.AncientDatadir()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
|
||||||
|
|
@ -253,7 +253,7 @@ func NewDatabaseWithFreezer(db ethdb.KeyValueStore, ancient string, namespace st
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// We are about to exit on error. Print database metdata beore exiting
|
// We are about to exit on error. Print database metadata before exiting
|
||||||
printChainMetadata(db)
|
printChainMetadata(db)
|
||||||
return nil, fmt.Errorf("gap in the chain between ancients [0 - #%d] and leveldb [#%d - #%d] ",
|
return nil, fmt.Errorf("gap in the chain between ancients [0 - #%d] and leveldb [#%d - #%d] ",
|
||||||
frozen-1, number, head)
|
frozen-1, number, head)
|
||||||
|
|
|
||||||
|
|
@ -108,7 +108,11 @@ func NewFreezer(datadir string, namespace string, readonly bool, maxTableSize ui
|
||||||
// Leveldb uses LOCK as the filelock filename. To prevent the
|
// Leveldb uses LOCK as the filelock filename. To prevent the
|
||||||
// name collision, we use FLOCK as the lock name.
|
// name collision, we use FLOCK as the lock name.
|
||||||
lock := flock.New(flockFile)
|
lock := flock.New(flockFile)
|
||||||
if locked, err := lock.TryLock(); err != nil {
|
tryLock := lock.TryLock
|
||||||
|
if readonly {
|
||||||
|
tryLock = lock.TryRLock
|
||||||
|
}
|
||||||
|
if locked, err := tryLock(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else if !locked {
|
} else if !locked {
|
||||||
return nil, errors.New("locking failed")
|
return nil, errors.New("locking failed")
|
||||||
|
|
|
||||||
|
|
@ -212,6 +212,9 @@ func (t *freezerTable) repair() error {
|
||||||
}
|
}
|
||||||
// Ensure the index is a multiple of indexEntrySize bytes
|
// Ensure the index is a multiple of indexEntrySize bytes
|
||||||
if overflow := stat.Size() % indexEntrySize; overflow != 0 {
|
if overflow := stat.Size() % indexEntrySize; overflow != 0 {
|
||||||
|
if t.readonly {
|
||||||
|
return fmt.Errorf("index file(path: %s, name: %s) size is not a multiple of %d", t.path, t.name, indexEntrySize)
|
||||||
|
}
|
||||||
truncateFreezerFile(t.index, stat.Size()-overflow) // New file can't trigger this path
|
truncateFreezerFile(t.index, stat.Size()-overflow) // New file can't trigger this path
|
||||||
}
|
}
|
||||||
// Retrieve the file sizes and prepare for truncation
|
// Retrieve the file sizes and prepare for truncation
|
||||||
|
|
@ -270,6 +273,9 @@ func (t *freezerTable) repair() error {
|
||||||
// Keep truncating both files until they come in sync
|
// Keep truncating both files until they come in sync
|
||||||
contentExp = int64(lastIndex.offset)
|
contentExp = int64(lastIndex.offset)
|
||||||
for contentExp != contentSize {
|
for contentExp != contentSize {
|
||||||
|
if t.readonly {
|
||||||
|
return fmt.Errorf("freezer table(path: %s, name: %s, num: %d) is corrupted", t.path, t.name, lastIndex.filenum)
|
||||||
|
}
|
||||||
verbose = true
|
verbose = true
|
||||||
// Truncate the head file to the last offset pointer
|
// Truncate the head file to the last offset pointer
|
||||||
if contentExp < contentSize {
|
if contentExp < contentSize {
|
||||||
|
|
|
||||||
|
|
@ -283,6 +283,57 @@ func TestFreezerReadonlyValidate(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestFreezerConcurrentReadonly(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
tables := map[string]bool{"a": true}
|
||||||
|
dir := t.TempDir()
|
||||||
|
|
||||||
|
f, err := NewFreezer(dir, "", false, 2049, tables)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("can't open freezer", err)
|
||||||
|
}
|
||||||
|
var item = make([]byte, 1024)
|
||||||
|
batch := f.tables["a"].newBatch()
|
||||||
|
items := uint64(10)
|
||||||
|
for i := uint64(0); i < items; i++ {
|
||||||
|
require.NoError(t, batch.AppendRaw(i, item))
|
||||||
|
}
|
||||||
|
require.NoError(t, batch.commit())
|
||||||
|
if loaded := f.tables["a"].items.Load(); loaded != items {
|
||||||
|
t.Fatalf("unexpected number of items in table, want: %d, have: %d", items, loaded)
|
||||||
|
}
|
||||||
|
require.NoError(t, f.Close())
|
||||||
|
|
||||||
|
var (
|
||||||
|
wg sync.WaitGroup
|
||||||
|
fs = make([]*Freezer, 5)
|
||||||
|
errs = make([]error, 5)
|
||||||
|
)
|
||||||
|
for i := 0; i < 5; i++ {
|
||||||
|
wg.Add(1)
|
||||||
|
go func(i int) {
|
||||||
|
defer wg.Done()
|
||||||
|
|
||||||
|
f, err := NewFreezer(dir, "", true, 2049, tables)
|
||||||
|
if err == nil {
|
||||||
|
fs[i] = f
|
||||||
|
} else {
|
||||||
|
errs[i] = err
|
||||||
|
}
|
||||||
|
}(i)
|
||||||
|
}
|
||||||
|
|
||||||
|
wg.Wait()
|
||||||
|
|
||||||
|
for i := range fs {
|
||||||
|
if err := errs[i]; err != nil {
|
||||||
|
t.Fatal("failed to open freezer", err)
|
||||||
|
}
|
||||||
|
require.NoError(t, fs[i].Close())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func newFreezerForTesting(t *testing.T, tables map[string]bool) (*Freezer, string) {
|
func newFreezerForTesting(t *testing.T, tables map[string]bool) (*Freezer, string) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -446,6 +446,10 @@ func (dl *diskLayer) generateRange(ctx *generatorContext, trieId *trie.ID, prefi
|
||||||
internal += time.Since(istart)
|
internal += time.Since(istart)
|
||||||
}
|
}
|
||||||
if iter.Err != nil {
|
if iter.Err != nil {
|
||||||
|
// Trie errors should never happen. Still, in case of a bug, expose the
|
||||||
|
// error here, as the outer code will presume errors are interrupts, not
|
||||||
|
// some deeper issues.
|
||||||
|
log.Error("State snapshotter failed to iterate trie", "err", err)
|
||||||
return false, nil, iter.Err
|
return false, nil, iter.Err
|
||||||
}
|
}
|
||||||
// Delete all stale snapshot states remaining
|
// Delete all stale snapshot states remaining
|
||||||
|
|
|
||||||
|
|
@ -135,6 +135,9 @@ type StateDB struct {
|
||||||
StorageUpdated int
|
StorageUpdated int
|
||||||
AccountDeleted int
|
AccountDeleted int
|
||||||
StorageDeleted int
|
StorageDeleted int
|
||||||
|
|
||||||
|
// Testing hooks
|
||||||
|
onCommit func(states *triestate.Set) // Hook invoked when commit is performed
|
||||||
}
|
}
|
||||||
|
|
||||||
// New creates a new state from a given trie.
|
// New creates a new state from a given trie.
|
||||||
|
|
@ -970,7 +973,7 @@ func (s *StateDB) fastDeleteStorage(addrHash common.Hash, root common.Hash) (boo
|
||||||
return true, size, nil, nil, nil
|
return true, size, nil, nil, nil
|
||||||
}
|
}
|
||||||
slot := common.CopyBytes(iter.Slot())
|
slot := common.CopyBytes(iter.Slot())
|
||||||
if iter.Error() != nil { // error might occur after Slot function
|
if err := iter.Error(); err != nil { // error might occur after Slot function
|
||||||
return false, 0, nil, nil, err
|
return false, 0, nil, nil, err
|
||||||
}
|
}
|
||||||
size += common.StorageSize(common.HashLength + len(slot))
|
size += common.StorageSize(common.HashLength + len(slot))
|
||||||
|
|
@ -980,7 +983,7 @@ func (s *StateDB) fastDeleteStorage(addrHash common.Hash, root common.Hash) (boo
|
||||||
return false, 0, nil, nil, err
|
return false, 0, nil, nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if iter.Error() != nil { // error might occur during iteration
|
if err := iter.Error(); err != nil { // error might occur during iteration
|
||||||
return false, 0, nil, nil, err
|
return false, 0, nil, nil, err
|
||||||
}
|
}
|
||||||
if stack.Hash() != root {
|
if stack.Hash() != root {
|
||||||
|
|
@ -1058,12 +1061,10 @@ func (s *StateDB) deleteStorage(addr common.Address, addrHash common.Hash, root
|
||||||
slotDeletionSkip.Inc(1)
|
slotDeletionSkip.Inc(1)
|
||||||
}
|
}
|
||||||
n := int64(len(slots))
|
n := int64(len(slots))
|
||||||
if n > slotDeletionMaxCount.Value() {
|
|
||||||
slotDeletionMaxCount.Update(n)
|
slotDeletionMaxCount.UpdateIfGt(int64(len(slots)))
|
||||||
}
|
slotDeletionMaxSize.UpdateIfGt(int64(size))
|
||||||
if int64(size) > slotDeletionMaxSize.Value() {
|
|
||||||
slotDeletionMaxSize.Update(int64(size))
|
|
||||||
}
|
|
||||||
slotDeletionTimer.UpdateSince(start)
|
slotDeletionTimer.UpdateSince(start)
|
||||||
slotDeletionCount.Mark(n)
|
slotDeletionCount.Mark(n)
|
||||||
slotDeletionSize.Mark(int64(size))
|
slotDeletionSize.Mark(int64(size))
|
||||||
|
|
@ -1276,13 +1277,17 @@ func (s *StateDB) Commit(block uint64, deleteEmptyObjects bool) (common.Hash, er
|
||||||
}
|
}
|
||||||
if root != origin {
|
if root != origin {
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
if err := s.db.TrieDB().Update(root, origin, block, nodes, triestate.New(s.accountsOrigin, s.storagesOrigin, incomplete)); err != nil {
|
set := triestate.New(s.accountsOrigin, s.storagesOrigin, incomplete)
|
||||||
|
if err := s.db.TrieDB().Update(root, origin, block, nodes, set); err != nil {
|
||||||
return common.Hash{}, err
|
return common.Hash{}, err
|
||||||
}
|
}
|
||||||
s.originalRoot = root
|
s.originalRoot = root
|
||||||
if metrics.EnabledExpensive {
|
if metrics.EnabledExpensive {
|
||||||
s.TrieDBCommits += time.Since(start)
|
s.TrieDBCommits += time.Since(start)
|
||||||
}
|
}
|
||||||
|
if s.onCommit != nil {
|
||||||
|
s.onCommit(set)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Clear all internal flags at the end of commit operation.
|
// Clear all internal flags at the end of commit operation.
|
||||||
s.accounts = make(map[common.Hash][]byte)
|
s.accounts = make(map[common.Hash][]byte)
|
||||||
|
|
|
||||||
|
|
@ -181,7 +181,7 @@ func (test *stateTest) run() bool {
|
||||||
storageList = append(storageList, copy2DSet(states.Storages))
|
storageList = append(storageList, copy2DSet(states.Storages))
|
||||||
}
|
}
|
||||||
disk = rawdb.NewMemoryDatabase()
|
disk = rawdb.NewMemoryDatabase()
|
||||||
tdb = trie.NewDatabase(disk, &trie.Config{OnCommit: onCommit, PathDB: pathdb.Defaults})
|
tdb = trie.NewDatabase(disk, &trie.Config{PathDB: pathdb.Defaults})
|
||||||
sdb = NewDatabaseWithNodeDB(disk, tdb)
|
sdb = NewDatabaseWithNodeDB(disk, tdb)
|
||||||
byzantium = rand.Intn(2) == 0
|
byzantium = rand.Intn(2) == 0
|
||||||
)
|
)
|
||||||
|
|
@ -206,6 +206,8 @@ func (test *stateTest) run() bool {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
state.onCommit = onCommit
|
||||||
|
|
||||||
for i, action := range actions {
|
for i, action := range actions {
|
||||||
if i%test.chunk == 0 && i != 0 {
|
if i%test.chunk == 0 && i != 0 {
|
||||||
if byzantium {
|
if byzantium {
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/consensus"
|
"github.com/ethereum/go-ethereum/consensus"
|
||||||
"github.com/ethereum/go-ethereum/consensus/misc"
|
"github.com/ethereum/go-ethereum/consensus/misc"
|
||||||
|
"github.com/ethereum/go-ethereum/consensus/misc/eip4844"
|
||||||
"github.com/ethereum/go-ethereum/core/state"
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
|
|
@ -135,8 +136,10 @@ func applyTransaction(msg *Message, config *params.ChainConfig, gp *GasPool, sta
|
||||||
receipt.TxHash = tx.Hash()
|
receipt.TxHash = tx.Hash()
|
||||||
receipt.GasUsed = result.UsedGas
|
receipt.GasUsed = result.UsedGas
|
||||||
|
|
||||||
|
if tx.Type() == types.BlobTxType {
|
||||||
receipt.BlobGasUsed = uint64(len(tx.BlobHashes()) * params.BlobTxBlobGasPerBlob)
|
receipt.BlobGasUsed = uint64(len(tx.BlobHashes()) * params.BlobTxBlobGasPerBlob)
|
||||||
receipt.BlobGasPrice = tx.BlobGasFeeCap()
|
receipt.BlobGasPrice = eip4844.CalcBlobFee(*evm.Context.ExcessBlobGas)
|
||||||
|
}
|
||||||
|
|
||||||
// If the transaction created a contract, store the creation address in the receipt.
|
// If the transaction created a contract, store the creation address in the receipt.
|
||||||
if msg.To == nil {
|
if msg.To == nil {
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,5 @@
|
||||||
// Code generated by rlpgen. DO NOT EDIT.
|
// Code generated by rlpgen. DO NOT EDIT.
|
||||||
|
|
||||||
//go:build !norlpgen
|
|
||||||
// +build !norlpgen
|
|
||||||
|
|
||||||
package types
|
package types
|
||||||
|
|
||||||
import "github.com/ethereum/go-ethereum/rlp"
|
import "github.com/ethereum/go-ethereum/rlp"
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,5 @@
|
||||||
// Code generated by rlpgen. DO NOT EDIT.
|
// Code generated by rlpgen. DO NOT EDIT.
|
||||||
|
|
||||||
//go:build !norlpgen
|
|
||||||
// +build !norlpgen
|
|
||||||
|
|
||||||
package types
|
package types
|
||||||
|
|
||||||
import "github.com/ethereum/go-ethereum/rlp"
|
import "github.com/ethereum/go-ethereum/rlp"
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,5 @@
|
||||||
// Code generated by rlpgen. DO NOT EDIT.
|
// Code generated by rlpgen. DO NOT EDIT.
|
||||||
|
|
||||||
//go:build !norlpgen
|
|
||||||
// +build !norlpgen
|
|
||||||
|
|
||||||
package types
|
package types
|
||||||
|
|
||||||
import "github.com/ethereum/go-ethereum/rlp"
|
import "github.com/ethereum/go-ethereum/rlp"
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,5 @@
|
||||||
// Code generated by rlpgen. DO NOT EDIT.
|
// Code generated by rlpgen. DO NOT EDIT.
|
||||||
|
|
||||||
//go:build !norlpgen
|
|
||||||
// +build !norlpgen
|
|
||||||
|
|
||||||
package types
|
package types
|
||||||
|
|
||||||
import "github.com/ethereum/go-ethereum/rlp"
|
import "github.com/ethereum/go-ethereum/rlp"
|
||||||
|
|
|
||||||
|
|
@ -362,6 +362,9 @@ func (api *DebugAPI) getModifiedAccounts(startBlock, endBlock *types.Block) ([]c
|
||||||
// The (from, to) parameters are the sequence of blocks to search, which can go
|
// The (from, to) parameters are the sequence of blocks to search, which can go
|
||||||
// either forwards or backwards
|
// either forwards or backwards
|
||||||
func (api *DebugAPI) GetAccessibleState(from, to rpc.BlockNumber) (uint64, error) {
|
func (api *DebugAPI) GetAccessibleState(from, to rpc.BlockNumber) (uint64, error) {
|
||||||
|
if api.eth.blockchain.TrieDB().Scheme() == rawdb.PathScheme {
|
||||||
|
return 0, errors.New("state history is not yet available in path-based scheme")
|
||||||
|
}
|
||||||
db := api.eth.ChainDb()
|
db := api.eth.ChainDb()
|
||||||
var pivot uint64
|
var pivot uint64
|
||||||
if p := rawdb.ReadLastPivotNumber(db); p != nil {
|
if p := rawdb.ReadLastPivotNumber(db); p != nil {
|
||||||
|
|
@ -422,6 +425,9 @@ func (api *DebugAPI) GetAccessibleState(from, to rpc.BlockNumber) (uint64, error
|
||||||
// If the value is shorter than the block generation time, or even 0 or negative,
|
// If the value is shorter than the block generation time, or even 0 or negative,
|
||||||
// the node will flush trie after processing each block (effectively archive mode).
|
// the node will flush trie after processing each block (effectively archive mode).
|
||||||
func (api *DebugAPI) SetTrieFlushInterval(interval string) error {
|
func (api *DebugAPI) SetTrieFlushInterval(interval string) error {
|
||||||
|
if api.eth.blockchain.TrieDB().Scheme() == rawdb.PathScheme {
|
||||||
|
return errors.New("trie flush interval is undefined for path-based scheme")
|
||||||
|
}
|
||||||
t, err := time.ParseDuration(interval)
|
t, err := time.ParseDuration(interval)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
@ -431,6 +437,9 @@ func (api *DebugAPI) SetTrieFlushInterval(interval string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetTrieFlushInterval gets the current value of in-memory trie flush interval
|
// GetTrieFlushInterval gets the current value of in-memory trie flush interval
|
||||||
func (api *DebugAPI) GetTrieFlushInterval() string {
|
func (api *DebugAPI) GetTrieFlushInterval() (string, error) {
|
||||||
return api.eth.blockchain.GetTrieFlushInterval().String()
|
if api.eth.blockchain.TrieDB().Scheme() == rawdb.PathScheme {
|
||||||
|
return "", errors.New("trie flush interval is undefined for path-based scheme")
|
||||||
|
}
|
||||||
|
return api.eth.blockchain.GetTrieFlushInterval().String(), nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -387,7 +387,7 @@ func (s *Ethereum) shouldPreserve(header *types.Header) bool {
|
||||||
// r5 A [X] F G
|
// r5 A [X] F G
|
||||||
// r6 [X]
|
// r6 [X]
|
||||||
//
|
//
|
||||||
// In the round5, the inturn signer E is offline, so the worst case
|
// In the round5, the in-turn signer E is offline, so the worst case
|
||||||
// is A, F and G sign the block of round5 and reject the block of opponents
|
// is A, F and G sign the block of round5 and reject the block of opponents
|
||||||
// and in the round6, the last available signer B is offline, the whole
|
// and in the round6, the last available signer B is offline, the whole
|
||||||
// network is stuck.
|
// network is stuck.
|
||||||
|
|
|
||||||
|
|
@ -207,21 +207,21 @@ func (api *ConsensusAPI) verifyPayloadAttributes(attr *engine.PayloadAttributes)
|
||||||
c := api.eth.BlockChain().Config()
|
c := api.eth.BlockChain().Config()
|
||||||
|
|
||||||
// Verify withdrawals attribute for Shanghai.
|
// Verify withdrawals attribute for Shanghai.
|
||||||
if err := checkAttribute(c.IsShanghai, attr.Withdrawals != nil, attr.Timestamp); err != nil {
|
if err := checkAttribute(c.IsShanghai, attr.Withdrawals != nil, c.LondonBlock, attr.Timestamp); err != nil {
|
||||||
return fmt.Errorf("invalid withdrawals: %w", err)
|
return fmt.Errorf("invalid withdrawals: %w", err)
|
||||||
}
|
}
|
||||||
// Verify beacon root attribute for Cancun.
|
// Verify beacon root attribute for Cancun.
|
||||||
if err := checkAttribute(c.IsCancun, attr.BeaconRoot != nil, attr.Timestamp); err != nil {
|
if err := checkAttribute(c.IsCancun, attr.BeaconRoot != nil, c.LondonBlock, attr.Timestamp); err != nil {
|
||||||
return fmt.Errorf("invalid parent beacon block root: %w", err)
|
return fmt.Errorf("invalid parent beacon block root: %w", err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkAttribute(active func(*big.Int, uint64) bool, exists bool, time uint64) error {
|
func checkAttribute(active func(*big.Int, uint64) bool, exists bool, block *big.Int, time uint64) error {
|
||||||
if active(common.Big0, time) && !exists {
|
if active(block, time) && !exists {
|
||||||
return errors.New("fork active, missing expected attribute")
|
return errors.New("fork active, missing expected attribute")
|
||||||
}
|
}
|
||||||
if !active(common.Big0, time) && exists {
|
if !active(block, time) && exists {
|
||||||
return errors.New("fork inactive, unexpected attribute set")
|
return errors.New("fork inactive, unexpected attribute set")
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|
|
||||||
|
|
@ -398,7 +398,14 @@ func (d *Downloader) synchronise(id string, hash common.Hash, td, ttd *big.Int,
|
||||||
log.Info("Block synchronisation started")
|
log.Info("Block synchronisation started")
|
||||||
}
|
}
|
||||||
if mode == SnapSync {
|
if mode == SnapSync {
|
||||||
// Snap sync uses the snapshot namespace to store potentially flakey data until
|
// Snap sync will directly modify the persistent state, making the entire
|
||||||
|
// trie database unusable until the state is fully synced. To prevent any
|
||||||
|
// subsequent state reads, explicitly disable the trie database and state
|
||||||
|
// syncer is responsible to address and correct any state missing.
|
||||||
|
if d.blockchain.TrieDB().Scheme() == rawdb.PathScheme {
|
||||||
|
d.blockchain.TrieDB().Reset(types.EmptyRootHash)
|
||||||
|
}
|
||||||
|
// Snap sync uses the snapshot namespace to store potentially flaky data until
|
||||||
// sync completely heals and finishes. Pause snapshot maintenance in the mean-
|
// sync completely heals and finishes. Pause snapshot maintenance in the mean-
|
||||||
// time to prevent access.
|
// time to prevent access.
|
||||||
if snapshots := d.blockchain.Snapshots(); snapshots != nil { // Only nil in tests
|
if snapshots := d.blockchain.Snapshots(); snapshots != nil { // Only nil in tests
|
||||||
|
|
@ -1606,17 +1613,30 @@ func (d *Downloader) processSnapSyncContent() error {
|
||||||
|
|
||||||
// To cater for moving pivot points, track the pivot block and subsequently
|
// To cater for moving pivot points, track the pivot block and subsequently
|
||||||
// accumulated download results separately.
|
// accumulated download results separately.
|
||||||
|
//
|
||||||
|
// These will be nil up to the point where we reach the pivot, and will only
|
||||||
|
// be set temporarily if the synced blocks are piling up, but the pivot is
|
||||||
|
// still busy downloading. In that case, we need to occasionally check for
|
||||||
|
// pivot moves, so need to unblock the loop. These fields will accumulate
|
||||||
|
// the results in the meantime.
|
||||||
|
//
|
||||||
|
// Note, there's no issue with memory piling up since after 64 blocks the
|
||||||
|
// pivot will forcefully move so these accumulators will be dropped.
|
||||||
var (
|
var (
|
||||||
oldPivot *fetchResult // Locked in pivot block, might change eventually
|
oldPivot *fetchResult // Locked in pivot block, might change eventually
|
||||||
oldTail []*fetchResult // Downloaded content after the pivot
|
oldTail []*fetchResult // Downloaded content after the pivot
|
||||||
)
|
)
|
||||||
for {
|
for {
|
||||||
// Wait for the next batch of downloaded data to be available, and if the pivot
|
// Wait for the next batch of downloaded data to be available. If we have
|
||||||
// block became stale, move the goalpost
|
// not yet reached the pivot point, wait blockingly as there's no need to
|
||||||
results := d.queue.Results(oldPivot == nil) // Block if we're not monitoring pivot staleness
|
// spin-loop check for pivot moves. If we reached the pivot but have not
|
||||||
|
// yet processed it, check for results async, so we might notice pivot
|
||||||
|
// moves while state syncing. If the pivot was passed fully, block again
|
||||||
|
// as there's no more reason to check for pivot moves at all.
|
||||||
|
results := d.queue.Results(oldPivot == nil)
|
||||||
if len(results) == 0 {
|
if len(results) == 0 {
|
||||||
// If pivot sync is done, stop
|
// If pivot sync is done, stop
|
||||||
if oldPivot == nil {
|
if d.committed.Load() {
|
||||||
d.reportSnapSyncProgress(true)
|
d.reportSnapSyncProgress(true)
|
||||||
return sync.Cancel()
|
return sync.Cancel()
|
||||||
}
|
}
|
||||||
|
|
@ -1639,21 +1659,23 @@ func (d *Downloader) processSnapSyncContent() error {
|
||||||
pivot := d.pivotHeader
|
pivot := d.pivotHeader
|
||||||
d.pivotLock.RUnlock()
|
d.pivotLock.RUnlock()
|
||||||
|
|
||||||
if oldPivot == nil {
|
if oldPivot == nil { // no results piling up, we can move the pivot
|
||||||
if pivot.Root != sync.root {
|
if !d.committed.Load() { // not yet passed the pivot, we can move the pivot
|
||||||
|
if pivot.Root != sync.root { // pivot position changed, we can move the pivot
|
||||||
sync.Cancel()
|
sync.Cancel()
|
||||||
sync = d.syncState(pivot.Root)
|
sync = d.syncState(pivot.Root)
|
||||||
|
|
||||||
go closeOnErr(sync)
|
go closeOnErr(sync)
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
} else { // results already piled up, consume before handling pivot move
|
||||||
results = append(append([]*fetchResult{oldPivot}, oldTail...), results...)
|
results = append(append([]*fetchResult{oldPivot}, oldTail...), results...)
|
||||||
}
|
}
|
||||||
// Split around the pivot block and process the two sides via snap/full sync
|
// Split around the pivot block and process the two sides via snap/full sync
|
||||||
if !d.committed.Load() {
|
if !d.committed.Load() {
|
||||||
latest := results[len(results)-1].Header
|
latest := results[len(results)-1].Header
|
||||||
// If the height is above the pivot block by 2 sets, it means the pivot
|
// If the height is above the pivot block by 2 sets, it means the pivot
|
||||||
// become stale in the network and it was garbage collected, move to a
|
// become stale in the network, and it was garbage collected, move to a
|
||||||
// new pivot.
|
// new pivot.
|
||||||
//
|
//
|
||||||
// Note, we have `reorgProtHeaderDelay` number of blocks withheld, Those
|
// Note, we have `reorgProtHeaderDelay` number of blocks withheld, Those
|
||||||
|
|
|
||||||
|
|
@ -619,7 +619,7 @@ func toCallArg(msg ethereum.CallMsg) interface{} {
|
||||||
"to": msg.To,
|
"to": msg.To,
|
||||||
}
|
}
|
||||||
if len(msg.Data) > 0 {
|
if len(msg.Data) > 0 {
|
||||||
arg["data"] = hexutil.Bytes(msg.Data)
|
arg["input"] = hexutil.Bytes(msg.Data)
|
||||||
}
|
}
|
||||||
if msg.Value != nil {
|
if msg.Value != nil {
|
||||||
arg["value"] = (*hexutil.Big)(msg.Value)
|
arg["value"] = (*hexutil.Big)(msg.Value)
|
||||||
|
|
|
||||||
|
|
@ -225,7 +225,7 @@ func toCallArg(msg ethereum.CallMsg) interface{} {
|
||||||
"to": msg.To,
|
"to": msg.To,
|
||||||
}
|
}
|
||||||
if len(msg.Data) > 0 {
|
if len(msg.Data) > 0 {
|
||||||
arg["data"] = hexutil.Bytes(msg.Data)
|
arg["input"] = hexutil.Bytes(msg.Data)
|
||||||
}
|
}
|
||||||
if msg.Value != nil {
|
if msg.Value != nil {
|
||||||
arg["value"] = (*hexutil.Big)(msg.Value)
|
arg["value"] = (*hexutil.Big)(msg.Value)
|
||||||
|
|
|
||||||
14
go.mod
14
go.mod
|
|
@ -13,7 +13,7 @@ require (
|
||||||
github.com/btcsuite/btcd/btcec/v2 v2.2.0
|
github.com/btcsuite/btcd/btcec/v2 v2.2.0
|
||||||
github.com/cespare/cp v0.1.0
|
github.com/cespare/cp v0.1.0
|
||||||
github.com/cloudflare/cloudflare-go v0.14.0
|
github.com/cloudflare/cloudflare-go v0.14.0
|
||||||
github.com/cockroachdb/pebble v0.0.0-20230821143352-55b44ac08de8
|
github.com/cockroachdb/pebble v0.0.0-20230906160148-46873a6a7a06
|
||||||
github.com/consensys/gnark-crypto v0.10.0
|
github.com/consensys/gnark-crypto v0.10.0
|
||||||
github.com/crate-crypto/go-kzg-4844 v0.3.0
|
github.com/crate-crypto/go-kzg-4844 v0.3.0
|
||||||
github.com/davecgh/go-spew v1.1.1
|
github.com/davecgh/go-spew v1.1.1
|
||||||
|
|
@ -40,13 +40,13 @@ require (
|
||||||
github.com/holiman/billy v0.0.0-20230718173358-1c7e68d277a7
|
github.com/holiman/billy v0.0.0-20230718173358-1c7e68d277a7
|
||||||
github.com/holiman/bloomfilter/v2 v2.0.3
|
github.com/holiman/bloomfilter/v2 v2.0.3
|
||||||
github.com/holiman/uint256 v1.2.3
|
github.com/holiman/uint256 v1.2.3
|
||||||
github.com/huin/goupnp v1.0.3
|
github.com/huin/goupnp v1.3.0
|
||||||
github.com/influxdata/influxdb-client-go/v2 v2.4.0
|
github.com/influxdata/influxdb-client-go/v2 v2.4.0
|
||||||
github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c
|
github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c
|
||||||
github.com/jackpal/go-nat-pmp v1.0.2
|
github.com/jackpal/go-nat-pmp v1.0.2
|
||||||
github.com/jedisct1/go-minisign v0.0.0-20190909160543-45766022959e
|
github.com/jedisct1/go-minisign v0.0.0-20230811132847-661be99b8267
|
||||||
github.com/julienschmidt/httprouter v1.3.0
|
github.com/julienschmidt/httprouter v1.3.0
|
||||||
github.com/karalabe/usb v0.0.3-0.20230711191512-61db3e06439c
|
github.com/karalabe/usb v0.0.2
|
||||||
github.com/kylelemons/godebug v1.1.0
|
github.com/kylelemons/godebug v1.1.0
|
||||||
github.com/mattn/go-colorable v0.1.13
|
github.com/mattn/go-colorable v0.1.13
|
||||||
github.com/mattn/go-isatty v0.0.16
|
github.com/mattn/go-isatty v0.0.16
|
||||||
|
|
@ -61,13 +61,13 @@ require (
|
||||||
github.com/supranational/blst v0.3.11
|
github.com/supranational/blst v0.3.11
|
||||||
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7
|
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7
|
||||||
github.com/tyler-smith/go-bip39 v1.1.0
|
github.com/tyler-smith/go-bip39 v1.1.0
|
||||||
github.com/urfave/cli/v2 v2.24.1
|
github.com/urfave/cli/v2 v2.25.7
|
||||||
go.uber.org/automaxprocs v1.5.2
|
go.uber.org/automaxprocs v1.5.2
|
||||||
golang.org/x/crypto v0.9.0
|
golang.org/x/crypto v0.12.0
|
||||||
golang.org/x/exp v0.0.0-20230810033253-352e893a4cad
|
golang.org/x/exp v0.0.0-20230810033253-352e893a4cad
|
||||||
golang.org/x/sync v0.3.0
|
golang.org/x/sync v0.3.0
|
||||||
golang.org/x/sys v0.11.0
|
golang.org/x/sys v0.11.0
|
||||||
golang.org/x/text v0.9.0
|
golang.org/x/text v0.12.0
|
||||||
golang.org/x/time v0.3.0
|
golang.org/x/time v0.3.0
|
||||||
golang.org/x/tools v0.9.1
|
golang.org/x/tools v0.9.1
|
||||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0
|
gopkg.in/natefinch/lumberjack.v2 v2.0.0
|
||||||
|
|
|
||||||
32
go.sum
32
go.sum
|
|
@ -39,7 +39,7 @@ github.com/Azure/azure-sdk-for-go/sdk/internal v0.8.3/go.mod h1:KLF4gFr6DcKFZwSu
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.3.0 h1:Px2UA+2RvSSvv+RvJNuUB6n7rs5Wsel4dXLe90Um2n4=
|
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.3.0 h1:Px2UA+2RvSSvv+RvJNuUB6n7rs5Wsel4dXLe90Um2n4=
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.3.0/go.mod h1:tPaiy8S5bQ+S5sOiDlINkp7+Ef339+Nz5L5XO+cnOHo=
|
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.3.0/go.mod h1:tPaiy8S5bQ+S5sOiDlINkp7+Ef339+Nz5L5XO+cnOHo=
|
||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
github.com/BurntSushi/toml v1.2.1 h1:9F2/+DoOYIOksmaJFPw1tGFy1eDnIJXg+UHjuD8lTak=
|
github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8=
|
||||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||||
github.com/CloudyKit/fastprinter v0.0.0-20170127035650-74b38d55f37a/go.mod h1:EFZQ978U7x8IRnstaskI3IysnWY5Ao3QgZUKOXlsAdw=
|
github.com/CloudyKit/fastprinter v0.0.0-20170127035650-74b38d55f37a/go.mod h1:EFZQ978U7x8IRnstaskI3IysnWY5Ao3QgZUKOXlsAdw=
|
||||||
github.com/CloudyKit/jet v2.1.3-0.20180809161101-62edd43e4f88+incompatible/go.mod h1:HPYO+50pSWkPoj9Q/eq0aRGByCL6ScRlUmiEX5Zgm+w=
|
github.com/CloudyKit/jet v2.1.3-0.20180809161101-62edd43e4f88+incompatible/go.mod h1:HPYO+50pSWkPoj9Q/eq0aRGByCL6ScRlUmiEX5Zgm+w=
|
||||||
|
|
@ -115,8 +115,8 @@ github.com/cockroachdb/errors v1.8.1 h1:A5+txlVZfOqFBDa4mGz2bUWSp0aHElvHX2bKkdbQ
|
||||||
github.com/cockroachdb/errors v1.8.1/go.mod h1:qGwQn6JmZ+oMjuLwjWzUNqblqk0xl4CVV3SQbGwK7Ac=
|
github.com/cockroachdb/errors v1.8.1/go.mod h1:qGwQn6JmZ+oMjuLwjWzUNqblqk0xl4CVV3SQbGwK7Ac=
|
||||||
github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f h1:o/kfcElHqOiXqcou5a3rIlMc7oJbMQkeLk0VQJ7zgqY=
|
github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f h1:o/kfcElHqOiXqcou5a3rIlMc7oJbMQkeLk0VQJ7zgqY=
|
||||||
github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u985jwjWRlyHXQbwatDASoW0RMlZ/3i9yJHE2xLkI=
|
github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u985jwjWRlyHXQbwatDASoW0RMlZ/3i9yJHE2xLkI=
|
||||||
github.com/cockroachdb/pebble v0.0.0-20230821143352-55b44ac08de8 h1:2fNOyQqrHSjFdqnKqSLj9W7eGTcqKujJPA8vAuT1zN8=
|
github.com/cockroachdb/pebble v0.0.0-20230906160148-46873a6a7a06 h1:T+Np/xtzIjYM/P5NAw0e2Rf1FGvzDau1h54MKvx8G7w=
|
||||||
github.com/cockroachdb/pebble v0.0.0-20230821143352-55b44ac08de8/go.mod h1:bynZ3gvVyhlvjLI7PT6dmZ7g76xzJ7HpxfjgkzCGz6s=
|
github.com/cockroachdb/pebble v0.0.0-20230906160148-46873a6a7a06/go.mod h1:bynZ3gvVyhlvjLI7PT6dmZ7g76xzJ7HpxfjgkzCGz6s=
|
||||||
github.com/cockroachdb/redact v1.0.8 h1:8QG/764wK+vmEYoOlfobpe12EQcS81ukx/a4hdVMxNw=
|
github.com/cockroachdb/redact v1.0.8 h1:8QG/764wK+vmEYoOlfobpe12EQcS81ukx/a4hdVMxNw=
|
||||||
github.com/cockroachdb/redact v1.0.8/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg=
|
github.com/cockroachdb/redact v1.0.8/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg=
|
||||||
github.com/cockroachdb/sentry-go v0.6.1-cockroachdb.2 h1:IKgmqgMQlVJIZj19CdocBeSfSaiCbEBZGKODaixqtHM=
|
github.com/cockroachdb/sentry-go v0.6.1-cockroachdb.2 h1:IKgmqgMQlVJIZj19CdocBeSfSaiCbEBZGKODaixqtHM=
|
||||||
|
|
@ -324,9 +324,8 @@ github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iU
|
||||||
github.com/holiman/uint256 v1.2.3 h1:K8UWO1HUJpRMXBxbmaY1Y8IAMZC/RsKB+ArEnnK4l5o=
|
github.com/holiman/uint256 v1.2.3 h1:K8UWO1HUJpRMXBxbmaY1Y8IAMZC/RsKB+ArEnnK4l5o=
|
||||||
github.com/holiman/uint256 v1.2.3/go.mod h1:SC8Ryt4n+UBbPbIBKaG9zbbDlp4jOru9xFZmPzLUTxw=
|
github.com/holiman/uint256 v1.2.3/go.mod h1:SC8Ryt4n+UBbPbIBKaG9zbbDlp4jOru9xFZmPzLUTxw=
|
||||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||||
github.com/huin/goupnp v1.0.3 h1:N8No57ls+MnjlB+JPiCVSOyy/ot7MJTqlo7rn+NYSqQ=
|
github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc=
|
||||||
github.com/huin/goupnp v1.0.3/go.mod h1:ZxNlw5WqJj6wSsRK5+YfflQGXYfccj5VgQsMNixHM7Y=
|
github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8=
|
||||||
github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o=
|
|
||||||
github.com/hydrogen18/memlistener v0.0.0-20141126152155-54553eb933fb/go.mod h1:qEIFzExnS6016fRpRfxrExeVn2gbClQA99gQhnIcdhE=
|
github.com/hydrogen18/memlistener v0.0.0-20141126152155-54553eb933fb/go.mod h1:qEIFzExnS6016fRpRfxrExeVn2gbClQA99gQhnIcdhE=
|
||||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||||
github.com/ianlancetaylor/demangle v0.0.0-20220319035150-800ac71e25c2/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w=
|
github.com/ianlancetaylor/demangle v0.0.0-20220319035150-800ac71e25c2/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w=
|
||||||
|
|
@ -344,8 +343,8 @@ github.com/iris-contrib/i18n v0.0.0-20171121225848-987a633949d0/go.mod h1:pMCz62
|
||||||
github.com/iris-contrib/schema v0.0.1/go.mod h1:urYA3uvUNG1TIIjOSCzHr9/LmbQo8LrOcOqfqxa4hXw=
|
github.com/iris-contrib/schema v0.0.1/go.mod h1:urYA3uvUNG1TIIjOSCzHr9/LmbQo8LrOcOqfqxa4hXw=
|
||||||
github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus=
|
github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus=
|
||||||
github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc=
|
github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc=
|
||||||
github.com/jedisct1/go-minisign v0.0.0-20190909160543-45766022959e h1:UvSe12bq+Uj2hWd8aOlwPmoZ+CITRFrdit+sDGfAg8U=
|
github.com/jedisct1/go-minisign v0.0.0-20230811132847-661be99b8267 h1:TMtDYDHKYY15rFihtRfck/bfFqNfvcabqvXAFQfAUpY=
|
||||||
github.com/jedisct1/go-minisign v0.0.0-20190909160543-45766022959e/go.mod h1:G1CVv03EnqU1wYL2dFwXxW2An0az9JTl/ZsqXQeBlkU=
|
github.com/jedisct1/go-minisign v0.0.0-20230811132847-661be99b8267/go.mod h1:h1nSAbGFqGVzn6Jyl1R/iCcBUHN4g+gW1u9CoBTrb9E=
|
||||||
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
|
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
|
||||||
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
|
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
|
||||||
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
|
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
|
||||||
|
|
@ -363,8 +362,8 @@ github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7V
|
||||||
github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U=
|
github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U=
|
||||||
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
|
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
|
||||||
github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k=
|
github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k=
|
||||||
github.com/karalabe/usb v0.0.3-0.20230711191512-61db3e06439c h1:AqsttAyEyIEsNz5WLRwuRwjiT5CMDUfLk6cFJDVPebs=
|
github.com/karalabe/usb v0.0.2 h1:M6QQBNxF+CQ8OFvxrT90BA0qBOXymndZnk5q235mFc4=
|
||||||
github.com/karalabe/usb v0.0.3-0.20230711191512-61db3e06439c/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU=
|
github.com/karalabe/usb v0.0.2/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU=
|
||||||
github.com/kataras/golog v0.0.9/go.mod h1:12HJgwBIZFNGL0EJnMRhmvGA0PQGx8VFwrZtM4CqbAk=
|
github.com/kataras/golog v0.0.9/go.mod h1:12HJgwBIZFNGL0EJnMRhmvGA0PQGx8VFwrZtM4CqbAk=
|
||||||
github.com/kataras/iris/v12 v12.0.1/go.mod h1:udK4vLQKkdDqMGJJVd/msuMtN6hpYJhg/lSzuxjhO+U=
|
github.com/kataras/iris/v12 v12.0.1/go.mod h1:udK4vLQKkdDqMGJJVd/msuMtN6hpYJhg/lSzuxjhO+U=
|
||||||
github.com/kataras/neffos v0.0.10/go.mod h1:ZYmJC07hQPW67eKuzlfY7SO3bC0mw83A3j6im82hfqw=
|
github.com/kataras/neffos v0.0.10/go.mod h1:ZYmJC07hQPW67eKuzlfY7SO3bC0mw83A3j6im82hfqw=
|
||||||
|
|
@ -552,8 +551,8 @@ github.com/tyler-smith/go-bip39 v1.1.0/go.mod h1:gUYDtqQw1JS3ZJ8UWVcGTGqqr6YIN3C
|
||||||
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
|
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
|
||||||
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
|
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
|
||||||
github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
|
github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
|
||||||
github.com/urfave/cli/v2 v2.24.1 h1:/QYYr7g0EhwXEML8jO+8OYt5trPnLHS0p3mrgExJ5NU=
|
github.com/urfave/cli/v2 v2.25.7 h1:VAzn5oq403l5pHjc4OhD54+XGO9cdKVL/7lDjF+iKUs=
|
||||||
github.com/urfave/cli/v2 v2.24.1/go.mod h1:GHupkWPMM0M/sj1a2b4wUrWBPzazNrIjouW6fmdJLxc=
|
github.com/urfave/cli/v2 v2.25.7/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ=
|
||||||
github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4=
|
github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4=
|
||||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||||
github.com/valyala/fasthttp v1.6.0/go.mod h1:FstJa9V+Pj9vQ7OJie2qMHdwemEDaDiSdBnvPM1Su9w=
|
github.com/valyala/fasthttp v1.6.0/go.mod h1:FstJa9V+Pj9vQ7OJie2qMHdwemEDaDiSdBnvPM1Su9w=
|
||||||
|
|
@ -588,14 +587,13 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
|
||||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20190909091759-094676da4a83/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
|
||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
||||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g=
|
golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk=
|
||||||
golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0=
|
golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
|
||||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||||
|
|
@ -773,8 +771,8 @@ golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
|
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
|
||||||
golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
|
golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc=
|
||||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
|
|
|
||||||
|
|
@ -272,8 +272,6 @@ func (t *Transaction) GasPrice(ctx context.Context) hexutil.Big {
|
||||||
return hexutil.Big{}
|
return hexutil.Big{}
|
||||||
}
|
}
|
||||||
switch tx.Type() {
|
switch tx.Type() {
|
||||||
case types.AccessListTxType:
|
|
||||||
return hexutil.Big(*tx.GasPrice())
|
|
||||||
case types.DynamicFeeTxType:
|
case types.DynamicFeeTxType:
|
||||||
if block != nil {
|
if block != nil {
|
||||||
if baseFee, _ := block.BaseFeePerGas(ctx); baseFee != nil {
|
if baseFee, _ := block.BaseFeePerGas(ctx); baseFee != nil {
|
||||||
|
|
@ -312,9 +310,7 @@ func (t *Transaction) MaxFeePerGas(ctx context.Context) *hexutil.Big {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
switch tx.Type() {
|
switch tx.Type() {
|
||||||
case types.AccessListTxType:
|
case types.DynamicFeeTxType, types.BlobTxType:
|
||||||
return nil
|
|
||||||
case types.DynamicFeeTxType:
|
|
||||||
return (*hexutil.Big)(tx.GasFeeCap())
|
return (*hexutil.Big)(tx.GasFeeCap())
|
||||||
default:
|
default:
|
||||||
return nil
|
return nil
|
||||||
|
|
@ -327,15 +323,33 @@ func (t *Transaction) MaxPriorityFeePerGas(ctx context.Context) *hexutil.Big {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
switch tx.Type() {
|
switch tx.Type() {
|
||||||
case types.AccessListTxType:
|
case types.DynamicFeeTxType, types.BlobTxType:
|
||||||
return nil
|
|
||||||
case types.DynamicFeeTxType:
|
|
||||||
return (*hexutil.Big)(tx.GasTipCap())
|
return (*hexutil.Big)(tx.GasTipCap())
|
||||||
default:
|
default:
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *Transaction) MaxFeePerBlobGas(ctx context.Context) *hexutil.Big {
|
||||||
|
tx, _ := t.resolve(ctx)
|
||||||
|
if tx == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return (*hexutil.Big)(tx.BlobGasFeeCap())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Transaction) BlobVersionedHashes(ctx context.Context) *[]common.Hash {
|
||||||
|
tx, _ := t.resolve(ctx)
|
||||||
|
if tx == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if tx.Type() != types.BlobTxType {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
blobHashes := tx.BlobHashes()
|
||||||
|
return &blobHashes
|
||||||
|
}
|
||||||
|
|
||||||
func (t *Transaction) EffectiveTip(ctx context.Context) (*hexutil.Big, error) {
|
func (t *Transaction) EffectiveTip(ctx context.Context) (*hexutil.Big, error) {
|
||||||
tx, block := t.resolve(ctx)
|
tx, block := t.resolve(ctx)
|
||||||
if tx == nil {
|
if tx == nil {
|
||||||
|
|
@ -468,6 +482,40 @@ func (t *Transaction) CumulativeGasUsed(ctx context.Context) (*hexutil.Uint64, e
|
||||||
return &ret, nil
|
return &ret, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *Transaction) BlobGasUsed(ctx context.Context) (*hexutil.Uint64, error) {
|
||||||
|
tx, _ := t.resolve(ctx)
|
||||||
|
if tx == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
if tx.Type() != types.BlobTxType {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
receipt, err := t.getReceipt(ctx)
|
||||||
|
if err != nil || receipt == nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
ret := hexutil.Uint64(receipt.BlobGasUsed)
|
||||||
|
return &ret, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Transaction) BlobGasPrice(ctx context.Context) (*hexutil.Big, error) {
|
||||||
|
tx, _ := t.resolve(ctx)
|
||||||
|
if tx == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
if tx.Type() != types.BlobTxType {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
receipt, err := t.getReceipt(ctx)
|
||||||
|
if err != nil || receipt == nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
ret := (*hexutil.Big)(receipt.BlobGasPrice)
|
||||||
|
return ret, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (t *Transaction) CreatedContract(ctx context.Context, args BlockNumberArgs) (*Account, error) {
|
func (t *Transaction) CreatedContract(ctx context.Context, args BlockNumberArgs) (*Account, error) {
|
||||||
receipt, err := t.getReceipt(ctx)
|
receipt, err := t.getReceipt(ctx)
|
||||||
if err != nil || receipt == nil || receipt.ContractAddress == (common.Address{}) {
|
if err != nil || receipt == nil || receipt.ContractAddress == (common.Address{}) {
|
||||||
|
|
@ -1019,6 +1067,30 @@ func (b *Block) Withdrawals(ctx context.Context) (*[]*Withdrawal, error) {
|
||||||
return &ret, nil
|
return &ret, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b *Block) BlobGasUsed(ctx context.Context) (*hexutil.Uint64, error) {
|
||||||
|
header, err := b.resolveHeader(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if header.BlobGasUsed == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
ret := hexutil.Uint64(*header.BlobGasUsed)
|
||||||
|
return &ret, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Block) ExcessBlobGas(ctx context.Context) (*hexutil.Uint64, error) {
|
||||||
|
header, err := b.resolveHeader(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if header.ExcessBlobGas == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
ret := hexutil.Uint64(*header.ExcessBlobGas)
|
||||||
|
return &ret, nil
|
||||||
|
}
|
||||||
|
|
||||||
// BlockFilterCriteria encapsulates criteria passed to a `logs` accessor inside
|
// BlockFilterCriteria encapsulates criteria passed to a `logs` accessor inside
|
||||||
// a block.
|
// a block.
|
||||||
type BlockFilterCriteria struct {
|
type BlockFilterCriteria struct {
|
||||||
|
|
|
||||||
|
|
@ -71,8 +71,8 @@ const schema string = `
|
||||||
transaction: Transaction!
|
transaction: Transaction!
|
||||||
}
|
}
|
||||||
|
|
||||||
#EIP-2718
|
# EIP-2718
|
||||||
type AccessTuple{
|
type AccessTuple {
|
||||||
address: Address!
|
address: Address!
|
||||||
storageKeys : [Bytes32!]!
|
storageKeys : [Bytes32!]!
|
||||||
}
|
}
|
||||||
|
|
@ -112,6 +112,8 @@ const schema string = `
|
||||||
maxFeePerGas: BigInt
|
maxFeePerGas: BigInt
|
||||||
# MaxPriorityFeePerGas is the maximum miner tip per gas offered to include a transaction, in wei.
|
# MaxPriorityFeePerGas is the maximum miner tip per gas offered to include a transaction, in wei.
|
||||||
maxPriorityFeePerGas: BigInt
|
maxPriorityFeePerGas: BigInt
|
||||||
|
# MaxFeePerBlobGas is the maximum blob gas fee cap per blob the sender is willing to pay for blob transaction, in wei.
|
||||||
|
maxFeePerBlobGas: BigInt
|
||||||
# EffectiveTip is the actual amount of reward going to miner after considering the max fee cap.
|
# EffectiveTip is the actual amount of reward going to miner after considering the max fee cap.
|
||||||
effectiveTip: BigInt
|
effectiveTip: BigInt
|
||||||
# Gas is the maximum amount of gas this transaction can consume.
|
# Gas is the maximum amount of gas this transaction can consume.
|
||||||
|
|
@ -141,6 +143,10 @@ const schema string = `
|
||||||
# coerced into the EIP-1559 format by setting both maxFeePerGas and
|
# coerced into the EIP-1559 format by setting both maxFeePerGas and
|
||||||
# maxPriorityFeePerGas as the transaction's gas price.
|
# maxPriorityFeePerGas as the transaction's gas price.
|
||||||
effectiveGasPrice: BigInt
|
effectiveGasPrice: BigInt
|
||||||
|
# BlobGasUsed is the amount of blob gas used by this transaction.
|
||||||
|
blobGasUsed: Long
|
||||||
|
# blobGasPrice is the actual value per blob gas deducted from the senders account.
|
||||||
|
blobGasPrice: BigInt
|
||||||
# CreatedContract is the account that was created by a contract creation
|
# CreatedContract is the account that was created by a contract creation
|
||||||
# transaction. If the transaction was not a contract creation transaction,
|
# transaction. If the transaction was not a contract creation transaction,
|
||||||
# or it has not yet been mined, this field will be null.
|
# or it has not yet been mined, this field will be null.
|
||||||
|
|
@ -162,6 +168,8 @@ const schema string = `
|
||||||
# RawReceipt is the canonical encoding of the receipt. For post EIP-2718 typed transactions
|
# RawReceipt is the canonical encoding of the receipt. For post EIP-2718 typed transactions
|
||||||
# this is equivalent to TxType || ReceiptEncoding.
|
# this is equivalent to TxType || ReceiptEncoding.
|
||||||
rawReceipt: Bytes!
|
rawReceipt: Bytes!
|
||||||
|
# BlobVersionedHashes is a set of hash outputs from the blobs in the transaction.
|
||||||
|
blobVersionedHashes: [Bytes32!]
|
||||||
}
|
}
|
||||||
|
|
||||||
# BlockFilterCriteria encapsulates log filter criteria for a filter applied
|
# BlockFilterCriteria encapsulates log filter criteria for a filter applied
|
||||||
|
|
@ -267,6 +275,10 @@ const schema string = `
|
||||||
# Withdrawals is a list of withdrawals associated with this block. If
|
# Withdrawals is a list of withdrawals associated with this block. If
|
||||||
# withdrawals are unavailable for this block, this field will be null.
|
# withdrawals are unavailable for this block, this field will be null.
|
||||||
withdrawals: [Withdrawal!]
|
withdrawals: [Withdrawal!]
|
||||||
|
# BlobGasUsed is the total amount of gas used by the transactions.
|
||||||
|
blobGasUsed: Long
|
||||||
|
# ExcessBlobGas is a running total of blob gas consumed in excess of the target, prior to the block.
|
||||||
|
excessBlobGas: Long
|
||||||
}
|
}
|
||||||
|
|
||||||
# CallData represents the data associated with a local contract call.
|
# CallData represents the data associated with a local contract call.
|
||||||
|
|
@ -326,7 +338,7 @@ const schema string = `
|
||||||
}
|
}
|
||||||
|
|
||||||
# SyncState contains the current synchronisation state of the client.
|
# SyncState contains the current synchronisation state of the client.
|
||||||
type SyncState{
|
type SyncState {
|
||||||
# StartingBlock is the block number at which synchronisation started.
|
# StartingBlock is the block number at which synchronisation started.
|
||||||
startingBlock: Long!
|
startingBlock: Long!
|
||||||
# CurrentBlock is the point at which synchronisation has presently reached.
|
# CurrentBlock is the point at which synchronisation has presently reached.
|
||||||
|
|
|
||||||
|
|
@ -14,9 +14,6 @@
|
||||||
// You should have received a copy of the GNU Lesser General Public License
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
//go:build go1.6
|
|
||||||
// +build go1.6
|
|
||||||
|
|
||||||
package debug
|
package debug
|
||||||
|
|
||||||
import "runtime/debug"
|
import "runtime/debug"
|
||||||
|
|
|
||||||
|
|
@ -1,25 +0,0 @@
|
||||||
// Copyright 2016 The go-ethereum Authors
|
|
||||||
// This file is part of the go-ethereum library.
|
|
||||||
//
|
|
||||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU Lesser General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// The go-ethereum library 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 Lesser General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Lesser General Public License
|
|
||||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
//go:build !go1.6
|
|
||||||
// +build !go1.6
|
|
||||||
|
|
||||||
package debug
|
|
||||||
|
|
||||||
// LoudPanic panics in a way that gets all goroutine stacks printed on stderr.
|
|
||||||
func LoudPanic(x interface{}) {
|
|
||||||
panic(x)
|
|
||||||
}
|
|
||||||
|
|
@ -14,9 +14,6 @@
|
||||||
// You should have received a copy of the GNU Lesser General Public License
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
//go:build go1.5
|
|
||||||
// +build go1.5
|
|
||||||
|
|
||||||
package debug
|
package debug
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|
|
||||||
|
|
@ -1,32 +0,0 @@
|
||||||
// Copyright 2016 The go-ethereum Authors
|
|
||||||
// This file is part of the go-ethereum library.
|
|
||||||
//
|
|
||||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU Lesser General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// The go-ethereum library 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 Lesser General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Lesser General Public License
|
|
||||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
//go:build !go1.5
|
|
||||||
// +build !go1.5
|
|
||||||
|
|
||||||
// no-op implementation of tracing methods for Go < 1.5.
|
|
||||||
|
|
||||||
package debug
|
|
||||||
|
|
||||||
import "errors"
|
|
||||||
|
|
||||||
func (*HandlerT) StartGoTrace(string) error {
|
|
||||||
return errors.New("tracing is not supported on Go < 1.5")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*HandlerT) StopGoTrace() error {
|
|
||||||
return errors.New("tracing is not supported on Go < 1.5")
|
|
||||||
}
|
|
||||||
|
|
@ -1520,8 +1520,8 @@ func newRPCTransaction(tx *types.Transaction, blockHash common.Hash, blockNumber
|
||||||
func effectiveGasPrice(tx *types.Transaction, baseFee *big.Int) *big.Int {
|
func effectiveGasPrice(tx *types.Transaction, baseFee *big.Int) *big.Int {
|
||||||
fee := tx.GasTipCap()
|
fee := tx.GasTipCap()
|
||||||
fee = fee.Add(fee, baseFee)
|
fee = fee.Add(fee, baseFee)
|
||||||
if tx.GasTipCapIntCmp(fee) < 0 {
|
if tx.GasFeeCapIntCmp(fee) < 0 {
|
||||||
return tx.GasTipCap()
|
return tx.GasFeeCap()
|
||||||
}
|
}
|
||||||
return fee
|
return fee
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,11 +20,13 @@ import (
|
||||||
"encoding"
|
"encoding"
|
||||||
"errors"
|
"errors"
|
||||||
"flag"
|
"flag"
|
||||||
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
"os"
|
"os"
|
||||||
"os/user"
|
"os/user"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common/math"
|
"github.com/ethereum/go-ethereum/common/math"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
|
|
@ -68,6 +70,7 @@ type DirectoryFlag struct {
|
||||||
Value DirectoryString
|
Value DirectoryString
|
||||||
|
|
||||||
Aliases []string
|
Aliases []string
|
||||||
|
EnvVars []string
|
||||||
}
|
}
|
||||||
|
|
||||||
// For cli.Flag:
|
// For cli.Flag:
|
||||||
|
|
@ -79,6 +82,14 @@ func (f *DirectoryFlag) String() string { return cli.FlagStringer(f) }
|
||||||
// Apply called by cli library, grabs variable from environment (if in env)
|
// Apply called by cli library, grabs variable from environment (if in env)
|
||||||
// and adds variable to flag set for parsing.
|
// and adds variable to flag set for parsing.
|
||||||
func (f *DirectoryFlag) Apply(set *flag.FlagSet) error {
|
func (f *DirectoryFlag) Apply(set *flag.FlagSet) error {
|
||||||
|
for _, envVar := range f.EnvVars {
|
||||||
|
envVar = strings.TrimSpace(envVar)
|
||||||
|
if value, found := syscall.Getenv(envVar); found {
|
||||||
|
f.Value.Set(value)
|
||||||
|
f.HasBeenSet = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
eachName(f, func(name string) {
|
eachName(f, func(name string) {
|
||||||
set.Var(&f.Value, f.Name, f.Usage)
|
set.Var(&f.Value, f.Name, f.Usage)
|
||||||
})
|
})
|
||||||
|
|
@ -102,7 +113,7 @@ func (f *DirectoryFlag) GetCategory() string { return f.Category }
|
||||||
func (f *DirectoryFlag) TakesValue() bool { return true }
|
func (f *DirectoryFlag) TakesValue() bool { return true }
|
||||||
func (f *DirectoryFlag) GetUsage() string { return f.Usage }
|
func (f *DirectoryFlag) GetUsage() string { return f.Usage }
|
||||||
func (f *DirectoryFlag) GetValue() string { return f.Value.String() }
|
func (f *DirectoryFlag) GetValue() string { return f.Value.String() }
|
||||||
func (f *DirectoryFlag) GetEnvVars() []string { return nil } // env not supported
|
func (f *DirectoryFlag) GetEnvVars() []string { return f.EnvVars }
|
||||||
|
|
||||||
func (f *DirectoryFlag) GetDefaultText() string {
|
func (f *DirectoryFlag) GetDefaultText() string {
|
||||||
if f.DefaultText != "" {
|
if f.DefaultText != "" {
|
||||||
|
|
@ -156,6 +167,7 @@ type TextMarshalerFlag struct {
|
||||||
Value TextMarshaler
|
Value TextMarshaler
|
||||||
|
|
||||||
Aliases []string
|
Aliases []string
|
||||||
|
EnvVars []string
|
||||||
}
|
}
|
||||||
|
|
||||||
// For cli.Flag:
|
// For cli.Flag:
|
||||||
|
|
@ -165,6 +177,16 @@ func (f *TextMarshalerFlag) IsSet() bool { return f.HasBeenSet }
|
||||||
func (f *TextMarshalerFlag) String() string { return cli.FlagStringer(f) }
|
func (f *TextMarshalerFlag) String() string { return cli.FlagStringer(f) }
|
||||||
|
|
||||||
func (f *TextMarshalerFlag) Apply(set *flag.FlagSet) error {
|
func (f *TextMarshalerFlag) Apply(set *flag.FlagSet) error {
|
||||||
|
for _, envVar := range f.EnvVars {
|
||||||
|
envVar = strings.TrimSpace(envVar)
|
||||||
|
if value, found := syscall.Getenv(envVar); found {
|
||||||
|
if err := f.Value.UnmarshalText([]byte(value)); err != nil {
|
||||||
|
return fmt.Errorf("could not parse %q from environment variable %q for flag %s: %s", value, envVar, f.Name, err)
|
||||||
|
}
|
||||||
|
f.HasBeenSet = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
eachName(f, func(name string) {
|
eachName(f, func(name string) {
|
||||||
set.Var(textMarshalerVal{f.Value}, f.Name, f.Usage)
|
set.Var(textMarshalerVal{f.Value}, f.Name, f.Usage)
|
||||||
})
|
})
|
||||||
|
|
@ -187,7 +209,7 @@ func (f *TextMarshalerFlag) GetCategory() string { return f.Category }
|
||||||
|
|
||||||
func (f *TextMarshalerFlag) TakesValue() bool { return true }
|
func (f *TextMarshalerFlag) TakesValue() bool { return true }
|
||||||
func (f *TextMarshalerFlag) GetUsage() string { return f.Usage }
|
func (f *TextMarshalerFlag) GetUsage() string { return f.Usage }
|
||||||
func (f *TextMarshalerFlag) GetEnvVars() []string { return nil } // env not supported
|
func (f *TextMarshalerFlag) GetEnvVars() []string { return f.EnvVars }
|
||||||
|
|
||||||
func (f *TextMarshalerFlag) GetValue() string {
|
func (f *TextMarshalerFlag) GetValue() string {
|
||||||
t, err := f.Value.MarshalText()
|
t, err := f.Value.MarshalText()
|
||||||
|
|
@ -237,6 +259,7 @@ type BigFlag struct {
|
||||||
Value *big.Int
|
Value *big.Int
|
||||||
|
|
||||||
Aliases []string
|
Aliases []string
|
||||||
|
EnvVars []string
|
||||||
}
|
}
|
||||||
|
|
||||||
// For cli.Flag:
|
// For cli.Flag:
|
||||||
|
|
@ -246,6 +269,16 @@ func (f *BigFlag) IsSet() bool { return f.HasBeenSet }
|
||||||
func (f *BigFlag) String() string { return cli.FlagStringer(f) }
|
func (f *BigFlag) String() string { return cli.FlagStringer(f) }
|
||||||
|
|
||||||
func (f *BigFlag) Apply(set *flag.FlagSet) error {
|
func (f *BigFlag) Apply(set *flag.FlagSet) error {
|
||||||
|
for _, envVar := range f.EnvVars {
|
||||||
|
envVar = strings.TrimSpace(envVar)
|
||||||
|
if value, found := syscall.Getenv(envVar); found {
|
||||||
|
if _, ok := f.Value.SetString(value, 10); !ok {
|
||||||
|
return fmt.Errorf("could not parse %q from environment variable %q for flag %s", value, envVar, f.Name)
|
||||||
|
}
|
||||||
|
f.HasBeenSet = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
eachName(f, func(name string) {
|
eachName(f, func(name string) {
|
||||||
f.Value = new(big.Int)
|
f.Value = new(big.Int)
|
||||||
set.Var((*bigValue)(f.Value), f.Name, f.Usage)
|
set.Var((*bigValue)(f.Value), f.Name, f.Usage)
|
||||||
|
|
@ -271,7 +304,7 @@ func (f *BigFlag) GetCategory() string { return f.Category }
|
||||||
func (f *BigFlag) TakesValue() bool { return true }
|
func (f *BigFlag) TakesValue() bool { return true }
|
||||||
func (f *BigFlag) GetUsage() string { return f.Usage }
|
func (f *BigFlag) GetUsage() string { return f.Usage }
|
||||||
func (f *BigFlag) GetValue() string { return f.Value.String() }
|
func (f *BigFlag) GetValue() string { return f.Value.String() }
|
||||||
func (f *BigFlag) GetEnvVars() []string { return nil } // env not supported
|
func (f *BigFlag) GetEnvVars() []string { return f.EnvVars }
|
||||||
|
|
||||||
func (f *BigFlag) GetDefaultText() string {
|
func (f *BigFlag) GetDefaultText() string {
|
||||||
if f.DefaultText != "" {
|
if f.DefaultText != "" {
|
||||||
|
|
|
||||||
|
|
@ -18,13 +18,22 @@ package flags
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"regexp"
|
||||||
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/internal/version"
|
"github.com/ethereum/go-ethereum/internal/version"
|
||||||
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
|
"github.com/mattn/go-isatty"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// usecolor defines whether the CLI help should use colored output or normal dumb
|
||||||
|
// colorless terminal formatting.
|
||||||
|
var usecolor = (isatty.IsTerminal(os.Stdout.Fd()) || isatty.IsCygwinTerminal(os.Stdout.Fd())) && os.Getenv("TERM") != "dumb"
|
||||||
|
|
||||||
// NewApp creates an app with sane defaults.
|
// NewApp creates an app with sane defaults.
|
||||||
func NewApp(usage string) *cli.App {
|
func NewApp(usage string) *cli.App {
|
||||||
git, _ := version.VCS()
|
git, _ := version.VCS()
|
||||||
|
|
@ -129,6 +138,14 @@ func doMigrateFlags(ctx *cli.Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
if usecolor {
|
||||||
|
// Annotate all help categories with colors
|
||||||
|
cli.AppHelpTemplate = regexp.MustCompile("[A-Z ]+:").ReplaceAllString(cli.AppHelpTemplate, "\u001B[33m$0\u001B[0m")
|
||||||
|
|
||||||
|
// Annotate flag categories with colors (private template, so need to
|
||||||
|
// copy-paste the entire thing here...)
|
||||||
|
cli.AppHelpTemplate = strings.ReplaceAll(cli.AppHelpTemplate, "{{template \"visibleFlagCategoryTemplate\" .}}", "{{range .VisibleFlagCategories}}\n {{if .Name}}\u001B[33m{{.Name}}\u001B[0m\n\n {{end}}{{$flglen := len .Flags}}{{range $i, $e := .Flags}}{{if eq (subtract $flglen $i) 1}}{{$e}}\n{{else}}{{$e}}\n {{end}}{{end}}{{end}}")
|
||||||
|
}
|
||||||
cli.FlagStringer = FlagString
|
cli.FlagStringer = FlagString
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -138,37 +155,31 @@ func FlagString(f cli.Flag) string {
|
||||||
if !ok {
|
if !ok {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
needsPlaceholder := df.TakesValue()
|
needsPlaceholder := df.TakesValue()
|
||||||
placeholder := ""
|
placeholder := ""
|
||||||
if needsPlaceholder {
|
if needsPlaceholder {
|
||||||
placeholder = "value"
|
placeholder = "value"
|
||||||
}
|
}
|
||||||
|
|
||||||
namesText := pad(cli.FlagNamePrefixer(df.Names(), placeholder), 30)
|
namesText := cli.FlagNamePrefixer(df.Names(), placeholder)
|
||||||
|
|
||||||
defaultValueString := ""
|
defaultValueString := ""
|
||||||
if s := df.GetDefaultText(); s != "" {
|
if s := df.GetDefaultText(); s != "" {
|
||||||
defaultValueString = " (default: " + s + ")"
|
defaultValueString = " (default: " + s + ")"
|
||||||
}
|
}
|
||||||
|
|
||||||
usage := strings.TrimSpace(df.GetUsage())
|
|
||||||
envHint := strings.TrimSpace(cli.FlagEnvHinter(df.GetEnvVars(), ""))
|
envHint := strings.TrimSpace(cli.FlagEnvHinter(df.GetEnvVars(), ""))
|
||||||
if len(envHint) > 0 {
|
if envHint != "" {
|
||||||
usage += " " + envHint
|
envHint = " (" + envHint[1:len(envHint)-1] + ")"
|
||||||
}
|
}
|
||||||
|
usage := strings.TrimSpace(df.GetUsage())
|
||||||
usage = wordWrap(usage, 80)
|
usage = wordWrap(usage, 80)
|
||||||
usage = indent(usage, 10)
|
usage = indent(usage, 10)
|
||||||
|
|
||||||
return fmt.Sprintf("\n %s%s\n%s", namesText, defaultValueString, usage)
|
if usecolor {
|
||||||
}
|
return fmt.Sprintf("\n \u001B[32m%-35s%-35s\u001B[0m%s\n%s", namesText, defaultValueString, envHint, usage)
|
||||||
|
} else {
|
||||||
func pad(s string, length int) string {
|
return fmt.Sprintf("\n %-35s%-35s%s\n%s", namesText, defaultValueString, envHint, usage)
|
||||||
if len(s) < length {
|
|
||||||
s += strings.Repeat(" ", length-len(s))
|
|
||||||
}
|
}
|
||||||
return s
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func indent(s string, nspace int) string {
|
func indent(s string, nspace int) string {
|
||||||
|
|
@ -213,3 +224,78 @@ func wordWrap(s string, width int) string {
|
||||||
|
|
||||||
return output.String()
|
return output.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AutoEnvVars extends all the specific CLI flags with automatically generated
|
||||||
|
// env vars by capitalizing the flag, replacing . with _ and prefixing it with
|
||||||
|
// the specified string.
|
||||||
|
//
|
||||||
|
// Note, the prefix should *not* contain the separator underscore, that will be
|
||||||
|
// added automatically.
|
||||||
|
func AutoEnvVars(flags []cli.Flag, prefix string) {
|
||||||
|
for _, flag := range flags {
|
||||||
|
envvar := strings.ToUpper(prefix + "_" + strings.ReplaceAll(strings.ReplaceAll(flag.Names()[0], ".", "_"), "-", "_"))
|
||||||
|
|
||||||
|
switch flag := flag.(type) {
|
||||||
|
case *cli.StringFlag:
|
||||||
|
flag.EnvVars = append(flag.EnvVars, envvar)
|
||||||
|
|
||||||
|
case *cli.BoolFlag:
|
||||||
|
flag.EnvVars = append(flag.EnvVars, envvar)
|
||||||
|
|
||||||
|
case *cli.IntFlag:
|
||||||
|
flag.EnvVars = append(flag.EnvVars, envvar)
|
||||||
|
|
||||||
|
case *cli.Uint64Flag:
|
||||||
|
flag.EnvVars = append(flag.EnvVars, envvar)
|
||||||
|
|
||||||
|
case *cli.DurationFlag:
|
||||||
|
flag.EnvVars = append(flag.EnvVars, envvar)
|
||||||
|
|
||||||
|
case *cli.PathFlag:
|
||||||
|
flag.EnvVars = append(flag.EnvVars, envvar)
|
||||||
|
|
||||||
|
case *BigFlag:
|
||||||
|
flag.EnvVars = append(flag.EnvVars, envvar)
|
||||||
|
|
||||||
|
case *TextMarshalerFlag:
|
||||||
|
flag.EnvVars = append(flag.EnvVars, envvar)
|
||||||
|
|
||||||
|
case *DirectoryFlag:
|
||||||
|
flag.EnvVars = append(flag.EnvVars, envvar)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CheckEnvVars iterates over all the environment variables and checks if any of
|
||||||
|
// them look like a CLI flag but is not consumed. This can be used to detect old
|
||||||
|
// or mistyped names.
|
||||||
|
func CheckEnvVars(ctx *cli.Context, flags []cli.Flag, prefix string) {
|
||||||
|
known := make(map[string]string)
|
||||||
|
for _, flag := range flags {
|
||||||
|
docflag, ok := flag.(cli.DocGenerationFlag)
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for _, envvar := range docflag.GetEnvVars() {
|
||||||
|
known[envvar] = flag.Names()[0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
keyvals := os.Environ()
|
||||||
|
sort.Strings(keyvals)
|
||||||
|
|
||||||
|
for _, keyval := range keyvals {
|
||||||
|
key := strings.Split(keyval, "=")[0]
|
||||||
|
if !strings.HasPrefix(key, prefix) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if flag, ok := known[key]; ok {
|
||||||
|
if ctx.Count(flag) > 0 {
|
||||||
|
log.Info("Config environment variable found", "envvar", key, "shadowedby", "--"+flag)
|
||||||
|
} else {
|
||||||
|
log.Info("Config environment variable found", "envvar", key)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.Warn("Unknown config environment variable", "envvar", key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,8 +33,16 @@ var locationTrims = []string{
|
||||||
// format output.
|
// format output.
|
||||||
func PrintOrigins(print bool) {
|
func PrintOrigins(print bool) {
|
||||||
locationEnabled.Store(print)
|
locationEnabled.Store(print)
|
||||||
|
if print {
|
||||||
|
stackEnabled.Store(true)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// stackEnabled is an atomic flag controlling whether the log handler needs
|
||||||
|
// to store the callsite stack. This is needed in case any handler wants to
|
||||||
|
// print locations (locationEnabled), use vmodule, or print full stacks (BacktraceAt).
|
||||||
|
var stackEnabled atomic.Bool
|
||||||
|
|
||||||
// locationEnabled is an atomic flag controlling whether the terminal formatter
|
// locationEnabled is an atomic flag controlling whether the terminal formatter
|
||||||
// should append the log locations too when printing entries.
|
// should append the log locations too when printing entries.
|
||||||
var locationEnabled atomic.Bool
|
var locationEnabled atomic.Bool
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"reflect"
|
"reflect"
|
||||||
"sync"
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
|
|
||||||
"github.com/go-stack/stack"
|
"github.com/go-stack/stack"
|
||||||
)
|
)
|
||||||
|
|
@ -354,3 +355,21 @@ func (m muster) FileHandler(path string, fmtr Format) Handler {
|
||||||
func (m muster) NetHandler(network, addr string, fmtr Format) Handler {
|
func (m muster) NetHandler(network, addr string, fmtr Format) Handler {
|
||||||
return must(NetHandler(network, addr, fmtr))
|
return must(NetHandler(network, addr, fmtr))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// swapHandler wraps another handler that may be swapped out
|
||||||
|
// dynamically at runtime in a thread-safe fashion.
|
||||||
|
type swapHandler struct {
|
||||||
|
handler atomic.Value
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *swapHandler) Log(r *Record) error {
|
||||||
|
return (*h.handler.Load().(*Handler)).Log(r)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *swapHandler) Swap(newHandler Handler) {
|
||||||
|
h.handler.Store(&newHandler)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *swapHandler) Get() Handler {
|
||||||
|
return *h.handler.Load().(*Handler)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -139,7 +139,10 @@ func (h *GlogHandler) Vmodule(ruleset string) error {
|
||||||
h.patterns = filter
|
h.patterns = filter
|
||||||
h.siteCache = make(map[uintptr]Lvl)
|
h.siteCache = make(map[uintptr]Lvl)
|
||||||
h.override.Store(len(filter) != 0)
|
h.override.Store(len(filter) != 0)
|
||||||
|
// Enable location storage (globally)
|
||||||
|
if len(h.patterns) > 0 {
|
||||||
|
stackEnabled.Store(true)
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -172,7 +175,8 @@ func (h *GlogHandler) BacktraceAt(location string) error {
|
||||||
|
|
||||||
h.location = location
|
h.location = location
|
||||||
h.backtrace.Store(len(location) > 0)
|
h.backtrace.Store(len(location) > 0)
|
||||||
|
// Enable location storage (globally)
|
||||||
|
stackEnabled.Store(true)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,27 +0,0 @@
|
||||||
//go:build !go1.4
|
|
||||||
// +build !go1.4
|
|
||||||
|
|
||||||
package log
|
|
||||||
|
|
||||||
import (
|
|
||||||
"sync/atomic"
|
|
||||||
"unsafe"
|
|
||||||
)
|
|
||||||
|
|
||||||
// swapHandler wraps another handler that may be swapped out
|
|
||||||
// dynamically at runtime in a thread-safe fashion.
|
|
||||||
type swapHandler struct {
|
|
||||||
handler unsafe.Pointer
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *swapHandler) Log(r *Record) error {
|
|
||||||
return h.Get().Log(r)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *swapHandler) Get() Handler {
|
|
||||||
return *(*Handler)(atomic.LoadPointer(&h.handler))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *swapHandler) Swap(newHandler Handler) {
|
|
||||||
atomic.StorePointer(&h.handler, unsafe.Pointer(&newHandler))
|
|
||||||
}
|
|
||||||
|
|
@ -1,24 +0,0 @@
|
||||||
//go:build go1.4
|
|
||||||
// +build go1.4
|
|
||||||
|
|
||||||
package log
|
|
||||||
|
|
||||||
import "sync/atomic"
|
|
||||||
|
|
||||||
// swapHandler wraps another handler that may be swapped out
|
|
||||||
// dynamically at runtime in a thread-safe fashion.
|
|
||||||
type swapHandler struct {
|
|
||||||
handler atomic.Value
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *swapHandler) Log(r *Record) error {
|
|
||||||
return (*h.handler.Load().(*Handler)).Log(r)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *swapHandler) Swap(newHandler Handler) {
|
|
||||||
h.handler.Store(&newHandler)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *swapHandler) Get() Handler {
|
|
||||||
return *h.handler.Load().(*Handler)
|
|
||||||
}
|
|
||||||
|
|
@ -177,19 +177,22 @@ type logger struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *logger) write(msg string, lvl Lvl, ctx []interface{}, skip int) {
|
func (l *logger) write(msg string, lvl Lvl, ctx []interface{}, skip int) {
|
||||||
l.h.Log(&Record{
|
record := &Record{
|
||||||
Time: time.Now(),
|
Time: time.Now(),
|
||||||
Lvl: lvl,
|
Lvl: lvl,
|
||||||
Msg: msg,
|
Msg: msg,
|
||||||
Ctx: newContext(l.ctx, ctx),
|
Ctx: newContext(l.ctx, ctx),
|
||||||
Call: stack.Caller(skip),
|
|
||||||
KeyNames: RecordKeyNames{
|
KeyNames: RecordKeyNames{
|
||||||
Time: timeKey,
|
Time: timeKey,
|
||||||
Msg: msgKey,
|
Msg: msgKey,
|
||||||
Lvl: lvlKey,
|
Lvl: lvlKey,
|
||||||
Ctx: ctxKey,
|
Ctx: ctxKey,
|
||||||
},
|
},
|
||||||
})
|
}
|
||||||
|
if stackEnabled.Load() {
|
||||||
|
record.Call = stack.Caller(skip)
|
||||||
|
}
|
||||||
|
l.h.Log(record)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *logger) New(ctx ...interface{}) Logger {
|
func (l *logger) New(ctx ...interface{}) Logger {
|
||||||
|
|
|
||||||
67
log/logger_test.go
Normal file
67
log/logger_test.go
Normal file
|
|
@ -0,0 +1,67 @@
|
||||||
|
package log
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TestLoggingWithTrace checks that if BackTraceAt is set, then the
|
||||||
|
// gloghandler is capable of spitting out a stacktrace
|
||||||
|
func TestLoggingWithTrace(t *testing.T) {
|
||||||
|
defer stackEnabled.Store(stackEnabled.Load())
|
||||||
|
out := new(bytes.Buffer)
|
||||||
|
logger := New()
|
||||||
|
{
|
||||||
|
glog := NewGlogHandler(StreamHandler(out, TerminalFormat(false)))
|
||||||
|
glog.Verbosity(LvlTrace)
|
||||||
|
if err := glog.BacktraceAt("logger_test.go:24"); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
logger.SetHandler(glog)
|
||||||
|
}
|
||||||
|
logger.Trace("a message", "foo", "bar") // Will be bumped to INFO
|
||||||
|
have := out.String()
|
||||||
|
if !strings.HasPrefix(have, "INFO") {
|
||||||
|
t.Fatalf("backtraceat should bump level to info: %s", have)
|
||||||
|
}
|
||||||
|
// The timestamp is locale-dependent, so we want to trim that off
|
||||||
|
// "INFO [01-01|00:00:00.000] a messag ..." -> "a messag..."
|
||||||
|
have = strings.Split(have, "]")[1]
|
||||||
|
wantPrefix := " a message\n\ngoroutine"
|
||||||
|
if !strings.HasPrefix(have, wantPrefix) {
|
||||||
|
t.Errorf("\nhave: %q\nwant: %q\n", have, wantPrefix)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestLoggingWithVmodule checks that vmodule works.
|
||||||
|
func TestLoggingWithVmodule(t *testing.T) {
|
||||||
|
defer stackEnabled.Store(stackEnabled.Load())
|
||||||
|
out := new(bytes.Buffer)
|
||||||
|
logger := New()
|
||||||
|
{
|
||||||
|
glog := NewGlogHandler(StreamHandler(out, TerminalFormat(false)))
|
||||||
|
glog.Verbosity(LvlCrit)
|
||||||
|
logger.SetHandler(glog)
|
||||||
|
logger.Warn("This should not be seen", "ignored", "true")
|
||||||
|
glog.Vmodule("logger_test.go=5")
|
||||||
|
}
|
||||||
|
logger.Trace("a message", "foo", "bar")
|
||||||
|
have := out.String()
|
||||||
|
// The timestamp is locale-dependent, so we want to trim that off
|
||||||
|
// "INFO [01-01|00:00:00.000] a messag ..." -> "a messag..."
|
||||||
|
have = strings.Split(have, "]")[1]
|
||||||
|
want := " a message foo=bar\n"
|
||||||
|
if have != want {
|
||||||
|
t.Errorf("\nhave: %q\nwant: %q\n", have, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkTraceLogging(b *testing.B) {
|
||||||
|
Root().SetHandler(LvlFilterHandler(LvlInfo, StreamHandler(os.Stderr, TerminalFormat(true))))
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
Trace("a message", "v", i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -4,13 +4,16 @@ import (
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type CounterSnapshot interface {
|
||||||
|
Count() int64
|
||||||
|
}
|
||||||
|
|
||||||
// Counters hold an int64 value that can be incremented and decremented.
|
// Counters hold an int64 value that can be incremented and decremented.
|
||||||
type Counter interface {
|
type Counter interface {
|
||||||
Clear()
|
Clear()
|
||||||
Count() int64
|
|
||||||
Dec(int64)
|
Dec(int64)
|
||||||
Inc(int64)
|
Inc(int64)
|
||||||
Snapshot() Counter
|
Snapshot() CounterSnapshot
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetOrRegisterCounter returns an existing Counter or constructs and registers
|
// GetOrRegisterCounter returns an existing Counter or constructs and registers
|
||||||
|
|
@ -38,13 +41,13 @@ func NewCounter() Counter {
|
||||||
if !Enabled {
|
if !Enabled {
|
||||||
return NilCounter{}
|
return NilCounter{}
|
||||||
}
|
}
|
||||||
return &StandardCounter{}
|
return new(StandardCounter)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewCounterForced constructs a new StandardCounter and returns it no matter if
|
// NewCounterForced constructs a new StandardCounter and returns it no matter if
|
||||||
// the global switch is enabled or not.
|
// the global switch is enabled or not.
|
||||||
func NewCounterForced() Counter {
|
func NewCounterForced() Counter {
|
||||||
return &StandardCounter{}
|
return new(StandardCounter)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewRegisteredCounter constructs and registers a new StandardCounter.
|
// NewRegisteredCounter constructs and registers a new StandardCounter.
|
||||||
|
|
@ -70,75 +73,40 @@ func NewRegisteredCounterForced(name string, r Registry) Counter {
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
// CounterSnapshot is a read-only copy of another Counter.
|
// counterSnapshot is a read-only copy of another Counter.
|
||||||
type CounterSnapshot int64
|
type counterSnapshot int64
|
||||||
|
|
||||||
// Clear panics.
|
|
||||||
func (CounterSnapshot) Clear() {
|
|
||||||
panic("Clear called on a CounterSnapshot")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Count returns the count at the time the snapshot was taken.
|
// Count returns the count at the time the snapshot was taken.
|
||||||
func (c CounterSnapshot) Count() int64 { return int64(c) }
|
func (c counterSnapshot) Count() int64 { return int64(c) }
|
||||||
|
|
||||||
// Dec panics.
|
|
||||||
func (CounterSnapshot) Dec(int64) {
|
|
||||||
panic("Dec called on a CounterSnapshot")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Inc panics.
|
|
||||||
func (CounterSnapshot) Inc(int64) {
|
|
||||||
panic("Inc called on a CounterSnapshot")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Snapshot returns the snapshot.
|
|
||||||
func (c CounterSnapshot) Snapshot() Counter { return c }
|
|
||||||
|
|
||||||
// NilCounter is a no-op Counter.
|
// NilCounter is a no-op Counter.
|
||||||
type NilCounter struct{}
|
type NilCounter struct{}
|
||||||
|
|
||||||
// Clear is a no-op.
|
|
||||||
func (NilCounter) Clear() {}
|
func (NilCounter) Clear() {}
|
||||||
|
|
||||||
// Count is a no-op.
|
|
||||||
func (NilCounter) Count() int64 { return 0 }
|
|
||||||
|
|
||||||
// Dec is a no-op.
|
|
||||||
func (NilCounter) Dec(i int64) {}
|
func (NilCounter) Dec(i int64) {}
|
||||||
|
|
||||||
// Inc is a no-op.
|
|
||||||
func (NilCounter) Inc(i int64) {}
|
func (NilCounter) Inc(i int64) {}
|
||||||
|
func (NilCounter) Snapshot() CounterSnapshot { return (*emptySnapshot)(nil) }
|
||||||
// Snapshot is a no-op.
|
|
||||||
func (NilCounter) Snapshot() Counter { return NilCounter{} }
|
|
||||||
|
|
||||||
// StandardCounter is the standard implementation of a Counter and uses the
|
// StandardCounter is the standard implementation of a Counter and uses the
|
||||||
// sync/atomic package to manage a single int64 value.
|
// sync/atomic package to manage a single int64 value.
|
||||||
type StandardCounter struct {
|
type StandardCounter atomic.Int64
|
||||||
count atomic.Int64
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clear sets the counter to zero.
|
// Clear sets the counter to zero.
|
||||||
func (c *StandardCounter) Clear() {
|
func (c *StandardCounter) Clear() {
|
||||||
c.count.Store(0)
|
(*atomic.Int64)(c).Store(0)
|
||||||
}
|
|
||||||
|
|
||||||
// Count returns the current count.
|
|
||||||
func (c *StandardCounter) Count() int64 {
|
|
||||||
return c.count.Load()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dec decrements the counter by the given amount.
|
// Dec decrements the counter by the given amount.
|
||||||
func (c *StandardCounter) Dec(i int64) {
|
func (c *StandardCounter) Dec(i int64) {
|
||||||
c.count.Add(-i)
|
(*atomic.Int64)(c).Add(-i)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inc increments the counter by the given amount.
|
// Inc increments the counter by the given amount.
|
||||||
func (c *StandardCounter) Inc(i int64) {
|
func (c *StandardCounter) Inc(i int64) {
|
||||||
c.count.Add(i)
|
(*atomic.Int64)(c).Add(i)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Snapshot returns a read-only copy of the counter.
|
// Snapshot returns a read-only copy of the counter.
|
||||||
func (c *StandardCounter) Snapshot() Counter {
|
func (c *StandardCounter) Snapshot() CounterSnapshot {
|
||||||
return CounterSnapshot(c.Count())
|
return counterSnapshot((*atomic.Int64)(c).Load())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,13 +5,16 @@ import (
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type CounterFloat64Snapshot interface {
|
||||||
|
Count() float64
|
||||||
|
}
|
||||||
|
|
||||||
// CounterFloat64 holds a float64 value that can be incremented and decremented.
|
// CounterFloat64 holds a float64 value that can be incremented and decremented.
|
||||||
type CounterFloat64 interface {
|
type CounterFloat64 interface {
|
||||||
Clear()
|
Clear()
|
||||||
Count() float64
|
|
||||||
Dec(float64)
|
Dec(float64)
|
||||||
Inc(float64)
|
Inc(float64)
|
||||||
Snapshot() CounterFloat64
|
Snapshot() CounterFloat64Snapshot
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetOrRegisterCounterFloat64 returns an existing CounterFloat64 or constructs and registers
|
// GetOrRegisterCounterFloat64 returns an existing CounterFloat64 or constructs and registers
|
||||||
|
|
@ -71,47 +74,19 @@ func NewRegisteredCounterFloat64Forced(name string, r Registry) CounterFloat64 {
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
// CounterFloat64Snapshot is a read-only copy of another CounterFloat64.
|
// counterFloat64Snapshot is a read-only copy of another CounterFloat64.
|
||||||
type CounterFloat64Snapshot float64
|
type counterFloat64Snapshot float64
|
||||||
|
|
||||||
// Clear panics.
|
|
||||||
func (CounterFloat64Snapshot) Clear() {
|
|
||||||
panic("Clear called on a CounterFloat64Snapshot")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Count returns the value at the time the snapshot was taken.
|
// Count returns the value at the time the snapshot was taken.
|
||||||
func (c CounterFloat64Snapshot) Count() float64 { return float64(c) }
|
func (c counterFloat64Snapshot) Count() float64 { return float64(c) }
|
||||||
|
|
||||||
// Dec panics.
|
|
||||||
func (CounterFloat64Snapshot) Dec(float64) {
|
|
||||||
panic("Dec called on a CounterFloat64Snapshot")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Inc panics.
|
|
||||||
func (CounterFloat64Snapshot) Inc(float64) {
|
|
||||||
panic("Inc called on a CounterFloat64Snapshot")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Snapshot returns the snapshot.
|
|
||||||
func (c CounterFloat64Snapshot) Snapshot() CounterFloat64 { return c }
|
|
||||||
|
|
||||||
// NilCounterFloat64 is a no-op CounterFloat64.
|
|
||||||
type NilCounterFloat64 struct{}
|
type NilCounterFloat64 struct{}
|
||||||
|
|
||||||
// Clear is a no-op.
|
|
||||||
func (NilCounterFloat64) Clear() {}
|
func (NilCounterFloat64) Clear() {}
|
||||||
|
|
||||||
// Count is a no-op.
|
|
||||||
func (NilCounterFloat64) Count() float64 { return 0.0 }
|
func (NilCounterFloat64) Count() float64 { return 0.0 }
|
||||||
|
|
||||||
// Dec is a no-op.
|
|
||||||
func (NilCounterFloat64) Dec(i float64) {}
|
func (NilCounterFloat64) Dec(i float64) {}
|
||||||
|
|
||||||
// Inc is a no-op.
|
|
||||||
func (NilCounterFloat64) Inc(i float64) {}
|
func (NilCounterFloat64) Inc(i float64) {}
|
||||||
|
func (NilCounterFloat64) Snapshot() CounterFloat64Snapshot { return NilCounterFloat64{} }
|
||||||
// Snapshot is a no-op.
|
|
||||||
func (NilCounterFloat64) Snapshot() CounterFloat64 { return NilCounterFloat64{} }
|
|
||||||
|
|
||||||
// StandardCounterFloat64 is the standard implementation of a CounterFloat64 and uses the
|
// StandardCounterFloat64 is the standard implementation of a CounterFloat64 and uses the
|
||||||
// atomic to manage a single float64 value.
|
// atomic to manage a single float64 value.
|
||||||
|
|
@ -124,11 +99,6 @@ func (c *StandardCounterFloat64) Clear() {
|
||||||
c.floatBits.Store(0)
|
c.floatBits.Store(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Count returns the current value.
|
|
||||||
func (c *StandardCounterFloat64) Count() float64 {
|
|
||||||
return math.Float64frombits(c.floatBits.Load())
|
|
||||||
}
|
|
||||||
|
|
||||||
// Dec decrements the counter by the given amount.
|
// Dec decrements the counter by the given amount.
|
||||||
func (c *StandardCounterFloat64) Dec(v float64) {
|
func (c *StandardCounterFloat64) Dec(v float64) {
|
||||||
atomicAddFloat(&c.floatBits, -v)
|
atomicAddFloat(&c.floatBits, -v)
|
||||||
|
|
@ -140,8 +110,9 @@ func (c *StandardCounterFloat64) Inc(v float64) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Snapshot returns a read-only copy of the counter.
|
// Snapshot returns a read-only copy of the counter.
|
||||||
func (c *StandardCounterFloat64) Snapshot() CounterFloat64 {
|
func (c *StandardCounterFloat64) Snapshot() CounterFloat64Snapshot {
|
||||||
return CounterFloat64Snapshot(c.Count())
|
v := math.Float64frombits(c.floatBits.Load())
|
||||||
|
return counterFloat64Snapshot(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
func atomicAddFloat(fbits *atomic.Uint64, v float64) {
|
func atomicAddFloat(fbits *atomic.Uint64, v float64) {
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ func BenchmarkCounterFloat64Parallel(b *testing.B) {
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
if have, want := c.Count(), 10.0*float64(b.N); have != want {
|
if have, want := c.Snapshot().Count(), 10.0*float64(b.N); have != want {
|
||||||
b.Fatalf("have %f want %f", have, want)
|
b.Fatalf("have %f want %f", have, want)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -36,7 +36,7 @@ func TestCounterFloat64Clear(t *testing.T) {
|
||||||
c := NewCounterFloat64()
|
c := NewCounterFloat64()
|
||||||
c.Inc(1.0)
|
c.Inc(1.0)
|
||||||
c.Clear()
|
c.Clear()
|
||||||
if count := c.Count(); count != 0 {
|
if count := c.Snapshot().Count(); count != 0 {
|
||||||
t.Errorf("c.Count(): 0 != %v\n", count)
|
t.Errorf("c.Count(): 0 != %v\n", count)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -44,7 +44,7 @@ func TestCounterFloat64Clear(t *testing.T) {
|
||||||
func TestCounterFloat64Dec1(t *testing.T) {
|
func TestCounterFloat64Dec1(t *testing.T) {
|
||||||
c := NewCounterFloat64()
|
c := NewCounterFloat64()
|
||||||
c.Dec(1.0)
|
c.Dec(1.0)
|
||||||
if count := c.Count(); count != -1.0 {
|
if count := c.Snapshot().Count(); count != -1.0 {
|
||||||
t.Errorf("c.Count(): -1.0 != %v\n", count)
|
t.Errorf("c.Count(): -1.0 != %v\n", count)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -52,7 +52,7 @@ func TestCounterFloat64Dec1(t *testing.T) {
|
||||||
func TestCounterFloat64Dec2(t *testing.T) {
|
func TestCounterFloat64Dec2(t *testing.T) {
|
||||||
c := NewCounterFloat64()
|
c := NewCounterFloat64()
|
||||||
c.Dec(2.0)
|
c.Dec(2.0)
|
||||||
if count := c.Count(); count != -2.0 {
|
if count := c.Snapshot().Count(); count != -2.0 {
|
||||||
t.Errorf("c.Count(): -2.0 != %v\n", count)
|
t.Errorf("c.Count(): -2.0 != %v\n", count)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -60,7 +60,7 @@ func TestCounterFloat64Dec2(t *testing.T) {
|
||||||
func TestCounterFloat64Inc1(t *testing.T) {
|
func TestCounterFloat64Inc1(t *testing.T) {
|
||||||
c := NewCounterFloat64()
|
c := NewCounterFloat64()
|
||||||
c.Inc(1.0)
|
c.Inc(1.0)
|
||||||
if count := c.Count(); count != 1.0 {
|
if count := c.Snapshot().Count(); count != 1.0 {
|
||||||
t.Errorf("c.Count(): 1.0 != %v\n", count)
|
t.Errorf("c.Count(): 1.0 != %v\n", count)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -68,7 +68,7 @@ func TestCounterFloat64Inc1(t *testing.T) {
|
||||||
func TestCounterFloat64Inc2(t *testing.T) {
|
func TestCounterFloat64Inc2(t *testing.T) {
|
||||||
c := NewCounterFloat64()
|
c := NewCounterFloat64()
|
||||||
c.Inc(2.0)
|
c.Inc(2.0)
|
||||||
if count := c.Count(); count != 2.0 {
|
if count := c.Snapshot().Count(); count != 2.0 {
|
||||||
t.Errorf("c.Count(): 2.0 != %v\n", count)
|
t.Errorf("c.Count(): 2.0 != %v\n", count)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -85,7 +85,7 @@ func TestCounterFloat64Snapshot(t *testing.T) {
|
||||||
|
|
||||||
func TestCounterFloat64Zero(t *testing.T) {
|
func TestCounterFloat64Zero(t *testing.T) {
|
||||||
c := NewCounterFloat64()
|
c := NewCounterFloat64()
|
||||||
if count := c.Count(); count != 0 {
|
if count := c.Snapshot().Count(); count != 0 {
|
||||||
t.Errorf("c.Count(): 0 != %v\n", count)
|
t.Errorf("c.Count(): 0 != %v\n", count)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -93,7 +93,7 @@ func TestCounterFloat64Zero(t *testing.T) {
|
||||||
func TestGetOrRegisterCounterFloat64(t *testing.T) {
|
func TestGetOrRegisterCounterFloat64(t *testing.T) {
|
||||||
r := NewRegistry()
|
r := NewRegistry()
|
||||||
NewRegisteredCounterFloat64("foo", r).Inc(47.0)
|
NewRegisteredCounterFloat64("foo", r).Inc(47.0)
|
||||||
if c := GetOrRegisterCounterFloat64("foo", r); c.Count() != 47.0 {
|
if c := GetOrRegisterCounterFloat64("foo", r).Snapshot(); c.Count() != 47.0 {
|
||||||
t.Fatal(c)
|
t.Fatal(c)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ func TestCounterClear(t *testing.T) {
|
||||||
c := NewCounter()
|
c := NewCounter()
|
||||||
c.Inc(1)
|
c.Inc(1)
|
||||||
c.Clear()
|
c.Clear()
|
||||||
if count := c.Count(); count != 0 {
|
if count := c.Snapshot().Count(); count != 0 {
|
||||||
t.Errorf("c.Count(): 0 != %v\n", count)
|
t.Errorf("c.Count(): 0 != %v\n", count)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -22,7 +22,7 @@ func TestCounterClear(t *testing.T) {
|
||||||
func TestCounterDec1(t *testing.T) {
|
func TestCounterDec1(t *testing.T) {
|
||||||
c := NewCounter()
|
c := NewCounter()
|
||||||
c.Dec(1)
|
c.Dec(1)
|
||||||
if count := c.Count(); count != -1 {
|
if count := c.Snapshot().Count(); count != -1 {
|
||||||
t.Errorf("c.Count(): -1 != %v\n", count)
|
t.Errorf("c.Count(): -1 != %v\n", count)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -30,7 +30,7 @@ func TestCounterDec1(t *testing.T) {
|
||||||
func TestCounterDec2(t *testing.T) {
|
func TestCounterDec2(t *testing.T) {
|
||||||
c := NewCounter()
|
c := NewCounter()
|
||||||
c.Dec(2)
|
c.Dec(2)
|
||||||
if count := c.Count(); count != -2 {
|
if count := c.Snapshot().Count(); count != -2 {
|
||||||
t.Errorf("c.Count(): -2 != %v\n", count)
|
t.Errorf("c.Count(): -2 != %v\n", count)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -38,7 +38,7 @@ func TestCounterDec2(t *testing.T) {
|
||||||
func TestCounterInc1(t *testing.T) {
|
func TestCounterInc1(t *testing.T) {
|
||||||
c := NewCounter()
|
c := NewCounter()
|
||||||
c.Inc(1)
|
c.Inc(1)
|
||||||
if count := c.Count(); count != 1 {
|
if count := c.Snapshot().Count(); count != 1 {
|
||||||
t.Errorf("c.Count(): 1 != %v\n", count)
|
t.Errorf("c.Count(): 1 != %v\n", count)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -46,7 +46,7 @@ func TestCounterInc1(t *testing.T) {
|
||||||
func TestCounterInc2(t *testing.T) {
|
func TestCounterInc2(t *testing.T) {
|
||||||
c := NewCounter()
|
c := NewCounter()
|
||||||
c.Inc(2)
|
c.Inc(2)
|
||||||
if count := c.Count(); count != 2 {
|
if count := c.Snapshot().Count(); count != 2 {
|
||||||
t.Errorf("c.Count(): 2 != %v\n", count)
|
t.Errorf("c.Count(): 2 != %v\n", count)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -63,7 +63,7 @@ func TestCounterSnapshot(t *testing.T) {
|
||||||
|
|
||||||
func TestCounterZero(t *testing.T) {
|
func TestCounterZero(t *testing.T) {
|
||||||
c := NewCounter()
|
c := NewCounter()
|
||||||
if count := c.Count(); count != 0 {
|
if count := c.Snapshot().Count(); count != 0 {
|
||||||
t.Errorf("c.Count(): 0 != %v\n", count)
|
t.Errorf("c.Count(): 0 != %v\n", count)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -71,7 +71,7 @@ func TestCounterZero(t *testing.T) {
|
||||||
func TestGetOrRegisterCounter(t *testing.T) {
|
func TestGetOrRegisterCounter(t *testing.T) {
|
||||||
r := NewRegistry()
|
r := NewRegistry()
|
||||||
NewRegisteredCounter("foo", r).Inc(47)
|
NewRegisteredCounter("foo", r).Inc(47)
|
||||||
if c := GetOrRegisterCounter("foo", r); c.Count() != 47 {
|
if c := GetOrRegisterCounter("foo", r).Snapshot(); c.Count() != 47 {
|
||||||
t.Fatal(c)
|
t.Fatal(c)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
package metrics
|
|
||||||
|
|
||||||
const epsilon = 0.0000000000000001
|
|
||||||
const epsilonPercentile = .00000000001
|
|
||||||
|
|
@ -7,11 +7,14 @@ import (
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type EWMASnapshot interface {
|
||||||
|
Rate() float64
|
||||||
|
}
|
||||||
|
|
||||||
// EWMAs continuously calculate an exponentially-weighted moving average
|
// EWMAs continuously calculate an exponentially-weighted moving average
|
||||||
// based on an outside source of clock ticks.
|
// based on an outside source of clock ticks.
|
||||||
type EWMA interface {
|
type EWMA interface {
|
||||||
Rate() float64
|
Snapshot() EWMASnapshot
|
||||||
Snapshot() EWMA
|
|
||||||
Tick()
|
Tick()
|
||||||
Update(int64)
|
Update(int64)
|
||||||
}
|
}
|
||||||
|
|
@ -36,39 +39,18 @@ func NewEWMA15() EWMA {
|
||||||
return NewEWMA(1 - math.Exp(-5.0/60.0/15))
|
return NewEWMA(1 - math.Exp(-5.0/60.0/15))
|
||||||
}
|
}
|
||||||
|
|
||||||
// EWMASnapshot is a read-only copy of another EWMA.
|
// ewmaSnapshot is a read-only copy of another EWMA.
|
||||||
type EWMASnapshot float64
|
type ewmaSnapshot float64
|
||||||
|
|
||||||
// Rate returns the rate of events per second at the time the snapshot was
|
// Rate returns the rate of events per second at the time the snapshot was
|
||||||
// taken.
|
// taken.
|
||||||
func (a EWMASnapshot) Rate() float64 { return float64(a) }
|
func (a ewmaSnapshot) Rate() float64 { return float64(a) }
|
||||||
|
|
||||||
// Snapshot returns the snapshot.
|
|
||||||
func (a EWMASnapshot) Snapshot() EWMA { return a }
|
|
||||||
|
|
||||||
// Tick panics.
|
|
||||||
func (EWMASnapshot) Tick() {
|
|
||||||
panic("Tick called on an EWMASnapshot")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update panics.
|
|
||||||
func (EWMASnapshot) Update(int64) {
|
|
||||||
panic("Update called on an EWMASnapshot")
|
|
||||||
}
|
|
||||||
|
|
||||||
// NilEWMA is a no-op EWMA.
|
// NilEWMA is a no-op EWMA.
|
||||||
type NilEWMA struct{}
|
type NilEWMA struct{}
|
||||||
|
|
||||||
// Rate is a no-op.
|
func (NilEWMA) Snapshot() EWMASnapshot { return (*emptySnapshot)(nil) }
|
||||||
func (NilEWMA) Rate() float64 { return 0.0 }
|
|
||||||
|
|
||||||
// Snapshot is a no-op.
|
|
||||||
func (NilEWMA) Snapshot() EWMA { return NilEWMA{} }
|
|
||||||
|
|
||||||
// Tick is a no-op.
|
|
||||||
func (NilEWMA) Tick() {}
|
func (NilEWMA) Tick() {}
|
||||||
|
|
||||||
// Update is a no-op.
|
|
||||||
func (NilEWMA) Update(n int64) {}
|
func (NilEWMA) Update(n int64) {}
|
||||||
|
|
||||||
// StandardEWMA is the standard implementation of an EWMA and tracks the number
|
// StandardEWMA is the standard implementation of an EWMA and tracks the number
|
||||||
|
|
@ -77,37 +59,50 @@ func (NilEWMA) Update(n int64) {}
|
||||||
type StandardEWMA struct {
|
type StandardEWMA struct {
|
||||||
uncounted atomic.Int64
|
uncounted atomic.Int64
|
||||||
alpha float64
|
alpha float64
|
||||||
rate float64
|
rate atomic.Uint64
|
||||||
init bool
|
init atomic.Bool
|
||||||
mutex sync.Mutex
|
mutex sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rate returns the moving average rate of events per second.
|
|
||||||
func (a *StandardEWMA) Rate() float64 {
|
|
||||||
a.mutex.Lock()
|
|
||||||
defer a.mutex.Unlock()
|
|
||||||
return a.rate * float64(time.Second)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Snapshot returns a read-only copy of the EWMA.
|
// Snapshot returns a read-only copy of the EWMA.
|
||||||
func (a *StandardEWMA) Snapshot() EWMA {
|
func (a *StandardEWMA) Snapshot() EWMASnapshot {
|
||||||
return EWMASnapshot(a.Rate())
|
r := math.Float64frombits(a.rate.Load()) * float64(time.Second)
|
||||||
|
return ewmaSnapshot(r)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tick ticks the clock to update the moving average. It assumes it is called
|
// Tick ticks the clock to update the moving average. It assumes it is called
|
||||||
// every five seconds.
|
// every five seconds.
|
||||||
func (a *StandardEWMA) Tick() {
|
func (a *StandardEWMA) Tick() {
|
||||||
count := a.uncounted.Load()
|
// Optimization to avoid mutex locking in the hot-path.
|
||||||
a.uncounted.Add(-count)
|
if a.init.Load() {
|
||||||
instantRate := float64(count) / float64(5*time.Second)
|
a.updateRate(a.fetchInstantRate())
|
||||||
a.mutex.Lock()
|
return
|
||||||
defer a.mutex.Unlock()
|
|
||||||
if a.init {
|
|
||||||
a.rate += a.alpha * (instantRate - a.rate)
|
|
||||||
} else {
|
|
||||||
a.init = true
|
|
||||||
a.rate = instantRate
|
|
||||||
}
|
}
|
||||||
|
// Slow-path: this is only needed on the first Tick() and preserves transactional updating
|
||||||
|
// of init and rate in the else block. The first conditional is needed below because
|
||||||
|
// a different thread could have set a.init = 1 between the time of the first atomic load and when
|
||||||
|
// the lock was acquired.
|
||||||
|
a.mutex.Lock()
|
||||||
|
if a.init.Load() {
|
||||||
|
// The fetchInstantRate() uses atomic loading, which is unnecessary in this critical section
|
||||||
|
// but again, this section is only invoked on the first successful Tick() operation.
|
||||||
|
a.updateRate(a.fetchInstantRate())
|
||||||
|
} else {
|
||||||
|
a.init.Store(true)
|
||||||
|
a.rate.Store(math.Float64bits(a.fetchInstantRate()))
|
||||||
|
}
|
||||||
|
a.mutex.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *StandardEWMA) fetchInstantRate() float64 {
|
||||||
|
count := a.uncounted.Swap(0)
|
||||||
|
return float64(count) / float64(5*time.Second)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *StandardEWMA) updateRate(instantRate float64) {
|
||||||
|
currentRate := math.Float64frombits(a.rate.Load())
|
||||||
|
currentRate += a.alpha * (instantRate - currentRate)
|
||||||
|
a.rate.Store(math.Float64bits(currentRate))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update adds n uncounted events.
|
// Update adds n uncounted events.
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,8 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const epsilon = 0.0000000000000001
|
||||||
|
|
||||||
func BenchmarkEWMA(b *testing.B) {
|
func BenchmarkEWMA(b *testing.B) {
|
||||||
a := NewEWMA1()
|
a := NewEWMA1()
|
||||||
b.ResetTimer()
|
b.ResetTimer()
|
||||||
|
|
@ -14,72 +16,33 @@ func BenchmarkEWMA(b *testing.B) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func BenchmarkEWMAParallel(b *testing.B) {
|
||||||
|
a := NewEWMA1()
|
||||||
|
b.ResetTimer()
|
||||||
|
|
||||||
|
b.RunParallel(func(pb *testing.PB) {
|
||||||
|
for pb.Next() {
|
||||||
|
a.Update(1)
|
||||||
|
a.Tick()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func TestEWMA1(t *testing.T) {
|
func TestEWMA1(t *testing.T) {
|
||||||
a := NewEWMA1()
|
a := NewEWMA1()
|
||||||
a.Update(3)
|
a.Update(3)
|
||||||
a.Tick()
|
a.Tick()
|
||||||
if rate := a.Rate(); math.Abs(0.6-rate) > epsilon {
|
for i, want := range []float64{0.6,
|
||||||
t.Errorf("initial a.Rate(): 0.6 != %v\n", rate)
|
0.22072766470286553, 0.08120116994196772, 0.029872241020718428,
|
||||||
|
0.01098938333324054, 0.004042768199451294, 0.0014872513059998212,
|
||||||
|
0.0005471291793327122, 0.00020127757674150815, 7.404588245200814e-05,
|
||||||
|
2.7239957857491083e-05, 1.0021020474147462e-05, 3.6865274119969525e-06,
|
||||||
|
1.3561976441886433e-06, 4.989172314621449e-07, 1.8354139230109722e-07,
|
||||||
|
} {
|
||||||
|
if rate := a.Snapshot().Rate(); math.Abs(want-rate) > epsilon {
|
||||||
|
t.Errorf("%d minute a.Snapshot().Rate(): %f != %v\n", i, want, rate)
|
||||||
}
|
}
|
||||||
elapseMinute(a)
|
elapseMinute(a)
|
||||||
if rate := a.Rate(); math.Abs(0.22072766470286553-rate) > epsilon {
|
|
||||||
t.Errorf("1 minute a.Rate(): 0.22072766470286553 != %v\n", rate)
|
|
||||||
}
|
|
||||||
elapseMinute(a)
|
|
||||||
if rate := a.Rate(); math.Abs(0.08120116994196772-rate) > epsilon {
|
|
||||||
t.Errorf("2 minute a.Rate(): 0.08120116994196772 != %v\n", rate)
|
|
||||||
}
|
|
||||||
elapseMinute(a)
|
|
||||||
if rate := a.Rate(); math.Abs(0.029872241020718428-rate) > epsilon {
|
|
||||||
t.Errorf("3 minute a.Rate(): 0.029872241020718428 != %v\n", rate)
|
|
||||||
}
|
|
||||||
elapseMinute(a)
|
|
||||||
if rate := a.Rate(); math.Abs(0.01098938333324054-rate) > epsilon {
|
|
||||||
t.Errorf("4 minute a.Rate(): 0.01098938333324054 != %v\n", rate)
|
|
||||||
}
|
|
||||||
elapseMinute(a)
|
|
||||||
if rate := a.Rate(); math.Abs(0.004042768199451294-rate) > epsilon {
|
|
||||||
t.Errorf("5 minute a.Rate(): 0.004042768199451294 != %v\n", rate)
|
|
||||||
}
|
|
||||||
elapseMinute(a)
|
|
||||||
if rate := a.Rate(); math.Abs(0.0014872513059998212-rate) > epsilon {
|
|
||||||
t.Errorf("6 minute a.Rate(): 0.0014872513059998212 != %v\n", rate)
|
|
||||||
}
|
|
||||||
elapseMinute(a)
|
|
||||||
if rate := a.Rate(); math.Abs(0.0005471291793327122-rate) > epsilon {
|
|
||||||
t.Errorf("7 minute a.Rate(): 0.0005471291793327122 != %v\n", rate)
|
|
||||||
}
|
|
||||||
elapseMinute(a)
|
|
||||||
if rate := a.Rate(); math.Abs(0.00020127757674150815-rate) > epsilon {
|
|
||||||
t.Errorf("8 minute a.Rate(): 0.00020127757674150815 != %v\n", rate)
|
|
||||||
}
|
|
||||||
elapseMinute(a)
|
|
||||||
if rate := a.Rate(); math.Abs(7.404588245200814e-05-rate) > epsilon {
|
|
||||||
t.Errorf("9 minute a.Rate(): 7.404588245200814e-05 != %v\n", rate)
|
|
||||||
}
|
|
||||||
elapseMinute(a)
|
|
||||||
if rate := a.Rate(); math.Abs(2.7239957857491083e-05-rate) > epsilon {
|
|
||||||
t.Errorf("10 minute a.Rate(): 2.7239957857491083e-05 != %v\n", rate)
|
|
||||||
}
|
|
||||||
elapseMinute(a)
|
|
||||||
if rate := a.Rate(); math.Abs(1.0021020474147462e-05-rate) > epsilon {
|
|
||||||
t.Errorf("11 minute a.Rate(): 1.0021020474147462e-05 != %v\n", rate)
|
|
||||||
}
|
|
||||||
elapseMinute(a)
|
|
||||||
if rate := a.Rate(); math.Abs(3.6865274119969525e-06-rate) > epsilon {
|
|
||||||
t.Errorf("12 minute a.Rate(): 3.6865274119969525e-06 != %v\n", rate)
|
|
||||||
}
|
|
||||||
elapseMinute(a)
|
|
||||||
if rate := a.Rate(); math.Abs(1.3561976441886433e-06-rate) > epsilon {
|
|
||||||
t.Errorf("13 minute a.Rate(): 1.3561976441886433e-06 != %v\n", rate)
|
|
||||||
}
|
|
||||||
elapseMinute(a)
|
|
||||||
if rate := a.Rate(); math.Abs(4.989172314621449e-07-rate) > epsilon {
|
|
||||||
t.Errorf("14 minute a.Rate(): 4.989172314621449e-07 != %v\n", rate)
|
|
||||||
}
|
|
||||||
elapseMinute(a)
|
|
||||||
if rate := a.Rate(); math.Abs(1.8354139230109722e-07-rate) > epsilon {
|
|
||||||
t.Errorf("15 minute a.Rate(): 1.8354139230109722e-07 != %v\n", rate)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -87,68 +50,17 @@ func TestEWMA5(t *testing.T) {
|
||||||
a := NewEWMA5()
|
a := NewEWMA5()
|
||||||
a.Update(3)
|
a.Update(3)
|
||||||
a.Tick()
|
a.Tick()
|
||||||
if rate := a.Rate(); math.Abs(0.6-rate) > epsilon {
|
for i, want := range []float64{
|
||||||
t.Errorf("initial a.Rate(): 0.6 != %v\n", rate)
|
0.6, 0.49123845184678905, 0.4021920276213837, 0.32928698165641596,
|
||||||
|
0.269597378470333, 0.2207276647028654, 0.18071652714732128,
|
||||||
|
0.14795817836496392, 0.12113791079679326, 0.09917933293295193,
|
||||||
|
0.08120116994196763, 0.06648189501740036, 0.05443077197364752,
|
||||||
|
0.04456414692860035, 0.03648603757513079, 0.0298722410207183831020718428,
|
||||||
|
} {
|
||||||
|
if rate := a.Snapshot().Rate(); math.Abs(want-rate) > epsilon {
|
||||||
|
t.Errorf("%d minute a.Snapshot().Rate(): %f != %v\n", i, want, rate)
|
||||||
}
|
}
|
||||||
elapseMinute(a)
|
elapseMinute(a)
|
||||||
if rate := a.Rate(); math.Abs(0.49123845184678905-rate) > epsilon {
|
|
||||||
t.Errorf("1 minute a.Rate(): 0.49123845184678905 != %v\n", rate)
|
|
||||||
}
|
|
||||||
elapseMinute(a)
|
|
||||||
if rate := a.Rate(); math.Abs(0.4021920276213837-rate) > epsilon {
|
|
||||||
t.Errorf("2 minute a.Rate(): 0.4021920276213837 != %v\n", rate)
|
|
||||||
}
|
|
||||||
elapseMinute(a)
|
|
||||||
if rate := a.Rate(); math.Abs(0.32928698165641596-rate) > epsilon {
|
|
||||||
t.Errorf("3 minute a.Rate(): 0.32928698165641596 != %v\n", rate)
|
|
||||||
}
|
|
||||||
elapseMinute(a)
|
|
||||||
if rate := a.Rate(); math.Abs(0.269597378470333-rate) > epsilon {
|
|
||||||
t.Errorf("4 minute a.Rate(): 0.269597378470333 != %v\n", rate)
|
|
||||||
}
|
|
||||||
elapseMinute(a)
|
|
||||||
if rate := a.Rate(); math.Abs(0.2207276647028654-rate) > epsilon {
|
|
||||||
t.Errorf("5 minute a.Rate(): 0.2207276647028654 != %v\n", rate)
|
|
||||||
}
|
|
||||||
elapseMinute(a)
|
|
||||||
if rate := a.Rate(); math.Abs(0.18071652714732128-rate) > epsilon {
|
|
||||||
t.Errorf("6 minute a.Rate(): 0.18071652714732128 != %v\n", rate)
|
|
||||||
}
|
|
||||||
elapseMinute(a)
|
|
||||||
if rate := a.Rate(); math.Abs(0.14795817836496392-rate) > epsilon {
|
|
||||||
t.Errorf("7 minute a.Rate(): 0.14795817836496392 != %v\n", rate)
|
|
||||||
}
|
|
||||||
elapseMinute(a)
|
|
||||||
if rate := a.Rate(); math.Abs(0.12113791079679326-rate) > epsilon {
|
|
||||||
t.Errorf("8 minute a.Rate(): 0.12113791079679326 != %v\n", rate)
|
|
||||||
}
|
|
||||||
elapseMinute(a)
|
|
||||||
if rate := a.Rate(); math.Abs(0.09917933293295193-rate) > epsilon {
|
|
||||||
t.Errorf("9 minute a.Rate(): 0.09917933293295193 != %v\n", rate)
|
|
||||||
}
|
|
||||||
elapseMinute(a)
|
|
||||||
if rate := a.Rate(); math.Abs(0.08120116994196763-rate) > epsilon {
|
|
||||||
t.Errorf("10 minute a.Rate(): 0.08120116994196763 != %v\n", rate)
|
|
||||||
}
|
|
||||||
elapseMinute(a)
|
|
||||||
if rate := a.Rate(); math.Abs(0.06648189501740036-rate) > epsilon {
|
|
||||||
t.Errorf("11 minute a.Rate(): 0.06648189501740036 != %v\n", rate)
|
|
||||||
}
|
|
||||||
elapseMinute(a)
|
|
||||||
if rate := a.Rate(); math.Abs(0.05443077197364752-rate) > epsilon {
|
|
||||||
t.Errorf("12 minute a.Rate(): 0.05443077197364752 != %v\n", rate)
|
|
||||||
}
|
|
||||||
elapseMinute(a)
|
|
||||||
if rate := a.Rate(); math.Abs(0.04456414692860035-rate) > epsilon {
|
|
||||||
t.Errorf("13 minute a.Rate(): 0.04456414692860035 != %v\n", rate)
|
|
||||||
}
|
|
||||||
elapseMinute(a)
|
|
||||||
if rate := a.Rate(); math.Abs(0.03648603757513079-rate) > epsilon {
|
|
||||||
t.Errorf("14 minute a.Rate(): 0.03648603757513079 != %v\n", rate)
|
|
||||||
}
|
|
||||||
elapseMinute(a)
|
|
||||||
if rate := a.Rate(); math.Abs(0.0298722410207183831020718428-rate) > epsilon {
|
|
||||||
t.Errorf("15 minute a.Rate(): 0.0298722410207183831020718428 != %v\n", rate)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -156,68 +68,17 @@ func TestEWMA15(t *testing.T) {
|
||||||
a := NewEWMA15()
|
a := NewEWMA15()
|
||||||
a.Update(3)
|
a.Update(3)
|
||||||
a.Tick()
|
a.Tick()
|
||||||
if rate := a.Rate(); math.Abs(0.6-rate) > epsilon {
|
for i, want := range []float64{
|
||||||
t.Errorf("initial a.Rate(): 0.6 != %v\n", rate)
|
0.6, 0.5613041910189706, 0.5251039914257684, 0.4912384518467888184678905,
|
||||||
|
0.459557003018789, 0.4299187863442732, 0.4021920276213831,
|
||||||
|
0.37625345116383313, 0.3519877317060185, 0.3292869816564153165641596,
|
||||||
|
0.3080502714195546, 0.2881831806538789, 0.26959737847033216,
|
||||||
|
0.2522102307052083, 0.23594443252115815, 0.2207276647028646247028654470286553,
|
||||||
|
} {
|
||||||
|
if rate := a.Snapshot().Rate(); math.Abs(want-rate) > epsilon {
|
||||||
|
t.Errorf("%d minute a.Snapshot().Rate(): %f != %v\n", i, want, rate)
|
||||||
}
|
}
|
||||||
elapseMinute(a)
|
elapseMinute(a)
|
||||||
if rate := a.Rate(); math.Abs(0.5613041910189706-rate) > epsilon {
|
|
||||||
t.Errorf("1 minute a.Rate(): 0.5613041910189706 != %v\n", rate)
|
|
||||||
}
|
|
||||||
elapseMinute(a)
|
|
||||||
if rate := a.Rate(); math.Abs(0.5251039914257684-rate) > epsilon {
|
|
||||||
t.Errorf("2 minute a.Rate(): 0.5251039914257684 != %v\n", rate)
|
|
||||||
}
|
|
||||||
elapseMinute(a)
|
|
||||||
if rate := a.Rate(); math.Abs(0.4912384518467888184678905-rate) > epsilon {
|
|
||||||
t.Errorf("3 minute a.Rate(): 0.4912384518467888184678905 != %v\n", rate)
|
|
||||||
}
|
|
||||||
elapseMinute(a)
|
|
||||||
if rate := a.Rate(); math.Abs(0.459557003018789-rate) > epsilon {
|
|
||||||
t.Errorf("4 minute a.Rate(): 0.459557003018789 != %v\n", rate)
|
|
||||||
}
|
|
||||||
elapseMinute(a)
|
|
||||||
if rate := a.Rate(); math.Abs(0.4299187863442732-rate) > epsilon {
|
|
||||||
t.Errorf("5 minute a.Rate(): 0.4299187863442732 != %v\n", rate)
|
|
||||||
}
|
|
||||||
elapseMinute(a)
|
|
||||||
if rate := a.Rate(); math.Abs(0.4021920276213831-rate) > epsilon {
|
|
||||||
t.Errorf("6 minute a.Rate(): 0.4021920276213831 != %v\n", rate)
|
|
||||||
}
|
|
||||||
elapseMinute(a)
|
|
||||||
if rate := a.Rate(); math.Abs(0.37625345116383313-rate) > epsilon {
|
|
||||||
t.Errorf("7 minute a.Rate(): 0.37625345116383313 != %v\n", rate)
|
|
||||||
}
|
|
||||||
elapseMinute(a)
|
|
||||||
if rate := a.Rate(); math.Abs(0.3519877317060185-rate) > epsilon {
|
|
||||||
t.Errorf("8 minute a.Rate(): 0.3519877317060185 != %v\n", rate)
|
|
||||||
}
|
|
||||||
elapseMinute(a)
|
|
||||||
if rate := a.Rate(); math.Abs(0.3292869816564153165641596-rate) > epsilon {
|
|
||||||
t.Errorf("9 minute a.Rate(): 0.3292869816564153165641596 != %v\n", rate)
|
|
||||||
}
|
|
||||||
elapseMinute(a)
|
|
||||||
if rate := a.Rate(); math.Abs(0.3080502714195546-rate) > epsilon {
|
|
||||||
t.Errorf("10 minute a.Rate(): 0.3080502714195546 != %v\n", rate)
|
|
||||||
}
|
|
||||||
elapseMinute(a)
|
|
||||||
if rate := a.Rate(); math.Abs(0.2881831806538789-rate) > epsilon {
|
|
||||||
t.Errorf("11 minute a.Rate(): 0.2881831806538789 != %v\n", rate)
|
|
||||||
}
|
|
||||||
elapseMinute(a)
|
|
||||||
if rate := a.Rate(); math.Abs(0.26959737847033216-rate) > epsilon {
|
|
||||||
t.Errorf("12 minute a.Rate(): 0.26959737847033216 != %v\n", rate)
|
|
||||||
}
|
|
||||||
elapseMinute(a)
|
|
||||||
if rate := a.Rate(); math.Abs(0.2522102307052083-rate) > epsilon {
|
|
||||||
t.Errorf("13 minute a.Rate(): 0.2522102307052083 != %v\n", rate)
|
|
||||||
}
|
|
||||||
elapseMinute(a)
|
|
||||||
if rate := a.Rate(); math.Abs(0.23594443252115815-rate) > epsilon {
|
|
||||||
t.Errorf("14 minute a.Rate(): 0.23594443252115815 != %v\n", rate)
|
|
||||||
}
|
|
||||||
elapseMinute(a)
|
|
||||||
if rate := a.Rate(); math.Abs(0.2207276647028646247028654470286553-rate) > epsilon {
|
|
||||||
t.Errorf("15 minute a.Rate(): 0.2207276647028646247028654470286553 != %v\n", rate)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -109,25 +109,25 @@ func (exp *exp) getInfo(name string) *expvar.String {
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
func (exp *exp) publishCounter(name string, metric metrics.Counter) {
|
func (exp *exp) publishCounter(name string, metric metrics.CounterSnapshot) {
|
||||||
v := exp.getInt(name)
|
v := exp.getInt(name)
|
||||||
v.Set(metric.Count())
|
v.Set(metric.Count())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (exp *exp) publishCounterFloat64(name string, metric metrics.CounterFloat64) {
|
func (exp *exp) publishCounterFloat64(name string, metric metrics.CounterFloat64Snapshot) {
|
||||||
v := exp.getFloat(name)
|
v := exp.getFloat(name)
|
||||||
v.Set(metric.Count())
|
v.Set(metric.Count())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (exp *exp) publishGauge(name string, metric metrics.Gauge) {
|
func (exp *exp) publishGauge(name string, metric metrics.GaugeSnapshot) {
|
||||||
v := exp.getInt(name)
|
v := exp.getInt(name)
|
||||||
v.Set(metric.Value())
|
v.Set(metric.Value())
|
||||||
}
|
}
|
||||||
func (exp *exp) publishGaugeFloat64(name string, metric metrics.GaugeFloat64) {
|
func (exp *exp) publishGaugeFloat64(name string, metric metrics.GaugeFloat64Snapshot) {
|
||||||
exp.getFloat(name).Set(metric.Value())
|
exp.getFloat(name).Set(metric.Value())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (exp *exp) publishGaugeInfo(name string, metric metrics.GaugeInfo) {
|
func (exp *exp) publishGaugeInfo(name string, metric metrics.GaugeInfoSnapshot) {
|
||||||
exp.getInfo(name).Set(metric.Value().String())
|
exp.getInfo(name).Set(metric.Value().String())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -176,28 +176,28 @@ func (exp *exp) publishTimer(name string, metric metrics.Timer) {
|
||||||
|
|
||||||
func (exp *exp) publishResettingTimer(name string, metric metrics.ResettingTimer) {
|
func (exp *exp) publishResettingTimer(name string, metric metrics.ResettingTimer) {
|
||||||
t := metric.Snapshot()
|
t := metric.Snapshot()
|
||||||
ps := t.Percentiles([]float64{50, 75, 95, 99})
|
ps := t.Percentiles([]float64{0.50, 0.75, 0.95, 0.99})
|
||||||
exp.getInt(name + ".count").Set(int64(len(t.Values())))
|
exp.getInt(name + ".count").Set(int64(t.Count()))
|
||||||
exp.getFloat(name + ".mean").Set(t.Mean())
|
exp.getFloat(name + ".mean").Set(t.Mean())
|
||||||
exp.getInt(name + ".50-percentile").Set(ps[0])
|
exp.getFloat(name + ".50-percentile").Set(ps[0])
|
||||||
exp.getInt(name + ".75-percentile").Set(ps[1])
|
exp.getFloat(name + ".75-percentile").Set(ps[1])
|
||||||
exp.getInt(name + ".95-percentile").Set(ps[2])
|
exp.getFloat(name + ".95-percentile").Set(ps[2])
|
||||||
exp.getInt(name + ".99-percentile").Set(ps[3])
|
exp.getFloat(name + ".99-percentile").Set(ps[3])
|
||||||
}
|
}
|
||||||
|
|
||||||
func (exp *exp) syncToExpvar() {
|
func (exp *exp) syncToExpvar() {
|
||||||
exp.registry.Each(func(name string, i interface{}) {
|
exp.registry.Each(func(name string, i interface{}) {
|
||||||
switch i := i.(type) {
|
switch i := i.(type) {
|
||||||
case metrics.Counter:
|
case metrics.Counter:
|
||||||
exp.publishCounter(name, i)
|
exp.publishCounter(name, i.Snapshot())
|
||||||
case metrics.CounterFloat64:
|
case metrics.CounterFloat64:
|
||||||
exp.publishCounterFloat64(name, i)
|
exp.publishCounterFloat64(name, i.Snapshot())
|
||||||
case metrics.Gauge:
|
case metrics.Gauge:
|
||||||
exp.publishGauge(name, i)
|
exp.publishGauge(name, i.Snapshot())
|
||||||
case metrics.GaugeFloat64:
|
case metrics.GaugeFloat64:
|
||||||
exp.publishGaugeFloat64(name, i)
|
exp.publishGaugeFloat64(name, i.Snapshot())
|
||||||
case metrics.GaugeInfo:
|
case metrics.GaugeInfo:
|
||||||
exp.publishGaugeInfo(name, i)
|
exp.publishGaugeInfo(name, i.Snapshot())
|
||||||
case metrics.Histogram:
|
case metrics.Histogram:
|
||||||
exp.publishHistogram(name, i)
|
exp.publishHistogram(name, i)
|
||||||
case metrics.Meter:
|
case metrics.Meter:
|
||||||
|
|
|
||||||
110
metrics/gauge.go
110
metrics/gauge.go
|
|
@ -2,13 +2,18 @@ package metrics
|
||||||
|
|
||||||
import "sync/atomic"
|
import "sync/atomic"
|
||||||
|
|
||||||
|
// gaugeSnapshot contains a readonly int64.
|
||||||
|
type GaugeSnapshot interface {
|
||||||
|
Value() int64
|
||||||
|
}
|
||||||
|
|
||||||
// Gauges hold an int64 value that can be set arbitrarily.
|
// Gauges hold an int64 value that can be set arbitrarily.
|
||||||
type Gauge interface {
|
type Gauge interface {
|
||||||
Snapshot() Gauge
|
Snapshot() GaugeSnapshot
|
||||||
Update(int64)
|
Update(int64)
|
||||||
|
UpdateIfGt(int64)
|
||||||
Dec(int64)
|
Dec(int64)
|
||||||
Inc(int64)
|
Inc(int64)
|
||||||
Value() int64
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetOrRegisterGauge returns an existing Gauge or constructs and registers a
|
// GetOrRegisterGauge returns an existing Gauge or constructs and registers a
|
||||||
|
|
@ -38,66 +43,21 @@ func NewRegisteredGauge(name string, r Registry) Gauge {
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewFunctionalGauge constructs a new FunctionalGauge.
|
// gaugeSnapshot is a read-only copy of another Gauge.
|
||||||
func NewFunctionalGauge(f func() int64) Gauge {
|
type gaugeSnapshot int64
|
||||||
if !Enabled {
|
|
||||||
return NilGauge{}
|
|
||||||
}
|
|
||||||
return &FunctionalGauge{value: f}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewRegisteredFunctionalGauge constructs and registers a new StandardGauge.
|
|
||||||
func NewRegisteredFunctionalGauge(name string, r Registry, f func() int64) Gauge {
|
|
||||||
c := NewFunctionalGauge(f)
|
|
||||||
if nil == r {
|
|
||||||
r = DefaultRegistry
|
|
||||||
}
|
|
||||||
r.Register(name, c)
|
|
||||||
return c
|
|
||||||
}
|
|
||||||
|
|
||||||
// GaugeSnapshot is a read-only copy of another Gauge.
|
|
||||||
type GaugeSnapshot int64
|
|
||||||
|
|
||||||
// Snapshot returns the snapshot.
|
|
||||||
func (g GaugeSnapshot) Snapshot() Gauge { return g }
|
|
||||||
|
|
||||||
// Update panics.
|
|
||||||
func (GaugeSnapshot) Update(int64) {
|
|
||||||
panic("Update called on a GaugeSnapshot")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Dec panics.
|
|
||||||
func (GaugeSnapshot) Dec(int64) {
|
|
||||||
panic("Dec called on a GaugeSnapshot")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Inc panics.
|
|
||||||
func (GaugeSnapshot) Inc(int64) {
|
|
||||||
panic("Inc called on a GaugeSnapshot")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Value returns the value at the time the snapshot was taken.
|
// Value returns the value at the time the snapshot was taken.
|
||||||
func (g GaugeSnapshot) Value() int64 { return int64(g) }
|
func (g gaugeSnapshot) Value() int64 { return int64(g) }
|
||||||
|
|
||||||
// NilGauge is a no-op Gauge.
|
// NilGauge is a no-op Gauge.
|
||||||
type NilGauge struct{}
|
type NilGauge struct{}
|
||||||
|
|
||||||
// Snapshot is a no-op.
|
func (NilGauge) Snapshot() GaugeSnapshot { return (*emptySnapshot)(nil) }
|
||||||
func (NilGauge) Snapshot() Gauge { return NilGauge{} }
|
|
||||||
|
|
||||||
// Update is a no-op.
|
|
||||||
func (NilGauge) Update(v int64) {}
|
func (NilGauge) Update(v int64) {}
|
||||||
|
func (NilGauge) UpdateIfGt(v int64) {}
|
||||||
// Dec is a no-op.
|
|
||||||
func (NilGauge) Dec(i int64) {}
|
func (NilGauge) Dec(i int64) {}
|
||||||
|
|
||||||
// Inc is a no-op.
|
|
||||||
func (NilGauge) Inc(i int64) {}
|
func (NilGauge) Inc(i int64) {}
|
||||||
|
|
||||||
// Value is a no-op.
|
|
||||||
func (NilGauge) Value() int64 { return 0 }
|
|
||||||
|
|
||||||
// StandardGauge is the standard implementation of a Gauge and uses the
|
// StandardGauge is the standard implementation of a Gauge and uses the
|
||||||
// sync/atomic package to manage a single int64 value.
|
// sync/atomic package to manage a single int64 value.
|
||||||
type StandardGauge struct {
|
type StandardGauge struct {
|
||||||
|
|
@ -105,8 +65,8 @@ type StandardGauge struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Snapshot returns a read-only copy of the gauge.
|
// Snapshot returns a read-only copy of the gauge.
|
||||||
func (g *StandardGauge) Snapshot() Gauge {
|
func (g *StandardGauge) Snapshot() GaugeSnapshot {
|
||||||
return GaugeSnapshot(g.Value())
|
return gaugeSnapshot(g.value.Load())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update updates the gauge's value.
|
// Update updates the gauge's value.
|
||||||
|
|
@ -114,9 +74,17 @@ func (g *StandardGauge) Update(v int64) {
|
||||||
g.value.Store(v)
|
g.value.Store(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Value returns the gauge's current value.
|
// Update updates the gauge's value if v is larger then the current valie.
|
||||||
func (g *StandardGauge) Value() int64 {
|
func (g *StandardGauge) UpdateIfGt(v int64) {
|
||||||
return g.value.Load()
|
for {
|
||||||
|
exist := g.value.Load()
|
||||||
|
if exist >= v {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if g.value.CompareAndSwap(exist, v) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dec decrements the gauge's current value by the given amount.
|
// Dec decrements the gauge's current value by the given amount.
|
||||||
|
|
@ -128,31 +96,3 @@ func (g *StandardGauge) Dec(i int64) {
|
||||||
func (g *StandardGauge) Inc(i int64) {
|
func (g *StandardGauge) Inc(i int64) {
|
||||||
g.value.Add(i)
|
g.value.Add(i)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FunctionalGauge returns value from given function
|
|
||||||
type FunctionalGauge struct {
|
|
||||||
value func() int64
|
|
||||||
}
|
|
||||||
|
|
||||||
// Value returns the gauge's current value.
|
|
||||||
func (g FunctionalGauge) Value() int64 {
|
|
||||||
return g.value()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Snapshot returns the snapshot.
|
|
||||||
func (g FunctionalGauge) Snapshot() Gauge { return GaugeSnapshot(g.Value()) }
|
|
||||||
|
|
||||||
// Update panics.
|
|
||||||
func (FunctionalGauge) Update(int64) {
|
|
||||||
panic("Update called on a FunctionalGauge")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Dec panics.
|
|
||||||
func (FunctionalGauge) Dec(int64) {
|
|
||||||
panic("Dec called on a FunctionalGauge")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Inc panics.
|
|
||||||
func (FunctionalGauge) Inc(int64) {
|
|
||||||
panic("Inc called on a FunctionalGauge")
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -5,13 +5,16 @@ import (
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GaugeFloat64s hold a float64 value that can be set arbitrarily.
|
type GaugeFloat64Snapshot interface {
|
||||||
type GaugeFloat64 interface {
|
|
||||||
Snapshot() GaugeFloat64
|
|
||||||
Update(float64)
|
|
||||||
Value() float64
|
Value() float64
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GaugeFloat64 hold a float64 value that can be set arbitrarily.
|
||||||
|
type GaugeFloat64 interface {
|
||||||
|
Snapshot() GaugeFloat64Snapshot
|
||||||
|
Update(float64)
|
||||||
|
}
|
||||||
|
|
||||||
// GetOrRegisterGaugeFloat64 returns an existing GaugeFloat64 or constructs and registers a
|
// GetOrRegisterGaugeFloat64 returns an existing GaugeFloat64 or constructs and registers a
|
||||||
// new StandardGaugeFloat64.
|
// new StandardGaugeFloat64.
|
||||||
func GetOrRegisterGaugeFloat64(name string, r Registry) GaugeFloat64 {
|
func GetOrRegisterGaugeFloat64(name string, r Registry) GaugeFloat64 {
|
||||||
|
|
@ -39,48 +42,17 @@ func NewRegisteredGaugeFloat64(name string, r Registry) GaugeFloat64 {
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewFunctionalGauge constructs a new FunctionalGauge.
|
// gaugeFloat64Snapshot is a read-only copy of another GaugeFloat64.
|
||||||
func NewFunctionalGaugeFloat64(f func() float64) GaugeFloat64 {
|
type gaugeFloat64Snapshot float64
|
||||||
if !Enabled {
|
|
||||||
return NilGaugeFloat64{}
|
|
||||||
}
|
|
||||||
return &FunctionalGaugeFloat64{value: f}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewRegisteredFunctionalGauge constructs and registers a new StandardGauge.
|
|
||||||
func NewRegisteredFunctionalGaugeFloat64(name string, r Registry, f func() float64) GaugeFloat64 {
|
|
||||||
c := NewFunctionalGaugeFloat64(f)
|
|
||||||
if nil == r {
|
|
||||||
r = DefaultRegistry
|
|
||||||
}
|
|
||||||
r.Register(name, c)
|
|
||||||
return c
|
|
||||||
}
|
|
||||||
|
|
||||||
// GaugeFloat64Snapshot is a read-only copy of another GaugeFloat64.
|
|
||||||
type GaugeFloat64Snapshot float64
|
|
||||||
|
|
||||||
// Snapshot returns the snapshot.
|
|
||||||
func (g GaugeFloat64Snapshot) Snapshot() GaugeFloat64 { return g }
|
|
||||||
|
|
||||||
// Update panics.
|
|
||||||
func (GaugeFloat64Snapshot) Update(float64) {
|
|
||||||
panic("Update called on a GaugeFloat64Snapshot")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Value returns the value at the time the snapshot was taken.
|
// Value returns the value at the time the snapshot was taken.
|
||||||
func (g GaugeFloat64Snapshot) Value() float64 { return float64(g) }
|
func (g gaugeFloat64Snapshot) Value() float64 { return float64(g) }
|
||||||
|
|
||||||
// NilGauge is a no-op Gauge.
|
// NilGauge is a no-op Gauge.
|
||||||
type NilGaugeFloat64 struct{}
|
type NilGaugeFloat64 struct{}
|
||||||
|
|
||||||
// Snapshot is a no-op.
|
func (NilGaugeFloat64) Snapshot() GaugeFloat64Snapshot { return NilGaugeFloat64{} }
|
||||||
func (NilGaugeFloat64) Snapshot() GaugeFloat64 { return NilGaugeFloat64{} }
|
|
||||||
|
|
||||||
// Update is a no-op.
|
|
||||||
func (NilGaugeFloat64) Update(v float64) {}
|
func (NilGaugeFloat64) Update(v float64) {}
|
||||||
|
|
||||||
// Value is a no-op.
|
|
||||||
func (NilGaugeFloat64) Value() float64 { return 0.0 }
|
func (NilGaugeFloat64) Value() float64 { return 0.0 }
|
||||||
|
|
||||||
// StandardGaugeFloat64 is the standard implementation of a GaugeFloat64 and uses
|
// StandardGaugeFloat64 is the standard implementation of a GaugeFloat64 and uses
|
||||||
|
|
@ -90,34 +62,12 @@ type StandardGaugeFloat64 struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Snapshot returns a read-only copy of the gauge.
|
// Snapshot returns a read-only copy of the gauge.
|
||||||
func (g *StandardGaugeFloat64) Snapshot() GaugeFloat64 {
|
func (g *StandardGaugeFloat64) Snapshot() GaugeFloat64Snapshot {
|
||||||
return GaugeFloat64Snapshot(g.Value())
|
v := math.Float64frombits(g.floatBits.Load())
|
||||||
|
return gaugeFloat64Snapshot(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update updates the gauge's value.
|
// Update updates the gauge's value.
|
||||||
func (g *StandardGaugeFloat64) Update(v float64) {
|
func (g *StandardGaugeFloat64) Update(v float64) {
|
||||||
g.floatBits.Store(math.Float64bits(v))
|
g.floatBits.Store(math.Float64bits(v))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Value returns the gauge's current value.
|
|
||||||
func (g *StandardGaugeFloat64) Value() float64 {
|
|
||||||
return math.Float64frombits(g.floatBits.Load())
|
|
||||||
}
|
|
||||||
|
|
||||||
// FunctionalGaugeFloat64 returns value from given function
|
|
||||||
type FunctionalGaugeFloat64 struct {
|
|
||||||
value func() float64
|
|
||||||
}
|
|
||||||
|
|
||||||
// Value returns the gauge's current value.
|
|
||||||
func (g FunctionalGaugeFloat64) Value() float64 {
|
|
||||||
return g.value()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Snapshot returns the snapshot.
|
|
||||||
func (g FunctionalGaugeFloat64) Snapshot() GaugeFloat64 { return GaugeFloat64Snapshot(g.Value()) }
|
|
||||||
|
|
||||||
// Update panics.
|
|
||||||
func (FunctionalGaugeFloat64) Update(float64) {
|
|
||||||
panic("Update called on a FunctionalGaugeFloat64")
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -26,19 +26,11 @@ func BenchmarkGaugeFloat64Parallel(b *testing.B) {
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
if have, want := c.Value(), float64(b.N-1); have != want {
|
if have, want := c.Snapshot().Value(), float64(b.N-1); have != want {
|
||||||
b.Fatalf("have %f want %f", have, want)
|
b.Fatalf("have %f want %f", have, want)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGaugeFloat64(t *testing.T) {
|
|
||||||
g := NewGaugeFloat64()
|
|
||||||
g.Update(47.0)
|
|
||||||
if v := g.Value(); 47.0 != v {
|
|
||||||
t.Errorf("g.Value(): 47.0 != %v\n", v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGaugeFloat64Snapshot(t *testing.T) {
|
func TestGaugeFloat64Snapshot(t *testing.T) {
|
||||||
g := NewGaugeFloat64()
|
g := NewGaugeFloat64()
|
||||||
g.Update(47.0)
|
g.Update(47.0)
|
||||||
|
|
@ -53,28 +45,7 @@ func TestGetOrRegisterGaugeFloat64(t *testing.T) {
|
||||||
r := NewRegistry()
|
r := NewRegistry()
|
||||||
NewRegisteredGaugeFloat64("foo", r).Update(47.0)
|
NewRegisteredGaugeFloat64("foo", r).Update(47.0)
|
||||||
t.Logf("registry: %v", r)
|
t.Logf("registry: %v", r)
|
||||||
if g := GetOrRegisterGaugeFloat64("foo", r); 47.0 != g.Value() {
|
if g := GetOrRegisterGaugeFloat64("foo", r).Snapshot(); 47.0 != g.Value() {
|
||||||
t.Fatal(g)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFunctionalGaugeFloat64(t *testing.T) {
|
|
||||||
var counter float64
|
|
||||||
fg := NewFunctionalGaugeFloat64(func() float64 {
|
|
||||||
counter++
|
|
||||||
return counter
|
|
||||||
})
|
|
||||||
fg.Value()
|
|
||||||
fg.Value()
|
|
||||||
if counter != 2 {
|
|
||||||
t.Error("counter != 2")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGetOrRegisterFunctionalGaugeFloat64(t *testing.T) {
|
|
||||||
r := NewRegistry()
|
|
||||||
NewRegisteredFunctionalGaugeFloat64("foo", r, func() float64 { return 47 })
|
|
||||||
if g := GetOrRegisterGaugeFloat64("foo", r); g.Value() != 47 {
|
|
||||||
t.Fatal(g)
|
t.Fatal(g)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,14 +5,17 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GaugeInfos hold a GaugeInfoValue value that can be set arbitrarily.
|
type GaugeInfoSnapshot interface {
|
||||||
type GaugeInfo interface {
|
|
||||||
Snapshot() GaugeInfo
|
|
||||||
Update(GaugeInfoValue)
|
|
||||||
Value() GaugeInfoValue
|
Value() GaugeInfoValue
|
||||||
}
|
}
|
||||||
|
|
||||||
// GaugeInfoValue is a mappng of (string) keys to (string) values
|
// GaugeInfos hold a GaugeInfoValue value that can be set arbitrarily.
|
||||||
|
type GaugeInfo interface {
|
||||||
|
Update(GaugeInfoValue)
|
||||||
|
Snapshot() GaugeInfoSnapshot
|
||||||
|
}
|
||||||
|
|
||||||
|
// GaugeInfoValue is a mapping of keys to values
|
||||||
type GaugeInfoValue map[string]string
|
type GaugeInfoValue map[string]string
|
||||||
|
|
||||||
func (val GaugeInfoValue) String() string {
|
func (val GaugeInfoValue) String() string {
|
||||||
|
|
@ -49,48 +52,16 @@ func NewRegisteredGaugeInfo(name string, r Registry) GaugeInfo {
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewFunctionalGauge constructs a new FunctionalGauge.
|
// gaugeInfoSnapshot is a read-only copy of another GaugeInfo.
|
||||||
func NewFunctionalGaugeInfo(f func() GaugeInfoValue) GaugeInfo {
|
type gaugeInfoSnapshot GaugeInfoValue
|
||||||
if !Enabled {
|
|
||||||
return NilGaugeInfo{}
|
|
||||||
}
|
|
||||||
return &FunctionalGaugeInfo{value: f}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewRegisteredFunctionalGauge constructs and registers a new StandardGauge.
|
|
||||||
func NewRegisteredFunctionalGaugeInfo(name string, r Registry, f func() GaugeInfoValue) GaugeInfo {
|
|
||||||
c := NewFunctionalGaugeInfo(f)
|
|
||||||
if nil == r {
|
|
||||||
r = DefaultRegistry
|
|
||||||
}
|
|
||||||
r.Register(name, c)
|
|
||||||
return c
|
|
||||||
}
|
|
||||||
|
|
||||||
// GaugeInfoSnapshot is a read-only copy of another GaugeInfo.
|
|
||||||
type GaugeInfoSnapshot GaugeInfoValue
|
|
||||||
|
|
||||||
// Snapshot returns the snapshot.
|
|
||||||
func (g GaugeInfoSnapshot) Snapshot() GaugeInfo { return g }
|
|
||||||
|
|
||||||
// Update panics.
|
|
||||||
func (GaugeInfoSnapshot) Update(GaugeInfoValue) {
|
|
||||||
panic("Update called on a GaugeInfoSnapshot")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Value returns the value at the time the snapshot was taken.
|
// Value returns the value at the time the snapshot was taken.
|
||||||
func (g GaugeInfoSnapshot) Value() GaugeInfoValue { return GaugeInfoValue(g) }
|
func (g gaugeInfoSnapshot) Value() GaugeInfoValue { return GaugeInfoValue(g) }
|
||||||
|
|
||||||
// NilGauge is a no-op Gauge.
|
|
||||||
type NilGaugeInfo struct{}
|
type NilGaugeInfo struct{}
|
||||||
|
|
||||||
// Snapshot is a no-op.
|
func (NilGaugeInfo) Snapshot() GaugeInfoSnapshot { return NilGaugeInfo{} }
|
||||||
func (NilGaugeInfo) Snapshot() GaugeInfo { return NilGaugeInfo{} }
|
|
||||||
|
|
||||||
// Update is a no-op.
|
|
||||||
func (NilGaugeInfo) Update(v GaugeInfoValue) {}
|
func (NilGaugeInfo) Update(v GaugeInfoValue) {}
|
||||||
|
|
||||||
// Value is a no-op.
|
|
||||||
func (NilGaugeInfo) Value() GaugeInfoValue { return GaugeInfoValue{} }
|
func (NilGaugeInfo) Value() GaugeInfoValue { return GaugeInfoValue{} }
|
||||||
|
|
||||||
// StandardGaugeInfo is the standard implementation of a GaugeInfo and uses
|
// StandardGaugeInfo is the standard implementation of a GaugeInfo and uses
|
||||||
|
|
@ -101,8 +72,8 @@ type StandardGaugeInfo struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Snapshot returns a read-only copy of the gauge.
|
// Snapshot returns a read-only copy of the gauge.
|
||||||
func (g *StandardGaugeInfo) Snapshot() GaugeInfo {
|
func (g *StandardGaugeInfo) Snapshot() GaugeInfoSnapshot {
|
||||||
return GaugeInfoSnapshot(g.Value())
|
return gaugeInfoSnapshot(g.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update updates the gauge's value.
|
// Update updates the gauge's value.
|
||||||
|
|
@ -111,34 +82,3 @@ func (g *StandardGaugeInfo) Update(v GaugeInfoValue) {
|
||||||
defer g.mutex.Unlock()
|
defer g.mutex.Unlock()
|
||||||
g.value = v
|
g.value = v
|
||||||
}
|
}
|
||||||
|
|
||||||
// Value returns the gauge's current value.
|
|
||||||
func (g *StandardGaugeInfo) Value() GaugeInfoValue {
|
|
||||||
g.mutex.Lock()
|
|
||||||
defer g.mutex.Unlock()
|
|
||||||
return g.value
|
|
||||||
}
|
|
||||||
|
|
||||||
// FunctionalGaugeInfo returns value from given function
|
|
||||||
type FunctionalGaugeInfo struct {
|
|
||||||
value func() GaugeInfoValue
|
|
||||||
}
|
|
||||||
|
|
||||||
// Value returns the gauge's current value.
|
|
||||||
func (g FunctionalGaugeInfo) Value() GaugeInfoValue {
|
|
||||||
return g.value()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Value returns the gauge's current value in JSON string format
|
|
||||||
func (g FunctionalGaugeInfo) ValueJsonString() string {
|
|
||||||
data, _ := json.Marshal(g.value())
|
|
||||||
return string(data)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Snapshot returns the snapshot.
|
|
||||||
func (g FunctionalGaugeInfo) Snapshot() GaugeInfo { return GaugeInfoSnapshot(g.Value()) }
|
|
||||||
|
|
||||||
// Update panics.
|
|
||||||
func (FunctionalGaugeInfo) Update(GaugeInfoValue) {
|
|
||||||
panic("Update called on a FunctionalGaugeInfo")
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
package metrics
|
package metrics
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"strconv"
|
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -14,22 +13,14 @@ func TestGaugeInfoJsonString(t *testing.T) {
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
want := `{"anotherKey":"any_string_value","chain_id":"5","third_key":"anything"}`
|
want := `{"anotherKey":"any_string_value","chain_id":"5","third_key":"anything"}`
|
||||||
if have := g.Value().String(); have != want {
|
|
||||||
t.Errorf("\nhave: %v\nwant: %v\n", have, want)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGaugeInfoSnapshot(t *testing.T) {
|
original := g.Snapshot()
|
||||||
g := NewGaugeInfo()
|
|
||||||
g.Update(GaugeInfoValue{"value": "original"})
|
|
||||||
snapshot := g.Snapshot() // Snapshot @chainid 5
|
|
||||||
g.Update(GaugeInfoValue{"value": "updated"})
|
g.Update(GaugeInfoValue{"value": "updated"})
|
||||||
// The 'g' should be updated
|
|
||||||
if have, want := g.Value().String(), `{"value":"updated"}`; have != want {
|
if have := original.Value().String(); have != want {
|
||||||
t.Errorf("\nhave: %v\nwant: %v\n", have, want)
|
t.Errorf("\nhave: %v\nwant: %v\n", have, want)
|
||||||
}
|
}
|
||||||
// Snapshot should be unupdated
|
if have, want := g.Snapshot().Value().String(), `{"value":"updated"}`; have != want {
|
||||||
if have, want := snapshot.Value().String(), `{"value":"original"}`; have != want {
|
|
||||||
t.Errorf("\nhave: %v\nwant: %v\n", have, want)
|
t.Errorf("\nhave: %v\nwant: %v\n", have, want)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -38,38 +29,8 @@ func TestGetOrRegisterGaugeInfo(t *testing.T) {
|
||||||
r := NewRegistry()
|
r := NewRegistry()
|
||||||
NewRegisteredGaugeInfo("foo", r).Update(
|
NewRegisteredGaugeInfo("foo", r).Update(
|
||||||
GaugeInfoValue{"chain_id": "5"})
|
GaugeInfoValue{"chain_id": "5"})
|
||||||
g := GetOrRegisterGaugeInfo("foo", r)
|
g := GetOrRegisterGaugeInfo("foo", r).Snapshot()
|
||||||
if have, want := g.Value().String(), `{"chain_id":"5"}`; have != want {
|
if have, want := g.Value().String(), `{"chain_id":"5"}`; have != want {
|
||||||
t.Errorf("have\n%v\nwant\n%v\n", have, want)
|
t.Errorf("have\n%v\nwant\n%v\n", have, want)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestFunctionalGaugeInfo(t *testing.T) {
|
|
||||||
info := GaugeInfoValue{"chain_id": "0"}
|
|
||||||
counter := 1
|
|
||||||
// A "functional" gauge invokes the method to obtain the value
|
|
||||||
fg := NewFunctionalGaugeInfo(func() GaugeInfoValue {
|
|
||||||
info["chain_id"] = strconv.Itoa(counter)
|
|
||||||
counter++
|
|
||||||
return info
|
|
||||||
})
|
|
||||||
fg.Value()
|
|
||||||
fg.Value()
|
|
||||||
if have, want := info["chain_id"], "2"; have != want {
|
|
||||||
t.Errorf("have %v want %v", have, want)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGetOrRegisterFunctionalGaugeInfo(t *testing.T) {
|
|
||||||
r := NewRegistry()
|
|
||||||
NewRegisteredFunctionalGaugeInfo("foo", r, func() GaugeInfoValue {
|
|
||||||
return GaugeInfoValue{
|
|
||||||
"chain_id": "5",
|
|
||||||
}
|
|
||||||
})
|
|
||||||
want := `{"chain_id":"5"}`
|
|
||||||
have := GetOrRegisterGaugeInfo("foo", r).Value().String()
|
|
||||||
if have != want {
|
|
||||||
t.Errorf("have\n%v\nwant\n%v\n", have, want)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
package metrics
|
package metrics
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -13,14 +12,6 @@ func BenchmarkGauge(b *testing.B) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGauge(t *testing.T) {
|
|
||||||
g := NewGauge()
|
|
||||||
g.Update(int64(47))
|
|
||||||
if v := g.Value(); v != 47 {
|
|
||||||
t.Errorf("g.Value(): 47 != %v\n", v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGaugeSnapshot(t *testing.T) {
|
func TestGaugeSnapshot(t *testing.T) {
|
||||||
g := NewGauge()
|
g := NewGauge()
|
||||||
g.Update(int64(47))
|
g.Update(int64(47))
|
||||||
|
|
@ -34,35 +25,7 @@ func TestGaugeSnapshot(t *testing.T) {
|
||||||
func TestGetOrRegisterGauge(t *testing.T) {
|
func TestGetOrRegisterGauge(t *testing.T) {
|
||||||
r := NewRegistry()
|
r := NewRegistry()
|
||||||
NewRegisteredGauge("foo", r).Update(47)
|
NewRegisteredGauge("foo", r).Update(47)
|
||||||
if g := GetOrRegisterGauge("foo", r); g.Value() != 47 {
|
if g := GetOrRegisterGauge("foo", r); g.Snapshot().Value() != 47 {
|
||||||
t.Fatal(g)
|
t.Fatal(g)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestFunctionalGauge(t *testing.T) {
|
|
||||||
var counter int64
|
|
||||||
fg := NewFunctionalGauge(func() int64 {
|
|
||||||
counter++
|
|
||||||
return counter
|
|
||||||
})
|
|
||||||
fg.Value()
|
|
||||||
fg.Value()
|
|
||||||
if counter != 2 {
|
|
||||||
t.Error("counter != 2")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGetOrRegisterFunctionalGauge(t *testing.T) {
|
|
||||||
r := NewRegistry()
|
|
||||||
NewRegisteredFunctionalGauge("foo", r, func() int64 { return 47 })
|
|
||||||
if g := GetOrRegisterGauge("foo", r); g.Value() != 47 {
|
|
||||||
t.Fatal(g)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func ExampleGetOrRegisterGauge() {
|
|
||||||
m := "server.bytes_sent"
|
|
||||||
g := GetOrRegisterGauge(m, nil)
|
|
||||||
g.Update(47)
|
|
||||||
fmt.Println(g.Value()) // Output: 47
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -66,15 +66,15 @@ func graphite(c *GraphiteConfig) error {
|
||||||
c.Registry.Each(func(name string, i interface{}) {
|
c.Registry.Each(func(name string, i interface{}) {
|
||||||
switch metric := i.(type) {
|
switch metric := i.(type) {
|
||||||
case Counter:
|
case Counter:
|
||||||
fmt.Fprintf(w, "%s.%s.count %d %d\n", c.Prefix, name, metric.Count(), now)
|
fmt.Fprintf(w, "%s.%s.count %d %d\n", c.Prefix, name, metric.Snapshot().Count(), now)
|
||||||
case CounterFloat64:
|
case CounterFloat64:
|
||||||
fmt.Fprintf(w, "%s.%s.count %f %d\n", c.Prefix, name, metric.Count(), now)
|
fmt.Fprintf(w, "%s.%s.count %f %d\n", c.Prefix, name, metric.Snapshot().Count(), now)
|
||||||
case Gauge:
|
case Gauge:
|
||||||
fmt.Fprintf(w, "%s.%s.value %d %d\n", c.Prefix, name, metric.Value(), now)
|
fmt.Fprintf(w, "%s.%s.value %d %d\n", c.Prefix, name, metric.Snapshot().Value(), now)
|
||||||
case GaugeFloat64:
|
case GaugeFloat64:
|
||||||
fmt.Fprintf(w, "%s.%s.value %f %d\n", c.Prefix, name, metric.Value(), now)
|
fmt.Fprintf(w, "%s.%s.value %f %d\n", c.Prefix, name, metric.Snapshot().Value(), now)
|
||||||
case GaugeInfo:
|
case GaugeInfo:
|
||||||
fmt.Fprintf(w, "%s.%s.value %s %d\n", c.Prefix, name, metric.Value().String(), now)
|
fmt.Fprintf(w, "%s.%s.value %s %d\n", c.Prefix, name, metric.Snapshot().Value().String(), now)
|
||||||
case Histogram:
|
case Histogram:
|
||||||
h := metric.Snapshot()
|
h := metric.Snapshot()
|
||||||
ps := h.Percentiles(c.Percentiles)
|
ps := h.Percentiles(c.Percentiles)
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,14 @@
|
||||||
package metrics
|
package metrics
|
||||||
|
|
||||||
|
type HistogramSnapshot interface {
|
||||||
|
SampleSnapshot
|
||||||
|
}
|
||||||
|
|
||||||
// Histograms calculate distribution statistics from a series of int64 values.
|
// Histograms calculate distribution statistics from a series of int64 values.
|
||||||
type Histogram interface {
|
type Histogram interface {
|
||||||
Clear()
|
Clear()
|
||||||
Count() int64
|
|
||||||
Max() int64
|
|
||||||
Mean() float64
|
|
||||||
Min() int64
|
|
||||||
Percentile(float64) float64
|
|
||||||
Percentiles([]float64) []float64
|
|
||||||
Sample() Sample
|
|
||||||
Snapshot() Histogram
|
|
||||||
StdDev() float64
|
|
||||||
Sum() int64
|
|
||||||
Update(int64)
|
Update(int64)
|
||||||
Variance() float64
|
Snapshot() HistogramSnapshot
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetOrRegisterHistogram returns an existing Histogram or constructs and
|
// GetOrRegisterHistogram returns an existing Histogram or constructs and
|
||||||
|
|
@ -54,109 +48,13 @@ func NewRegisteredHistogram(name string, r Registry, s Sample) Histogram {
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
// HistogramSnapshot is a read-only copy of another Histogram.
|
|
||||||
type HistogramSnapshot struct {
|
|
||||||
sample *SampleSnapshot
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clear panics.
|
|
||||||
func (*HistogramSnapshot) Clear() {
|
|
||||||
panic("Clear called on a HistogramSnapshot")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Count returns the number of samples recorded at the time the snapshot was
|
|
||||||
// taken.
|
|
||||||
func (h *HistogramSnapshot) Count() int64 { return h.sample.Count() }
|
|
||||||
|
|
||||||
// Max returns the maximum value in the sample at the time the snapshot was
|
|
||||||
// taken.
|
|
||||||
func (h *HistogramSnapshot) Max() int64 { return h.sample.Max() }
|
|
||||||
|
|
||||||
// Mean returns the mean of the values in the sample at the time the snapshot
|
|
||||||
// was taken.
|
|
||||||
func (h *HistogramSnapshot) Mean() float64 { return h.sample.Mean() }
|
|
||||||
|
|
||||||
// Min returns the minimum value in the sample at the time the snapshot was
|
|
||||||
// taken.
|
|
||||||
func (h *HistogramSnapshot) Min() int64 { return h.sample.Min() }
|
|
||||||
|
|
||||||
// Percentile returns an arbitrary percentile of values in the sample at the
|
|
||||||
// time the snapshot was taken.
|
|
||||||
func (h *HistogramSnapshot) Percentile(p float64) float64 {
|
|
||||||
return h.sample.Percentile(p)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Percentiles returns a slice of arbitrary percentiles of values in the sample
|
|
||||||
// at the time the snapshot was taken.
|
|
||||||
func (h *HistogramSnapshot) Percentiles(ps []float64) []float64 {
|
|
||||||
return h.sample.Percentiles(ps)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sample returns the Sample underlying the histogram.
|
|
||||||
func (h *HistogramSnapshot) Sample() Sample { return h.sample }
|
|
||||||
|
|
||||||
// Snapshot returns the snapshot.
|
|
||||||
func (h *HistogramSnapshot) Snapshot() Histogram { return h }
|
|
||||||
|
|
||||||
// StdDev returns the standard deviation of the values in the sample at the
|
|
||||||
// time the snapshot was taken.
|
|
||||||
func (h *HistogramSnapshot) StdDev() float64 { return h.sample.StdDev() }
|
|
||||||
|
|
||||||
// Sum returns the sum in the sample at the time the snapshot was taken.
|
|
||||||
func (h *HistogramSnapshot) Sum() int64 { return h.sample.Sum() }
|
|
||||||
|
|
||||||
// Update panics.
|
|
||||||
func (*HistogramSnapshot) Update(int64) {
|
|
||||||
panic("Update called on a HistogramSnapshot")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Variance returns the variance of inputs at the time the snapshot was taken.
|
|
||||||
func (h *HistogramSnapshot) Variance() float64 { return h.sample.Variance() }
|
|
||||||
|
|
||||||
// NilHistogram is a no-op Histogram.
|
// NilHistogram is a no-op Histogram.
|
||||||
type NilHistogram struct{}
|
type NilHistogram struct{}
|
||||||
|
|
||||||
// Clear is a no-op.
|
|
||||||
func (NilHistogram) Clear() {}
|
func (NilHistogram) Clear() {}
|
||||||
|
func (NilHistogram) Snapshot() HistogramSnapshot { return (*emptySnapshot)(nil) }
|
||||||
// Count is a no-op.
|
|
||||||
func (NilHistogram) Count() int64 { return 0 }
|
|
||||||
|
|
||||||
// Max is a no-op.
|
|
||||||
func (NilHistogram) Max() int64 { return 0 }
|
|
||||||
|
|
||||||
// Mean is a no-op.
|
|
||||||
func (NilHistogram) Mean() float64 { return 0.0 }
|
|
||||||
|
|
||||||
// Min is a no-op.
|
|
||||||
func (NilHistogram) Min() int64 { return 0 }
|
|
||||||
|
|
||||||
// Percentile is a no-op.
|
|
||||||
func (NilHistogram) Percentile(p float64) float64 { return 0.0 }
|
|
||||||
|
|
||||||
// Percentiles is a no-op.
|
|
||||||
func (NilHistogram) Percentiles(ps []float64) []float64 {
|
|
||||||
return make([]float64, len(ps))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sample is a no-op.
|
|
||||||
func (NilHistogram) Sample() Sample { return NilSample{} }
|
|
||||||
|
|
||||||
// Snapshot is a no-op.
|
|
||||||
func (NilHistogram) Snapshot() Histogram { return NilHistogram{} }
|
|
||||||
|
|
||||||
// StdDev is a no-op.
|
|
||||||
func (NilHistogram) StdDev() float64 { return 0.0 }
|
|
||||||
|
|
||||||
// Sum is a no-op.
|
|
||||||
func (NilHistogram) Sum() int64 { return 0 }
|
|
||||||
|
|
||||||
// Update is a no-op.
|
|
||||||
func (NilHistogram) Update(v int64) {}
|
func (NilHistogram) Update(v int64) {}
|
||||||
|
|
||||||
// Variance is a no-op.
|
|
||||||
func (NilHistogram) Variance() float64 { return 0.0 }
|
|
||||||
|
|
||||||
// StandardHistogram is the standard implementation of a Histogram and uses a
|
// StandardHistogram is the standard implementation of a Histogram and uses a
|
||||||
// Sample to bound its memory use.
|
// Sample to bound its memory use.
|
||||||
type StandardHistogram struct {
|
type StandardHistogram struct {
|
||||||
|
|
@ -166,46 +64,10 @@ type StandardHistogram struct {
|
||||||
// Clear clears the histogram and its sample.
|
// Clear clears the histogram and its sample.
|
||||||
func (h *StandardHistogram) Clear() { h.sample.Clear() }
|
func (h *StandardHistogram) Clear() { h.sample.Clear() }
|
||||||
|
|
||||||
// Count returns the number of samples recorded since the histogram was last
|
|
||||||
// cleared.
|
|
||||||
func (h *StandardHistogram) Count() int64 { return h.sample.Count() }
|
|
||||||
|
|
||||||
// Max returns the maximum value in the sample.
|
|
||||||
func (h *StandardHistogram) Max() int64 { return h.sample.Max() }
|
|
||||||
|
|
||||||
// Mean returns the mean of the values in the sample.
|
|
||||||
func (h *StandardHistogram) Mean() float64 { return h.sample.Mean() }
|
|
||||||
|
|
||||||
// Min returns the minimum value in the sample.
|
|
||||||
func (h *StandardHistogram) Min() int64 { return h.sample.Min() }
|
|
||||||
|
|
||||||
// Percentile returns an arbitrary percentile of the values in the sample.
|
|
||||||
func (h *StandardHistogram) Percentile(p float64) float64 {
|
|
||||||
return h.sample.Percentile(p)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Percentiles returns a slice of arbitrary percentiles of the values in the
|
|
||||||
// sample.
|
|
||||||
func (h *StandardHistogram) Percentiles(ps []float64) []float64 {
|
|
||||||
return h.sample.Percentiles(ps)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sample returns the Sample underlying the histogram.
|
|
||||||
func (h *StandardHistogram) Sample() Sample { return h.sample }
|
|
||||||
|
|
||||||
// Snapshot returns a read-only copy of the histogram.
|
// Snapshot returns a read-only copy of the histogram.
|
||||||
func (h *StandardHistogram) Snapshot() Histogram {
|
func (h *StandardHistogram) Snapshot() HistogramSnapshot {
|
||||||
return &HistogramSnapshot{sample: h.sample.Snapshot().(*SampleSnapshot)}
|
return h.sample.Snapshot()
|
||||||
}
|
}
|
||||||
|
|
||||||
// StdDev returns the standard deviation of the values in the sample.
|
|
||||||
func (h *StandardHistogram) StdDev() float64 { return h.sample.StdDev() }
|
|
||||||
|
|
||||||
// Sum returns the sum in the sample.
|
|
||||||
func (h *StandardHistogram) Sum() int64 { return h.sample.Sum() }
|
|
||||||
|
|
||||||
// Update samples a new value.
|
// Update samples a new value.
|
||||||
func (h *StandardHistogram) Update(v int64) { h.sample.Update(v) }
|
func (h *StandardHistogram) Update(v int64) { h.sample.Update(v) }
|
||||||
|
|
||||||
// Variance returns the variance of the values in the sample.
|
|
||||||
func (h *StandardHistogram) Variance() float64 { return h.sample.Variance() }
|
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ func TestGetOrRegisterHistogram(t *testing.T) {
|
||||||
r := NewRegistry()
|
r := NewRegistry()
|
||||||
s := NewUniformSample(100)
|
s := NewUniformSample(100)
|
||||||
NewRegisteredHistogram("foo", r, s).Update(47)
|
NewRegisteredHistogram("foo", r, s).Update(47)
|
||||||
if h := GetOrRegisterHistogram("foo", r, s); h.Count() != 1 {
|
if h := GetOrRegisterHistogram("foo", r, s).Snapshot(); h.Count() != 1 {
|
||||||
t.Fatal(h)
|
t.Fatal(h)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -24,11 +24,11 @@ func TestHistogram10000(t *testing.T) {
|
||||||
for i := 1; i <= 10000; i++ {
|
for i := 1; i <= 10000; i++ {
|
||||||
h.Update(int64(i))
|
h.Update(int64(i))
|
||||||
}
|
}
|
||||||
testHistogram10000(t, h)
|
testHistogram10000(t, h.Snapshot())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestHistogramEmpty(t *testing.T) {
|
func TestHistogramEmpty(t *testing.T) {
|
||||||
h := NewHistogram(NewUniformSample(100))
|
h := NewHistogram(NewUniformSample(100)).Snapshot()
|
||||||
if count := h.Count(); count != 0 {
|
if count := h.Count(); count != 0 {
|
||||||
t.Errorf("h.Count(): 0 != %v\n", count)
|
t.Errorf("h.Count(): 0 != %v\n", count)
|
||||||
}
|
}
|
||||||
|
|
@ -66,7 +66,7 @@ func TestHistogramSnapshot(t *testing.T) {
|
||||||
testHistogram10000(t, snapshot)
|
testHistogram10000(t, snapshot)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testHistogram10000(t *testing.T, h Histogram) {
|
func testHistogram10000(t *testing.T, h HistogramSnapshot) {
|
||||||
if count := h.Count(); count != 10000 {
|
if count := h.Count(); count != 10000 {
|
||||||
t.Errorf("h.Count(): 10000 != %v\n", count)
|
t.Errorf("h.Count(): 10000 != %v\n", count)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
48
metrics/inactive.go
Normal file
48
metrics/inactive.go
Normal file
|
|
@ -0,0 +1,48 @@
|
||||||
|
// Copyright 2023 The go-ethereum Authors
|
||||||
|
// This file is part of the go-ethereum library.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// The go-ethereum library 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 Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package metrics
|
||||||
|
|
||||||
|
// compile-time checks that interfaces are implemented.
|
||||||
|
var (
|
||||||
|
_ SampleSnapshot = (*emptySnapshot)(nil)
|
||||||
|
_ HistogramSnapshot = (*emptySnapshot)(nil)
|
||||||
|
_ CounterSnapshot = (*emptySnapshot)(nil)
|
||||||
|
_ GaugeSnapshot = (*emptySnapshot)(nil)
|
||||||
|
_ MeterSnapshot = (*emptySnapshot)(nil)
|
||||||
|
_ EWMASnapshot = (*emptySnapshot)(nil)
|
||||||
|
_ TimerSnapshot = (*emptySnapshot)(nil)
|
||||||
|
)
|
||||||
|
|
||||||
|
type emptySnapshot struct{}
|
||||||
|
|
||||||
|
func (*emptySnapshot) Count() int64 { return 0 }
|
||||||
|
func (*emptySnapshot) Max() int64 { return 0 }
|
||||||
|
func (*emptySnapshot) Mean() float64 { return 0.0 }
|
||||||
|
func (*emptySnapshot) Min() int64 { return 0 }
|
||||||
|
func (*emptySnapshot) Percentile(p float64) float64 { return 0.0 }
|
||||||
|
func (*emptySnapshot) Percentiles(ps []float64) []float64 { return make([]float64, len(ps)) }
|
||||||
|
func (*emptySnapshot) Size() int { return 0 }
|
||||||
|
func (*emptySnapshot) StdDev() float64 { return 0.0 }
|
||||||
|
func (*emptySnapshot) Sum() int64 { return 0 }
|
||||||
|
func (*emptySnapshot) Values() []int64 { return []int64{} }
|
||||||
|
func (*emptySnapshot) Variance() float64 { return 0.0 }
|
||||||
|
func (*emptySnapshot) Value() int64 { return 0 }
|
||||||
|
func (*emptySnapshot) Rate() float64 { return 0.0 }
|
||||||
|
func (*emptySnapshot) Rate1() float64 { return 0.0 }
|
||||||
|
func (*emptySnapshot) Rate5() float64 { return 0.0 }
|
||||||
|
func (*emptySnapshot) Rate15() float64 { return 0.0 }
|
||||||
|
func (*emptySnapshot) RateMean() float64 { return 0.0 }
|
||||||
|
|
@ -11,13 +11,13 @@ func readMeter(namespace, name string, i interface{}) (string, map[string]interf
|
||||||
case metrics.Counter:
|
case metrics.Counter:
|
||||||
measurement := fmt.Sprintf("%s%s.count", namespace, name)
|
measurement := fmt.Sprintf("%s%s.count", namespace, name)
|
||||||
fields := map[string]interface{}{
|
fields := map[string]interface{}{
|
||||||
"value": metric.Count(),
|
"value": metric.Snapshot().Count(),
|
||||||
}
|
}
|
||||||
return measurement, fields
|
return measurement, fields
|
||||||
case metrics.CounterFloat64:
|
case metrics.CounterFloat64:
|
||||||
measurement := fmt.Sprintf("%s%s.count", namespace, name)
|
measurement := fmt.Sprintf("%s%s.count", namespace, name)
|
||||||
fields := map[string]interface{}{
|
fields := map[string]interface{}{
|
||||||
"value": metric.Count(),
|
"value": metric.Snapshot().Count(),
|
||||||
}
|
}
|
||||||
return measurement, fields
|
return measurement, fields
|
||||||
case metrics.Gauge:
|
case metrics.Gauge:
|
||||||
|
|
@ -99,20 +99,19 @@ func readMeter(namespace, name string, i interface{}) (string, map[string]interf
|
||||||
return measurement, fields
|
return measurement, fields
|
||||||
case metrics.ResettingTimer:
|
case metrics.ResettingTimer:
|
||||||
t := metric.Snapshot()
|
t := metric.Snapshot()
|
||||||
if len(t.Values()) == 0 {
|
if t.Count() == 0 {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
ps := t.Percentiles([]float64{50, 95, 99})
|
ps := t.Percentiles([]float64{0.50, 0.95, 0.99})
|
||||||
val := t.Values()
|
|
||||||
measurement := fmt.Sprintf("%s%s.span", namespace, name)
|
measurement := fmt.Sprintf("%s%s.span", namespace, name)
|
||||||
fields := map[string]interface{}{
|
fields := map[string]interface{}{
|
||||||
"count": len(val),
|
"count": t.Count(),
|
||||||
"max": val[len(val)-1],
|
"max": t.Max(),
|
||||||
"mean": t.Mean(),
|
"mean": t.Mean(),
|
||||||
"min": val[0],
|
"min": t.Min(),
|
||||||
"p50": ps[0],
|
"p50": int(ps[0]),
|
||||||
"p95": ps[1],
|
"p95": int(ps[1]),
|
||||||
"p99": ps[2],
|
"p99": int(ps[2]),
|
||||||
}
|
}
|
||||||
return measurement, fields
|
return measurement, fields
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -96,7 +96,7 @@ func TestExampleV2(t *testing.T) {
|
||||||
}
|
}
|
||||||
if have != want {
|
if have != want {
|
||||||
t.Errorf("\nhave:\n%v\nwant:\n%v\n", have, want)
|
t.Errorf("\nhave:\n%v\nwant:\n%v\n", have, want)
|
||||||
t.Logf("have vs want:\n %v", findFirstDiffPos(have, want))
|
t.Logf("have vs want:\n%v", findFirstDiffPos(have, want))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
4
metrics/influxdb/testdata/influxdbv1.want
vendored
4
metrics/influxdb/testdata/influxdbv1.want
vendored
|
|
@ -1,3 +1,5 @@
|
||||||
|
goth.system/cpu/schedlatency.histogram count=5645i,max=41943040i,mean=1819544.0410983171,min=0i,p25=0,p50=0,p75=7168,p95=16777216,p99=29360128,p999=33554432,p9999=33554432,stddev=6393570.217198883,variance=40877740122252.57 978307200000000000
|
||||||
|
goth.system/memory/pauses.histogram count=14i,max=229376i,mean=50066.28571428572,min=5120i,p25=10240,p50=32768,p75=57344,p95=196608,p99=196608,p999=196608,p9999=196608,stddev=54726.062410783874,variance=2994941906.9890113 978307200000000000
|
||||||
goth.test/counter.count value=12345 978307200000000000
|
goth.test/counter.count value=12345 978307200000000000
|
||||||
goth.test/counter_float64.count value=54321.98 978307200000000000
|
goth.test/counter_float64.count value=54321.98 978307200000000000
|
||||||
goth.test/gauge.gauge value=23456i 978307200000000000
|
goth.test/gauge.gauge value=23456i 978307200000000000
|
||||||
|
|
@ -5,5 +7,5 @@ goth.test/gauge_float64.gauge value=34567.89 978307200000000000
|
||||||
goth.test/gauge_info.gauge value="{\"arch\":\"amd64\",\"commit\":\"7caa2d8163ae3132c1c2d6978c76610caee2d949\",\"os\":\"linux\",\"protocol_versions\":\"64 65 66\",\"version\":\"1.10.18-unstable\"}" 978307200000000000
|
goth.test/gauge_info.gauge value="{\"arch\":\"amd64\",\"commit\":\"7caa2d8163ae3132c1c2d6978c76610caee2d949\",\"os\":\"linux\",\"protocol_versions\":\"64 65 66\",\"version\":\"1.10.18-unstable\"}" 978307200000000000
|
||||||
goth.test/histogram.histogram count=3i,max=3i,mean=2,min=1i,p25=1,p50=2,p75=3,p95=3,p99=3,p999=3,p9999=3,stddev=0.816496580927726,variance=0.6666666666666666 978307200000000000
|
goth.test/histogram.histogram count=3i,max=3i,mean=2,min=1i,p25=1,p50=2,p75=3,p95=3,p99=3,p999=3,p9999=3,stddev=0.816496580927726,variance=0.6666666666666666 978307200000000000
|
||||||
goth.test/meter.meter count=0i,m1=0,m15=0,m5=0,mean=0 978307200000000000
|
goth.test/meter.meter count=0i,m1=0,m15=0,m5=0,mean=0 978307200000000000
|
||||||
goth.test/resetting_timer.span count=6i,max=120000000i,mean=30000000,min=10000000i,p50=12000000i,p95=120000000i,p99=120000000i 978307200000000000
|
goth.test/resetting_timer.span count=6i,max=120000000i,mean=30000000,min=10000000i,p50=12500000i,p95=120000000i,p99=120000000i 978307200000000000
|
||||||
goth.test/timer.timer count=6i,m1=0,m15=0,m5=0,max=120000000i,mean=38333333.333333336,meanrate=0,min=20000000i,p50=22500000,p75=48000000,p95=120000000,p99=120000000,p999=120000000,p9999=120000000,stddev=36545253.529775314,variance=1335555555555555.2 978307200000000000
|
goth.test/timer.timer count=6i,m1=0,m15=0,m5=0,max=120000000i,mean=38333333.333333336,meanrate=0,min=20000000i,p50=22500000,p75=48000000,p95=120000000,p99=120000000,p999=120000000,p9999=120000000,stddev=36545253.529775314,variance=1335555555555555.2 978307200000000000
|
||||||
|
|
|
||||||
4
metrics/influxdb/testdata/influxdbv2.want
vendored
4
metrics/influxdb/testdata/influxdbv2.want
vendored
|
|
@ -1,3 +1,5 @@
|
||||||
|
goth.system/cpu/schedlatency.histogram count=5645i,max=41943040i,mean=1819544.0410983171,min=0i,p25=0,p50=0,p75=7168,p95=16777216,p99=29360128,p999=33554432,p9999=33554432,stddev=6393570.217198883,variance=40877740122252.57 978307200000000000
|
||||||
|
goth.system/memory/pauses.histogram count=14i,max=229376i,mean=50066.28571428572,min=5120i,p25=10240,p50=32768,p75=57344,p95=196608,p99=196608,p999=196608,p9999=196608,stddev=54726.062410783874,variance=2994941906.9890113 978307200000000000
|
||||||
goth.test/counter.count value=12345 978307200000000000
|
goth.test/counter.count value=12345 978307200000000000
|
||||||
goth.test/counter_float64.count value=54321.98 978307200000000000
|
goth.test/counter_float64.count value=54321.98 978307200000000000
|
||||||
goth.test/gauge.gauge value=23456i 978307200000000000
|
goth.test/gauge.gauge value=23456i 978307200000000000
|
||||||
|
|
@ -5,5 +7,5 @@ goth.test/gauge_float64.gauge value=34567.89 978307200000000000
|
||||||
goth.test/gauge_info.gauge value="{\"arch\":\"amd64\",\"commit\":\"7caa2d8163ae3132c1c2d6978c76610caee2d949\",\"os\":\"linux\",\"protocol_versions\":\"64 65 66\",\"version\":\"1.10.18-unstable\"}" 978307200000000000
|
goth.test/gauge_info.gauge value="{\"arch\":\"amd64\",\"commit\":\"7caa2d8163ae3132c1c2d6978c76610caee2d949\",\"os\":\"linux\",\"protocol_versions\":\"64 65 66\",\"version\":\"1.10.18-unstable\"}" 978307200000000000
|
||||||
goth.test/histogram.histogram count=3i,max=3i,mean=2,min=1i,p25=1,p50=2,p75=3,p95=3,p99=3,p999=3,p9999=3,stddev=0.816496580927726,variance=0.6666666666666666 978307200000000000
|
goth.test/histogram.histogram count=3i,max=3i,mean=2,min=1i,p25=1,p50=2,p75=3,p95=3,p99=3,p999=3,p9999=3,stddev=0.816496580927726,variance=0.6666666666666666 978307200000000000
|
||||||
goth.test/meter.meter count=0i,m1=0,m15=0,m5=0,mean=0 978307200000000000
|
goth.test/meter.meter count=0i,m1=0,m15=0,m5=0,mean=0 978307200000000000
|
||||||
goth.test/resetting_timer.span count=6i,max=120000000i,mean=30000000,min=10000000i,p50=12000000i,p95=120000000i,p99=120000000i 978307200000000000
|
goth.test/resetting_timer.span count=6i,max=120000000i,mean=30000000,min=10000000i,p50=12500000i,p95=120000000i,p99=120000000i 978307200000000000
|
||||||
goth.test/timer.timer count=6i,m1=0,m15=0,m5=0,max=120000000i,mean=38333333.333333336,meanrate=0,min=20000000i,p50=22500000,p75=48000000,p95=120000000,p99=120000000,p999=120000000,p9999=120000000,stddev=36545253.529775314,variance=1335555555555555.2 978307200000000000
|
goth.test/timer.timer count=6i,m1=0,m15=0,m5=0,max=120000000i,mean=38333333.333333336,meanrate=0,min=20000000i,p50=22500000,p75=48000000,p95=120000000,p99=120000000,p999=120000000,p9999=120000000,stddev=36545253.529775314,variance=1335555555555555.2 978307200000000000
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,9 @@
|
||||||
package internal
|
package internal
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/gob"
|
||||||
|
metrics2 "runtime/metrics"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/metrics"
|
"github.com/ethereum/go-ethereum/metrics"
|
||||||
|
|
@ -38,7 +41,15 @@ func ExampleMetrics() metrics.Registry {
|
||||||
"commit": "7caa2d8163ae3132c1c2d6978c76610caee2d949",
|
"commit": "7caa2d8163ae3132c1c2d6978c76610caee2d949",
|
||||||
"protocol_versions": "64 65 66",
|
"protocol_versions": "64 65 66",
|
||||||
})
|
})
|
||||||
metrics.NewRegisteredHistogram("test/histogram", registry, metrics.NewSampleSnapshot(3, []int64{1, 2, 3}))
|
|
||||||
|
{
|
||||||
|
s := metrics.NewUniformSample(3)
|
||||||
|
s.Update(1)
|
||||||
|
s.Update(2)
|
||||||
|
s.Update(3)
|
||||||
|
//metrics.NewRegisteredHistogram("test/histogram", registry, metrics.NewSampleSnapshot(3, []int64{1, 2, 3}))
|
||||||
|
metrics.NewRegisteredHistogram("test/histogram", registry, s)
|
||||||
|
}
|
||||||
registry.Register("test/meter", metrics.NewInactiveMeter())
|
registry.Register("test/meter", metrics.NewInactiveMeter())
|
||||||
{
|
{
|
||||||
timer := metrics.NewRegisteredResettingTimer("test/resetting_timer", registry)
|
timer := metrics.NewRegisteredResettingTimer("test/resetting_timer", registry)
|
||||||
|
|
@ -60,5 +71,25 @@ func ExampleMetrics() metrics.Registry {
|
||||||
timer.Stop()
|
timer.Stop()
|
||||||
}
|
}
|
||||||
registry.Register("test/empty_resetting_timer", metrics.NewResettingTimer().Snapshot())
|
registry.Register("test/empty_resetting_timer", metrics.NewResettingTimer().Snapshot())
|
||||||
|
|
||||||
|
{ // go runtime metrics
|
||||||
|
var sLatency = "7\xff\x81\x03\x01\x01\x10Float64Histogram\x01\xff\x82\x00\x01\x02\x01\x06Counts\x01\xff\x84\x00\x01\aBuckets\x01\xff\x86\x00\x00\x00\x16\xff\x83\x02\x01\x01\b[]uint64\x01\xff\x84\x00\x01\x06\x00\x00\x17\xff\x85\x02\x01\x01\t[]float64\x01\xff\x86\x00\x01\b\x00\x00\xfe\x06T\xff\x82\x01\xff\xa2\x00\xfe\r\xef\x00\x01\x02\x02\x04\x05\x04\b\x15\x17 B?6.L;$!2) \x1a? \x190aH7FY6#\x190\x1d\x14\x10\x1b\r\t\x04\x03\x01\x01\x00\x03\x02\x00\x03\x05\x05\x02\x02\x06\x04\v\x06\n\x15\x18\x13'&.\x12=H/L&\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\xff\xa3\xfe\xf0\xff\x00\xf8\x95\xd6&\xe8\v.q>\xf8\x95\xd6&\xe8\v.\x81>\xf8\xdfA:\xdc\x11ʼn>\xf8\x95\xd6&\xe8\v.\x91>\xf8:\x8c0\xe2\x8ey\x95>\xf8\xdfA:\xdc\x11ř>\xf8\x84\xf7C֔\x10\x9e>\xf8\x95\xd6&\xe8\v.\xa1>\xf8:\x8c0\xe2\x8ey\xa5>\xf8\xdfA:\xdc\x11ũ>\xf8\x84\xf7C֔\x10\xae>\xf8\x95\xd6&\xe8\v.\xb1>\xf8:\x8c0\xe2\x8ey\xb5>\xf8\xdfA:\xdc\x11Ź>\xf8\x84\xf7C֔\x10\xbe>\xf8\x95\xd6&\xe8\v.\xc1>\xf8:\x8c0\xe2\x8ey\xc5>\xf8\xdfA:\xdc\x11\xc5\xc9>\xf8\x84\xf7C֔\x10\xce>\xf8\x95\xd6&\xe8\v.\xd1>\xf8:\x8c0\xe2\x8ey\xd5>\xf8\xdfA:\xdc\x11\xc5\xd9>\xf8\x84\xf7C֔\x10\xde>\xf8\x95\xd6&\xe8\v.\xe1>\xf8:\x8c0\xe2\x8ey\xe5>\xf8\xdfA:\xdc\x11\xc5\xe9>\xf8\x84\xf7C֔\x10\xee>\xf8\x95\xd6&\xe8\v.\xf1>\xf8:\x8c0\xe2\x8ey\xf5>\xf8\xdfA:\xdc\x11\xc5\xf9>\xf8\x84\xf7C֔\x10\xfe>\xf8\x95\xd6&\xe8\v.\x01?\xf8:\x8c0\xe2\x8ey\x05?\xf8\xdfA:\xdc\x11\xc5\t?\xf8\x84\xf7C֔\x10\x0e?\xf8\x95\xd6&\xe8\v.\x11?\xf8:\x8c0\xe2\x8ey\x15?\xf8\xdfA:\xdc\x11\xc5\x19?\xf8\x84\xf7C֔\x10\x1e?\xf8\x95\xd6&\xe8\v.!?\xf8:\x8c0\xe2\x8ey%?\xf8\xdfA:\xdc\x11\xc5)?\xf8\x84\xf7C֔\x10.?\xf8\x95\xd6&\xe8\v.1?\xf8:\x8c0\xe2\x8ey5?\xf8\xdfA:\xdc\x11\xc59?\xf8\x84\xf7C֔\x10>?\xf8\x95\xd6&\xe8\v.A?\xf8:\x8c0\xe2\x8eyE?\xf8\xdfA:\xdc\x11\xc5I?\xf8\x84\xf7C֔\x10N?\xf8\x95\xd6&\xe8\v.Q?\xf8:\x8c0\xe2\x8eyU?\xf8\xdfA:\xdc\x11\xc5Y?\xf8\x84\xf7C֔\x10^?\xf8\x95\xd6&\xe8\v.a?\xf8:\x8c0\xe2\x8eye?\xf8\xdfA:\xdc\x11\xc5i?\xf8\x84\xf7C֔\x10n?\xf8\x95\xd6&\xe8\v.q?\xf8:\x8c0\xe2\x8eyu?\xf8\xdfA:\xdc\x11\xc5y?\xf8\x84\xf7C֔\x10~?\xf8\x95\xd6&\xe8\v.\x81?\xf8:\x8c0\xe2\x8ey\x85?\xf8\xdfA:\xdc\x11ʼn?\xf8\x84\xf7C֔\x10\x8e?\xf8\x95\xd6&\xe8\v.\x91?\xf8:\x8c0\xe2\x8ey\x95?\xf8\xdfA:\xdc\x11ř?\xf8\x84\xf7C֔\x10\x9e?\xf8\x95\xd6&\xe8\v.\xa1?\xf8:\x8c0\xe2\x8ey\xa5?\xf8\xdfA:\xdc\x11ũ?\xf8\x84\xf7C֔\x10\xae?\xf8\x95\xd6&\xe8\v.\xb1?\xf8:\x8c0\xe2\x8ey\xb5?\xf8\xdfA:\xdc\x11Ź?\xf8\x84\xf7C֔\x10\xbe?\xf8\x95\xd6&\xe8\v.\xc1?\xf8:\x8c0\xe2\x8ey\xc5?\xf8\xdfA:\xdc\x11\xc5\xc9?\xf8\x84\xf7C֔\x10\xce?\xf8\x95\xd6&\xe8\v.\xd1?\xf8:\x8c0\xe2\x8ey\xd5?\xf8\xdfA:\xdc\x11\xc5\xd9?\xf8\x84\xf7C֔\x10\xde?\xf8\x95\xd6&\xe8\v.\xe1?\xf8:\x8c0\xe2\x8ey\xe5?\xf8\xdfA:\xdc\x11\xc5\xe9?\xf8\x84\xf7C֔\x10\xee?\xf8\x95\xd6&\xe8\v.\xf1?\xf8:\x8c0\xe2\x8ey\xf5?\xf8\xdfA:\xdc\x11\xc5\xf9?\xf8\x84\xf7C֔\x10\xfe?\xf8\x95\xd6&\xe8\v.\x01@\xf8:\x8c0\xe2\x8ey\x05@\xf8\xdfA:\xdc\x11\xc5\t@\xf8\x84\xf7C֔\x10\x0e@\xf8\x95\xd6&\xe8\v.\x11@\xf8:\x8c0\xe2\x8ey\x15@\xf8\xdfA:\xdc\x11\xc5\x19@\xf8\x84\xf7C֔\x10\x1e@\xf8\x95\xd6&\xe8\v.!@\xf8:\x8c0\xe2\x8ey%@\xf8\xdfA:\xdc\x11\xc5)@\xf8\x84\xf7C֔\x10.@\xf8\x95\xd6&\xe8\v.1@\xf8:\x8c0\xe2\x8ey5@\xf8\xdfA:\xdc\x11\xc59@\xf8\x84\xf7C֔\x10>@\xf8\x95\xd6&\xe8\v.A@\xf8:\x8c0\xe2\x8eyE@\xf8\xdfA:\xdc\x11\xc5I@\xf8\x84\xf7C֔\x10N@\xf8\x95\xd6&\xe8\v.Q@\xf8:\x8c0\xe2\x8eyU@\xf8\xdfA:\xdc\x11\xc5Y@\xf8\x84\xf7C֔\x10^@\xf8\x95\xd6&\xe8\v.a@\xf8:\x8c0\xe2\x8eye@\xf8\xdfA:\xdc\x11\xc5i@\xf8\x84\xf7C֔\x10n@\xf8\x95\xd6&\xe8\v.q@\xf8:\x8c0\xe2\x8eyu@\xf8\xdfA:\xdc\x11\xc5y@\xf8\x84\xf7C֔\x10~@\xf8\x95\xd6&\xe8\v.\x81@\xf8:\x8c0\xe2\x8ey\x85@\xf8\xdfA:\xdc\x11ʼn@\xf8\x84\xf7C֔\x10\x8e@\xf8\x95\xd6&\xe8\v.\x91@\xf8:\x8c0\xe2\x8ey\x95@\xf8\xdfA:\xdc\x11ř@\xf8\x84\xf7C֔\x10\x9e@\xf8\x95\xd6&\xe8\v.\xa1@\xf8:\x8c0\xe2\x8ey\xa5@\xf8\xdfA:\xdc\x11ũ@\xf8\x84\xf7C֔\x10\xae@\xf8\x95\xd6&\xe8\v.\xb1@\xf8:\x8c0\xe2\x8ey\xb5@\xf8\xdfA:\xdc\x11Ź@\xf8\x84\xf7C֔\x10\xbe@\xf8\x95\xd6&\xe8\v.\xc1@\xf8:\x8c0\xe2\x8ey\xc5@\xf8\xdfA:\xdc\x11\xc5\xc9@\xf8\x84\xf7C֔\x10\xce@\xf8\x95\xd6&\xe8\v.\xd1@\xf8:\x8c0\xe2\x8ey\xd5@\xf8\xdfA:\xdc\x11\xc5\xd9@\xf8\x84\xf7C֔\x10\xde@\xf8\x95\xd6&\xe8\v.\xe1@\xf8:\x8c0\xe2\x8ey\xe5@\xf8\xdfA:\xdc\x11\xc5\xe9@\xf8\x84\xf7C֔\x10\xee@\xf8\x95\xd6&\xe8\v.\xf1@\xf8:\x8c0\xe2\x8ey\xf5@\xf8\xdfA:\xdc\x11\xc5\xf9@\xf8\x84\xf7C֔\x10\xfe@\xf8\x95\xd6&\xe8\v.\x01A\xfe\xf0\x7f\x00"
|
||||||
|
var gcPauses = "7\xff\x81\x03\x01\x01\x10Float64Histogram\x01\xff\x82\x00\x01\x02\x01\x06Counts\x01\xff\x84\x00\x01\aBuckets\x01\xff\x86\x00\x00\x00\x16\xff\x83\x02\x01\x01\b[]uint64\x01\xff\x84\x00\x01\x06\x00\x00\x17\xff\x85\x02\x01\x01\t[]float64\x01\xff\x86\x00\x01\b\x00\x00\xfe\x06R\xff\x82\x01\xff\xa2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x01\x01\x00\x01\x00\x00\x00\x01\x01\x01\x01\x01\x01\x01\x00\x02\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\xff\xa3\xfe\xf0\xff\x00\xf8\x95\xd6&\xe8\v.q>\xf8\x95\xd6&\xe8\v.\x81>\xf8\xdfA:\xdc\x11ʼn>\xf8\x95\xd6&\xe8\v.\x91>\xf8:\x8c0\xe2\x8ey\x95>\xf8\xdfA:\xdc\x11ř>\xf8\x84\xf7C֔\x10\x9e>\xf8\x95\xd6&\xe8\v.\xa1>\xf8:\x8c0\xe2\x8ey\xa5>\xf8\xdfA:\xdc\x11ũ>\xf8\x84\xf7C֔\x10\xae>\xf8\x95\xd6&\xe8\v.\xb1>\xf8:\x8c0\xe2\x8ey\xb5>\xf8\xdfA:\xdc\x11Ź>\xf8\x84\xf7C֔\x10\xbe>\xf8\x95\xd6&\xe8\v.\xc1>\xf8:\x8c0\xe2\x8ey\xc5>\xf8\xdfA:\xdc\x11\xc5\xc9>\xf8\x84\xf7C֔\x10\xce>\xf8\x95\xd6&\xe8\v.\xd1>\xf8:\x8c0\xe2\x8ey\xd5>\xf8\xdfA:\xdc\x11\xc5\xd9>\xf8\x84\xf7C֔\x10\xde>\xf8\x95\xd6&\xe8\v.\xe1>\xf8:\x8c0\xe2\x8ey\xe5>\xf8\xdfA:\xdc\x11\xc5\xe9>\xf8\x84\xf7C֔\x10\xee>\xf8\x95\xd6&\xe8\v.\xf1>\xf8:\x8c0\xe2\x8ey\xf5>\xf8\xdfA:\xdc\x11\xc5\xf9>\xf8\x84\xf7C֔\x10\xfe>\xf8\x95\xd6&\xe8\v.\x01?\xf8:\x8c0\xe2\x8ey\x05?\xf8\xdfA:\xdc\x11\xc5\t?\xf8\x84\xf7C֔\x10\x0e?\xf8\x95\xd6&\xe8\v.\x11?\xf8:\x8c0\xe2\x8ey\x15?\xf8\xdfA:\xdc\x11\xc5\x19?\xf8\x84\xf7C֔\x10\x1e?\xf8\x95\xd6&\xe8\v.!?\xf8:\x8c0\xe2\x8ey%?\xf8\xdfA:\xdc\x11\xc5)?\xf8\x84\xf7C֔\x10.?\xf8\x95\xd6&\xe8\v.1?\xf8:\x8c0\xe2\x8ey5?\xf8\xdfA:\xdc\x11\xc59?\xf8\x84\xf7C֔\x10>?\xf8\x95\xd6&\xe8\v.A?\xf8:\x8c0\xe2\x8eyE?\xf8\xdfA:\xdc\x11\xc5I?\xf8\x84\xf7C֔\x10N?\xf8\x95\xd6&\xe8\v.Q?\xf8:\x8c0\xe2\x8eyU?\xf8\xdfA:\xdc\x11\xc5Y?\xf8\x84\xf7C֔\x10^?\xf8\x95\xd6&\xe8\v.a?\xf8:\x8c0\xe2\x8eye?\xf8\xdfA:\xdc\x11\xc5i?\xf8\x84\xf7C֔\x10n?\xf8\x95\xd6&\xe8\v.q?\xf8:\x8c0\xe2\x8eyu?\xf8\xdfA:\xdc\x11\xc5y?\xf8\x84\xf7C֔\x10~?\xf8\x95\xd6&\xe8\v.\x81?\xf8:\x8c0\xe2\x8ey\x85?\xf8\xdfA:\xdc\x11ʼn?\xf8\x84\xf7C֔\x10\x8e?\xf8\x95\xd6&\xe8\v.\x91?\xf8:\x8c0\xe2\x8ey\x95?\xf8\xdfA:\xdc\x11ř?\xf8\x84\xf7C֔\x10\x9e?\xf8\x95\xd6&\xe8\v.\xa1?\xf8:\x8c0\xe2\x8ey\xa5?\xf8\xdfA:\xdc\x11ũ?\xf8\x84\xf7C֔\x10\xae?\xf8\x95\xd6&\xe8\v.\xb1?\xf8:\x8c0\xe2\x8ey\xb5?\xf8\xdfA:\xdc\x11Ź?\xf8\x84\xf7C֔\x10\xbe?\xf8\x95\xd6&\xe8\v.\xc1?\xf8:\x8c0\xe2\x8ey\xc5?\xf8\xdfA:\xdc\x11\xc5\xc9?\xf8\x84\xf7C֔\x10\xce?\xf8\x95\xd6&\xe8\v.\xd1?\xf8:\x8c0\xe2\x8ey\xd5?\xf8\xdfA:\xdc\x11\xc5\xd9?\xf8\x84\xf7C֔\x10\xde?\xf8\x95\xd6&\xe8\v.\xe1?\xf8:\x8c0\xe2\x8ey\xe5?\xf8\xdfA:\xdc\x11\xc5\xe9?\xf8\x84\xf7C֔\x10\xee?\xf8\x95\xd6&\xe8\v.\xf1?\xf8:\x8c0\xe2\x8ey\xf5?\xf8\xdfA:\xdc\x11\xc5\xf9?\xf8\x84\xf7C֔\x10\xfe?\xf8\x95\xd6&\xe8\v.\x01@\xf8:\x8c0\xe2\x8ey\x05@\xf8\xdfA:\xdc\x11\xc5\t@\xf8\x84\xf7C֔\x10\x0e@\xf8\x95\xd6&\xe8\v.\x11@\xf8:\x8c0\xe2\x8ey\x15@\xf8\xdfA:\xdc\x11\xc5\x19@\xf8\x84\xf7C֔\x10\x1e@\xf8\x95\xd6&\xe8\v.!@\xf8:\x8c0\xe2\x8ey%@\xf8\xdfA:\xdc\x11\xc5)@\xf8\x84\xf7C֔\x10.@\xf8\x95\xd6&\xe8\v.1@\xf8:\x8c0\xe2\x8ey5@\xf8\xdfA:\xdc\x11\xc59@\xf8\x84\xf7C֔\x10>@\xf8\x95\xd6&\xe8\v.A@\xf8:\x8c0\xe2\x8eyE@\xf8\xdfA:\xdc\x11\xc5I@\xf8\x84\xf7C֔\x10N@\xf8\x95\xd6&\xe8\v.Q@\xf8:\x8c0\xe2\x8eyU@\xf8\xdfA:\xdc\x11\xc5Y@\xf8\x84\xf7C֔\x10^@\xf8\x95\xd6&\xe8\v.a@\xf8:\x8c0\xe2\x8eye@\xf8\xdfA:\xdc\x11\xc5i@\xf8\x84\xf7C֔\x10n@\xf8\x95\xd6&\xe8\v.q@\xf8:\x8c0\xe2\x8eyu@\xf8\xdfA:\xdc\x11\xc5y@\xf8\x84\xf7C֔\x10~@\xf8\x95\xd6&\xe8\v.\x81@\xf8:\x8c0\xe2\x8ey\x85@\xf8\xdfA:\xdc\x11ʼn@\xf8\x84\xf7C֔\x10\x8e@\xf8\x95\xd6&\xe8\v.\x91@\xf8:\x8c0\xe2\x8ey\x95@\xf8\xdfA:\xdc\x11ř@\xf8\x84\xf7C֔\x10\x9e@\xf8\x95\xd6&\xe8\v.\xa1@\xf8:\x8c0\xe2\x8ey\xa5@\xf8\xdfA:\xdc\x11ũ@\xf8\x84\xf7C֔\x10\xae@\xf8\x95\xd6&\xe8\v.\xb1@\xf8:\x8c0\xe2\x8ey\xb5@\xf8\xdfA:\xdc\x11Ź@\xf8\x84\xf7C֔\x10\xbe@\xf8\x95\xd6&\xe8\v.\xc1@\xf8:\x8c0\xe2\x8ey\xc5@\xf8\xdfA:\xdc\x11\xc5\xc9@\xf8\x84\xf7C֔\x10\xce@\xf8\x95\xd6&\xe8\v.\xd1@\xf8:\x8c0\xe2\x8ey\xd5@\xf8\xdfA:\xdc\x11\xc5\xd9@\xf8\x84\xf7C֔\x10\xde@\xf8\x95\xd6&\xe8\v.\xe1@\xf8:\x8c0\xe2\x8ey\xe5@\xf8\xdfA:\xdc\x11\xc5\xe9@\xf8\x84\xf7C֔\x10\xee@\xf8\x95\xd6&\xe8\v.\xf1@\xf8:\x8c0\xe2\x8ey\xf5@\xf8\xdfA:\xdc\x11\xc5\xf9@\xf8\x84\xf7C֔\x10\xfe@\xf8\x95\xd6&\xe8\v.\x01A\xfe\xf0\x7f\x00"
|
||||||
|
|
||||||
|
var secondsToNs = float64(time.Second)
|
||||||
|
|
||||||
|
dserialize := func(data string) *metrics2.Float64Histogram {
|
||||||
|
var res metrics2.Float64Histogram
|
||||||
|
if err := gob.NewDecoder(bytes.NewReader([]byte(data))).Decode(&res); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return &res
|
||||||
|
}
|
||||||
|
cpuSchedLatency := metrics.RuntimeHistogramFromData(secondsToNs, dserialize(sLatency))
|
||||||
|
registry.Register("system/cpu/schedlatency", cpuSchedLatency)
|
||||||
|
|
||||||
|
memPauses := metrics.RuntimeHistogramFromData(secondsToNs, dserialize(gcPauses))
|
||||||
|
registry.Register("system/memory/pauses", memPauses)
|
||||||
|
}
|
||||||
return registry
|
return registry
|
||||||
}
|
}
|
||||||
|
|
|
||||||
27
metrics/internal/sampledata_test.go
Normal file
27
metrics/internal/sampledata_test.go
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
package internal
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/gob"
|
||||||
|
"fmt"
|
||||||
|
metrics2 "runtime/metrics"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/metrics"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestCollectRuntimeMetrics(t *testing.T) {
|
||||||
|
t.Skip("Only used for generating testdata")
|
||||||
|
serialize := func(path string, histogram *metrics2.Float64Histogram) {
|
||||||
|
var f = new(bytes.Buffer)
|
||||||
|
if err := gob.NewEncoder(f).Encode(histogram); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
fmt.Printf("var %v = %q\n", path, f.Bytes())
|
||||||
|
}
|
||||||
|
time.Sleep(2 * time.Second)
|
||||||
|
stats := metrics.ReadRuntimeStats()
|
||||||
|
serialize("schedlatency", stats.SchedLatency)
|
||||||
|
serialize("gcpauses", stats.GCPauses)
|
||||||
|
}
|
||||||
|
|
@ -61,16 +61,16 @@ func (rep *Reporter) Run() {
|
||||||
|
|
||||||
// calculate sum of squares from data provided by metrics.Histogram
|
// calculate sum of squares from data provided by metrics.Histogram
|
||||||
// see http://en.wikipedia.org/wiki/Standard_deviation#Rapid_calculation_methods
|
// see http://en.wikipedia.org/wiki/Standard_deviation#Rapid_calculation_methods
|
||||||
func sumSquares(s metrics.Sample) float64 {
|
func sumSquares(icount int64, mean, stDev float64) float64 {
|
||||||
count := float64(s.Count())
|
count := float64(icount)
|
||||||
sumSquared := math.Pow(count*s.Mean(), 2)
|
sumSquared := math.Pow(count*mean, 2)
|
||||||
sumSquares := math.Pow(count*s.StdDev(), 2) + sumSquared/count
|
sumSquares := math.Pow(count*stDev, 2) + sumSquared/count
|
||||||
if math.IsNaN(sumSquares) {
|
if math.IsNaN(sumSquares) {
|
||||||
return 0.0
|
return 0.0
|
||||||
}
|
}
|
||||||
return sumSquares
|
return sumSquares
|
||||||
}
|
}
|
||||||
func sumSquaresTimer(t metrics.Timer) float64 {
|
func sumSquaresTimer(t metrics.TimerSnapshot) float64 {
|
||||||
count := float64(t.Count())
|
count := float64(t.Count())
|
||||||
sumSquared := math.Pow(count*t.Mean(), 2)
|
sumSquared := math.Pow(count*t.Mean(), 2)
|
||||||
sumSquares := math.Pow(count*t.StdDev(), 2) + sumSquared/count
|
sumSquares := math.Pow(count*t.StdDev(), 2) + sumSquared/count
|
||||||
|
|
@ -97,9 +97,10 @@ func (rep *Reporter) BuildRequest(now time.Time, r metrics.Registry) (snapshot B
|
||||||
measurement[Period] = rep.Interval.Seconds()
|
measurement[Period] = rep.Interval.Seconds()
|
||||||
switch m := metric.(type) {
|
switch m := metric.(type) {
|
||||||
case metrics.Counter:
|
case metrics.Counter:
|
||||||
if m.Count() > 0 {
|
ms := m.Snapshot()
|
||||||
|
if ms.Count() > 0 {
|
||||||
measurement[Name] = fmt.Sprintf("%s.%s", name, "count")
|
measurement[Name] = fmt.Sprintf("%s.%s", name, "count")
|
||||||
measurement[Value] = float64(m.Count())
|
measurement[Value] = float64(ms.Count())
|
||||||
measurement[Attributes] = map[string]interface{}{
|
measurement[Attributes] = map[string]interface{}{
|
||||||
DisplayUnitsLong: Operations,
|
DisplayUnitsLong: Operations,
|
||||||
DisplayUnitsShort: OperationsShort,
|
DisplayUnitsShort: OperationsShort,
|
||||||
|
|
@ -108,9 +109,9 @@ func (rep *Reporter) BuildRequest(now time.Time, r metrics.Registry) (snapshot B
|
||||||
snapshot.Counters = append(snapshot.Counters, measurement)
|
snapshot.Counters = append(snapshot.Counters, measurement)
|
||||||
}
|
}
|
||||||
case metrics.CounterFloat64:
|
case metrics.CounterFloat64:
|
||||||
if m.Count() > 0 {
|
if count := m.Snapshot().Count(); count > 0 {
|
||||||
measurement[Name] = fmt.Sprintf("%s.%s", name, "count")
|
measurement[Name] = fmt.Sprintf("%s.%s", name, "count")
|
||||||
measurement[Value] = m.Count()
|
measurement[Value] = count
|
||||||
measurement[Attributes] = map[string]interface{}{
|
measurement[Attributes] = map[string]interface{}{
|
||||||
DisplayUnitsLong: Operations,
|
DisplayUnitsLong: Operations,
|
||||||
DisplayUnitsShort: OperationsShort,
|
DisplayUnitsShort: OperationsShort,
|
||||||
|
|
@ -120,44 +121,45 @@ func (rep *Reporter) BuildRequest(now time.Time, r metrics.Registry) (snapshot B
|
||||||
}
|
}
|
||||||
case metrics.Gauge:
|
case metrics.Gauge:
|
||||||
measurement[Name] = name
|
measurement[Name] = name
|
||||||
measurement[Value] = float64(m.Value())
|
measurement[Value] = float64(m.Snapshot().Value())
|
||||||
snapshot.Gauges = append(snapshot.Gauges, measurement)
|
snapshot.Gauges = append(snapshot.Gauges, measurement)
|
||||||
case metrics.GaugeFloat64:
|
case metrics.GaugeFloat64:
|
||||||
measurement[Name] = name
|
measurement[Name] = name
|
||||||
measurement[Value] = m.Value()
|
measurement[Value] = m.Snapshot().Value()
|
||||||
snapshot.Gauges = append(snapshot.Gauges, measurement)
|
snapshot.Gauges = append(snapshot.Gauges, measurement)
|
||||||
case metrics.GaugeInfo:
|
case metrics.GaugeInfo:
|
||||||
measurement[Name] = name
|
measurement[Name] = name
|
||||||
measurement[Value] = m.Value()
|
measurement[Value] = m.Snapshot().Value()
|
||||||
snapshot.Gauges = append(snapshot.Gauges, measurement)
|
snapshot.Gauges = append(snapshot.Gauges, measurement)
|
||||||
case metrics.Histogram:
|
case metrics.Histogram:
|
||||||
if m.Count() > 0 {
|
ms := m.Snapshot()
|
||||||
|
if ms.Count() > 0 {
|
||||||
gauges := make([]Measurement, histogramGaugeCount)
|
gauges := make([]Measurement, histogramGaugeCount)
|
||||||
s := m.Sample()
|
|
||||||
measurement[Name] = fmt.Sprintf("%s.%s", name, "hist")
|
measurement[Name] = fmt.Sprintf("%s.%s", name, "hist")
|
||||||
measurement[Count] = uint64(s.Count())
|
measurement[Count] = uint64(ms.Count())
|
||||||
measurement[Max] = float64(s.Max())
|
measurement[Max] = float64(ms.Max())
|
||||||
measurement[Min] = float64(s.Min())
|
measurement[Min] = float64(ms.Min())
|
||||||
measurement[Sum] = float64(s.Sum())
|
measurement[Sum] = float64(ms.Sum())
|
||||||
measurement[SumSquares] = sumSquares(s)
|
measurement[SumSquares] = sumSquares(ms.Count(), ms.Mean(), ms.StdDev())
|
||||||
gauges[0] = measurement
|
gauges[0] = measurement
|
||||||
for i, p := range rep.Percentiles {
|
for i, p := range rep.Percentiles {
|
||||||
gauges[i+1] = Measurement{
|
gauges[i+1] = Measurement{
|
||||||
Name: fmt.Sprintf("%s.%.2f", measurement[Name], p),
|
Name: fmt.Sprintf("%s.%.2f", measurement[Name], p),
|
||||||
Value: s.Percentile(p),
|
Value: ms.Percentile(p),
|
||||||
Period: measurement[Period],
|
Period: measurement[Period],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
snapshot.Gauges = append(snapshot.Gauges, gauges...)
|
snapshot.Gauges = append(snapshot.Gauges, gauges...)
|
||||||
}
|
}
|
||||||
case metrics.Meter:
|
case metrics.Meter:
|
||||||
|
ms := m.Snapshot()
|
||||||
measurement[Name] = name
|
measurement[Name] = name
|
||||||
measurement[Value] = float64(m.Count())
|
measurement[Value] = float64(ms.Count())
|
||||||
snapshot.Counters = append(snapshot.Counters, measurement)
|
snapshot.Counters = append(snapshot.Counters, measurement)
|
||||||
snapshot.Gauges = append(snapshot.Gauges,
|
snapshot.Gauges = append(snapshot.Gauges,
|
||||||
Measurement{
|
Measurement{
|
||||||
Name: fmt.Sprintf("%s.%s", name, "1min"),
|
Name: fmt.Sprintf("%s.%s", name, "1min"),
|
||||||
Value: m.Rate1(),
|
Value: ms.Rate1(),
|
||||||
Period: int64(rep.Interval.Seconds()),
|
Period: int64(rep.Interval.Seconds()),
|
||||||
Attributes: map[string]interface{}{
|
Attributes: map[string]interface{}{
|
||||||
DisplayUnitsLong: Operations,
|
DisplayUnitsLong: Operations,
|
||||||
|
|
@ -167,7 +169,7 @@ func (rep *Reporter) BuildRequest(now time.Time, r metrics.Registry) (snapshot B
|
||||||
},
|
},
|
||||||
Measurement{
|
Measurement{
|
||||||
Name: fmt.Sprintf("%s.%s", name, "5min"),
|
Name: fmt.Sprintf("%s.%s", name, "5min"),
|
||||||
Value: m.Rate5(),
|
Value: ms.Rate5(),
|
||||||
Period: int64(rep.Interval.Seconds()),
|
Period: int64(rep.Interval.Seconds()),
|
||||||
Attributes: map[string]interface{}{
|
Attributes: map[string]interface{}{
|
||||||
DisplayUnitsLong: Operations,
|
DisplayUnitsLong: Operations,
|
||||||
|
|
@ -177,7 +179,7 @@ func (rep *Reporter) BuildRequest(now time.Time, r metrics.Registry) (snapshot B
|
||||||
},
|
},
|
||||||
Measurement{
|
Measurement{
|
||||||
Name: fmt.Sprintf("%s.%s", name, "15min"),
|
Name: fmt.Sprintf("%s.%s", name, "15min"),
|
||||||
Value: m.Rate15(),
|
Value: ms.Rate15(),
|
||||||
Period: int64(rep.Interval.Seconds()),
|
Period: int64(rep.Interval.Seconds()),
|
||||||
Attributes: map[string]interface{}{
|
Attributes: map[string]interface{}{
|
||||||
DisplayUnitsLong: Operations,
|
DisplayUnitsLong: Operations,
|
||||||
|
|
@ -187,26 +189,27 @@ func (rep *Reporter) BuildRequest(now time.Time, r metrics.Registry) (snapshot B
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
case metrics.Timer:
|
case metrics.Timer:
|
||||||
|
ms := m.Snapshot()
|
||||||
measurement[Name] = name
|
measurement[Name] = name
|
||||||
measurement[Value] = float64(m.Count())
|
measurement[Value] = float64(ms.Count())
|
||||||
snapshot.Counters = append(snapshot.Counters, measurement)
|
snapshot.Counters = append(snapshot.Counters, measurement)
|
||||||
if m.Count() > 0 {
|
if ms.Count() > 0 {
|
||||||
libratoName := fmt.Sprintf("%s.%s", name, "timer.mean")
|
libratoName := fmt.Sprintf("%s.%s", name, "timer.mean")
|
||||||
gauges := make([]Measurement, histogramGaugeCount)
|
gauges := make([]Measurement, histogramGaugeCount)
|
||||||
gauges[0] = Measurement{
|
gauges[0] = Measurement{
|
||||||
Name: libratoName,
|
Name: libratoName,
|
||||||
Count: uint64(m.Count()),
|
Count: uint64(ms.Count()),
|
||||||
Sum: m.Mean() * float64(m.Count()),
|
Sum: ms.Mean() * float64(ms.Count()),
|
||||||
Max: float64(m.Max()),
|
Max: float64(ms.Max()),
|
||||||
Min: float64(m.Min()),
|
Min: float64(ms.Min()),
|
||||||
SumSquares: sumSquaresTimer(m),
|
SumSquares: sumSquaresTimer(ms),
|
||||||
Period: int64(rep.Interval.Seconds()),
|
Period: int64(rep.Interval.Seconds()),
|
||||||
Attributes: rep.TimerAttributes,
|
Attributes: rep.TimerAttributes,
|
||||||
}
|
}
|
||||||
for i, p := range rep.Percentiles {
|
for i, p := range rep.Percentiles {
|
||||||
gauges[i+1] = Measurement{
|
gauges[i+1] = Measurement{
|
||||||
Name: fmt.Sprintf("%s.timer.%2.0f", name, p*100),
|
Name: fmt.Sprintf("%s.timer.%2.0f", name, p*100),
|
||||||
Value: m.Percentile(p),
|
Value: ms.Percentile(p),
|
||||||
Period: int64(rep.Interval.Seconds()),
|
Period: int64(rep.Interval.Seconds()),
|
||||||
Attributes: rep.TimerAttributes,
|
Attributes: rep.TimerAttributes,
|
||||||
}
|
}
|
||||||
|
|
@ -215,7 +218,7 @@ func (rep *Reporter) BuildRequest(now time.Time, r metrics.Registry) (snapshot B
|
||||||
snapshot.Gauges = append(snapshot.Gauges,
|
snapshot.Gauges = append(snapshot.Gauges,
|
||||||
Measurement{
|
Measurement{
|
||||||
Name: fmt.Sprintf("%s.%s", name, "rate.1min"),
|
Name: fmt.Sprintf("%s.%s", name, "rate.1min"),
|
||||||
Value: m.Rate1(),
|
Value: ms.Rate1(),
|
||||||
Period: int64(rep.Interval.Seconds()),
|
Period: int64(rep.Interval.Seconds()),
|
||||||
Attributes: map[string]interface{}{
|
Attributes: map[string]interface{}{
|
||||||
DisplayUnitsLong: Operations,
|
DisplayUnitsLong: Operations,
|
||||||
|
|
@ -225,7 +228,7 @@ func (rep *Reporter) BuildRequest(now time.Time, r metrics.Registry) (snapshot B
|
||||||
},
|
},
|
||||||
Measurement{
|
Measurement{
|
||||||
Name: fmt.Sprintf("%s.%s", name, "rate.5min"),
|
Name: fmt.Sprintf("%s.%s", name, "rate.5min"),
|
||||||
Value: m.Rate5(),
|
Value: ms.Rate5(),
|
||||||
Period: int64(rep.Interval.Seconds()),
|
Period: int64(rep.Interval.Seconds()),
|
||||||
Attributes: map[string]interface{}{
|
Attributes: map[string]interface{}{
|
||||||
DisplayUnitsLong: Operations,
|
DisplayUnitsLong: Operations,
|
||||||
|
|
@ -235,7 +238,7 @@ func (rep *Reporter) BuildRequest(now time.Time, r metrics.Registry) (snapshot B
|
||||||
},
|
},
|
||||||
Measurement{
|
Measurement{
|
||||||
Name: fmt.Sprintf("%s.%s", name, "rate.15min"),
|
Name: fmt.Sprintf("%s.%s", name, "rate.15min"),
|
||||||
Value: m.Rate15(),
|
Value: ms.Rate15(),
|
||||||
Period: int64(rep.Interval.Seconds()),
|
Period: int64(rep.Interval.Seconds()),
|
||||||
Attributes: map[string]interface{}{
|
Attributes: map[string]interface{}{
|
||||||
DisplayUnitsLong: Operations,
|
DisplayUnitsLong: Operations,
|
||||||
|
|
|
||||||
|
|
@ -23,19 +23,19 @@ func LogScaled(r Registry, freq time.Duration, scale time.Duration, l Logger) {
|
||||||
switch metric := i.(type) {
|
switch metric := i.(type) {
|
||||||
case Counter:
|
case Counter:
|
||||||
l.Printf("counter %s\n", name)
|
l.Printf("counter %s\n", name)
|
||||||
l.Printf(" count: %9d\n", metric.Count())
|
l.Printf(" count: %9d\n", metric.Snapshot().Count())
|
||||||
case CounterFloat64:
|
case CounterFloat64:
|
||||||
l.Printf("counter %s\n", name)
|
l.Printf("counter %s\n", name)
|
||||||
l.Printf(" count: %f\n", metric.Count())
|
l.Printf(" count: %f\n", metric.Snapshot().Count())
|
||||||
case Gauge:
|
case Gauge:
|
||||||
l.Printf("gauge %s\n", name)
|
l.Printf("gauge %s\n", name)
|
||||||
l.Printf(" value: %9d\n", metric.Value())
|
l.Printf(" value: %9d\n", metric.Snapshot().Value())
|
||||||
case GaugeFloat64:
|
case GaugeFloat64:
|
||||||
l.Printf("gauge %s\n", name)
|
l.Printf("gauge %s\n", name)
|
||||||
l.Printf(" value: %f\n", metric.Value())
|
l.Printf(" value: %f\n", metric.Snapshot().Value())
|
||||||
case GaugeInfo:
|
case GaugeInfo:
|
||||||
l.Printf("gauge %s\n", name)
|
l.Printf("gauge %s\n", name)
|
||||||
l.Printf(" value: %s\n", metric.Value())
|
l.Printf(" value: %s\n", metric.Snapshot().Value())
|
||||||
case Healthcheck:
|
case Healthcheck:
|
||||||
metric.Check()
|
metric.Check()
|
||||||
l.Printf("healthcheck %s\n", name)
|
l.Printf("healthcheck %s\n", name)
|
||||||
|
|
|
||||||
205
metrics/meter.go
205
metrics/meter.go
|
|
@ -1,21 +1,25 @@
|
||||||
package metrics
|
package metrics
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"math"
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Meters count events to produce exponentially-weighted moving average rates
|
type MeterSnapshot interface {
|
||||||
// at one-, five-, and fifteen-minutes and a mean rate.
|
|
||||||
type Meter interface {
|
|
||||||
Count() int64
|
Count() int64
|
||||||
Mark(int64)
|
|
||||||
Rate1() float64
|
Rate1() float64
|
||||||
Rate5() float64
|
Rate5() float64
|
||||||
Rate15() float64
|
Rate15() float64
|
||||||
RateMean() float64
|
RateMean() float64
|
||||||
Snapshot() Meter
|
}
|
||||||
|
|
||||||
|
// Meters count events to produce exponentially-weighted moving average rates
|
||||||
|
// at one-, five-, and fifteen-minutes and a mean rate.
|
||||||
|
type Meter interface {
|
||||||
|
Mark(int64)
|
||||||
|
Snapshot() MeterSnapshot
|
||||||
Stop()
|
Stop()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -30,17 +34,6 @@ func GetOrRegisterMeter(name string, r Registry) Meter {
|
||||||
return r.GetOrRegister(name, NewMeter).(Meter)
|
return r.GetOrRegister(name, NewMeter).(Meter)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetOrRegisterMeterForced returns an existing Meter or constructs and registers a
|
|
||||||
// new StandardMeter no matter the global switch is enabled or not.
|
|
||||||
// Be sure to unregister the meter from the registry once it is of no use to
|
|
||||||
// allow for garbage collection.
|
|
||||||
func GetOrRegisterMeterForced(name string, r Registry) Meter {
|
|
||||||
if nil == r {
|
|
||||||
r = DefaultRegistry
|
|
||||||
}
|
|
||||||
return r.GetOrRegister(name, NewMeterForced).(Meter)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewMeter constructs a new StandardMeter and launches a goroutine.
|
// NewMeter constructs a new StandardMeter and launches a goroutine.
|
||||||
// Be sure to call Stop() once the meter is of no use to allow for garbage collection.
|
// Be sure to call Stop() once the meter is of no use to allow for garbage collection.
|
||||||
func NewMeter() Meter {
|
func NewMeter() Meter {
|
||||||
|
|
@ -68,115 +61,53 @@ func NewInactiveMeter() Meter {
|
||||||
return m
|
return m
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewMeterForced constructs a new StandardMeter and launches a goroutine no matter
|
|
||||||
// the global switch is enabled or not.
|
|
||||||
// Be sure to call Stop() once the meter is of no use to allow for garbage collection.
|
|
||||||
func NewMeterForced() Meter {
|
|
||||||
m := newStandardMeter()
|
|
||||||
arbiter.Lock()
|
|
||||||
defer arbiter.Unlock()
|
|
||||||
arbiter.meters[m] = struct{}{}
|
|
||||||
if !arbiter.started {
|
|
||||||
arbiter.started = true
|
|
||||||
go arbiter.tick()
|
|
||||||
}
|
|
||||||
return m
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewRegisteredMeter constructs and registers a new StandardMeter
|
// NewRegisteredMeter constructs and registers a new StandardMeter
|
||||||
// and launches a goroutine.
|
// and launches a goroutine.
|
||||||
// Be sure to unregister the meter from the registry once it is of no use to
|
// Be sure to unregister the meter from the registry once it is of no use to
|
||||||
// allow for garbage collection.
|
// allow for garbage collection.
|
||||||
func NewRegisteredMeter(name string, r Registry) Meter {
|
func NewRegisteredMeter(name string, r Registry) Meter {
|
||||||
c := NewMeter()
|
return GetOrRegisterMeter(name, r)
|
||||||
if nil == r {
|
|
||||||
r = DefaultRegistry
|
|
||||||
}
|
|
||||||
r.Register(name, c)
|
|
||||||
return c
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewRegisteredMeterForced constructs and registers a new StandardMeter
|
// meterSnapshot is a read-only copy of the meter's internal values.
|
||||||
// and launches a goroutine no matter the global switch is enabled or not.
|
type meterSnapshot struct {
|
||||||
// Be sure to unregister the meter from the registry once it is of no use to
|
|
||||||
// allow for garbage collection.
|
|
||||||
func NewRegisteredMeterForced(name string, r Registry) Meter {
|
|
||||||
c := NewMeterForced()
|
|
||||||
if nil == r {
|
|
||||||
r = DefaultRegistry
|
|
||||||
}
|
|
||||||
r.Register(name, c)
|
|
||||||
return c
|
|
||||||
}
|
|
||||||
|
|
||||||
// MeterSnapshot is a read-only copy of another Meter.
|
|
||||||
type MeterSnapshot struct {
|
|
||||||
temp atomic.Int64
|
|
||||||
count int64
|
count int64
|
||||||
rate1, rate5, rate15, rateMean float64
|
rate1, rate5, rate15, rateMean float64
|
||||||
}
|
}
|
||||||
|
|
||||||
// Count returns the count of events at the time the snapshot was taken.
|
// Count returns the count of events at the time the snapshot was taken.
|
||||||
func (m *MeterSnapshot) Count() int64 { return m.count }
|
func (m *meterSnapshot) Count() int64 { return m.count }
|
||||||
|
|
||||||
// Mark panics.
|
|
||||||
func (*MeterSnapshot) Mark(n int64) {
|
|
||||||
panic("Mark called on a MeterSnapshot")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Rate1 returns the one-minute moving average rate of events per second at the
|
// Rate1 returns the one-minute moving average rate of events per second at the
|
||||||
// time the snapshot was taken.
|
// time the snapshot was taken.
|
||||||
func (m *MeterSnapshot) Rate1() float64 { return m.rate1 }
|
func (m *meterSnapshot) Rate1() float64 { return m.rate1 }
|
||||||
|
|
||||||
// Rate5 returns the five-minute moving average rate of events per second at
|
// Rate5 returns the five-minute moving average rate of events per second at
|
||||||
// the time the snapshot was taken.
|
// the time the snapshot was taken.
|
||||||
func (m *MeterSnapshot) Rate5() float64 { return m.rate5 }
|
func (m *meterSnapshot) Rate5() float64 { return m.rate5 }
|
||||||
|
|
||||||
// Rate15 returns the fifteen-minute moving average rate of events per second
|
// Rate15 returns the fifteen-minute moving average rate of events per second
|
||||||
// at the time the snapshot was taken.
|
// at the time the snapshot was taken.
|
||||||
func (m *MeterSnapshot) Rate15() float64 { return m.rate15 }
|
func (m *meterSnapshot) Rate15() float64 { return m.rate15 }
|
||||||
|
|
||||||
// RateMean returns the meter's mean rate of events per second at the time the
|
// RateMean returns the meter's mean rate of events per second at the time the
|
||||||
// snapshot was taken.
|
// snapshot was taken.
|
||||||
func (m *MeterSnapshot) RateMean() float64 { return m.rateMean }
|
func (m *meterSnapshot) RateMean() float64 { return m.rateMean }
|
||||||
|
|
||||||
// Snapshot returns the snapshot.
|
|
||||||
func (m *MeterSnapshot) Snapshot() Meter { return m }
|
|
||||||
|
|
||||||
// Stop is a no-op.
|
|
||||||
func (m *MeterSnapshot) Stop() {}
|
|
||||||
|
|
||||||
// NilMeter is a no-op Meter.
|
// NilMeter is a no-op Meter.
|
||||||
type NilMeter struct{}
|
type NilMeter struct{}
|
||||||
|
|
||||||
// Count is a no-op.
|
|
||||||
func (NilMeter) Count() int64 { return 0 }
|
func (NilMeter) Count() int64 { return 0 }
|
||||||
|
|
||||||
// Mark is a no-op.
|
|
||||||
func (NilMeter) Mark(n int64) {}
|
func (NilMeter) Mark(n int64) {}
|
||||||
|
func (NilMeter) Snapshot() MeterSnapshot { return (*emptySnapshot)(nil) }
|
||||||
// Rate1 is a no-op.
|
|
||||||
func (NilMeter) Rate1() float64 { return 0.0 }
|
|
||||||
|
|
||||||
// Rate5 is a no-op.
|
|
||||||
func (NilMeter) Rate5() float64 { return 0.0 }
|
|
||||||
|
|
||||||
// Rate15 is a no-op.
|
|
||||||
func (NilMeter) Rate15() float64 { return 0.0 }
|
|
||||||
|
|
||||||
// RateMean is a no-op.
|
|
||||||
func (NilMeter) RateMean() float64 { return 0.0 }
|
|
||||||
|
|
||||||
// Snapshot is a no-op.
|
|
||||||
func (NilMeter) Snapshot() Meter { return NilMeter{} }
|
|
||||||
|
|
||||||
// Stop is a no-op.
|
|
||||||
func (NilMeter) Stop() {}
|
func (NilMeter) Stop() {}
|
||||||
|
|
||||||
// StandardMeter is the standard implementation of a Meter.
|
// StandardMeter is the standard implementation of a Meter.
|
||||||
type StandardMeter struct {
|
type StandardMeter struct {
|
||||||
lock sync.RWMutex
|
count atomic.Int64
|
||||||
snapshot *MeterSnapshot
|
uncounted atomic.Int64 // not yet added to the EWMAs
|
||||||
|
rateMean atomic.Uint64
|
||||||
|
|
||||||
a1, a5, a15 EWMA
|
a1, a5, a15 EWMA
|
||||||
startTime time.Time
|
startTime time.Time
|
||||||
stopped atomic.Bool
|
stopped atomic.Bool
|
||||||
|
|
@ -184,7 +115,6 @@ type StandardMeter struct {
|
||||||
|
|
||||||
func newStandardMeter() *StandardMeter {
|
func newStandardMeter() *StandardMeter {
|
||||||
return &StandardMeter{
|
return &StandardMeter{
|
||||||
snapshot: &MeterSnapshot{},
|
|
||||||
a1: NewEWMA1(),
|
a1: NewEWMA1(),
|
||||||
a5: NewEWMA5(),
|
a5: NewEWMA5(),
|
||||||
a15: NewEWMA15(),
|
a15: NewEWMA15(),
|
||||||
|
|
@ -194,97 +124,42 @@ func newStandardMeter() *StandardMeter {
|
||||||
|
|
||||||
// Stop stops the meter, Mark() will be a no-op if you use it after being stopped.
|
// Stop stops the meter, Mark() will be a no-op if you use it after being stopped.
|
||||||
func (m *StandardMeter) Stop() {
|
func (m *StandardMeter) Stop() {
|
||||||
stopped := m.stopped.Swap(true)
|
if stopped := m.stopped.Swap(true); !stopped {
|
||||||
if !stopped {
|
|
||||||
arbiter.Lock()
|
arbiter.Lock()
|
||||||
delete(arbiter.meters, m)
|
delete(arbiter.meters, m)
|
||||||
arbiter.Unlock()
|
arbiter.Unlock()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Count returns the number of events recorded.
|
|
||||||
// It updates the meter to be as accurate as possible
|
|
||||||
func (m *StandardMeter) Count() int64 {
|
|
||||||
m.lock.Lock()
|
|
||||||
defer m.lock.Unlock()
|
|
||||||
m.updateMeter()
|
|
||||||
return m.snapshot.count
|
|
||||||
}
|
|
||||||
|
|
||||||
// Mark records the occurrence of n events.
|
// Mark records the occurrence of n events.
|
||||||
func (m *StandardMeter) Mark(n int64) {
|
func (m *StandardMeter) Mark(n int64) {
|
||||||
m.snapshot.temp.Add(n)
|
m.uncounted.Add(n)
|
||||||
}
|
|
||||||
|
|
||||||
// Rate1 returns the one-minute moving average rate of events per second.
|
|
||||||
func (m *StandardMeter) Rate1() float64 {
|
|
||||||
m.lock.RLock()
|
|
||||||
defer m.lock.RUnlock()
|
|
||||||
return m.snapshot.rate1
|
|
||||||
}
|
|
||||||
|
|
||||||
// Rate5 returns the five-minute moving average rate of events per second.
|
|
||||||
func (m *StandardMeter) Rate5() float64 {
|
|
||||||
m.lock.RLock()
|
|
||||||
defer m.lock.RUnlock()
|
|
||||||
return m.snapshot.rate5
|
|
||||||
}
|
|
||||||
|
|
||||||
// Rate15 returns the fifteen-minute moving average rate of events per second.
|
|
||||||
func (m *StandardMeter) Rate15() float64 {
|
|
||||||
m.lock.RLock()
|
|
||||||
defer m.lock.RUnlock()
|
|
||||||
return m.snapshot.rate15
|
|
||||||
}
|
|
||||||
|
|
||||||
// RateMean returns the meter's mean rate of events per second.
|
|
||||||
func (m *StandardMeter) RateMean() float64 {
|
|
||||||
m.lock.RLock()
|
|
||||||
defer m.lock.RUnlock()
|
|
||||||
return m.snapshot.rateMean
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Snapshot returns a read-only copy of the meter.
|
// Snapshot returns a read-only copy of the meter.
|
||||||
func (m *StandardMeter) Snapshot() Meter {
|
func (m *StandardMeter) Snapshot() MeterSnapshot {
|
||||||
m.lock.RLock()
|
return &meterSnapshot{
|
||||||
snapshot := MeterSnapshot{
|
count: m.count.Load() + m.uncounted.Load(),
|
||||||
count: m.snapshot.count,
|
rate1: m.a1.Snapshot().Rate(),
|
||||||
rate1: m.snapshot.rate1,
|
rate5: m.a5.Snapshot().Rate(),
|
||||||
rate5: m.snapshot.rate5,
|
rate15: m.a15.Snapshot().Rate(),
|
||||||
rate15: m.snapshot.rate15,
|
rateMean: math.Float64frombits(m.rateMean.Load()),
|
||||||
rateMean: m.snapshot.rateMean,
|
|
||||||
}
|
}
|
||||||
snapshot.temp.Store(m.snapshot.temp.Load())
|
|
||||||
m.lock.RUnlock()
|
|
||||||
return &snapshot
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *StandardMeter) updateSnapshot() {
|
|
||||||
// should run with write lock held on m.lock
|
|
||||||
snapshot := m.snapshot
|
|
||||||
snapshot.rate1 = m.a1.Rate()
|
|
||||||
snapshot.rate5 = m.a5.Rate()
|
|
||||||
snapshot.rate15 = m.a15.Rate()
|
|
||||||
snapshot.rateMean = float64(snapshot.count) / time.Since(m.startTime).Seconds()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *StandardMeter) updateMeter() {
|
|
||||||
// should only run with write lock held on m.lock
|
|
||||||
n := m.snapshot.temp.Swap(0)
|
|
||||||
m.snapshot.count += n
|
|
||||||
m.a1.Update(n)
|
|
||||||
m.a5.Update(n)
|
|
||||||
m.a15.Update(n)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *StandardMeter) tick() {
|
func (m *StandardMeter) tick() {
|
||||||
m.lock.Lock()
|
// Take the uncounted values, add to count
|
||||||
defer m.lock.Unlock()
|
n := m.uncounted.Swap(0)
|
||||||
m.updateMeter()
|
count := m.count.Add(n)
|
||||||
|
m.rateMean.Store(math.Float64bits(float64(count) / time.Since(m.startTime).Seconds()))
|
||||||
|
// Update the EWMA's internal state
|
||||||
|
m.a1.Update(n)
|
||||||
|
m.a5.Update(n)
|
||||||
|
m.a15.Update(n)
|
||||||
|
// And trigger them to calculate the rates
|
||||||
m.a1.Tick()
|
m.a1.Tick()
|
||||||
m.a5.Tick()
|
m.a5.Tick()
|
||||||
m.a15.Tick()
|
m.a15.Tick()
|
||||||
m.updateSnapshot()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// meterArbiter ticks meters every 5s from a single goroutine.
|
// meterArbiter ticks meters every 5s from a single goroutine.
|
||||||
|
|
|
||||||
|
|
@ -12,11 +12,17 @@ func BenchmarkMeter(b *testing.B) {
|
||||||
m.Mark(1)
|
m.Mark(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
func TestMeter(t *testing.T) {
|
||||||
|
m := NewMeter()
|
||||||
|
m.Mark(47)
|
||||||
|
if v := m.Snapshot().Count(); v != 47 {
|
||||||
|
t.Fatalf("have %d want %d", v, 47)
|
||||||
|
}
|
||||||
|
}
|
||||||
func TestGetOrRegisterMeter(t *testing.T) {
|
func TestGetOrRegisterMeter(t *testing.T) {
|
||||||
r := NewRegistry()
|
r := NewRegistry()
|
||||||
NewRegisteredMeter("foo", r).Mark(47)
|
NewRegisteredMeter("foo", r).Mark(47)
|
||||||
if m := GetOrRegisterMeter("foo", r); m.Count() != 47 {
|
if m := GetOrRegisterMeter("foo", r).Snapshot(); m.Count() != 47 {
|
||||||
t.Fatal(m.Count())
|
t.Fatal(m.Count())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -31,10 +37,10 @@ func TestMeterDecay(t *testing.T) {
|
||||||
ma.meters[m] = struct{}{}
|
ma.meters[m] = struct{}{}
|
||||||
m.Mark(1)
|
m.Mark(1)
|
||||||
ma.tickMeters()
|
ma.tickMeters()
|
||||||
rateMean := m.RateMean()
|
rateMean := m.Snapshot().RateMean()
|
||||||
time.Sleep(100 * time.Millisecond)
|
time.Sleep(100 * time.Millisecond)
|
||||||
ma.tickMeters()
|
ma.tickMeters()
|
||||||
if m.RateMean() >= rateMean {
|
if m.Snapshot().RateMean() >= rateMean {
|
||||||
t.Error("m.RateMean() didn't decrease")
|
t.Error("m.RateMean() didn't decrease")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -42,7 +48,7 @@ func TestMeterDecay(t *testing.T) {
|
||||||
func TestMeterNonzero(t *testing.T) {
|
func TestMeterNonzero(t *testing.T) {
|
||||||
m := NewMeter()
|
m := NewMeter()
|
||||||
m.Mark(3)
|
m.Mark(3)
|
||||||
if count := m.Count(); count != 3 {
|
if count := m.Snapshot().Count(); count != 3 {
|
||||||
t.Errorf("m.Count(): 3 != %v\n", count)
|
t.Errorf("m.Count(): 3 != %v\n", count)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -59,16 +65,8 @@ func TestMeterStop(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMeterSnapshot(t *testing.T) {
|
|
||||||
m := NewMeter()
|
|
||||||
m.Mark(1)
|
|
||||||
if snapshot := m.Snapshot(); m.RateMean() != snapshot.RateMean() {
|
|
||||||
t.Fatal(snapshot)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMeterZero(t *testing.T) {
|
func TestMeterZero(t *testing.T) {
|
||||||
m := NewMeter()
|
m := NewMeter().Snapshot()
|
||||||
if count := m.Count(); count != 0 {
|
if count := m.Count(); count != 0 {
|
||||||
t.Errorf("m.Count(): 0 != %v\n", count)
|
t.Errorf("m.Count(): 0 != %v\n", count)
|
||||||
}
|
}
|
||||||
|
|
@ -79,13 +77,13 @@ func TestMeterRepeat(t *testing.T) {
|
||||||
for i := 0; i < 101; i++ {
|
for i := 0; i < 101; i++ {
|
||||||
m.Mark(int64(i))
|
m.Mark(int64(i))
|
||||||
}
|
}
|
||||||
if count := m.Count(); count != 5050 {
|
if count := m.Snapshot().Count(); count != 5050 {
|
||||||
t.Errorf("m.Count(): 5050 != %v\n", count)
|
t.Errorf("m.Count(): 5050 != %v\n", count)
|
||||||
}
|
}
|
||||||
for i := 0; i < 101; i++ {
|
for i := 0; i < 101; i++ {
|
||||||
m.Mark(int64(i))
|
m.Mark(int64(i))
|
||||||
}
|
}
|
||||||
if count := m.Count(); count != 10100 {
|
if count := m.Snapshot().Count(); count != 10100 {
|
||||||
t.Errorf("m.Count(): 10100 != %v\n", count)
|
t.Errorf("m.Count(): 10100 != %v\n", count)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,9 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"runtime/metrics"
|
"runtime/metrics"
|
||||||
"runtime/pprof"
|
"runtime/pprof"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
|
|
@ -30,13 +32,35 @@ var EnabledExpensive = false
|
||||||
// enablerFlags is the CLI flag names to use to enable metrics collections.
|
// enablerFlags is the CLI flag names to use to enable metrics collections.
|
||||||
var enablerFlags = []string{"metrics"}
|
var enablerFlags = []string{"metrics"}
|
||||||
|
|
||||||
|
// enablerEnvVars is the env var names to use to enable metrics collections.
|
||||||
|
var enablerEnvVars = []string{"GETH_METRICS"}
|
||||||
|
|
||||||
// expensiveEnablerFlags is the CLI flag names to use to enable metrics collections.
|
// expensiveEnablerFlags is the CLI flag names to use to enable metrics collections.
|
||||||
var expensiveEnablerFlags = []string{"metrics.expensive"}
|
var expensiveEnablerFlags = []string{"metrics.expensive"}
|
||||||
|
|
||||||
|
// expensiveEnablerEnvVars is the env var names to use to enable metrics collections.
|
||||||
|
var expensiveEnablerEnvVars = []string{"GETH_METRICS_EXPENSIVE"}
|
||||||
|
|
||||||
// Init enables or disables the metrics system. Since we need this to run before
|
// Init enables or disables the metrics system. Since we need this to run before
|
||||||
// any other code gets to create meters and timers, we'll actually do an ugly hack
|
// any other code gets to create meters and timers, we'll actually do an ugly hack
|
||||||
// and peek into the command line args for the metrics flag.
|
// and peek into the command line args for the metrics flag.
|
||||||
func init() {
|
func init() {
|
||||||
|
for _, enabler := range enablerEnvVars {
|
||||||
|
if val, found := syscall.Getenv(enabler); found && !Enabled {
|
||||||
|
if enable, _ := strconv.ParseBool(val); enable { // ignore error, flag parser will choke on it later
|
||||||
|
log.Info("Enabling metrics collection")
|
||||||
|
Enabled = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, enabler := range expensiveEnablerEnvVars {
|
||||||
|
if val, found := syscall.Getenv(enabler); found && !EnabledExpensive {
|
||||||
|
if enable, _ := strconv.ParseBool(val); enable { // ignore error, flag parser will choke on it later
|
||||||
|
log.Info("Enabling expensive metrics collection")
|
||||||
|
EnabledExpensive = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
for _, arg := range os.Args {
|
for _, arg := range os.Args {
|
||||||
flag := strings.TrimLeft(arg, "-")
|
flag := strings.TrimLeft(arg, "-")
|
||||||
|
|
||||||
|
|
@ -85,6 +109,12 @@ var runtimeSamples = []metrics.Sample{
|
||||||
{Name: "/sched/latencies:seconds"}, // histogram
|
{Name: "/sched/latencies:seconds"}, // histogram
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ReadRuntimeStats() *runtimeStats {
|
||||||
|
r := new(runtimeStats)
|
||||||
|
readRuntimeStats(r)
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
func readRuntimeStats(v *runtimeStats) {
|
func readRuntimeStats(v *runtimeStats) {
|
||||||
metrics.Read(runtimeSamples)
|
metrics.Read(runtimeSamples)
|
||||||
for _, s := range runtimeSamples {
|
for _, s := range runtimeSamples {
|
||||||
|
|
|
||||||
|
|
@ -98,8 +98,8 @@ func Example() {
|
||||||
t.Time(func() { time.Sleep(10 * time.Millisecond) })
|
t.Time(func() { time.Sleep(10 * time.Millisecond) })
|
||||||
t.Update(1)
|
t.Update(1)
|
||||||
|
|
||||||
fmt.Println(c.Count())
|
fmt.Println(c.Snapshot().Count())
|
||||||
fmt.Println(t.Min())
|
fmt.Println(t.Snapshot().Min())
|
||||||
// Output: 17
|
// Output: 17
|
||||||
// 1
|
// 1
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -65,15 +65,15 @@ func (c *OpenTSDBConfig) writeRegistry(w io.Writer, now int64, shortHostname str
|
||||||
c.Registry.Each(func(name string, i interface{}) {
|
c.Registry.Each(func(name string, i interface{}) {
|
||||||
switch metric := i.(type) {
|
switch metric := i.(type) {
|
||||||
case Counter:
|
case Counter:
|
||||||
fmt.Fprintf(w, "put %s.%s.count %d %d host=%s\n", c.Prefix, name, now, metric.Count(), shortHostname)
|
fmt.Fprintf(w, "put %s.%s.count %d %d host=%s\n", c.Prefix, name, now, metric.Snapshot().Count(), shortHostname)
|
||||||
case CounterFloat64:
|
case CounterFloat64:
|
||||||
fmt.Fprintf(w, "put %s.%s.count %d %f host=%s\n", c.Prefix, name, now, metric.Count(), shortHostname)
|
fmt.Fprintf(w, "put %s.%s.count %d %f host=%s\n", c.Prefix, name, now, metric.Snapshot().Count(), shortHostname)
|
||||||
case Gauge:
|
case Gauge:
|
||||||
fmt.Fprintf(w, "put %s.%s.value %d %d host=%s\n", c.Prefix, name, now, metric.Value(), shortHostname)
|
fmt.Fprintf(w, "put %s.%s.value %d %d host=%s\n", c.Prefix, name, now, metric.Snapshot().Value(), shortHostname)
|
||||||
case GaugeFloat64:
|
case GaugeFloat64:
|
||||||
fmt.Fprintf(w, "put %s.%s.value %d %f host=%s\n", c.Prefix, name, now, metric.Value(), shortHostname)
|
fmt.Fprintf(w, "put %s.%s.value %d %f host=%s\n", c.Prefix, name, now, metric.Snapshot().Value(), shortHostname)
|
||||||
case GaugeInfo:
|
case GaugeInfo:
|
||||||
fmt.Fprintf(w, "put %s.%s.value %d %s host=%s\n", c.Prefix, name, now, metric.Value().String(), shortHostname)
|
fmt.Fprintf(w, "put %s.%s.value %d %s host=%s\n", c.Prefix, name, now, metric.Snapshot().Value().String(), shortHostname)
|
||||||
case Histogram:
|
case Histogram:
|
||||||
h := metric.Snapshot()
|
h := metric.Snapshot()
|
||||||
ps := h.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999})
|
ps := h.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999})
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package metrics
|
package metrics
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
@ -47,5 +48,19 @@ func TestExampleOpenTSB(t *testing.T) {
|
||||||
}
|
}
|
||||||
if have, want := w.String(), string(wantB); have != want {
|
if have, want := w.String(), string(wantB); have != want {
|
||||||
t.Errorf("\nhave:\n%v\nwant:\n%v\n", have, want)
|
t.Errorf("\nhave:\n%v\nwant:\n%v\n", have, want)
|
||||||
|
t.Logf("have vs want:\n%v", findFirstDiffPos(have, want))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func findFirstDiffPos(a, b string) string {
|
||||||
|
yy := strings.Split(b, "\n")
|
||||||
|
for i, x := range strings.Split(a, "\n") {
|
||||||
|
if i >= len(yy) {
|
||||||
|
return fmt.Sprintf("have:%d: %s\nwant:%d: <EOF>", i, x, i)
|
||||||
|
}
|
||||||
|
if y := yy[i]; x != y {
|
||||||
|
return fmt.Sprintf("have:%d: %s\nwant:%d: %s", i, x, i, y)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -75,27 +75,27 @@ func (c *collector) Add(name string, i any) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *collector) addCounter(name string, m metrics.Counter) {
|
func (c *collector) addCounter(name string, m metrics.CounterSnapshot) {
|
||||||
c.writeGaugeCounter(name, m.Count())
|
c.writeGaugeCounter(name, m.Count())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *collector) addCounterFloat64(name string, m metrics.CounterFloat64) {
|
func (c *collector) addCounterFloat64(name string, m metrics.CounterFloat64Snapshot) {
|
||||||
c.writeGaugeCounter(name, m.Count())
|
c.writeGaugeCounter(name, m.Count())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *collector) addGauge(name string, m metrics.Gauge) {
|
func (c *collector) addGauge(name string, m metrics.GaugeSnapshot) {
|
||||||
c.writeGaugeCounter(name, m.Value())
|
c.writeGaugeCounter(name, m.Value())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *collector) addGaugeFloat64(name string, m metrics.GaugeFloat64) {
|
func (c *collector) addGaugeFloat64(name string, m metrics.GaugeFloat64Snapshot) {
|
||||||
c.writeGaugeCounter(name, m.Value())
|
c.writeGaugeCounter(name, m.Value())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *collector) addGaugeInfo(name string, m metrics.GaugeInfo) {
|
func (c *collector) addGaugeInfo(name string, m metrics.GaugeInfoSnapshot) {
|
||||||
c.writeGaugeInfo(name, m.Value())
|
c.writeGaugeInfo(name, m.Value())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *collector) addHistogram(name string, m metrics.Histogram) {
|
func (c *collector) addHistogram(name string, m metrics.HistogramSnapshot) {
|
||||||
pv := []float64{0.5, 0.75, 0.95, 0.99, 0.999, 0.9999}
|
pv := []float64{0.5, 0.75, 0.95, 0.99, 0.999, 0.9999}
|
||||||
ps := m.Percentiles(pv)
|
ps := m.Percentiles(pv)
|
||||||
c.writeSummaryCounter(name, m.Count())
|
c.writeSummaryCounter(name, m.Count())
|
||||||
|
|
@ -106,11 +106,11 @@ func (c *collector) addHistogram(name string, m metrics.Histogram) {
|
||||||
c.buff.WriteRune('\n')
|
c.buff.WriteRune('\n')
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *collector) addMeter(name string, m metrics.Meter) {
|
func (c *collector) addMeter(name string, m metrics.MeterSnapshot) {
|
||||||
c.writeGaugeCounter(name, m.Count())
|
c.writeGaugeCounter(name, m.Count())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *collector) addTimer(name string, m metrics.Timer) {
|
func (c *collector) addTimer(name string, m metrics.TimerSnapshot) {
|
||||||
pv := []float64{0.5, 0.75, 0.95, 0.99, 0.999, 0.9999}
|
pv := []float64{0.5, 0.75, 0.95, 0.99, 0.999, 0.9999}
|
||||||
ps := m.Percentiles(pv)
|
ps := m.Percentiles(pv)
|
||||||
c.writeSummaryCounter(name, m.Count())
|
c.writeSummaryCounter(name, m.Count())
|
||||||
|
|
@ -121,13 +121,12 @@ func (c *collector) addTimer(name string, m metrics.Timer) {
|
||||||
c.buff.WriteRune('\n')
|
c.buff.WriteRune('\n')
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *collector) addResettingTimer(name string, m metrics.ResettingTimer) {
|
func (c *collector) addResettingTimer(name string, m metrics.ResettingTimerSnapshot) {
|
||||||
if len(m.Values()) <= 0 {
|
if m.Count() <= 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ps := m.Percentiles([]float64{50, 95, 99})
|
ps := m.Percentiles([]float64{0.50, 0.95, 0.99})
|
||||||
val := m.Values()
|
c.writeSummaryCounter(name, m.Count())
|
||||||
c.writeSummaryCounter(name, len(val))
|
|
||||||
c.buff.WriteString(fmt.Sprintf(typeSummaryTpl, mutateKey(name)))
|
c.buff.WriteString(fmt.Sprintf(typeSummaryTpl, mutateKey(name)))
|
||||||
c.writeSummaryPercentile(name, "0.50", ps[0])
|
c.writeSummaryPercentile(name, "0.50", ps[0])
|
||||||
c.writeSummaryPercentile(name, "0.95", ps[1])
|
c.writeSummaryPercentile(name, "0.95", ps[1])
|
||||||
|
|
|
||||||
|
|
@ -55,10 +55,10 @@ func findFirstDiffPos(a, b string) string {
|
||||||
yy := strings.Split(b, "\n")
|
yy := strings.Split(b, "\n")
|
||||||
for i, x := range strings.Split(a, "\n") {
|
for i, x := range strings.Split(a, "\n") {
|
||||||
if i >= len(yy) {
|
if i >= len(yy) {
|
||||||
return fmt.Sprintf("a:%d: %s\nb:%d: <EOF>", i, x, i)
|
return fmt.Sprintf("have:%d: %s\nwant:%d: <EOF>", i, x, i)
|
||||||
}
|
}
|
||||||
if y := yy[i]; x != y {
|
if y := yy[i]; x != y {
|
||||||
return fmt.Sprintf("a:%d: %s\nb:%d: %s", i, x, i, y)
|
return fmt.Sprintf("have:%d: %s\nwant:%d: %s", i, x, i, y)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue