diff --git a/go.mod b/go.mod index c958d23..05487a1 100644 --- a/go.mod +++ b/go.mod @@ -18,6 +18,8 @@ require ( github.com/prometheus/client_model v0.5.0 // indirect github.com/prometheus/common v0.48.0 // indirect github.com/prometheus/procfs v0.12.0 // indirect + go.uber.org/multierr v1.10.0 // indirect + go.uber.org/zap v1.27.0 // indirect golang.org/x/sys v0.17.0 // indirect google.golang.org/protobuf v1.33.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index 07ec9eb..5ca7cc6 100644 --- a/go.sum +++ b/go.sum @@ -27,6 +27,10 @@ github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjR github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ= +go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= +go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= diff --git a/pkg/rpc/client.go b/pkg/rpc/client.go index a3f9019..d028f24 100644 --- a/pkg/rpc/client.go +++ b/pkg/rpc/client.go @@ -5,8 +5,9 @@ import ( "context" "encoding/json" "fmt" + "github.com/asymmetric-research/solana_exporter/pkg/slog" + "go.uber.org/zap" "io" - "k8s.io/klog/v2" "net/http" "slices" "time" @@ -17,6 +18,7 @@ type ( HttpClient http.Client RpcUrl string HttpTimeout time.Duration + logger *zap.SugaredLogger } rpcRequest struct { @@ -99,26 +101,27 @@ const ( ) func NewRPCClient(rpcAddr string, httpTimeout time.Duration) *Client { - return &Client{HttpClient: http.Client{}, RpcUrl: rpcAddr, HttpTimeout: httpTimeout} + return &Client{HttpClient: http.Client{}, RpcUrl: rpcAddr, HttpTimeout: httpTimeout, logger: slog.Get()} } func getResponse[T any]( ctx context.Context, client *Client, method string, params []any, rpcResponse *response[T], ) error { + logger := slog.Get() // format request: request := &rpcRequest{Version: "2.0", ID: 1, Method: method, Params: params} buffer, err := json.Marshal(request) if err != nil { - klog.Fatalf("failed to marshal request: %v", err) + logger.Fatalf("failed to marshal request: %v", err) } - klog.V(2).Infof("jsonrpc request: %s", string(buffer)) + logger.Debugf("jsonrpc request: %s", string(buffer)) // make request: ctx, cancel := context.WithTimeout(ctx, client.HttpTimeout) defer cancel() req, err := http.NewRequestWithContext(ctx, "POST", client.RpcUrl, bytes.NewBuffer(buffer)) if err != nil { - klog.Fatalf("failed to create request: %v", err) + logger.Fatalf("failed to create request: %v", err) } req.Header.Set("content-type", "application/json") @@ -134,7 +137,7 @@ func getResponse[T any]( return fmt.Errorf("error processing %s rpc call: %w", method, err) } // log response: - klog.V(2).Infof("%s response: %v", method, string(body)) + logger.Debugf("%s response: %v", method, string(body)) // unmarshal the response into the predicted format if err = json.Unmarshal(body, rpcResponse); err != nil { @@ -207,7 +210,7 @@ func (c *Client) GetBlockProduction( ) (*BlockProduction, error) { // can't provide a last slot without a first: if firstSlot == nil && lastSlot != nil { - klog.Fatalf("can't provide a last slot without a first!") + c.logger.Fatalf("can't provide a last slot without a first!") } // format params: @@ -221,7 +224,7 @@ func (c *Client) GetBlockProduction( // make sure first and last slot are in order: if *firstSlot > *lastSlot { err := fmt.Errorf("last slot %v is greater than first slot %v", *lastSlot, *firstSlot) - klog.Fatalf("%v", err) + c.logger.Fatalf("%v", err) } blockRange["lastSlot"] = *lastSlot } @@ -286,13 +289,13 @@ func (c *Client) GetBlock( ) (*Block, error) { detailsOptions := []string{"full", "accounts", "none"} if !slices.Contains(detailsOptions, transactionDetails) { - klog.Fatalf( + c.logger.Fatalf( "%s is not a valid transaction-details option, must be one of %v", transactionDetails, detailsOptions, ) } if commitment == CommitmentProcessed { // as per https://solana.com/docs/rpc/http/getblock - klog.Fatalf("commitment '%v' is not supported for GetBlock", CommitmentProcessed) + c.logger.Fatalf("commitment '%v' is not supported for GetBlock", CommitmentProcessed) } config := map[string]any{ "commitment": commitment, @@ -329,7 +332,7 @@ func (c *Client) GetIdentity(ctx context.Context) (string, error) { return resp.Result.Identity, nil } -// MinimumLedgerSlot returns the lowest slot that the node has information about in its ledger. +// GetMinimumLedgerSlot returns the lowest slot that the node has information about in its ledger. // See API docs: https://solana.com/docs/rpc/http/minimumledgerslot func (c *Client) GetMinimumLedgerSlot(ctx context.Context) (*int64, error) { var resp response[int64] diff --git a/pkg/slog/main.go b/pkg/slog/main.go new file mode 100644 index 0000000..57809f3 --- /dev/null +++ b/pkg/slog/main.go @@ -0,0 +1,23 @@ +package slog + +import ( + "go.uber.org/zap" +) + +var log *zap.SugaredLogger + +// Init initializes the logger +func Init() { + logger, _ := zap.NewProduction() + log = logger.Sugar() +} + +// Get returns the global logger instance +func Get() *zap.SugaredLogger { + return log +} + +// Sync flushes any buffered log entries +func Sync() error { + return log.Sync() +}