Skip to content

Commit

Permalink
Rpc logger (#61)
Browse files Browse the repository at this point in the history
* update SubscribeEpochs

* add logger for rpc request

* update doc

* remove comment

* simplify logger

Co-authored-by: dayong <dayong@conflux-chain.org>
  • Loading branch information
wangdayong228 and dayong authored Apr 22, 2021
1 parent 16b4157 commit 97831af
Show file tree
Hide file tree
Showing 9 changed files with 126 additions and 40 deletions.
25 changes: 16 additions & 9 deletions api.md
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ creat account manager if option.KeystorePath not empty.
#### func NewClientWithRPCRequester

```go
func NewClientWithRPCRequester(rpcRequester rpcRequester) (*Client, error)
func NewClientWithRPCRequester(rpcRequester RpcRequester) (*Client, error)
```
NewClientWithRPCRequester creates client with specified rpcRequester

Expand Down Expand Up @@ -631,16 +631,17 @@ GetVoteList returns vote list of the given account.
func (client *Client) MustNewAddress(base32OrHex string) types.Address
```
MustNewAddress create conflux address by base32 string or hex40 string, if
base32OrHex is base32 and networkID is setted it will check if networkID match.
it will painc if error occured.
base32OrHex is base32 and networkID is passed it will create cfx Address use
networkID of current client. it will painc if error occured.

#### func (*Client) NewAddress

```go
func (client *Client) NewAddress(base32OrHex string) (types.Address, error)
```
NewAddress create conflux address by base32 string or hex40 string, if
base32OrHex is base32 and networkID is setted it will check if networkID match.
base32OrHex is base32 and networkID is passed it will create cfx Address use
networkID of current client.

#### func (*Client) SendRawTransaction

Expand Down Expand Up @@ -675,10 +676,11 @@ signature "r,s,v" and sends it to node, and returns responsed transaction.
#### func (*Client) SubscribeEpochs

```go
func (client *Client) SubscribeEpochs(channel chan types.WebsocketEpochResponse) (*rpc.ClientSubscription, error)
func (client *Client) SubscribeEpochs(channel chan types.WebsocketEpochResponse, subscriptionEpochType ...types.Epoch) (*rpc.ClientSubscription, error)
```
SubscribeEpochs subscribes consensus results: the total order of blocks, as
expressed by a sequence of epochs.
expressed by a sequence of epochs. Currently subscriptionEpochType only support
"latest_mined" and "latest_state"

#### func (*Client) SubscribeLogs

Expand Down Expand Up @@ -713,14 +715,19 @@ WaitForTransationReceipt waits for transaction receipt valid

```go
type ClientOption struct {
KeystorePath string
RetryCount int
RetryInterval time.Duration
KeystorePath string
RetryCount int
RetryInterval time.Duration
CallRpcLogger CallRPCLogger
BatchCallRPCLogger BatchCallRPCLogger
}
```

ClientOption for set keystore path and flags for retry

The simplest way to set logger is to use the types.DefaultCallRpcLogger and
types.DefaultBatchCallRPCLogger

### type Contract

```go
Expand Down
66 changes: 45 additions & 21 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,20 @@ const errMsgApplyTxValues = "failed to apply default transaction values"
type Client struct {
AccountManager AccountManagerOperator
nodeURL string
rpcRequester rpcRequester
rpcRequester RpcRequester
networkID uint32
option ClientOption
}

// ClientOption for set keystore path and flags for retry
//
// The simplest way to set logger is to use the types.DefaultCallRpcLog and types.DefaultBatchCallRPCLog
type ClientOption struct {
KeystorePath string
RetryCount int
RetryInterval time.Duration
KeystorePath string
RetryCount int
RetryInterval time.Duration
CallRpcLog func(method string, args []interface{}, result interface{}, resultError error, duration time.Duration)
BatchCallRPCLog func(b []rpc.BatchElem, err error, duration time.Duration)
}

// NewClient creates an instance of Client with specified conflux node url, it will creat account manager if option.KeystorePath not empty.
Expand All @@ -44,7 +49,7 @@ func NewClient(nodeURL string, option ...ClientOption) (*Client, error) {
realOption = option[0]
}

client, err := newClientWithRetry(nodeURL, realOption.KeystorePath, realOption.RetryCount, realOption.RetryInterval)
client, err := newClientWithRetry(nodeURL, realOption)
if err != nil {
return nil, errors.Wrap(err, "failed to new client with retry")
}
Expand All @@ -53,47 +58,57 @@ func NewClient(nodeURL string, option ...ClientOption) (*Client, error) {
}

// NewClientWithRPCRequester creates client with specified rpcRequester
func NewClientWithRPCRequester(rpcRequester rpcRequester) (*Client, error) {
func NewClientWithRPCRequester(rpcRequester RpcRequester) (*Client, error) {
return &Client{
rpcRequester: rpcRequester,
}, nil
}

// NewClientWithRetry creates a retryable new instance of Client with specified conflux node url and retry options.
//
// the retryInterval will be set to 1 second if pass 0
func newClientWithRetry(nodeURL string, keystorePath string, retryCount int, retryInterval time.Duration) (*Client, error) {
// the clientOption.RetryInterval will be set to 1 second if pass 0
func newClientWithRetry(nodeURL string, clientOption ClientOption) (*Client, error) {

var client Client
client.nodeURL = nodeURL
client.option = clientOption

rpcClient, err := rpc.Dial(nodeURL)
if err != nil {
return nil, errors.Wrap(err, "failed to dial to fullnode")
}

if retryCount == 0 {
if client.option.RetryCount == 0 {
client.rpcRequester = rpcClient
} else {
// Interval 0 is meaningless and may lead full node busy, so default sets it to 1 second
if retryInterval == 0 {
retryInterval = time.Second
if client.option.RetryInterval == 0 {
client.option.RetryInterval = time.Second
}

client.rpcRequester = &rpcClientWithRetry{
inner: rpcClient,
retryCount: retryCount,
interval: retryInterval,
retryCount: client.option.RetryCount,
interval: client.option.RetryInterval,
}
}

if client.option.CallRpcLog == nil {
client.option.CallRpcLog = func(method string, args []interface{}, result interface{}, resultError error, duration time.Duration) {
}
}

if client.option.BatchCallRPCLog == nil {
client.option.BatchCallRPCLog = func(b []rpc.BatchElem, err error, duration time.Duration) {}
}

_, err = client.GetNetworkID()
if err != nil {
return nil, errors.Wrap(err, "failed to get networkID")
}

if keystorePath != "" {
am := NewAccountManager(keystorePath, client.networkID)
if client.option.KeystorePath != "" {
am := NewAccountManager(client.option.KeystorePath, client.networkID)
client.SetAccountManager(am)
}

Expand All @@ -105,7 +120,7 @@ func (client *Client) GetNodeURL() string {
return client.nodeURL
}

// NewAddress create conflux address by base32 string or hex40 string, if base32OrHex is base32 and networkID is setted it will check if networkID match.
// NewAddress create conflux address by base32 string or hex40 string, if base32OrHex is base32 and networkID is passed it will create cfx Address use networkID of current client.
func (client *Client) NewAddress(base32OrHex string) (types.Address, error) {
networkID, err := client.GetNetworkID()
if err != nil {
Expand All @@ -114,7 +129,7 @@ func (client *Client) NewAddress(base32OrHex string) (types.Address, error) {
return cfxaddress.New(base32OrHex, networkID)
}

// MustNewAddress create conflux address by base32 string or hex40 string, if base32OrHex is base32 and networkID is setted it will check if networkID match.
// MustNewAddress create conflux address by base32 string or hex40 string, if base32OrHex is base32 and networkID is passed it will create cfx Address use networkID of current client.
// it will painc if error occured.
func (client *Client) MustNewAddress(base32OrHex string) types.Address {
address, err := client.NewAddress(base32OrHex)
Expand All @@ -130,7 +145,10 @@ func (client *Client) MustNewAddress(base32OrHex string) types.Address {
// The result must be a pointer so that package json can unmarshal into it. You
// can also pass nil, in which case the result is ignored.
func (client *Client) CallRPC(result interface{}, method string, args ...interface{}) error {
return client.rpcRequester.Call(result, method, args...)
start := time.Now()
err := client.rpcRequester.Call(result, method, args...)
client.option.CallRpcLog(method, args, result, err, time.Since(start))
return err
}

// BatchCallRPC sends all given requests as a single batch and waits for the server
Expand All @@ -141,7 +159,10 @@ func (client *Client) CallRPC(result interface{}, method string, args ...interfa
//
// Note that batch calls may not be executed atomically on the server side.
func (client *Client) BatchCallRPC(b []rpc.BatchElem) error {
return client.rpcRequester.BatchCall(b)
start := time.Now()
err := client.rpcRequester.BatchCall(b)
client.option.BatchCallRPCLog(b, err, time.Since(start))
return err
}

// SetAccountManager sets account manager for sign transaction
Expand Down Expand Up @@ -932,8 +953,11 @@ func (client *Client) SubscribeNewHeads(channel chan types.BlockHeader) (*rpc.Cl
return client.rpcRequester.Subscribe(context.Background(), "cfx", channel, "newHeads")
}

// SubscribeEpochs subscribes consensus results: the total order of blocks, as expressed by a sequence of epochs.
func (client *Client) SubscribeEpochs(channel chan types.WebsocketEpochResponse) (*rpc.ClientSubscription, error) {
// SubscribeEpochs subscribes consensus results: the total order of blocks, as expressed by a sequence of epochs. Currently subscriptionEpochType only support "latest_mined" and "latest_state"
func (client *Client) SubscribeEpochs(channel chan types.WebsocketEpochResponse, subscriptionEpochType ...types.Epoch) (*rpc.ClientSubscription, error) {
if len(subscriptionEpochType) > 0 {
return client.rpcRequester.Subscribe(context.Background(), "cfx", channel, "epochs", subscriptionEpochType[0].String())
}
return client.rpcRequester.Subscribe(context.Background(), "cfx", channel, "epochs")
}

Expand Down
4 changes: 2 additions & 2 deletions client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ func _TestNewClient(t *testing.T) {
})
defer guard.Unpatch()

client, err := newClientWithRetry("", "", 0, 0)
client, err := newClientWithRetry("", ClientOption{})
Convey("Return error", func() {
So(err, ShouldNotEqual, nil)
So(client, ShouldEqual, nil)
Expand All @@ -46,7 +46,7 @@ func _TestNewClient(t *testing.T) {
})
defer guard.Unpatch()

client, err := newClientWithRetry("", "", 0, 0)
client, err := newClientWithRetry("", ClientOption{})
// fmt.Printf("client:%+v,err:%+v", client, err)

Convey("Return client instance", func() {
Expand Down
10 changes: 5 additions & 5 deletions example/context/config.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
NodeURL = "http://127.0.0.1:12539"
BlockHash = "0x33649d83178942524f52c3a3a7b9a86ea161f72ef2e5c40494ca1341c7a86c9d"
TransactionHash = "0xdca75fe1d4c3187702b433a29609c8ef3125d7a2936a80348f9ea6f400110cea"
BlockHashOfNewContract = "0x3e5f823bcb4228e00b8da839667285e551499382e928b43dbebecf82088df5bf"
ERC20Address = "NET4021259308:TYPE.CONTRACT:ACC2PMEWZKPR34N3DEU10S2DM47SSBMXS2RFYWAD9X"
NodeURL = "http://127.0.0.1:22537"
BlockHash = "0xbbbf51dab51c02413413edf0c5d9e03f7c2bfeb584d4154d82f0b38cd63f2e22"
TransactionHash = "0x1498b96d6e3976b8f167a49436addcb907bb8c202df6100aebb2441a55654691"
BlockHashOfNewContract = "0x2e7dd6c1896dd15729fd9f3573b5a6033464385951f557f44906e8a32d3f1307"
ERC20Address = "NET8958:TYPE.CONTRACT:ACC2PMEWZKPR34N3DEU10S2DM47SSBMXS2CUF67X96"
5 changes: 3 additions & 2 deletions example/context/prepare.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package context

import (
"fmt"
"log"
"os"
"path"
"runtime"
Expand Down Expand Up @@ -59,7 +58,7 @@ func getConfig() {
config = exampletypes.Config{}
_, err := toml.DecodeFile(configPath, &config)
if err != nil {
log.Fatal(err)
panic(err)
}

fmt.Printf("- to get config done: %+v\n", JSONFmt(config))
Expand All @@ -74,6 +73,8 @@ func initClient() {
KeystorePath: path.Join(currentDir, "keystore"),
RetryCount: 10,
RetryInterval: time.Second,
// CallRpcLog: types.DefaultCallRPCLog,
// BatchCallRPCLog: types.DefaultBatchCallRPCLog,
}
client, err = sdk.NewClient(config.NodeURL, option)
if err != nil {
Expand Down
15 changes: 15 additions & 0 deletions example/example_client/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
sdk "github.com/Conflux-Chain/go-conflux-sdk"
"github.com/Conflux-Chain/go-conflux-sdk/example/context"
exampletypes "github.com/Conflux-Chain/go-conflux-sdk/example/context/types"
"github.com/Conflux-Chain/go-conflux-sdk/rpc"
"github.com/Conflux-Chain/go-conflux-sdk/types"
"github.com/Conflux-Chain/go-conflux-sdk/types/cfxaddress"
address "github.com/Conflux-Chain/go-conflux-sdk/types/cfxaddress"
Expand Down Expand Up @@ -100,6 +101,8 @@ func run(_client *sdk.Client) {
subscribeNewHeads()
subscribeEpochs()
subscribeLogs()

batchCall()
}

func newAddress() {
Expand Down Expand Up @@ -595,6 +598,18 @@ func subscribeLogs() {
sub.Unsubscribe()
}

func batchCall() {
elems := make([]rpc.BatchElem, 2)
elems[0] = rpc.BatchElem{Method: "cfx_epochNumber", Result: &hexutil.Big{}, Args: []interface{}{}}
elems[1] = rpc.BatchElem{Method: "cfx_getBalance", Result: &hexutil.Big{}, Args: []interface{}{client.MustNewAddress("cfxtest:aap9kthvctunvf030rbkk9k7zbzyz12dajp1u3sp4g")}}
err := client.BatchCallRPC(elems)
if err != nil {
panic(err)
} else {
fmt.Printf("batch call rpc done:%+v\n", elems)
}
}

func printResult(method string, args []interface{}, result interface{}, err error) {
if err != nil {
fmt.Printf("- call method %v with args %+v error: %v\n\n", method, args, err.Error())
Expand Down
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -48,14 +48,17 @@ github.com/deckarep/golang-set v0.0.0-20180603214616-504e848d77ea h1:j4317fAZh7X
github.com/deckarep/golang-set v0.0.0-20180603214616-504e848d77ea/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
github.com/dlclark/regexp2 v1.2.0 h1:8sAhBGEM0dRWogWqWyQeIJnxjWO6oIjl8FKqREDsGfk=
github.com/dlclark/regexp2 v1.2.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
github.com/docker/docker v1.4.2-0.20180625184442-8e610b2b55bf/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/dop251/goja v0.0.0-20200721192441-a695b0cdd498 h1:Y9vTBSsV4hSwPSj4bacAU/eSnV3dAxVpepaghAdhGoQ=
github.com/dop251/goja v0.0.0-20200721192441-a695b0cdd498/go.mod h1:Mw6PkjjMXWbTj+nnj4s3QPXq1jaT0s5pC0iFD4+BOAA=
github.com/dvyukov/go-fuzz v0.0.0-20200318091601-be3528f3a813/go.mod h1:11Gm+ccJnvAhCNLlf5+cS9KjtbaD5I5zaZpFMsTHWTw=
github.com/edsrzf/mmap-go v0.0.0-20160512033002-935e0e8a636c h1:JHHhtb9XWJrGNMcrVP6vyzO4dusgi/HnceHTgxSejUM=
github.com/edsrzf/mmap-go v0.0.0-20160512033002-935e0e8a636c/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
github.com/ethereum/go-ethereum v1.9.25 h1:mMiw/zOOtCLdGLWfcekua0qPrJTe7FVIiHJ4IKNTfR0=
github.com/ethereum/go-ethereum v1.9.25/go.mod h1:vMkFiYLHI4tgPw4k2j4MHKoovchFE8plZ0M9VMk4/oM=
github.com/fatih/color v1.3.0 h1:YehCCcyeQ6Km0D6+IapqPinWBK6y+0eB5umvZXK9WPs=
github.com/fatih/color v1.3.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fjl/memsize v0.0.0-20180418122429-ca190fb6ffbc h1:jtW8jbpkO4YirRSyepBOH8E+2HEw6/hKkBvFPwhUN8c=
github.com/fjl/memsize v0.0.0-20180418122429-ca190fb6ffbc/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0=
Expand All @@ -71,6 +74,7 @@ github.com/go-logfmt/logfmt v0.3.0 h1:8HUsc87TaSWLKwrnumgC8/YconD2fJQsRJAsWaPg2i
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-ole/go-ole v1.2.1 h1:2lOsA72HgjxAuMlKpFiCbHTvu44PIVkZ5hqm3RSdI/E=
github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8=
github.com/go-sourcemap/sourcemap v2.1.2+incompatible h1:0b/xya7BKGhXuqFESKM4oIiRo9WOt2ebz7KxfreD6ug=
github.com/go-sourcemap/sourcemap v2.1.2+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg=
github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
Expand Down
12 changes: 11 additions & 1 deletion interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,9 +120,19 @@ type AccountManagerOperator interface {
Sign(tx types.UnsignedTransaction, passphrase string) (v byte, r, s []byte, err error)
}

type rpcRequester interface {
type RpcRequester interface {
Call(resultPtr interface{}, method string, args ...interface{}) error
BatchCall(b []rpc.BatchElem) error
Subscribe(ctx context.Context, namespace string, channel interface{}, args ...interface{}) (*rpc.ClientSubscription, error)
Close()
}

type CallRPCLogger interface {
Info(method string, args []interface{}, result interface{}, duration time.Duration)
Error(method string, args []interface{}, resultError error, duration time.Duration)
}

type BatchCallRPCLogger interface {
Info(b []rpc.BatchElem, duration time.Duration)
Error(b []rpc.BatchElem, err error, duration time.Duration)
}
25 changes: 25 additions & 0 deletions types/rpc_log.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package types

import (
"fmt"
"time"

"github.com/Conflux-Chain/go-conflux-sdk/rpc"
"github.com/Conflux-Chain/go-conflux-sdk/utils"
)

func DefaultCallRPCLog(method string, args []interface{}, result interface{}, resultError error, duration time.Duration) {
if resultError == nil {
fmt.Printf("call rpc %v sucessfully, args %+v, result %+v, use %v\n", method, utils.PrettyJSON(args), utils.PrettyJSON(result), duration)
return
}
fmt.Printf("call rpc %v failed, args %+v, error: %+v, use %v\n", method, args, resultError, duration)
}

func DefaultBatchCallRPCLog(b []rpc.BatchElem, err error, duration time.Duration) {
if err == nil {
fmt.Printf("batch call %+v sucessfully, use %v\n", b, duration)
return
}
fmt.Printf("batch call %+v failed, error: %+v, use %v\n", b, err, duration)
}

0 comments on commit 97831af

Please sign in to comment.