Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cmd: add jaeger service name flag #303

Merged
merged 1 commit into from
Mar 30, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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