Skip to content

Commit

Permalink
cmd: add jaeger service name flag
Browse files Browse the repository at this point in the history
  • Loading branch information
corverroos committed Mar 29, 2022
1 parent 1de96c5 commit 148575e
Show file tree
Hide file tree
Showing 7 changed files with 91 additions and 6 deletions.
6 changes: 5 additions & 1 deletion app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ type Config struct {
ValidatorAPIAddr string
BeaconNodeAddr string
JaegerAddr string
JaegerService string
SimnetBMock bool
SimnetVMock bool

Expand Down Expand Up @@ -406,7 +407,10 @@ func wireVAPIRouter(life *lifecycle.Manager, conf Config, handler validatorapi.H

// wireTracing constructs the global tracer and registers it with the life cycle manager.
func wireTracing(life *lifecycle.Manager, conf Config) error {
stopjaeger, err := tracer.Init(tracer.WithJaegerOrNoop(conf.JaegerAddr))
stopjaeger, err := tracer.Init(
tracer.WithJaegerOrNoop(conf.JaegerAddr),
tracer.WithJaegerService(conf.JaegerService),
)
if err != nil {
return errors.Wrap(err, "init jaeger tracing")
}
Expand Down
35 changes: 30 additions & 5 deletions app/tracer/trace.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package tracer
import (
"context"
"io"
"net"

"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/exporters/jaeger"
Expand All @@ -39,6 +40,14 @@ func Start(ctx context.Context, spanName string, opts ...trace.SpanStartOption)
return tracer.Start(ctx, spanName, opts...)
}

// RootedCtx returns a copy of the parent context containing a tracing span context
// rooted to the trace ID. All spans started from the context will be rooted to the trace ID.
func RootedCtx(ctx context.Context, traceID trace.TraceID) context.Context {
return trace.ContextWithSpanContext(ctx, trace.NewSpanContext(trace.SpanContextConfig{
TraceID: traceID,
}))
}

// Init initialises the global tracer via the option(s) defaulting to a noop tracer. It returns a shutdown function.
func Init(opts ...func(*options)) (func(context.Context) error, error) {
var o options
Expand All @@ -57,7 +66,7 @@ func Init(opts ...func(*options)) (func(context.Context) error, error) {
return nil, err
}

tp := newTraceProvider(exp)
tp := newTraceProvider(exp, o.jaegerService)

// Set globals
otel.SetTracerProvider(tp)
Expand All @@ -67,7 +76,8 @@ func Init(opts ...func(*options)) (func(context.Context) error, error) {
}

type options struct {
expFunc func() (sdktrace.SpanExporter, error)
jaegerService string
expFunc func() (sdktrace.SpanExporter, error)
}

// WithStdOut returns an option to configure an OpenTelemetry exporter for tracing
Expand Down Expand Up @@ -95,11 +105,26 @@ func WithJaegerOrNoop(jaegerAddr string) func(*options) {
return WithJaeger(jaegerAddr)
}

// WithJaegerService returns an option to configure the jaeger service name.
func WithJaegerService(service string) func(*options) {
return func(o *options) {
o.jaegerService = service
}
}

// WithJaeger returns an option to configure an OpenTelemetry tracing exporter for Jaeger.
func WithJaeger(addr string) func(*options) {
return func(o *options) {
o.expFunc = func() (sdktrace.SpanExporter, error) {
ex, err := jaeger.New(jaeger.WithCollectorEndpoint(jaeger.WithEndpoint(addr)))
host, port, err := net.SplitHostPort(addr)
if err != nil {
return nil, errors.Wrap(err, "parse jaeger address (host:port)")
}

ex, err := jaeger.New(jaeger.WithAgentEndpoint(
jaeger.WithAgentHost(host),
jaeger.WithAgentPort(port),
))
if err != nil {
return nil, errors.Wrap(err, "jaeger exporter")
}
Expand All @@ -109,10 +134,10 @@ func WithJaeger(addr string) func(*options) {
}
}

func newTraceProvider(exp sdktrace.SpanExporter) *sdktrace.TracerProvider {
func newTraceProvider(exp sdktrace.SpanExporter, service string) *sdktrace.TracerProvider {
r := resource.NewWithAttributes(
semconv.SchemaURL,
semconv.ServiceNameKey.String("charon"),
semconv.ServiceNameKey.String(service),
)

tp := sdktrace.NewTracerProvider(
Expand Down
1 change: 1 addition & 0 deletions cmd/cmd_internal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ func TestCmdFlags(t *testing.T) {
ValidatorAPIAddr: "127.0.0.1:3500",
BeaconNodeAddr: "http://localhost/",
JaegerAddr: "",
JaegerService: "charon",
},
},
}
Expand Down
1 change: 1 addition & 0 deletions cmd/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ func bindRunFlags(flags *pflag.FlagSet, config *app.Config) {
flags.StringVar(&config.ValidatorAPIAddr, "validator-api-address", "127.0.0.1:3500", "Listening address (ip and port) for validator-facing traffic proxying the beacon-node API")
flags.StringVar(&config.MonitoringAddr, "monitoring-address", "127.0.0.1:8088", "Listening address (ip and port) for the monitoring API (prometheus, pprof)")
flags.StringVar(&config.JaegerAddr, "jaeger-address", "", "Listening address for jaeger tracing")
flags.StringVar(&config.JaegerService, "jaeger-service", "charon", "Service name used for jaeger tracing")
flags.BoolVar(&config.SimnetBMock, "simnet-beacon-mock", false, "Enables an internal mock beacon node for running a simnet.")
flags.BoolVar(&config.SimnetVMock, "simnet-validator-mock", false, "Enables an internal mock validator client when running a simnet. Requires simnet-beacon-mock.")
}
Expand Down
28 changes: 28 additions & 0 deletions core/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,17 @@ package core

import (
"bytes"
"context"
"encoding/hex"
"fmt"
"hash/fnv"

eth2v1 "github.com/attestantio/go-eth2-client/api/v1"
eth2p0 "github.com/attestantio/go-eth2-client/spec/phase0"
"go.opentelemetry.io/otel/trace"

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

// DutyType enumerates the different types of duties.
Expand Down Expand Up @@ -70,6 +74,18 @@ func (d Duty) String() string {
return fmt.Sprintf("%d/%s", d.Slot, d.Type)
}

// NewAttesterDuty returns a new attester duty. It is a convenience function that is
// slightly more readable and concise than the struct literal equivalent:
// core.Duty{Slot: slot, Type: core.DutyAttester}
// vs
// core.NewAttesterDuty(slot)
func NewAttesterDuty(slot int64) Duty {
return Duty{
Slot: slot,
Type: DutyAttester,
}
}

const (
pkLen = 98 // "0x" + hex.Encode([48]byte) = 2+2*48
sigLen = 96
Expand Down Expand Up @@ -191,3 +207,15 @@ type AggSignedData struct {
func (a AggSignedData) Equal(b AggSignedData) bool {
return bytes.Equal(a.Data, b.Data) && bytes.Equal(a.Signature, b.Signature)
}

// DutyTraceRoot returns a copy of the parent context containing a tracing span context rooted
// to the duty.
func DutyTraceRoot(ctx context.Context, duty Duty) context.Context {
h := fnv.New128a()
_, _ = h.Write([]byte(duty.String()))

var traceID trace.TraceID
copy(traceID[:], h.Sum(nil))

return tracer.RootedCtx(ctx, traceID)
}
25 changes: 25 additions & 0 deletions core/types_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,13 @@
package core_test

import (
"context"
"io"
"testing"

"github.com/stretchr/testify/require"

"github.com/obolnetwork/charon/app/tracer"
"github.com/obolnetwork/charon/core"
"github.com/obolnetwork/charon/testutil"
)
Expand Down Expand Up @@ -54,3 +57,25 @@ func TestAggSignedData_Equal(t *testing.T) {
require.False(t, testAggSignedData1.Equal(testAggSignedData4))
require.False(t, testAggSignedData1.Equal(testAggSignedData5))
}

func TestWithDutySpanCtx(t *testing.T) {
ctx := context.Background()
stop, err := tracer.Init(tracer.WithStdOut(io.Discard))
require.NoError(t, err)
defer func() {
require.NoError(t, stop(context.Background()))
}()

_, span1 := tracer.Start(core.DutyTraceRoot(ctx, core.Duty{}), "span1")
_, span2 := tracer.Start(core.DutyTraceRoot(ctx, core.Duty{}), "span2")

require.Equal(t, "7d0b160d5b04eac85dd1eaf0585c5b82", span1.SpanContext().TraceID().String())
require.Equal(t, span1.SpanContext().TraceID(), span2.SpanContext().TraceID())
require.NotEqual(t, span1.SpanContext().SpanID(), span2.SpanContext().SpanID())

require.True(t, span1.SpanContext().IsValid())
require.True(t, span1.SpanContext().IsSampled())

require.True(t, span2.SpanContext().IsValid())
require.True(t, span2.SpanContext().IsSampled())
}
1 change: 1 addition & 0 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ Flags:
--data-dir string The directory where charon will store all its internal data (default "./charon/data")
-h, --help help for run
--jaeger-address string Listening address for jaeger tracing
--jaeger-service string Service name used for jaeger tracing (default "charon")
--log-format string Log format; console, logfmt or json (default "console")
--log-level string Log level; debug, info, warn or error (default "info")
--manifest-file string The path to the manifest file defining distributed validator cluster (default "./charon/manifest.json")
Expand Down

0 comments on commit 148575e

Please sign in to comment.