Skip to content

Commit

Permalink
app/eth2wrap: implement eth2 wrapper for metrics and errors (#359)
Browse files Browse the repository at this point in the history
Add a `app/eth2wrap` package the contains a `Service` type that wraps `eth2http.Service` by adding prometheus metrics and error wrapping (for proper stack traces). It uses code generation.

category: feature
ticket: #362
  • Loading branch information
corverroos authored Apr 6, 2022
1 parent 85337ba commit 85c04cf
Show file tree
Hide file tree
Showing 5 changed files with 859 additions and 1 deletion.
4 changes: 3 additions & 1 deletion app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import (
"go.uber.org/automaxprocs/maxprocs"

"github.com/obolnetwork/charon/app/errors"
"github.com/obolnetwork/charon/app/eth2wrap"
"github.com/obolnetwork/charon/app/lifecycle"
"github.com/obolnetwork/charon/app/log"
"github.com/obolnetwork/charon/app/retry"
Expand Down Expand Up @@ -254,12 +255,13 @@ func wireCoreWorkflow(ctx context.Context, life *lifecycle.Manager, conf Config,
if err != nil {
return err
}

conf.BeaconNodeAddr = bmock.HTTPAddr()
eth2Cl = bmock
life.RegisterStop(lifecycle.StopBeaconMock, lifecycle.HookFuncErr(bmock.Close))
} else {
var err error
eth2Cl, err = eth2http.New(ctx,
eth2Cl, err = eth2wrap.NewHTTPService(ctx,
eth2http.WithLogLevel(1),
eth2http.WithAddress(conf.BeaconNodeAddr),
)
Expand Down
80 changes: 80 additions & 0 deletions app/eth2wrap/eth2wrap.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
// Copyright © 2021 Obol Technologies Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Package eth2wrap provides a wrapper for eth2http.Service adding prometheus metrics and error wrapping.
package eth2wrap

import (
"context"
"time"

eth2http "github.com/attestantio/go-eth2-client/http"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"

"github.com/obolnetwork/charon/app/errors"
)

//go:generate go run genwrap/genwrap.go

var (
latencyHist = promauto.NewHistogramVec(prometheus.HistogramOpts{
Namespace: "core",
Subsystem: "eth2",
Name: "latency_seconds",
Help: "Latency in seconds for eth2 beacon node requests",
}, []string{"endpoint"})

errorCount = promauto.NewCounterVec(prometheus.CounterOpts{
Namespace: "core",
Subsystem: "eth2",
Name: "errors_total",
Help: "Total number of errors returned by eth2 beacon node requests",
}, []string{"endpoint"})
)

// NewHTTPService returns a new instrumented eth2 http service.
func NewHTTPService(ctx context.Context, params ...eth2http.Parameter) (*Service, error) {
eth2Svc, err := eth2http.New(ctx, params...)
if err != nil {
return nil, errors.Wrap(err, "new et2http")
}

eth2Cl, ok := eth2Svc.(*eth2http.Service)
if !ok {
return nil, errors.New("invalid eth2http service")
}

return &Service{Service: eth2Cl}, nil
}

// Service wraps an eth2http.Service adding prometheus metrics and error wrapping.
type Service struct {
*eth2http.Service
}

// latency measures endpoint latency.
// Usage:
// defer latency("endpoint")()
func latency(endpoint string) func() {
t0 := time.Now()
return func() {
latencyHist.WithLabelValues(endpoint).Observe(time.Since(t0).Seconds())
}
}

// incError increments the error counter.
func incError(endpoint string) {
errorCount.WithLabelValues(endpoint).Inc()
}
Loading

0 comments on commit 85c04cf

Please sign in to comment.