diff --git a/.golangci.yml b/.golangci.yml index a17d6a3..4847901 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -78,9 +78,6 @@ linters-settings: - github.com/caitlinelfring/go-env-default - github.com/go-http-utils/headers - github.com/carlmjohnson/flowmatic - - github.com/go-chi/httplog/v2 - - github.com/go-chi/chi/v5 - - github.com/urfave/cli/v2 issues: max-same-issues: 0 # unlimited diff --git a/Dockerfile b/Dockerfile index 07ea105..c807252 100644 --- a/Dockerfile +++ b/Dockerfile @@ -7,7 +7,7 @@ RUN apk add --update-cache \ WORKDIR /src COPY . . -RUN go build . +RUN go build -o rpc-gateway cmd/rpcgateway/main.go FROM alpine:3.19 diff --git a/README.md b/README.md index 585818f..1888d99 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ go test -v ./... To run the app locally ```console -DEBUG=true go run . --config example_config.yml +DEBUG=true go run cmd/rpcgateway/main.go --config example_config.yml ``` ## Configuration diff --git a/cmd/rpcgateway/main.go b/cmd/rpcgateway/main.go new file mode 100644 index 0000000..058a7f4 --- /dev/null +++ b/cmd/rpcgateway/main.go @@ -0,0 +1,65 @@ +package main + +import ( + "context" + "flag" + "os" + "os/signal" + "syscall" + + "github.com/0xProject/rpc-gateway/internal/rpcgateway" + "github.com/carlmjohnson/flowmatic" + "github.com/pkg/errors" + "go.uber.org/zap" +) + +func main() { + c, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM) + defer stop() + + debugLogEnabled := os.Getenv("DEBUG") == "true" + logLevel := zap.WarnLevel + if debugLogEnabled { + logLevel = zap.DebugLevel + } + zapConfig := zap.NewProductionConfig() + zapConfig.Level = zap.NewAtomicLevelAt(logLevel) + logger, _ := zapConfig.Build() + + // We replace the global logger with this initialized here for simplyfication. + // Do see: https://github.com/uber-go/zap/blob/master/FAQ.md#why-include-package-global-loggers + // ref: https://pkg.go.dev/go.uber.org/zap?utm_source=godoc#ReplaceGlobals + // + zap.ReplaceGlobals(logger) + defer func() { + err := logger.Sync() // flushes buffer, if any + if err != nil { + logger.Error("failed to flush logger with err: %s", zap.Error(err)) + } + }() + + // Initialize config + configFileLocation := flag.String("config", "./config.yml", "path to rpc gateway config file") + flag.Parse() + config, err := rpcgateway.NewRPCGatewayFromConfigFile(*configFileLocation) + if err != nil { + logger.Fatal("failed to get config", zap.Error(err)) + } + + service := rpcgateway.NewRPCGateway(*config) + + err = flowmatic.Do( + func() error { + return errors.Wrap(service.Start(c), "cannot start a service") + }, + func() error { + <-c.Done() + + return errors.Wrap(service.Stop(c), "cannot stop a service") + }, + ) + + if err != nil { + logger.Fatal("errors", zap.Error(err)) + } +} diff --git a/example_config.yml b/example_config.yml index 3c0d5dc..f953f60 100644 --- a/example_config.yml +++ b/example_config.yml @@ -12,12 +12,8 @@ healthChecks: successThreshold: 1 # how many successes to be marked as healthy again targets: - - name: "Ankr" + - name: "QuickNode" connection: http: # ws is supported by default, it will be a sticky connection. url: "https://rpc.ankr.com/eth" # compression: true # Specify if the target supports request compression - - name: "Cloudflare" - connection: - http: - url: "https://cloudflare-eth.com" diff --git a/go.mod b/go.mod index 19b5ba4..c00ffb0 100644 --- a/go.mod +++ b/go.mod @@ -7,13 +7,13 @@ require ( github.com/caitlinelfring/go-env-default v1.1.0 github.com/carlmjohnson/flowmatic v0.23.4 github.com/ethereum/go-ethereum v1.13.12 - github.com/go-chi/chi/v5 v5.0.12 - github.com/go-chi/httplog/v2 v2.0.9 github.com/go-http-utils/headers v0.0.0-20181008091004-fed159eddc2a + github.com/gorilla/mux v1.8.1 github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.18.0 + github.com/purini-to/zapmw v1.1.0 github.com/stretchr/testify v1.8.4 - github.com/urfave/cli/v2 v2.25.7 + go.uber.org/zap v1.26.0 gopkg.in/yaml.v2 v2.4.0 ) @@ -22,7 +22,6 @@ require ( github.com/beorn7/perks v1.0.1 // indirect github.com/carlmjohnson/deque v0.23.1 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect - github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/deckarep/golang-set/v2 v2.6.0 // indirect github.com/go-ole/go-ole v1.3.0 // indirect @@ -32,12 +31,11 @@ require ( github.com/prometheus/client_model v0.5.0 // indirect github.com/prometheus/common v0.47.0 // indirect github.com/prometheus/procfs v0.12.0 // indirect - github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/shirou/gopsutil v3.21.11+incompatible // indirect github.com/tklauser/go-sysconf v0.3.13 // indirect github.com/tklauser/numcpus v0.7.0 // indirect - github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect github.com/yusufpapurcu/wmi v1.2.4 // indirect + go.uber.org/multierr v1.11.0 // indirect golang.org/x/crypto v0.19.0 // indirect golang.org/x/exp v0.0.0-20240213143201-ec583247a57a // indirect golang.org/x/mod v0.15.0 // indirect diff --git a/go.sum b/go.sum index 95c6628..823739e 100644 --- a/go.sum +++ b/go.sum @@ -20,8 +20,6 @@ github.com/consensys/bavard v0.1.13 h1:oLhMLOFGTLdlda/kma4VOJazblc7IM5y5QPd2A/Yj github.com/consensys/bavard v0.1.13/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI= github.com/consensys/gnark-crypto v0.12.1 h1:lHH39WuuFgVHONRl3J0LRBtuYdQTumFSDtJF7HpyG8M= github.com/consensys/gnark-crypto v0.12.1/go.mod h1:v2Gy7L/4ZRosZ7Ivs+9SfUDr0f5UlG+EM5t7MPHiLuY= -github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= -github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/crate-crypto/go-kzg-4844 v0.7.0 h1:C0vgZRk4q4EZ/JgPfzuSoxdCq3C3mOZMBShovmncxvA= github.com/crate-crypto/go-kzg-4844 v0.7.0/go.mod h1:1kMhvPgI0Ky3yIa+9lFySEBUBXkYxeOi8ZF1sYioxhc= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= @@ -34,10 +32,7 @@ github.com/ethereum/c-kzg-4844 v0.4.0 h1:3MS1s4JtA868KpJxroZoepdV0ZKBp3u/O5HcZ7R github.com/ethereum/c-kzg-4844 v0.4.0/go.mod h1:VewdlzQmpT5QSrVhbBuGoCdFJkpaJlO1aQputP83wc0= github.com/ethereum/go-ethereum v1.13.12 h1:iDr9UM2JWkngBHGovRJEQn4Kor7mT4gt9rUZqB5M29Y= github.com/ethereum/go-ethereum v1.13.12/go.mod h1:hKL2Qcj1OvStXNSEDbucexqnEt1Wh4Cz329XsjAalZY= -github.com/go-chi/chi/v5 v5.0.12 h1:9euLV5sTrTNTRUU9POmDUvfxyj6LAABLUcEWO+JJb4s= -github.com/go-chi/chi/v5 v5.0.12/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= -github.com/go-chi/httplog/v2 v2.0.9 h1:RK1TBETd4SSwu075tcfm0KKxR/k98RUfzmOWxLaocGg= -github.com/go-chi/httplog/v2 v2.0.9/go.mod h1:/XXdxicJsp4BA5fapgIC3VuTD+z0Z/VzukoB3VDc1YE= +github.com/go-chi/chi v4.0.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ= github.com/go-http-utils/headers v0.0.0-20181008091004-fed159eddc2a h1:v6zMvHuY9yue4+QkG/HQ/W67wvtQmWJ4SDo9aK/GIno= github.com/go-http-utils/headers v0.0.0-20181008091004-fed159eddc2a/go.mod h1:I79BieaU4fxrw4LMXby6q5OS9XnoR9UIKLOzDFjUmuw= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= @@ -45,6 +40,9 @@ github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/gorilla/mux v1.7.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= +github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY= github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY= github.com/holiman/uint256 v1.2.4 h1:jUc4Nk8fm9jZabQuqr2JzednajVmBpC+oiTiXZJEApU= @@ -67,10 +65,10 @@ github.com/prometheus/common v0.47.0 h1:p5Cz0FNHo7SnWOmWmoRozVcjEp0bIVU8cV7OShpj github.com/prometheus/common v0.47.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc= github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= +github.com/purini-to/zapmw v1.1.0 h1:izEoLBAv2nXrvIqEndnMdZepwMec2pXLIe/hT1lKSwI= +github.com/purini-to/zapmw v1.1.0/go.mod h1:jJEKz2/jGpBvCjK48sHgJ1/mF80CQ1CuzVx+KR42GII= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= -github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= -github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI= github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= @@ -81,12 +79,17 @@ github.com/tklauser/go-sysconf v0.3.13 h1:GBUpcahXSpR2xN01jhkNAbTLRk2Yzgggk8IM08 github.com/tklauser/go-sysconf v0.3.13/go.mod h1:zwleP4Q4OehZHGn4CYZDipCgg9usW5IJePewFCGVEa0= github.com/tklauser/numcpus v0.7.0 h1:yjuerZP127QG9m5Zh/mSO4wqurYil27tHrqwRoRjpr4= github.com/tklauser/numcpus v0.7.0/go.mod h1:bb6dMVcj8A42tSE7i32fsIUCbQNllK5iDguyOZRUzAY= -github.com/urfave/cli/v2 v2.25.7 h1:VAzn5oq403l5pHjc4OhD54+XGO9cdKVL/7lDjF+iKUs= -github.com/urfave/cli/v2 v2.25.7/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ= -github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= -github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= +go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk= +go.uber.org/goleak v1.2.0/go.mod h1:XJYK+MuIchqpmGmUSAzotztawfKvYLUIgg7guXrwVUo= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= +go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= +go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo= golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= golang.org/x/exp v0.0.0-20240213143201-ec583247a57a h1:HinSgX1tJRX3KsL//Gxynpw5CTOAIPhgL4W8PNiIpVE= diff --git a/internal/metrics/metrics.go b/internal/metrics/metrics.go index 46d8a7d..4fa68e5 100644 --- a/internal/metrics/metrics.go +++ b/internal/metrics/metrics.go @@ -5,8 +5,6 @@ import ( "net/http" "time" - "github.com/go-chi/chi/v5" - "github.com/go-chi/chi/v5/middleware" "github.com/prometheus/client_golang/prometheus/promhttp" ) @@ -23,14 +21,16 @@ func (s *Server) Stop() error { } func NewServer(config Config) *Server { - r := chi.NewRouter() + mux := http.NewServeMux() - r.Use(middleware.Heartbeat("/healthz")) - r.Handle("/metrics", promhttp.Handler()) + mux.HandleFunc("/healthz", func(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusOK) + }) + mux.Handle("/metrics", promhttp.Handler()) return &Server{ server: &http.Server{ - Handler: r, + Handler: mux, Addr: fmt.Sprintf(":%d", config.Port), WriteTimeout: time.Second * 15, ReadTimeout: time.Second * 15, diff --git a/internal/proxy/healthchecker.go b/internal/proxy/healthchecker.go index 0bdc5d4..6071df7 100644 --- a/internal/proxy/healthchecker.go +++ b/internal/proxy/healthchecker.go @@ -2,13 +2,13 @@ package proxy import ( "context" - "log/slog" "net/http" "sync" "time" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/rpc" + "go.uber.org/zap" ) const ( @@ -16,9 +16,8 @@ const ( ) type HealthCheckerConfig struct { - URL string - Name string // identifier imported from RPC gateway config - Logger *slog.Logger + URL string + Name string // identifier imported from RPC gateway config // How often to check health. Interval time.Duration `yaml:"healthcheckInterval"` @@ -37,7 +36,6 @@ type HealthChecker struct { client *rpc.Client httpClient *http.Client config HealthCheckerConfig - logger *slog.Logger // latest known blockNumber from the RPC. blockNumber uint64 @@ -59,7 +57,6 @@ func NewHealthChecker(config HealthCheckerConfig) (*HealthChecker, error) { client.SetHeader("User-Agent", userAgent) healthchecker := &HealthChecker{ - logger: config.Logger.With("nodeprovider", config.Name), client: client, httpClient: &http.Client{}, config: config, @@ -80,11 +77,11 @@ func (h *HealthChecker) checkBlockNumber(c context.Context) (uint64, error) { err := h.client.CallContext(c, &blockNumber, "eth_blockNumber") if err != nil { - h.logger.Error("could not fetch block number", "error", err) + zap.L().Warn("error fetching the block number", zap.Error(err), zap.String("name", h.config.Name)) return 0, err } - h.logger.Debug("fetch block number completed", "blockNumber", uint64(blockNumber)) + zap.L().Debug("fetched block", zap.Uint64("blockNumber", uint64(blockNumber)), zap.String("rpcProvider", h.config.Name)) return uint64(blockNumber), nil } @@ -95,12 +92,12 @@ func (h *HealthChecker) checkBlockNumber(c context.Context) (uint64, error) { // RPC provider's side. func (h *HealthChecker) checkGasLimit(c context.Context) (uint64, error) { gasLimit, err := performGasLeftCall(c, h.httpClient, h.config.URL) + zap.L().Debug("fetched gas limit", zap.Uint64("gasLimit", gasLimit), zap.String("rpcProvider", h.config.Name)) if err != nil { - h.logger.Error("could not fetch gas limit", "error", err) + zap.L().Warn("failed fetching the gas limit", zap.Error(err), zap.String("rpcProvider", h.config.Name)) return gasLimit, err } - h.logger.Debug("fetch gas limit completed", "gasLimit", gasLimit) return gasLimit, nil } diff --git a/internal/proxy/healthchecker_test.go b/internal/proxy/healthchecker_test.go index 72216bd..69a14a2 100644 --- a/internal/proxy/healthchecker_test.go +++ b/internal/proxy/healthchecker_test.go @@ -2,18 +2,23 @@ package proxy import ( "context" - "log/slog" "net/http" - "os" "testing" "time" "github.com/caitlinelfring/go-env-default" "github.com/stretchr/testify/assert" + "go.uber.org/zap" ) // TestBasicHealthchecker checks if it runs with default options. func TestBasicHealthchecker(t *testing.T) { + logger, _ := zap.NewDevelopment() + // We replace the global logger with this initialized here for simplyfication. + // Do see: https://github.com/uber-go/zap/blob/master/FAQ.md#why-include-package-global-loggers + // ref: https://pkg.go.dev/go.uber.org/zap?utm_source=godoc#ReplaceGlobals + zap.ReplaceGlobals(logger) + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() @@ -23,7 +28,6 @@ func TestBasicHealthchecker(t *testing.T) { Timeout: 2 * time.Second, FailureThreshold: 1, SuccessThreshold: 1, - Logger: slog.New(slog.NewTextHandler(os.Stderr, nil)), } healthchecker, err := NewHealthChecker(healtcheckConfig) diff --git a/internal/proxy/healthcheckmanager.go b/internal/proxy/healthcheckmanager.go index 31b9bb6..93825af 100644 --- a/internal/proxy/healthcheckmanager.go +++ b/internal/proxy/healthcheckmanager.go @@ -2,23 +2,21 @@ package proxy import ( "context" - "log/slog" "strconv" "time" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" + "go.uber.org/zap" ) type HealthCheckManagerConfig struct { Targets []NodeProviderConfig Config HealthCheckConfig - Logger *slog.Logger } type HealthCheckManager struct { - hcs []*HealthChecker - logger *slog.Logger + hcs []*HealthChecker metricRPCProviderInfo *prometheus.GaugeVec metricRPCProviderStatus *prometheus.GaugeVec @@ -28,7 +26,6 @@ type HealthCheckManager struct { func NewHealthCheckManager(config HealthCheckManagerConfig) *HealthCheckManager { hcm := &HealthCheckManager{ - logger: config.Logger, metricRPCProviderInfo: promauto.NewGaugeVec( prometheus.GaugeOpts{ Name: "zeroex_rpc_gateway_provider_info", @@ -64,7 +61,6 @@ func NewHealthCheckManager(config HealthCheckManagerConfig) *HealthCheckManager for _, target := range config.Targets { hc, err := NewHealthChecker( HealthCheckerConfig{ - Logger: config.Logger, URL: target.Connection.HTTP.URL, Name: target.Name, Interval: config.Config.Interval, @@ -133,7 +129,7 @@ func (h *HealthCheckManager) Stop(c context.Context) error { for _, hc := range h.hcs { err := hc.Stop(c) if err != nil { - h.logger.Error("could not stop health check manager", "error", err) + zap.L().Error("healtchecker stop error", zap.Error(err)) } } diff --git a/internal/proxy/proxy_test.go b/internal/proxy/proxy_test.go index cc4647e..e2791ad 100644 --- a/internal/proxy/proxy_test.go +++ b/internal/proxy/proxy_test.go @@ -4,10 +4,8 @@ import ( "bytes" "compress/gzip" "io" - "log/slog" "net/http" "net/http/httptest" - "os" "strconv" "testing" "time" @@ -69,7 +67,6 @@ func TestHttpFailoverProxyRerouteRequests(t *testing.T) { healthcheckManager := NewHealthCheckManager(HealthCheckManagerConfig{ Targets: rpcGatewayConfig.Targets, Config: rpcGatewayConfig.HealthChecks, - Logger: slog.New(slog.NewTextHandler(os.Stderr, nil)), }) // Setup HttpFailoverProxy but not starting the HealthCheckManager @@ -121,7 +118,6 @@ func TestHttpFailoverProxyDecompressRequest(t *testing.T) { healthcheckManager := NewHealthCheckManager(HealthCheckManagerConfig{ Targets: rpcGatewayConfig.Targets, Config: rpcGatewayConfig.HealthChecks, - Logger: slog.New(slog.NewTextHandler(os.Stderr, nil)), }) // Setup HttpFailoverProxy but not starting the HealthCheckManager // so the no target will be tainted or marked as unhealthy by the HealthCheckManager @@ -176,7 +172,6 @@ func TestHttpFailoverProxyWithCompressionSupportedTarget(t *testing.T) { healthcheckManager := NewHealthCheckManager(HealthCheckManagerConfig{ Targets: rpcGatewayConfig.Targets, Config: rpcGatewayConfig.HealthChecks, - Logger: slog.New(slog.NewTextHandler(os.Stderr, nil)), }) // Setup HttpFailoverProxy but not starting the HealthCheckManager // so the no target will be tainted or marked as unhealthy by the HealthCheckManager @@ -241,7 +236,6 @@ func TestHTTPFailoverProxyWhenCannotConnectToPrimaryProvider(t *testing.T) { healthcheckManager := NewHealthCheckManager(HealthCheckManagerConfig{ Targets: rpcGatewayConfig.Targets, Config: rpcGatewayConfig.HealthChecks, - Logger: slog.New(slog.NewTextHandler(os.Stderr, nil)), }) // Setup HttpFailoverProxy but not starting the HealthCheckManager so the diff --git a/internal/rpcgateway/rpcgateway.go b/internal/rpcgateway/rpcgateway.go index 32fba0e..86af174 100644 --- a/internal/rpcgateway/rpcgateway.go +++ b/internal/rpcgateway/rpcgateway.go @@ -3,7 +3,6 @@ package rpcgateway import ( "context" "fmt" - "log/slog" "net/http" "os" "time" @@ -11,9 +10,11 @@ import ( "github.com/0xProject/rpc-gateway/internal/metrics" "github.com/0xProject/rpc-gateway/internal/proxy" "github.com/carlmjohnson/flowmatic" - "github.com/go-chi/chi/v5" - "github.com/go-chi/httplog/v2" + "github.com/gorilla/mux" "github.com/pkg/errors" + "github.com/purini-to/zapmw" + "go.uber.org/zap" + "go.uber.org/zap/zapcore" "gopkg.in/yaml.v2" ) @@ -58,25 +59,10 @@ func (r *RPCGateway) Stop(c context.Context) error { } func NewRPCGateway(config RPCGatewayConfig) *RPCGateway { - logLevel := slog.LevelWarn - if os.Getenv("DEBUG") == "true" { - logLevel = slog.LevelDebug - } - - logger := httplog.NewLogger("rpc-gateway", httplog.Options{ - JSON: true, - RequestHeaders: true, - LogLevel: logLevel, - }) - hcm := proxy.NewHealthCheckManager( proxy.HealthCheckManagerConfig{ Targets: config.Targets, Config: config.HealthChecks, - Logger: slog.New( - slog.NewJSONHandler(os.Stderr, &slog.HandlerOptions{ - Level: logLevel, - })), }) proxy := proxy.NewProxy( proxy.Config{ @@ -87,9 +73,14 @@ func NewRPCGateway(config RPCGatewayConfig) *RPCGateway { hcm, ) - r := chi.NewRouter() - r.Use(httplog.RequestLogger(logger)) - r.Handle("/", proxy) + r := mux.NewRouter() + + r.Use( + zapmw.WithZap(zap.L()), + zapmw.Request(zapcore.InfoLevel, "request"), + zapmw.Recoverer(zapcore.ErrorLevel, "recover", zapmw.RecovererDefault), + ) + r.PathPrefix("/").Handler(proxy) return &RPCGateway{ config: config, diff --git a/internal/rpcgateway/rpcgateway_test.go b/internal/rpcgateway/rpcgateway_test.go index e6f58cf..11c0584 100644 --- a/internal/rpcgateway/rpcgateway_test.go +++ b/internal/rpcgateway/rpcgateway_test.go @@ -15,6 +15,7 @@ import ( "github.com/go-http-utils/headers" "github.com/prometheus/client_golang/prometheus" "github.com/stretchr/testify/assert" + "go.uber.org/zap" ) var rpcGatewayConfig = ` @@ -58,6 +59,10 @@ type TestURL struct { func TestRpcGatewayFailover(t *testing.T) { prometheus.DefaultRegisterer = prometheus.NewRegistry() + // initial setup + logger, _ := zap.NewDevelopment() + zap.ReplaceGlobals(logger) + // RPC backends setup onReq := func(r *http.Request) { fmt.Println("got request") diff --git a/main.go b/main.go deleted file mode 100644 index f0ea4ce..0000000 --- a/main.go +++ /dev/null @@ -1,54 +0,0 @@ -package main - -import ( - "context" - "fmt" - "os" - "os/signal" - "syscall" - - "github.com/0xProject/rpc-gateway/internal/rpcgateway" - "github.com/carlmjohnson/flowmatic" - "github.com/pkg/errors" - "github.com/urfave/cli/v2" -) - -func main() { - c, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM) - defer stop() - - app := &cli.App{ - Name: "rpc-gateway", - Usage: "The failover proxy for node providers.", - Flags: []cli.Flag{ - &cli.StringFlag{ - Name: "config", - Usage: "The configuration file path.", - Required: true, - }, - }, - Action: func(cc *cli.Context) error { - config, err := rpcgateway.NewRPCGatewayFromConfigFile(cc.String("config")) - if err != nil { - return err - } - - service := rpcgateway.NewRPCGateway(*config) - - return flowmatic.Do( - func() error { - return errors.Wrap(service.Start(c), "cannot start a service") - }, - func() error { - <-c.Done() - - return errors.Wrap(service.Stop(c), "cannot stop a service") - }, - ) - }, - } - - if err := app.Run(os.Args); err != nil { - fmt.Fprintf(os.Stderr, "error: %v", err) - } -}