From 1cf5e6c79fa2458a889aa64f055ca726c8961b8a Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Wed, 29 Oct 2025 15:44:07 -0400 Subject: [PATCH 01/52] feat: add tracing --- log/tracer.go | 120 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 120 insertions(+) create mode 100644 log/tracer.go diff --git a/log/tracer.go b/log/tracer.go new file mode 100644 index 000000000000..ed247b73ed6a --- /dev/null +++ b/log/tracer.go @@ -0,0 +1,120 @@ +package log + +import "context" + +// Tracer is an interface for creating and managing spans. +// It may be backed by open telemetry or other tracing libraries, +// Spans may also be used for collecting timing metrics. +// It embeds the Logger interface. Log events may be associated with spans. +type Tracer interface { + Logger + + // StartSpan starts a new span with the given operation name and key-value pair attributes. + // If there is a parent span, the new span will be a child of that span. + // It is recommended to use a defer statement to end the span like this: + // span := tracer.StartSpan("my-span") + // defer span.End() + StartSpan(operation string, kvs ...any) Span + + // StartSpanContext attempts to retrieve an existing tracer from the context and then starts a new span + // as a child of that span. + // If no tracer is found, it returns a new span that is a child of this tracer instance. + // This is useful if a span may have been set in the context, but we are not sure. + // The function also returns a context with the span added to it. + StartSpanContext(ctx context.Context, operation string, kvs ...any) (context.Context, Span) + + // RootTracer returns a root-level tracer that is not part of any existing span. + // Use this when starting async work to ensure its spans are not timed as part of the current span. + // Example usage: + // rootTracer := tracer.RootTracer() + // go func() { + // span := rootTracer.StartSpan("my-go-routine") + // defer span.End() + // doSomething() + // }() + RootTracer() Tracer +} + +// Span is an interface for managing spans and creating nested spans via the embedded Tracer interface. +type Span interface { + // Tracer is embedded to allow for the creation of nested spans. + Tracer + + // SetAttrs sets additional key-value attributes on the span. + SetAttrs(kvs ...any) + + // SetErr records an optional error on the span and optionally adds additional key-value pair attributes. + // It returns the error value unchanged, allowing use in return statements. + // If err is nil, the span is marked as successful. + // If err is not nil, the span is marked as failed. + // This does NOT end the span, you must still call End. + // Example usage: + // span := tracer.StartSpan("my-span") + // defer span.End() + // err := doSomething() + // return span.SetErr(err, "additional", "info") // okay to call with a nil error + SetErr(err error, kvs ...any) error + + // End marks the end of a span and is designed to be used in a defer statement right after the span is created. + // Calling End on a span that has already ended is a no-op. + // Example usage: + // span := tracer.StartSpan("my-span") + // defer span.End() + End() +} + +type traceContextKeyType string + +const traceContextKey traceContextKeyType = "trace-context" + +func ContextWithTracer(ctx context.Context, tracer Tracer) context.Context { + return context.WithValue(ctx, traceContextKey, tracer) +} + +// TracerFromContext returns the Tracer from the context. +// If no Tracer is found, it returns a no-op Tracer that is safe to use. +func TracerFromContext(ctx context.Context) Tracer { + if tracer, ok := ctx.Value(traceContextKey).(Tracer); ok { + return tracer + } + return NewNopTracer() +} + +// NewNopTracer returns a Tracer that does nothing. +func NewNopTracer() Tracer { + return nopTracer{} +} + +type nopTracer struct { + nopLogger +} + +func (n nopTracer) StartSpanContext(ctx context.Context, operation string, kvs ...any) (context.Context, Span) { + if tracer, ok := ctx.Value(traceContextKey).(Tracer); ok { + span := tracer.StartSpan(operation, kvs...) + return ContextWithTracer(ctx, span), span + } + // no tracer found in context, create a new span, no need to add to context + return ctx, nopSpan{} +} + +func (n nopTracer) StartSpan(string, ...any) Span { + return nopSpan{} +} + +func (n nopTracer) RootTracer() Tracer { + return n +} + +type nopSpan struct { + nopTracer +} + +func (n nopSpan) SetAttrs(...any) {} + +func (n nopSpan) SetErr(err error, _ ...any) error { return err } + +func (n nopSpan) End() {} + +var _ Tracer = nopTracer{} +var _ Span = nopSpan{} From a207f94910406dbe944d4e6a74c47b1a68f10840 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Wed, 29 Oct 2025 16:54:12 -0400 Subject: [PATCH 02/52] work on otel tracer impl --- log/tracer.go | 39 +++-------- telemetry/otel.go | 168 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 176 insertions(+), 31 deletions(-) create mode 100644 telemetry/otel.go diff --git a/log/tracer.go b/log/tracer.go index ed247b73ed6a..cfb99eafdb57 100644 --- a/log/tracer.go +++ b/log/tracer.go @@ -23,16 +23,15 @@ type Tracer interface { // The function also returns a context with the span added to it. StartSpanContext(ctx context.Context, operation string, kvs ...any) (context.Context, Span) - // RootTracer returns a root-level tracer that is not part of any existing span. + // StartRootSpan returns a root-level span that doesn't have a parent. // Use this when starting async work to ensure its spans are not timed as part of the current span. // Example usage: - // rootTracer := tracer.RootTracer() // go func() { - // span := rootTracer.StartSpan("my-go-routine") + // ctx, span := outerSpan.StartRootSpan(ctx, "my-go-routine") // defer span.End() // doSomething() // }() - RootTracer() Tracer + StartRootSpan(ctx context.Context, operation string, kvs ...any) (context.Context, Span) } // Span is an interface for managing spans and creating nested spans via the embedded Tracer interface. @@ -63,23 +62,6 @@ type Span interface { End() } -type traceContextKeyType string - -const traceContextKey traceContextKeyType = "trace-context" - -func ContextWithTracer(ctx context.Context, tracer Tracer) context.Context { - return context.WithValue(ctx, traceContextKey, tracer) -} - -// TracerFromContext returns the Tracer from the context. -// If no Tracer is found, it returns a no-op Tracer that is safe to use. -func TracerFromContext(ctx context.Context) Tracer { - if tracer, ok := ctx.Value(traceContextKey).(Tracer); ok { - return tracer - } - return NewNopTracer() -} - // NewNopTracer returns a Tracer that does nothing. func NewNopTracer() Tracer { return nopTracer{} @@ -89,21 +71,16 @@ type nopTracer struct { nopLogger } -func (n nopTracer) StartSpanContext(ctx context.Context, operation string, kvs ...any) (context.Context, Span) { - if tracer, ok := ctx.Value(traceContextKey).(Tracer); ok { - span := tracer.StartSpan(operation, kvs...) - return ContextWithTracer(ctx, span), span - } - // no tracer found in context, create a new span, no need to add to context +func (n nopTracer) StartRootSpan(ctx context.Context, operation string, kvs ...any) (context.Context, Span) { return ctx, nopSpan{} } -func (n nopTracer) StartSpan(string, ...any) Span { - return nopSpan{} +func (n nopTracer) StartSpanContext(ctx context.Context, _ string, _ ...any) (context.Context, Span) { + return ctx, nopSpan{} } -func (n nopTracer) RootTracer() Tracer { - return n +func (n nopTracer) StartSpan(string, ...any) Span { + return nopSpan{} } type nopSpan struct { diff --git a/telemetry/otel.go b/telemetry/otel.go new file mode 100644 index 000000000000..b3172d39abb3 --- /dev/null +++ b/telemetry/otel.go @@ -0,0 +1,168 @@ +package telemetry + +import ( + "context" + "fmt" + + otelattr "go.opentelemetry.io/otel/attribute" + otelcodes "go.opentelemetry.io/otel/codes" + oteltrace "go.opentelemetry.io/otel/trace" + + "cosmossdk.io/log" +) + +type OtelSpan struct { + tracer oteltrace.Tracer + ctx context.Context + span oteltrace.Span + persistentAttrs []otelattr.KeyValue +} + +func NewOtelSpan(tracer oteltrace.Tracer, ctx context.Context, operation string, kvs ...any) (context.Context, *OtelSpan) { + ctx, span := tracer.Start(ctx, operation, oteltrace.WithAttributes(toKVs(kvs)...)) + return ctx, &OtelSpan{ + tracer: tracer, + ctx: ctx, + span: span, + } +} + +func (o *OtelSpan) addEvent(level, msg string, keyVals ...any) { + o.span.AddEvent(msg, + oteltrace.WithAttributes(o.persistentAttrs...), + oteltrace.WithAttributes(toKVs(keyVals...)...), + oteltrace.WithAttributes(otelattr.String("level", level)), + ) +} + +func (o *OtelSpan) Info(msg string, keyVals ...any) { + o.addEvent("info", msg, keyVals...) +} + +func (o *OtelSpan) Warn(msg string, keyVals ...any) { + o.addEvent("warn", msg, keyVals...) +} + +func (o *OtelSpan) Error(msg string, keyVals ...any) { + o.addEvent("error", msg, keyVals...) +} + +func (o *OtelSpan) Debug(msg string, keyVals ...any) { + o.addEvent("debug", msg, keyVals...) +} + +func (o *OtelSpan) With(keyVals ...any) log.Logger { + attrs := toKVs(keyVals...) + persistentAttrs := make([]otelattr.KeyValue, 0, len(o.persistentAttrs)+len(attrs)) + persistentAttrs = append(persistentAttrs, o.persistentAttrs...) + persistentAttrs = append(persistentAttrs, attrs...) + return &OtelSpan{ + tracer: o.tracer, + ctx: o.ctx, + span: o.span, + persistentAttrs: persistentAttrs, + } +} + +func (o *OtelSpan) Impl() any { + return o.span +} + +func (o *OtelSpan) startSpan(ctx context.Context, operation string, kvs []any, opts ...oteltrace.SpanStartOption) *OtelSpan { + if len(o.persistentAttrs) > 0 { + opts = append(opts, oteltrace.WithAttributes(o.persistentAttrs...)) + } + opts = append(opts, oteltrace.WithAttributes(toKVs(kvs...)...)) + ctx, span := o.tracer.Start(ctx, operation, opts...) + return &OtelSpan{ + tracer: o.tracer, + ctx: ctx, + span: span, + persistentAttrs: o.persistentAttrs, + } +} + +func (o *OtelSpan) StartSpan(operation string, kvs ...any) log.Span { + return o.startSpan(o.ctx, operation, kvs) +} + +func (o *OtelSpan) StartSpanContext(ctx context.Context, operation string, kvs ...any) (context.Context, log.Span) { + if !oteltrace.SpanContextFromContext(ctx).IsValid() { + // if we don't have a valid span in the context, use the one from the tracer + ctx = o.ctx + } + span := o.startSpan(ctx, operation, kvs) + return span.ctx, span +} + +func (o *OtelSpan) StartRootSpan(ctx context.Context, operation string, kvs ...any) (context.Context, log.Span) { + span := o.startSpan(ctx, operation, kvs, oteltrace.WithNewRoot()) + return span.ctx, span +} + +func (o *OtelSpan) SetAttrs(kvs ...any) { + o.span.SetAttributes(toKVs(kvs...)...) +} + +func (o *OtelSpan) SetErr(err error, kvs ...any) error { + if err == nil { + o.span.SetStatus(otelcodes.Ok, "OK") + } else { + o.span.RecordError(err) + o.span.SetStatus(otelcodes.Error, err.Error()) + } + if len(kvs) > 0 { + o.span.SetAttributes(toKVs(kvs...)...) + } + return err +} + +func (o *OtelSpan) End() { + o.span.End() +} + +var _ log.Span = (*OtelSpan)(nil) + +func toKVs(kvs ...any) []otelattr.KeyValue { + if len(kvs)%2 != 0 { + panic(fmt.Sprintf("kvs must have even length, got %d", len(kvs))) + } + res := make([]otelattr.KeyValue, 0, len(kvs)/2) + for i := 0; i < len(kvs); i += 2 { + key, ok := kvs[i].(string) + if !ok { + panic("key must be string") + } + res = append(res, otelattr.KeyValue{ + Key: otelattr.Key(key), + Value: toValue(kvs[i+1]), + }) + } + return res +} + +func toValue(value any) otelattr.Value { + switch v := value.(type) { + case bool: + return otelattr.BoolValue(v) + case string: + return otelattr.StringValue(v) + case int64: + return otelattr.Int64Value(v) + case int: + return otelattr.IntValue(v) + case float64: + return otelattr.Float64Value(v) + case []string: + return otelattr.StringSliceValue(v) + case []int64: + return otelattr.Int64SliceValue(v) + case []int: + return otelattr.IntSliceValue(v) + case []float64: + return otelattr.Float64SliceValue(v) + default: + return otelattr.StringValue(fmt.Sprintf("%+v", value)) + } + +} From ee0bfb37891f12fb2483ac22063a7429d51a99c3 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Wed, 29 Oct 2025 16:54:59 -0400 Subject: [PATCH 03/52] add basic baseapp tracing --- baseapp/abci.go | 41 ++++++++++++++++++++++++++---- baseapp/baseapp.go | 49 +++++++++++++++++++++++++++++------- baseapp/genesis.go | 2 +- baseapp/test_helpers.go | 9 ++++--- baseapp/txnrunner/default.go | 7 ++++-- blockstm/executor.go | 4 ++- blockstm/txnrunner.go | 5 ++-- blockstm/types.go | 4 ++- client/v2/go.mod | 2 +- client/v2/go.sum | 4 +-- go.mod | 4 ++- go.sum | 6 ++--- simapp/go.mod | 6 ++++- simapp/go.sum | 4 +-- systemtests/go.mod | 2 +- systemtests/go.sum | 4 +-- tests/go.mod | 2 +- tests/go.sum | 4 +-- tests/systemtests/go.mod | 2 +- tests/systemtests/go.sum | 4 +-- types/abci.go | 4 ++- 21 files changed, 123 insertions(+), 46 deletions(-) diff --git a/baseapp/abci.go b/baseapp/abci.go index f7ede1c840f6..dd4999af0334 100644 --- a/baseapp/abci.go +++ b/baseapp/abci.go @@ -39,6 +39,9 @@ const ( ) func (app *BaseApp) InitChain(req *abci.RequestInitChain) (*abci.ResponseInitChain, error) { + span := app.tracer.StartSpan("InitChain") + defer span.End() + if req.ChainId != app.chainID { return nil, fmt.Errorf("invalid chain-id on InitChain; expected: %s, got: %s", app.chainID, req.ChainId) } @@ -153,6 +156,9 @@ func (app *BaseApp) Info(_ *abci.RequestInfo) (*abci.ResponseInfo, error) { // Query implements the ABCI interface. It delegates to CommitMultiStore if it // implements Queryable. func (app *BaseApp) Query(_ context.Context, req *abci.RequestQuery) (resp *abci.ResponseQuery, err error) { + span := app.tracer.StartSpan("Query") + defer span.End() + // add panic recovery for all queries // // Ref: https://github.com/cosmos/cosmos-sdk/pull/8039 @@ -342,6 +348,9 @@ func (app *BaseApp) ApplySnapshotChunk(req *abci.RequestApplySnapshotChunk) (*ab // will contain relevant error information. Regardless of tx execution outcome, // the ResponseCheckTx will contain the relevant gas execution context. func (app *BaseApp) CheckTx(req *abci.RequestCheckTx) (*abci.ResponseCheckTx, error) { + span := app.tracer.StartSpan("CheckTx") + defer span.End() + var mode sdk.ExecMode switch req.Type { @@ -356,7 +365,7 @@ func (app *BaseApp) CheckTx(req *abci.RequestCheckTx) (*abci.ResponseCheckTx, er } if app.abciHandlers.CheckTxHandler == nil { - gasInfo, result, anteEvents, err := app.RunTx(mode, req.Tx, nil, -1, nil, nil) + gasInfo, result, anteEvents, err := app.RunTx(mode, req.Tx, nil, -1, nil, nil, span) if err != nil { return sdkerrors.ResponseCheckTxWithEvents(err, gasInfo.GasWanted, gasInfo.GasUsed, anteEvents, app.trace), nil } @@ -372,7 +381,7 @@ func (app *BaseApp) CheckTx(req *abci.RequestCheckTx) (*abci.ResponseCheckTx, er // Create wrapper to avoid users overriding the execution mode runTx := func(txBytes []byte, tx sdk.Tx) (gInfo sdk.GasInfo, result *sdk.Result, anteEvents []abci.Event, err error) { - return app.RunTx(mode, txBytes, tx, -1, nil, nil) + return app.RunTx(mode, txBytes, tx, -1, nil, nil, span) } return app.abciHandlers.CheckTxHandler(runTx, req) @@ -392,6 +401,9 @@ func (app *BaseApp) CheckTx(req *abci.RequestCheckTx) (*abci.ResponseCheckTx, er // Ref: https://github.com/cosmos/cosmos-sdk/blob/main/docs/architecture/adr-060-abci-1.0.md // Ref: https://github.com/cometbft/cometbft/blob/main/spec/abci/abci%2B%2B_basic_concepts.md func (app *BaseApp) PrepareProposal(req *abci.RequestPrepareProposal) (resp *abci.ResponsePrepareProposal, err error) { + span := app.tracer.StartSpan("PrepareProposal") + defer span.End() + if app.abciHandlers.PrepareProposalHandler == nil { return nil, errors.New("PrepareProposal handler not set") } @@ -479,6 +491,9 @@ func (app *BaseApp) PrepareProposal(req *abci.RequestPrepareProposal) (resp *abc // Ref: https://github.com/cosmos/cosmos-sdk/blob/main/docs/architecture/adr-060-abci-1.0.md // Ref: https://github.com/cometbft/cometbft/blob/main/spec/abci/abci%2B%2B_basic_concepts.md func (app *BaseApp) ProcessProposal(req *abci.RequestProcessProposal) (resp *abci.ResponseProcessProposal, err error) { + span := app.tracer.StartSpan("ProcessProposal") + defer span.End() + if app.abciHandlers.ProcessProposalHandler == nil { return nil, errors.New("ProcessProposal handler not set") } @@ -576,6 +591,9 @@ func (app *BaseApp) ProcessProposal(req *abci.RequestProcessProposal) (resp *abc // height and are committed in the subsequent height, i.e. H+2. An error is // returned if vote extensions are not enabled or if extendVote fails or panics. func (app *BaseApp) ExtendVote(_ context.Context, req *abci.RequestExtendVote) (resp *abci.ResponseExtendVote, err error) { + span := app.tracer.StartSpan("ExtendVote") + defer span.End() + // Always reset state given that ExtendVote and VerifyVoteExtension can timeout // and be called again in a subsequent round. var ctx sdk.Context @@ -649,6 +667,9 @@ func (app *BaseApp) ExtendVote(_ context.Context, req *abci.RequestExtendVote) ( // phase. The response MUST be deterministic. An error is returned if vote // extensions are not enabled or if verifyVoteExt fails or panics. func (app *BaseApp) VerifyVoteExtension(req *abci.RequestVerifyVoteExtension) (resp *abci.ResponseVerifyVoteExtension, err error) { + span := app.tracer.StartSpan("VerifyVoteExtension") + defer span.End() + if app.abciHandlers.VerifyVoteExtensionHandler == nil { return nil, errors.New("application VerifyVoteExtension handler not set") } @@ -717,6 +738,9 @@ func (app *BaseApp) VerifyVoteExtension(req *abci.RequestVerifyVoteExtension) (r // only used to handle early cancellation, for anything related to state app.stateManager.GetState(execModeFinalize).Context() // must be used. func (app *BaseApp) internalFinalizeBlock(ctx context.Context, req *abci.RequestFinalizeBlock) (*abci.ResponseFinalizeBlock, error) { + span := app.tracer.StartSpan("internalFinalizeBlock") + defer span.End() + var events []abci.Event if err := app.checkHalt(req.Height, req.Time); err != nil { @@ -782,14 +806,14 @@ func (app *BaseApp) internalFinalizeBlock(ctx context.Context, req *abci.Request WithHeaderHash(req.Hash)) } - preblockEvents, err := app.preBlock(req) + preblockEvents, err := app.preBlock(span, req) if err != nil { return nil, err } events = append(events, preblockEvents...) - beginBlock, err := app.beginBlock(req) + beginBlock, err := app.beginBlock(span, req) if err != nil { return nil, err } @@ -846,7 +870,7 @@ func (app *BaseApp) internalFinalizeBlock(ctx context.Context, req *abci.Request WithBlockGasUsed(blockGasUsed). WithBlockGasWanted(blockGasWanted), ) - endBlock, err := app.endBlock(finalizeState.Context()) + endBlock, err := app.endBlock(span, finalizeState.Context()) if err != nil { return nil, err } @@ -874,6 +898,7 @@ func (app *BaseApp) executeTxsWithExecutor(ctx context.Context, ms storetypes.Mu if app.txRunner == nil { app.txRunner = txnrunner.NewDefaultRunner( app.txDecoder, + app.tracer, ) } @@ -891,6 +916,9 @@ func (app *BaseApp) executeTxsWithExecutor(ctx context.Context, ms storetypes.Mu // extensions into the proposal, which should not themselves be executed in cases // where they adhere to the sdk.Tx interface. func (app *BaseApp) FinalizeBlock(req *abci.RequestFinalizeBlock) (res *abci.ResponseFinalizeBlock, err error) { + span := app.tracer.StartSpan("FinalizeBlock") + defer span.End() + defer func() { if res == nil { return @@ -958,6 +986,9 @@ func (app *BaseApp) checkHalt(height int64, time time.Time) error { // against that height and gracefully halt if it matches the latest committed // height. func (app *BaseApp) Commit() (*abci.ResponseCommit, error) { + span := app.tracer.StartSpan("Commit") + defer span.End() + finalizeState := app.stateManager.GetState(execModeFinalize) header := finalizeState.Context().BlockHeader() retainHeight := app.GetBlockRetentionHeight(header.Height) diff --git a/baseapp/baseapp.go b/baseapp/baseapp.go index 31fd20b1f7e7..14b42770af07 100644 --- a/baseapp/baseapp.go +++ b/baseapp/baseapp.go @@ -18,12 +18,13 @@ import ( protov2 "google.golang.org/protobuf/proto" errorsmod "cosmossdk.io/errors" - "cosmossdk.io/log" "cosmossdk.io/store" storemetrics "cosmossdk.io/store/metrics" "cosmossdk.io/store/snapshots" storetypes "cosmossdk.io/store/types" + "cosmossdk.io/log" + "github.com/cosmos/cosmos-sdk/baseapp/config" "github.com/cosmos/cosmos-sdk/baseapp/oe" "github.com/cosmos/cosmos-sdk/baseapp/state" @@ -64,6 +65,7 @@ type BaseApp struct { // initialized on creation mu sync.Mutex // mu protects the fields below. logger log.Logger + tracer log.Tracer name string // application name from abci.BlockInfo db dbm.DB // common DB backend cms storetypes.CommitMultiStore // Main (uncached) state @@ -186,6 +188,13 @@ func NewBaseApp( gasConfig: config.GasConfig{QueryGasLimit: math.MaxUint64}, } + // initialize tracer + tracer, ok := app.logger.(log.Tracer) + if !ok { + tracer = log.NewNopTracer() + } + app.tracer = tracer + for _, option := range options { option(app) } @@ -651,7 +660,10 @@ func (app *BaseApp) cacheTxContext(ctx sdk.Context, txBytes []byte) (sdk.Context return ctx.WithMultiStore(msCache), msCache } -func (app *BaseApp) preBlock(req *abci.RequestFinalizeBlock) ([]abci.Event, error) { +func (app *BaseApp) preBlock(tracer log.Tracer, req *abci.RequestFinalizeBlock) ([]abci.Event, error) { + span := tracer.StartSpan("preBlock") + defer span.End() + var events []abci.Event if app.abciHandlers.PreBlocker != nil { finalizeState := app.stateManager.GetState(execModeFinalize) @@ -674,7 +686,7 @@ func (app *BaseApp) preBlock(req *abci.RequestFinalizeBlock) ([]abci.Event, erro return events, nil } -func (app *BaseApp) beginBlock(_ *abci.RequestFinalizeBlock) (sdk.BeginBlock, error) { +func (app *BaseApp) beginBlock(tracer log.Tracer, _ *abci.RequestFinalizeBlock) (sdk.BeginBlock, error) { var ( resp sdk.BeginBlock err error @@ -700,7 +712,7 @@ func (app *BaseApp) beginBlock(_ *abci.RequestFinalizeBlock) (sdk.BeginBlock, er return resp, nil } -func (app *BaseApp) deliverTx(tx []byte, txMultiStore storetypes.MultiStore, txIndex int, incarnationCache map[string]any) *abci.ExecTxResult { +func (app *BaseApp) deliverTx(tx []byte, txMultiStore storetypes.MultiStore, txIndex int, incarnationCache map[string]any, tracer log.Tracer) *abci.ExecTxResult { gInfo := sdk.GasInfo{} resultStr := "successful" @@ -713,7 +725,7 @@ func (app *BaseApp) deliverTx(tx []byte, txMultiStore storetypes.MultiStore, txI telemetry.SetGauge(float32(gInfo.GasWanted), "tx", "gas", "wanted") }() - gInfo, result, anteEvents, err := app.RunTx(execModeFinalize, tx, nil, txIndex, txMultiStore, incarnationCache) + gInfo, result, anteEvents, err := app.RunTx(execModeFinalize, tx, nil, txIndex, txMultiStore, incarnationCache, tracer) if err != nil { resultStr = "failed" resp = sdkerrors.ResponseExecTxResultWithEvents( @@ -739,7 +751,10 @@ func (app *BaseApp) deliverTx(tx []byte, txMultiStore storetypes.MultiStore, txI // endBlock is an application-defined function that is called after transactions // have been processed in FinalizeBlock. -func (app *BaseApp) endBlock(_ context.Context) (sdk.EndBlock, error) { +func (app *BaseApp) endBlock(tracer log.Tracer, _ context.Context) (sdk.EndBlock, error) { + span := tracer.StartSpan("endBlock") + defer span.End() + var endblock sdk.EndBlock if app.abciHandlers.EndBlocker != nil { @@ -772,7 +787,10 @@ func (app *BaseApp) endBlock(_ context.Context) (sdk.EndBlock, error) { // and execute successfully. An error is returned otherwise. // both txbytes and the decoded tx are passed to runTx to avoid the state machine encoding the tx and decoding the transaction twice // passing the decoded tx to runTX is optional, it will be decoded if the tx is nil -func (app *BaseApp) RunTx(mode sdk.ExecMode, txBytes []byte, tx sdk.Tx, txIndex int, txMultiStore storetypes.MultiStore, incarnationCache map[string]any) (gInfo sdk.GasInfo, result *sdk.Result, anteEvents []abci.Event, err error) { +func (app *BaseApp) RunTx(mode sdk.ExecMode, txBytes []byte, tx sdk.Tx, txIndex int, txMultiStore storetypes.MultiStore, incarnationCache map[string]any, tracer log.Tracer) (gInfo sdk.GasInfo, result *sdk.Result, anteEvents []abci.Event, err error) { + span := tracer.StartSpan("RunTx", "txBytes", txBytes, "txIndex", txIndex, "mode", mode) + defer span.End() + // NOTE: GasWanted should be returned by the AnteHandler. GasUsed is // determined by the GasMeter. We need access to the context to get the gas // meter, so we initialize upfront. @@ -861,7 +879,9 @@ func (app *BaseApp) RunTx(mode sdk.ExecMode, txBytes []byte, tx sdk.Tx, txIndex // performance benefits, but it'll be more difficult to get right. anteCtx, msCache = app.cacheTxContext(ctx, txBytes) anteCtx = anteCtx.WithEventManager(sdk.NewEventManager()) + anteSpan := tracer.StartSpan("anteHandler") newCtx, err := app.anteHandler(anteCtx, tx, mode == execModeSimulate) + anteSpan.End() if !newCtx.IsZero() { // At this point, newCtx.MultiStore() is a store branch, or something else @@ -910,6 +930,7 @@ func (app *BaseApp) RunTx(mode sdk.ExecMode, txBytes []byte, tx sdk.Tx, txIndex // in case message processing fails. At this point, the MultiStore // is a branch of a branch. runMsgCtx, msCache := app.cacheTxContext(ctx, txBytes) + runMsgCtx = runMsgCtx.WithLogger(tracer) // attach the tracer to the context as the logger // Attempt to execute all messages and only update state if all messages pass // and we're in DeliverTx. Note, runMsgs will never return a reference to a @@ -968,6 +989,14 @@ func (app *BaseApp) RunTx(mode sdk.ExecMode, txBytes []byte, tx sdk.Tx, txIndex // Handler does not exist for a given message route. Otherwise, a reference to a // Result is returned. The caller must not commit state if an error is returned. func (app *BaseApp) runMsgs(ctx sdk.Context, msgs []sdk.Msg, msgsV2 []protov2.Message, mode sdk.ExecMode) (*sdk.Result, error) { + // extract the tracer from the context + tracer, ok := ctx.Logger().(log.Tracer) + if !ok { + tracer = log.NewNopTracer() + } + span := tracer.StartSpan("runMsgs") + defer span.End() + events := sdk.EmptyEvents() var msgResponses []*codectypes.Any @@ -984,11 +1013,13 @@ func (app *BaseApp) runMsgs(ctx sdk.Context, msgs []sdk.Msg, msgsV2 []protov2.Me return nil, errorsmod.Wrapf(sdkerrors.ErrUnknownRequest, "no message handler found for %T", msg) } + msgSpan := span.StartSpan("msgHandler", "msgType", sdk.MsgTypeURL(msg), "msgIndex", i) // ADR 031 request type routing msgResult, err := handler(ctx, msg) if err != nil { return nil, errorsmod.Wrapf(err, "failed to execute message; message index: %d", i) } + msgSpan.End() // create message events msgEvents, err := createEvents(app.cdc, msgResult.GetEvents(), msg, msgsV2[i]) @@ -1077,7 +1108,7 @@ func (app *BaseApp) PrepareProposalVerifyTx(tx sdk.Tx) ([]byte, error) { return nil, err } - _, _, _, err = app.RunTx(execModePrepareProposal, bz, tx, -1, nil, nil) + _, _, _, err = app.RunTx(execModePrepareProposal, bz, tx, -1, nil, nil, app.tracer) if err != nil { return nil, err } @@ -1096,7 +1127,7 @@ func (app *BaseApp) ProcessProposalVerifyTx(txBz []byte) (sdk.Tx, error) { return nil, err } - _, _, _, err = app.RunTx(execModeProcessProposal, txBz, tx, -1, nil, nil) + _, _, _, err = app.RunTx(execModeProcessProposal, txBz, tx, -1, nil, nil, app.tracer) if err != nil { return nil, err } diff --git a/baseapp/genesis.go b/baseapp/genesis.go index 547a1322d8a7..cbc1adc5d709 100644 --- a/baseapp/genesis.go +++ b/baseapp/genesis.go @@ -13,7 +13,7 @@ var _ genesis.TxHandler = (*BaseApp)(nil) // ExecuteGenesisTx implements genesis.GenesisState from // cosmossdk.io/core/genesis to set initial state in genesis func (ba *BaseApp) ExecuteGenesisTx(tx []byte) error { - res := ba.deliverTx(tx, nil, -1, nil) + res := ba.deliverTx(tx, nil, -1, nil, ba.tracer) if res.Code != types.CodeTypeOK { return errors.New(res.Log) diff --git a/baseapp/test_helpers.go b/baseapp/test_helpers.go index 6144552490b2..560f96e61834 100644 --- a/baseapp/test_helpers.go +++ b/baseapp/test_helpers.go @@ -5,6 +5,7 @@ import ( errorsmod "cosmossdk.io/errors" + "cosmossdk.io/log" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) @@ -19,13 +20,13 @@ func (app *BaseApp) SimCheck(txEncoder sdk.TxEncoder, tx sdk.Tx) (sdk.GasInfo, * return sdk.GasInfo{}, nil, errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, "%s", err) } - gasInfo, result, _, err := app.RunTx(execModeCheck, bz, tx, -1, nil, nil) + gasInfo, result, _, err := app.RunTx(execModeCheck, bz, tx, -1, nil, nil, log.NewNopTracer()) return gasInfo, result, err } // Simulate executes a tx in simulate mode to get result and gas info. func (app *BaseApp) Simulate(txBytes []byte) (sdk.GasInfo, *sdk.Result, error) { - gasInfo, result, _, err := app.RunTx(execModeSimulate, txBytes, nil, -1, nil, nil) + gasInfo, result, _, err := app.RunTx(execModeSimulate, txBytes, nil, -1, nil, nil, log.NewNopTracer()) return gasInfo, result, err } @@ -36,7 +37,7 @@ func (app *BaseApp) SimDeliver(txEncoder sdk.TxEncoder, tx sdk.Tx) (sdk.GasInfo, return sdk.GasInfo{}, nil, errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, "%s", err) } - gasInfo, result, _, err := app.RunTx(execModeFinalize, bz, tx, -1, nil, nil) + gasInfo, result, _, err := app.RunTx(execModeFinalize, bz, tx, -1, nil, nil, log.NewNopTracer()) return gasInfo, result, err } @@ -47,7 +48,7 @@ func (app *BaseApp) SimTxFinalizeBlock(txEncoder sdk.TxEncoder, tx sdk.Tx) (sdk. return sdk.GasInfo{}, nil, errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, "%s", err) } - gasInfo, result, _, err := app.RunTx(execModeFinalize, bz, tx, -1, nil, nil) + gasInfo, result, _, err := app.RunTx(execModeFinalize, bz, tx, -1, nil, nil, log.NewNopTracer()) return gasInfo, result, err } diff --git a/baseapp/txnrunner/default.go b/baseapp/txnrunner/default.go index d92f8099d4dd..01b9921fc512 100644 --- a/baseapp/txnrunner/default.go +++ b/baseapp/txnrunner/default.go @@ -7,21 +7,24 @@ import ( storetypes "cosmossdk.io/store/types" + "cosmossdk.io/log" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) var _ sdk.TxRunner = DefaultRunner{} -func NewDefaultRunner(txDecoder sdk.TxDecoder) *DefaultRunner { +func NewDefaultRunner(txDecoder sdk.TxDecoder, tracer log.Tracer) *DefaultRunner { return &DefaultRunner{ txDecoder: txDecoder, + tracer: tracer, } } // DefaultRunner is the default TxnRunner implementation which executes the transactions in a block sequentially. type DefaultRunner struct { txDecoder sdk.TxDecoder + tracer log.Tracer } func (d DefaultRunner) Run(ctx context.Context, _ storetypes.MultiStore, txs [][]byte, deliverTx sdk.DeliverTxFunc) ([]*abci.ExecTxResult, error) { @@ -31,7 +34,7 @@ func (d DefaultRunner) Run(ctx context.Context, _ storetypes.MultiStore, txs [][ var response *abci.ExecTxResult if _, err := d.txDecoder(rawTx); err == nil { - response = deliverTx(rawTx, nil, i, nil) + response = deliverTx(rawTx, nil, i, nil, d.tracer) } else { // In the case where a transaction included in a block proposal is malformed, // we still want to return a default response to comet. This is because comet diff --git a/blockstm/executor.go b/blockstm/executor.go index 4014c4ead966..8ee790c486b9 100644 --- a/blockstm/executor.go +++ b/blockstm/executor.go @@ -3,6 +3,8 @@ package blockstm import ( "context" "fmt" + + "cosmossdk.io/log" ) // Executor fields are not mutated during execution. @@ -84,6 +86,6 @@ func (e *Executor) NeedsReexecution(version TxnVersion) (TxnVersion, TaskKind) { func (e *Executor) execute(txn TxnIndex) *MultiMVMemoryView { view := e.mvMemory.View(txn) - e.txExecutor(txn, view) + e.txExecutor(txn, view, log.TracerFromContext(e.ctx)) return view } diff --git a/blockstm/txnrunner.go b/blockstm/txnrunner.go index 9e50c60522ea..eb3461e93a8a 100644 --- a/blockstm/txnrunner.go +++ b/blockstm/txnrunner.go @@ -10,6 +10,7 @@ import ( "cosmossdk.io/collections" storetypes "cosmossdk.io/store/types" + "cosmossdk.io/log" sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -78,7 +79,7 @@ func (e STMRunner) Run(ctx context.Context, ms storetypes.MultiStore, txs [][]by stmMultiStoreWrapper{ms}, e.workers, estimates, - func(txn TxnIndex, ms MultiStore) { + func(txn TxnIndex, ms MultiStore, tracer log.Tracer) { var cache map[string]any // only one of the concurrent incarnations gets the cache if there are any, otherwise execute without @@ -92,7 +93,7 @@ func (e STMRunner) Run(ctx context.Context, ms storetypes.MultiStore, txs [][]by if memTxs != nil { memTx = memTxs[txn] } - results[txn] = deliverTx(memTx, msWrapper{ms}, int(txn), cache) + results[txn] = deliverTx(memTx, msWrapper{ms}, int(txn), cache, tracer) if v != nil { incarnationCache[txn].Store(v) diff --git a/blockstm/types.go b/blockstm/types.go index 873647b2f077..fa533dfdfefc 100644 --- a/blockstm/types.go +++ b/blockstm/types.go @@ -2,6 +2,8 @@ package blockstm import ( storetypes "cosmossdk.io/store/types" + + "cosmossdk.io/log" ) const ( @@ -59,7 +61,7 @@ type ReadSet struct { type MultiReadSet = map[int]*ReadSet // TxExecutor executes transactions on top of a multi-version memory view. -type TxExecutor func(TxnIndex, MultiStore) +type TxExecutor func(TxnIndex, MultiStore, log.Tracer) type MultiStore interface { GetStore(storetypes.StoreKey) storetypes.Store diff --git a/client/v2/go.mod b/client/v2/go.mod index eb6f5f9b2d1d..6c630e66cc06 100644 --- a/client/v2/go.mod +++ b/client/v2/go.mod @@ -153,7 +153,7 @@ require ( go.uber.org/zap v1.27.0 // indirect go.yaml.in/yaml/v2 v2.4.3 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect - golang.org/x/arch v0.21.0 // indirect + golang.org/x/arch v0.22.0 // indirect golang.org/x/crypto v0.43.0 // indirect golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6 // indirect golang.org/x/net v0.46.0 // indirect diff --git a/client/v2/go.sum b/client/v2/go.sum index d153aa4782de..2a11b57d4188 100644 --- a/client/v2/go.sum +++ b/client/v2/go.sum @@ -749,8 +749,8 @@ go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0= go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= -golang.org/x/arch v0.21.0 h1:iTC9o7+wP6cPWpDWkivCvQFGAHDQ59SrSxsLPcnkArw= -golang.org/x/arch v0.21.0/go.mod h1:dNHoOeKiyja7GTvF9NJS1l3Z2yntpQNzgrjh1cU103A= +golang.org/x/arch v0.22.0 h1:c/Zle32i5ttqRXjdLyyHZESLD/bB90DCU1g9l/0YBDI= +golang.org/x/arch v0.22.0/go.mod h1:dNHoOeKiyja7GTvF9NJS1l3Z2yntpQNzgrjh1cU103A= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= diff --git a/go.mod b/go.mod index b1ea3cd743be..8354446245f7 100644 --- a/go.mod +++ b/go.mod @@ -217,7 +217,7 @@ require ( go.uber.org/zap v1.27.0 // indirect go.yaml.in/yaml/v2 v2.4.3 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect - golang.org/x/arch v0.21.0 // indirect + golang.org/x/arch v0.22.0 // indirect golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6 // indirect golang.org/x/net v0.46.0 // indirect golang.org/x/oauth2 v0.31.0 // indirect @@ -236,6 +236,8 @@ require ( // Here are the short-lived replace from the Cosmos SDK // Replace here are pending PRs, or version to be tagged +replace cosmossdk.io/log => ./log + // Below are the long-lived replace of the Cosmos SDK replace ( // use cosmos fork of keyring diff --git a/go.sum b/go.sum index 913cb7b9274d..2ea9388c678b 100644 --- a/go.sum +++ b/go.sum @@ -32,8 +32,6 @@ cosmossdk.io/depinject v1.2.1 h1:eD6FxkIjlVaNZT+dXTQuwQTKZrFZ4UrfCq1RKgzyhMw= cosmossdk.io/depinject v1.2.1/go.mod h1:lqQEycz0H2JXqvOgVwTsjEdMI0plswI7p6KX+MVqFOM= cosmossdk.io/errors v1.0.2 h1:wcYiJz08HThbWxd/L4jObeLaLySopyyuUFB5w4AGpCo= cosmossdk.io/errors v1.0.2/go.mod h1:0rjgiHkftRYPj//3DrD6y8hcm40HcPv/dR4R/4efr0k= -cosmossdk.io/log v1.6.1 h1:YXNwAgbDwMEKwDlCdH8vPcoggma48MgZrTQXCfmMBeI= -cosmossdk.io/log v1.6.1/go.mod h1:gMwsWyyDBjpdG9u2avCFdysXqxq28WJapJvu+vF1y+E= cosmossdk.io/math v1.5.3 h1:WH6tu6Z3AUCeHbeOSHg2mt9rnoiUWVWaQ2t6Gkll96U= cosmossdk.io/math v1.5.3/go.mod h1:uqcZv7vexnhMFJF+6zh9EWdm/+Ylyln34IvPnBauPCQ= cosmossdk.io/schema v1.1.0 h1:mmpuz3dzouCoyjjcMcA/xHBEmMChN+EHh8EHxHRHhzE= @@ -876,8 +874,8 @@ go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= -golang.org/x/arch v0.21.0 h1:iTC9o7+wP6cPWpDWkivCvQFGAHDQ59SrSxsLPcnkArw= -golang.org/x/arch v0.21.0/go.mod h1:dNHoOeKiyja7GTvF9NJS1l3Z2yntpQNzgrjh1cU103A= +golang.org/x/arch v0.22.0 h1:c/Zle32i5ttqRXjdLyyHZESLD/bB90DCU1g9l/0YBDI= +golang.org/x/arch v0.22.0/go.mod h1:dNHoOeKiyja7GTvF9NJS1l3Z2yntpQNzgrjh1cU103A= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= diff --git a/simapp/go.mod b/simapp/go.mod index 0040c7a5ad21..ec751f171381 100644 --- a/simapp/go.mod +++ b/simapp/go.mod @@ -210,7 +210,7 @@ require ( go.uber.org/zap v1.27.0 // indirect go.yaml.in/yaml/v2 v2.4.3 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect - golang.org/x/arch v0.21.0 // indirect + golang.org/x/arch v0.22.0 // indirect golang.org/x/crypto v0.43.0 // indirect golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6 // indirect golang.org/x/net v0.46.0 // indirect @@ -233,6 +233,10 @@ require ( sigs.k8s.io/yaml v1.6.0 // indirect ) +replace ( + cosmossdk.io/log => ../log +) + // Below are the long-lived replace of the SimApp replace ( // use cosmos fork of keyring diff --git a/simapp/go.sum b/simapp/go.sum index 84ce76cb5ec8..5d1407fd10c2 100644 --- a/simapp/go.sum +++ b/simapp/go.sum @@ -884,8 +884,8 @@ go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= -golang.org/x/arch v0.21.0 h1:iTC9o7+wP6cPWpDWkivCvQFGAHDQ59SrSxsLPcnkArw= -golang.org/x/arch v0.21.0/go.mod h1:dNHoOeKiyja7GTvF9NJS1l3Z2yntpQNzgrjh1cU103A= +golang.org/x/arch v0.22.0 h1:c/Zle32i5ttqRXjdLyyHZESLD/bB90DCU1g9l/0YBDI= +golang.org/x/arch v0.22.0/go.mod h1:dNHoOeKiyja7GTvF9NJS1l3Z2yntpQNzgrjh1cU103A= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= diff --git a/systemtests/go.mod b/systemtests/go.mod index befabb854c70..f8ed7b71fed4 100644 --- a/systemtests/go.mod +++ b/systemtests/go.mod @@ -152,7 +152,7 @@ require ( go.uber.org/zap v1.27.0 // indirect go.yaml.in/yaml/v2 v2.4.3 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect - golang.org/x/arch v0.21.0 // indirect + golang.org/x/arch v0.22.0 // indirect golang.org/x/crypto v0.43.0 // indirect golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6 // indirect golang.org/x/net v0.46.0 // indirect diff --git a/systemtests/go.sum b/systemtests/go.sum index ff93cb36b90a..4cfa4ee4d84e 100644 --- a/systemtests/go.sum +++ b/systemtests/go.sum @@ -758,8 +758,8 @@ go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0= go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= -golang.org/x/arch v0.21.0 h1:iTC9o7+wP6cPWpDWkivCvQFGAHDQ59SrSxsLPcnkArw= -golang.org/x/arch v0.21.0/go.mod h1:dNHoOeKiyja7GTvF9NJS1l3Z2yntpQNzgrjh1cU103A= +golang.org/x/arch v0.22.0 h1:c/Zle32i5ttqRXjdLyyHZESLD/bB90DCU1g9l/0YBDI= +golang.org/x/arch v0.22.0/go.mod h1:dNHoOeKiyja7GTvF9NJS1l3Z2yntpQNzgrjh1cU103A= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= diff --git a/tests/go.mod b/tests/go.mod index 6837685e3fcd..8c13fa6ff2f4 100644 --- a/tests/go.mod +++ b/tests/go.mod @@ -210,7 +210,7 @@ require ( go.uber.org/zap v1.27.0 // indirect go.yaml.in/yaml/v2 v2.4.3 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect - golang.org/x/arch v0.21.0 // indirect + golang.org/x/arch v0.22.0 // indirect golang.org/x/crypto v0.43.0 // indirect golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6 // indirect golang.org/x/net v0.46.0 // indirect diff --git a/tests/go.sum b/tests/go.sum index 3623a6f9fc87..416fb05e6ede 100644 --- a/tests/go.sum +++ b/tests/go.sum @@ -883,8 +883,8 @@ go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= -golang.org/x/arch v0.21.0 h1:iTC9o7+wP6cPWpDWkivCvQFGAHDQ59SrSxsLPcnkArw= -golang.org/x/arch v0.21.0/go.mod h1:dNHoOeKiyja7GTvF9NJS1l3Z2yntpQNzgrjh1cU103A= +golang.org/x/arch v0.22.0 h1:c/Zle32i5ttqRXjdLyyHZESLD/bB90DCU1g9l/0YBDI= +golang.org/x/arch v0.22.0/go.mod h1:dNHoOeKiyja7GTvF9NJS1l3Z2yntpQNzgrjh1cU103A= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= diff --git a/tests/systemtests/go.mod b/tests/systemtests/go.mod index fb79d5e7eacb..d91bf94d9312 100644 --- a/tests/systemtests/go.mod +++ b/tests/systemtests/go.mod @@ -158,7 +158,7 @@ require ( go.uber.org/zap v1.27.0 // indirect go.yaml.in/yaml/v2 v2.4.3 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect - golang.org/x/arch v0.21.0 // indirect + golang.org/x/arch v0.22.0 // indirect golang.org/x/crypto v0.43.0 // indirect golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6 // indirect golang.org/x/net v0.46.0 // indirect diff --git a/tests/systemtests/go.sum b/tests/systemtests/go.sum index 23efa26c0731..90428e129f04 100644 --- a/tests/systemtests/go.sum +++ b/tests/systemtests/go.sum @@ -756,8 +756,8 @@ go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0= go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= -golang.org/x/arch v0.21.0 h1:iTC9o7+wP6cPWpDWkivCvQFGAHDQ59SrSxsLPcnkArw= -golang.org/x/arch v0.21.0/go.mod h1:dNHoOeKiyja7GTvF9NJS1l3Z2yntpQNzgrjh1cU103A= +golang.org/x/arch v0.22.0 h1:c/Zle32i5ttqRXjdLyyHZESLD/bB90DCU1g9l/0YBDI= +golang.org/x/arch v0.22.0/go.mod h1:dNHoOeKiyja7GTvF9NJS1l3Z2yntpQNzgrjh1cU103A= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= diff --git a/types/abci.go b/types/abci.go index 06ca95d7b620..d80439ed8ac0 100644 --- a/types/abci.go +++ b/types/abci.go @@ -6,6 +6,8 @@ import ( abci "github.com/cometbft/cometbft/abci/types" storetypes "cosmossdk.io/store/types" + + "cosmossdk.io/log" ) // ABCIHandlers aggregates all ABCI handlers needed for an application. @@ -99,7 +101,7 @@ func (r ResponsePreBlock) IsConsensusParamsChanged() bool { type RunTx = func(txBytes []byte, tx Tx) (gInfo GasInfo, result *Result, anteEvents []abci.Event, err error) // DeliverTxFunc is the function called for each transaction in order to produce a single ExecTxResult -type DeliverTxFunc func(tx []byte, ms storetypes.MultiStore, txIndex int, incarnationCache map[string]any) *abci.ExecTxResult +type DeliverTxFunc func(tx []byte, ms storetypes.MultiStore, txIndex int, incarnationCache map[string]any, tracer log.Tracer) *abci.ExecTxResult // TxRunner defines an interface for types which can be used to execute the DeliverTxFunc. // It should return an array of *abci.ExecTxResult corresponding to the result of executing each transaction From d5f5ea4a8bfc86f01333337b1f5c5f52091263e7 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Wed, 29 Oct 2025 22:37:47 -0400 Subject: [PATCH 04/52] latest WIP --- simapp/sim_test.go | 2 +- telemetry/file_sink.go | 157 +++++++++++++++++++++++ telemetry/file_sink_test.go | 177 ++++++++++++++++++++++++++ telemetry/metrics.go | 185 ++++++++++++++++++++++++---- telemetry/metrics_span.go | 135 ++++++++++++++++++++ telemetry/{otel.go => otel_span.go} | 0 6 files changed, 628 insertions(+), 28 deletions(-) create mode 100644 telemetry/file_sink.go create mode 100644 telemetry/file_sink_test.go create mode 100644 telemetry/metrics_span.go rename telemetry/{otel.go => otel_span.go} (100%) diff --git a/simapp/sim_test.go b/simapp/sim_test.go index c76a12735d23..55ead7b3ce7f 100644 --- a/simapp/sim_test.go +++ b/simapp/sim_test.go @@ -157,7 +157,7 @@ func IsEmptyValidatorSetErr(err error) bool { } func TestAppStateDeterminism(t *testing.T) { - const numTimesToRunPerSeed = 3 + const numTimesToRunPerSeed = 1 var seeds []int64 if s := simcli.NewConfigFromFlags().Seed; s != simcli.DefaultSeedValue { // We will be overriding the random seed and just run a single simulation on the provided seed value diff --git a/telemetry/file_sink.go b/telemetry/file_sink.go new file mode 100644 index 000000000000..4c653558fd6d --- /dev/null +++ b/telemetry/file_sink.go @@ -0,0 +1,157 @@ +package telemetry + +import ( + "bufio" + "encoding/json" + "fmt" + "io" + "sync" + "time" + + "github.com/hashicorp/go-metrics" +) + +// FileSink writes metrics to a file as JSON lines (JSONL format). +// Each metric emission creates a single JSON line with timestamp, type, key, value, and labels. +// +// This sink is particularly useful for: +// - Test environments where metrics need to be inspected after execution +// - CI/CD pipelines where metrics should be logged for analysis +// - Debugging and local development +// +// The sink is thread-safe and buffers writes for performance. +// Call Close() to flush buffered data and close the underlying writer. +type FileSink struct { + writer *bufio.Writer + closer io.Closer + mu sync.Mutex + closed bool +} + +// metricLine represents a single metric emission in JSON format. +type metricLine struct { + Timestamp time.Time `json:"timestamp"` + Type string `json:"type"` + Key []string `json:"key"` + Value float32 `json:"value"` + Labels []metrics.Label `json:"labels,omitempty"` +} + +// NewFileSink creates a new FileSink that writes to the given io.WriteCloser. +// The sink buffers writes for performance. Call Close() to flush and close. +func NewFileSink(w io.WriteCloser) *FileSink { + return &FileSink{ + writer: bufio.NewWriter(w), + closer: w, + closed: false, + } +} + +// SetGauge implements metrics.MetricSink. +func (f *FileSink) SetGauge(key []string, val float32) { + f.SetGaugeWithLabels(key, val, nil) +} + +// SetGaugeWithLabels implements metrics.MetricSink. +func (f *FileSink) SetGaugeWithLabels(key []string, val float32, labels []metrics.Label) { + f.writeLine(metricLine{ + Timestamp: time.Now().UTC(), + Type: "gauge", + Key: key, + Value: val, + Labels: labels, + }) +} + +// EmitKey implements metrics.MetricSink. +func (f *FileSink) EmitKey(key []string, val float32) { + f.writeLine(metricLine{ + Timestamp: time.Now().UTC(), + Type: "kv", + Key: key, + Value: val, + }) +} + +// IncrCounter implements metrics.MetricSink. +func (f *FileSink) IncrCounter(key []string, val float32) { + f.IncrCounterWithLabels(key, val, nil) +} + +// IncrCounterWithLabels implements metrics.MetricSink. +func (f *FileSink) IncrCounterWithLabels(key []string, val float32, labels []metrics.Label) { + f.writeLine(metricLine{ + Timestamp: time.Now().UTC(), + Type: "counter", + Key: key, + Value: val, + Labels: labels, + }) +} + +// AddSample implements metrics.MetricSink. +func (f *FileSink) AddSample(key []string, val float32) { + f.AddSampleWithLabels(key, val, nil) +} + +// AddSampleWithLabels implements metrics.MetricSink. +func (f *FileSink) AddSampleWithLabels(key []string, val float32, labels []metrics.Label) { + f.writeLine(metricLine{ + Timestamp: time.Now().UTC(), + Type: "sample", + Key: key, + Value: val, + Labels: labels, + }) +} + +// writeLine writes a metric line to the file as JSON. +func (f *FileSink) writeLine(line metricLine) { + f.mu.Lock() + defer f.mu.Unlock() + + if f.closed { + return + } + + data, err := json.Marshal(line) + if err != nil { + // If JSON marshaling fails, write error to stderr but don't crash + fmt.Fprintf(io.Discard, "failed to marshal metric: %v\n", err) + return + } + + // Write JSON line with newline + if _, err := f.writer.Write(data); err != nil { + return + } + if err := f.writer.WriteByte('\n'); err != nil { + return + } +} + +// Close flushes any buffered data and closes the underlying writer. +// It is safe to call Close multiple times. +func (f *FileSink) Close() error { + f.mu.Lock() + defer f.mu.Unlock() + + if f.closed { + return nil + } + + f.closed = true + + // Flush buffered data + if err := f.writer.Flush(); err != nil { + f.closer.Close() // Try to close anyway + return fmt.Errorf("failed to flush metrics file: %w", err) + } + + // Close the underlying file + if err := f.closer.Close(); err != nil { + return fmt.Errorf("failed to close metrics file: %w", err) + } + + return nil +} diff --git a/telemetry/file_sink_test.go b/telemetry/file_sink_test.go new file mode 100644 index 000000000000..431bdfdbfd48 --- /dev/null +++ b/telemetry/file_sink_test.go @@ -0,0 +1,177 @@ +package telemetry + +import ( + "bufio" + "encoding/json" + "os" + "path/filepath" + "sync" + "testing" + + "github.com/hashicorp/go-metrics" + "github.com/stretchr/testify/require" +) + +func TestFileSink_BasicOperations(t *testing.T) { + tmpfile := filepath.Join(t.TempDir(), "metrics.jsonl") + file, err := os.Create(tmpfile) + require.NoError(t, err) + + sink := NewFileSink(file) + + // Emit various metric types + sink.IncrCounter([]string{"test", "counter"}, 1.5) + sink.SetGauge([]string{"test", "gauge"}, 42.0) + sink.AddSample([]string{"test", "sample"}, 100.0) + sink.EmitKey([]string{"test", "kv"}, 3.14) + + // Emit metrics with labels + labels := []metrics.Label{ + {Name: "module", Value: "bank"}, + {Name: "operation", Value: "send"}, + } + sink.IncrCounterWithLabels([]string{"test", "counter_labeled"}, 2.0, labels) + sink.SetGaugeWithLabels([]string{"test", "gauge_labeled"}, 99.0, labels) + sink.AddSampleWithLabels([]string{"test", "sample_labeled"}, 50.0, labels) + + // Close to flush + require.NoError(t, sink.Close()) + + // Read and verify file contents + data, err := os.ReadFile(tmpfile) + require.NoError(t, err) + + file2, err := os.Open(tmpfile) + require.NoError(t, err) + defer file2.Close() + + scanner := bufio.NewScanner(file2) + lineCount := 0 + for scanner.Scan() { + lineCount++ + var metric metricLine + err := json.Unmarshal(scanner.Bytes(), &metric) + require.NoError(t, err, "line %d should be valid JSON", lineCount) + require.NotZero(t, metric.Timestamp, "line %d should have timestamp", lineCount) + require.NotEmpty(t, metric.Type, "line %d should have type", lineCount) + require.NotEmpty(t, metric.Key, "line %d should have key", lineCount) + } + require.NoError(t, scanner.Err()) + require.Equal(t, 7, lineCount, "should have 7 metrics") + + // Verify specific metric formats + require.Contains(t, string(data), `"type":"counter"`) + require.Contains(t, string(data), `"type":"gauge"`) + require.Contains(t, string(data), `"type":"sample"`) + require.Contains(t, string(data), `"type":"kv"`) + require.Contains(t, string(data), `"key":["test","counter"]`) + require.Contains(t, string(data), `"value":1.5`) + require.Contains(t, string(data), `"labels":[{"Name":"module","Value":"bank"}`) +} + +func TestFileSink_ConcurrentWrites(t *testing.T) { + tmpfile := filepath.Join(t.TempDir(), "metrics_concurrent.jsonl") + file, err := os.Create(tmpfile) + require.NoError(t, err) + + sink := NewFileSink(file) + + // Spawn multiple goroutines writing metrics concurrently + const numGoroutines = 10 + const metricsPerGoroutine = 100 + + var wg sync.WaitGroup + wg.Add(numGoroutines) + + for i := 0; i < numGoroutines; i++ { + go func(id int) { + defer wg.Done() + for j := 0; j < metricsPerGoroutine; j++ { + sink.IncrCounter([]string{"concurrent", "test"}, float32(id)) + } + }(i) + } + + wg.Wait() + require.NoError(t, sink.Close()) + + // Count lines in file + file, err = os.Open(tmpfile) + require.NoError(t, err) + defer file.Close() + + scanner := bufio.NewScanner(file) + lineCount := 0 + for scanner.Scan() { + lineCount++ + } + require.NoError(t, scanner.Err()) + require.Equal(t, numGoroutines*metricsPerGoroutine, lineCount, "all metrics should be written") +} + +func TestFileSink_CloseIdempotent(t *testing.T) { + tmpfile := filepath.Join(t.TempDir(), "metrics_close.jsonl") + file, err := os.Create(tmpfile) + require.NoError(t, err) + + sink := NewFileSink(file) + sink.IncrCounter([]string{"test"}, 1.0) + + // Close multiple times should not error + require.NoError(t, sink.Close()) + require.NoError(t, sink.Close()) + require.NoError(t, sink.Close()) +} + +func TestFileSink_WritesAfterClose(t *testing.T) { + tmpfile := filepath.Join(t.TempDir(), "metrics_after_close.jsonl") + file, err := os.Create(tmpfile) + require.NoError(t, err) + + sink := NewFileSink(file) + sink.IncrCounter([]string{"before"}, 1.0) + require.NoError(t, sink.Close()) + + // Writes after close should be silently ignored (no panic) + sink.IncrCounter([]string{"after"}, 1.0) + + // File should only contain one metric + data, err := os.ReadFile(tmpfile) + require.NoError(t, err) + + scanner := bufio.NewScanner(bufio.NewReader(os.Open(tmpfile))) + lineCount := 0 + for scanner.Scan() { + lineCount++ + } + require.Equal(t, 1, lineCount, "only metric before close should be written") + require.Contains(t, string(data), `"key":["before"]`) + require.NotContains(t, string(data), `"key":["after"]`) +} + +func TestFileSink_JSONFormat(t *testing.T) { + tmpfile := filepath.Join(t.TempDir(), "metrics_json.jsonl") + file, err := os.Create(tmpfile) + require.NoError(t, err) + + sink := NewFileSink(file) + labels := []metrics.Label{{Name: "env", Value: "test"}} + sink.IncrCounterWithLabels([]string{"api", "requests"}, 5.0, labels) + require.NoError(t, sink.Close()) + + // Parse JSON and verify structure + data, err := os.ReadFile(tmpfile) + require.NoError(t, err) + + var metric metricLine + err = json.Unmarshal(data[:len(data)-1], &metric) // Remove trailing newline + require.NoError(t, err) + + require.Equal(t, "counter", metric.Type) + require.Equal(t, []string{"api", "requests"}, metric.Key) + require.Equal(t, float32(5.0), metric.Value) + require.Len(t, metric.Labels, 1) + require.Equal(t, "env", metric.Labels[0].Name) + require.Equal(t, "test", metric.Labels[0].Value) + require.NotZero(t, metric.Timestamp) +} diff --git a/telemetry/metrics.go b/telemetry/metrics.go index 67ace50c53ec..cae3dd2d3701 100644 --- a/telemetry/metrics.go +++ b/telemetry/metrics.go @@ -1,3 +1,41 @@ +// Package telemetry provides observability through metrics and distributed tracing. +// +// # Metrics Collection +// +// Metrics collection uses hashicorp/go-metrics with support for multiple sink backends: +// - mem: In-memory aggregation with SIGUSR1 signal dumping to stderr +// - prometheus: Prometheus registry for pull-based scraping via /metrics endpoint +// - statsd: Push-based metrics to StatsD daemon +// - dogstatsd: Push-based metrics to Datadog StatsD daemon with tagging +// - file: Write metrics to a file as JSON lines (useful for tests and debugging) +// +// Multiple sinks can be active simultaneously via FanoutSink (e.g., both in-memory and Prometheus). +// +// # Distributed Tracing +// +// Tracing support is provided via OtelSpan, which wraps OpenTelemetry for hierarchical span tracking. +// See otel.go for the log.Tracer implementation. +// +// # Usage +// +// Initialize metrics at application startup: +// +// m, err := telemetry.New(telemetry.Config{ +// Enabled: true, +// ServiceName: "cosmos-app", +// PrometheusRetentionTime: 60, +// GlobalLabels: [][]string{{"chain_id", "cosmoshub-1"}}, +// }) +// if err != nil { +// log.Fatal(err) +// } +// defer m.Close() +// +// Emit metrics from anywhere in the application: +// +// telemetry.IncrCounter(1, "tx", "processed") +// telemetry.SetGauge(1024, "mempool", "size") +// defer telemetry.MeasureSince(telemetry.Now(), "block", "execution") package telemetry import ( @@ -5,7 +43,9 @@ import ( "encoding/json" "errors" "fmt" + "io" "net/http" + "os" "time" "github.com/hashicorp/go-metrics" @@ -43,6 +83,7 @@ const ( MetricSinkInMem = "mem" MetricSinkStatsd = "statsd" MetricSinkDogsStatsd = "dogstatsd" + MetricSinkFile = "file" ) // DisplayableSink is an interface that defines a method for displaying metrics. @@ -52,63 +93,121 @@ type DisplayableSink interface { // Config defines the configuration options for application telemetry. type Config struct { - // Prefixed with keys to separate services + // ServiceName is the identifier for this service, used as a prefix for all metric keys. + // Example: "cosmos-app" → metrics like "cosmos-app.tx.count" ServiceName string `mapstructure:"service-name"` - // Enabled enables the application telemetry functionality. When enabled, - // an in-memory sink is also enabled by default. Operators may also enabled - // other sinks such as Prometheus. + // Enabled controls whether telemetry is active. When false, all telemetry operations + // become no-ops with zero overhead. When true, metrics collection is activated. Enabled bool `mapstructure:"enabled"` - // Enable prefixing gauge values with hostname + // EnableHostname prefixes gauge values with the hostname. + // Useful in multi-node deployments to identify which node emitted a metric. EnableHostname bool `mapstructure:"enable-hostname"` - // Enable adding hostname to labels + // EnableHostnameLabel adds a "hostname" label to all metrics. + // Alternative to EnableHostname that works better with label-based systems like Prometheus. EnableHostnameLabel bool `mapstructure:"enable-hostname-label"` - // Enable adding service to labels + // EnableServiceLabel adds a "service" label with the ServiceName to all metrics. + // Useful when aggregating metrics from multiple services in one monitoring system. EnableServiceLabel bool `mapstructure:"enable-service-label"` // PrometheusRetentionTime, when positive, enables a Prometheus metrics sink. - // It defines the retention duration in seconds. + // Defines how long (in seconds) metrics are retained in memory for scraping. + // The Prometheus sink is added to a FanoutSink alongside the primary sink. + // Recommended value: 60 seconds or more. PrometheusRetentionTime int64 `mapstructure:"prometheus-retention-time"` - // GlobalLabels defines a global set of name/value label tuples applied to all - // metrics emitted using the wrapper functions defined in telemetry package. + // GlobalLabels defines a set of key-value label pairs applied to ALL metrics. + // These labels are automatically attached to every metric emission. + // Useful for static identifiers like chain ID, environment, region, etc. // - // Example: - // [["chain_id", "cosmoshub-1"]] + // Example: [][]string{{"chain_id", "cosmoshub-1"}, {"env", "production"}} + // + // Note: The outer array contains label pairs, each inner array has exactly 2 elements [key, value]. GlobalLabels [][]string `mapstructure:"global-labels"` - // MetricsSink defines the type of metrics backend to use. + // MetricsSink defines the metrics backend type. Supported values: + // - "mem" (default): In-memory sink with SIGUSR1 dump-to-stderr capability + // - "prometheus": Prometheus exposition format (use with PrometheusRetentionTime) + // - "statsd": StatsD protocol (push-based, requires StatsdAddr) + // - "dogstatsd": Datadog-enhanced StatsD with tags (requires StatsdAddr, DatadogHostname) + // - "file": JSON lines written to a file (requires MetricsFile) + // + // Multiple sinks can be active via FanoutSink (e.g., mem + prometheus). MetricsSink string `mapstructure:"metrics-sink" default:"mem"` - // StatsdAddr defines the address of a statsd server to send metrics to. - // Only utilized if MetricsSink is set to "statsd" or "dogstatsd". + // StatsdAddr is the address of the StatsD or DogStatsD server (host:port). + // Only used when MetricsSink is "statsd" or "dogstatsd". + // Example: "localhost:8125" StatsdAddr string `mapstructure:"statsd-addr"` - // DatadogHostname defines the hostname to use when emitting metrics to - // Datadog. Only utilized if MetricsSink is set to "dogstatsd". + // DatadogHostname is the hostname to report when using DogStatsD. + // Only used when MetricsSink is "dogstatsd". + // If empty, the system hostname is used. DatadogHostname string `mapstructure:"datadog-hostname"` + + // MetricsFile is the file path to write metrics to in JSONL format. + // Only used when MetricsSink is "file". + // Each metric emission creates a JSON line: {"timestamp":"...","type":"counter","key":[...],"value":1.0} + // Example: "/tmp/metrics.jsonl" or "./metrics.jsonl" + MetricsFile string `mapstructure:"metrics-file"` + + TraceSink string `mapstructure:"trace-sink"` } -// Metrics defines a wrapper around application telemetry functionality. It allows -// metrics to be gathered at any point in time. When creating a Metrics object, -// internally, a global metrics is registered with a set of sinks as configured -// by the operator. In addition to the sinks, when a process gets a SIGUSR1, a -// dump of formatted recent metrics will be sent to STDERR. +// Metrics provides access to the application's metrics collection system. +// It wraps the go-metrics global registry and configured sinks. +// +// When using the in-memory sink, sending SIGUSR1 to the process (kill -USR1 ) +// will dump current metrics to stderr for debugging. +// +// The Metrics object maintains references to configured sinks and provides +// a Gather() method for pull-based metric retrieval (useful for testing and monitoring). +// +// When using the file sink, call Close() to flush buffered data and close the file. +// +// Note: go-metrics uses a singleton global registry. Only one Metrics instance +// should be created per process. type Metrics struct { sink metrics.MetricSink prometheusEnabled bool + closer io.Closer // non-nil when using file sink } -// GatherResponse is the response type of registered metrics +// GatherResponse contains collected metrics in the requested format. +// The Metrics field holds the serialized metric data, and ContentType +// indicates how it's encoded ("application/json" or prometheus text format). type GatherResponse struct { Metrics []byte ContentType string } -// New creates a new instance of Metrics +// New creates and initializes the metrics system with the given configuration. +// +// Returns nil if telemetry is disabled (cfg.Enabled == false), which allows +// callers to safely ignore the Metrics object. +// +// The function: +// - Initializes the go-metrics global registry +// - Configures the specified sink(s) (mem, prometheus, statsd, dogstatsd, file) +// - Sets up global labels to be applied to all metrics +// - Enables SIGUSR1 signal handling for in-memory sink dumps +// - Creates a FanoutSink if multiple sinks are needed (e.g., mem + prometheus) +// +// Example: +// +// m, err := telemetry.New(telemetry.Config{ +// Enabled: true, +// ServiceName: "cosmos-app", +// MetricsSink: telemetry.MetricSinkInMem, +// PrometheusRetentionTime: 60, +// }) +// if err != nil { +// return err +// } +// defer m.Close() func New(cfg Config) (_ *Metrics, rerr error) { globalTelemetryEnabled = cfg.Enabled if !cfg.Enabled { @@ -128,14 +227,26 @@ func New(cfg Config) (_ *Metrics, rerr error) { metricsConf.EnableHostnameLabel = cfg.EnableHostnameLabel var ( - sink metrics.MetricSink - err error + sink metrics.MetricSink + closer io.Closer + err error ) switch cfg.MetricsSink { case MetricSinkStatsd: sink, err = metrics.NewStatsdSink(cfg.StatsdAddr) case MetricSinkDogsStatsd: sink, err = datadog.NewDogStatsdSink(cfg.StatsdAddr, cfg.DatadogHostname) + case MetricSinkFile: + if cfg.MetricsFile == "" { + return nil, errors.New("metrics-file must be set when metrics-sink is 'file'") + } + file, err := os.OpenFile(cfg.MetricsFile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644) + if err != nil { + return nil, fmt.Errorf("failed to open metrics file: %w", err) + } + fileSink := NewFileSink(file) + sink = fileSink + closer = fileSink default: memSink := metrics.NewInmemSink(10*time.Second, time.Minute) sink = memSink @@ -151,7 +262,7 @@ func New(cfg Config) (_ *Metrics, rerr error) { return nil, err } - m := &Metrics{sink: sink} + m := &Metrics{sink: sink, closer: closer} fanout := metrics.FanoutSink{sink} if cfg.PrometheusRetentionTime > 0 { @@ -239,3 +350,23 @@ func (m *Metrics) gatherGeneric() (GatherResponse, error) { return GatherResponse{ContentType: "application/json", Metrics: content}, nil } + +// Close flushes any buffered data and closes resources associated with the metrics system. +// This is primarily needed when using the file sink to ensure all data is written to disk. +// It is safe to call Close() multiple times, and safe to call on a nil Metrics object. +// +// For other sink types (mem, statsd, prometheus), Close() is a no-op. +// +// Example: +// +// m, err := telemetry.New(cfg) +// if err != nil { +// return err +// } +// defer m.Close() +func (m *Metrics) Close() error { + if m == nil || m.closer == nil { + return nil + } + return m.closer.Close() +} diff --git a/telemetry/metrics_span.go b/telemetry/metrics_span.go new file mode 100644 index 000000000000..859d004bff9a --- /dev/null +++ b/telemetry/metrics_span.go @@ -0,0 +1,135 @@ +package telemetry + +import ( + "context" + "time" + + "github.com/hashicorp/go-metrics" + + "cosmossdk.io/log" +) + +// MetricsSpan is a log.Span implementation that emits timing and count metrics +// to go-metrics when the span ends. +// +// Unlike distributed tracing spans, MetricsSpan: +// - Does not support logging (Info/Warn/Error/Debug are no-ops) +// - Ignores span attributes (kvs parameters) +// - Emits aggregated metrics rather than individual trace events +// +// When End() is called, two metrics are emitted: +// - A timer metric with ".time" suffix (e.g., "query.get.time") +// - A counter metric with ".count" suffix (e.g., "query.get.count") +// +// Root path and labels are preserved across all spans created from this tracer, +// ensuring consistent metric namespacing and labeling throughout the span hierarchy. +type MetricsSpan struct { + metrics *metrics.Metrics + start time.Time + path []string + rootPath []string // Base path set at tracer creation, preserved across all spans + rootLabels []metrics.Label // Labels applied to all metrics emitted by this tracer +} + +// NewMetricsTracer creates a new MetricsSpan that acts as a root tracer. +// The rootPath defines the base metric name. If empty, metrics start from the root. +// The rootLabels are applied to all metrics emitted by this tracer and its children. +// +// Example: +// +// labels := []metrics.Label{{Name: "module", Value: "staking"}} +// tracer := NewMetricsTracer(metrics, []string{"app", "tx"}, labels) +// span := tracer.StartSpan("validate") +// defer span.End() +// // Emits: "app.tx.validate.time" and "app.tx.validate.count" with module=staking label +func NewMetricsTracer(m *metrics.Metrics, rootPath []string, rootLabels []metrics.Label) *MetricsSpan { + return &MetricsSpan{ + metrics: m, + path: rootPath, + rootPath: rootPath, + rootLabels: rootLabels, + start: time.Now(), + } +} + +// Logger methods are no-ops - MetricsSpan does not support logging. +func (m *MetricsSpan) Info(msg string, keyVals ...any) {} +func (m *MetricsSpan) Warn(msg string, keyVals ...any) {} +func (m *MetricsSpan) Error(msg string, keyVals ...any) {} +func (m *MetricsSpan) Debug(msg string, keyVals ...any) {} +func (m *MetricsSpan) With(keyVals ...any) log.Logger { return m } +func (m *MetricsSpan) Impl() any { return nil } + +// StartSpan creates a child span by appending the operation name to the current path. +// Root path and labels are preserved in the child span. +// The kvs parameters are ignored (metrics don't support dynamic attributes). +func (m *MetricsSpan) StartSpan(operation string, kvs ...any) log.Span { + path := make([]string, len(m.path)+1) + copy(path, m.path) + path[len(path)-1] = operation + return &MetricsSpan{ + metrics: m.metrics, + path: path, + rootPath: m.rootPath, + rootLabels: m.rootLabels, + start: time.Now(), + } +} + +// StartSpanContext creates a child span and returns the context unchanged. +// The span is not stored in the context. +func (m *MetricsSpan) StartSpanContext(ctx context.Context, operation string, kvs ...any) (context.Context, log.Span) { + return ctx, m.StartSpan(operation, kvs...) +} + +// StartRootSpan creates a new root span by combining the tracer's root path with the operation. +// Unlike StartSpan, this does not extend the current span's path - it starts fresh from the root path. +// Root labels are preserved in the new span. +// +// Example: +// +// tracer := NewMetricsTracer(metrics, []string{"app"}, nil) +// _, span := tracer.StartRootSpan(ctx, "process") +// defer span.End() +// // Emits: "app.process.time" and "app.process.count" +func (m *MetricsSpan) StartRootSpan(ctx context.Context, operation string, kvs ...any) (context.Context, log.Span) { + // Preserve root path and add operation to it + rootPath := append([]string{}, m.rootPath...) + rootPath = append(rootPath, operation) + + return ctx, &MetricsSpan{ + metrics: m.metrics, + path: rootPath, + rootPath: m.rootPath, + rootLabels: m.rootLabels, + start: time.Now(), + } +} + +// SetAttrs is a no-op - metrics don't support dynamic attributes. +func (m *MetricsSpan) SetAttrs(kvs ...any) {} + +// SetErr is a no-op but returns the error unchanged for convenience. +func (m *MetricsSpan) SetErr(err error, kvs ...any) error { return err } + +// End emits timing and count metrics with ".time" and ".count" suffixes. +// +// For a span with path ["query", "get"], this emits: +// - Timer: "query.get.time" with duration since start +// - Counter: "query.get.count" incremented by 1 +func (m *MetricsSpan) End() { + // Create paths with suffixes to avoid metric type conflicts + timePath := make([]string, len(m.path)+1) + copy(timePath, m.path) + timePath[len(timePath)-1] = "time" + + countPath := make([]string, len(m.path)+1) + copy(countPath, m.path) + countPath[len(countPath)-1] = "count" + + m.metrics.MeasureSince(timePath, m.start) + m.metrics.IncrCounter(countPath, 1) +} + +var _ log.Span = (*MetricsSpan)(nil) +var _ log.Tracer = (*MetricsSpan)(nil) diff --git a/telemetry/otel.go b/telemetry/otel_span.go similarity index 100% rename from telemetry/otel.go rename to telemetry/otel_span.go From 47f83e810fd19b583cbf277ee787625b215e06e3 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Thu, 30 Oct 2025 12:24:42 -0400 Subject: [PATCH 05/52] add trace exporter setup --- go.mod | 21 ++- go.sum | 42 +++-- log/tracer.go | 18 ++- telemetry/config.go | 150 ++++++++++++++++++ telemetry/doc.go | 39 +++++ telemetry/file_sink_test.go | 7 +- telemetry/metrics.go | 298 ++++++++++++++++-------------------- telemetry/metrics_span.go | 99 +++++++----- telemetry/metrics_test.go | 33 +++- telemetry/otel_span.go | 46 +++++- 10 files changed, 512 insertions(+), 241 deletions(-) create mode 100644 telemetry/config.go create mode 100644 telemetry/doc.go diff --git a/go.mod b/go.mod index 8354446245f7..d696ee4f4640 100644 --- a/go.mod +++ b/go.mod @@ -57,10 +57,17 @@ require ( github.com/tendermint/go-amino v0.16.0 github.com/test-go/testify v1.1.4 github.com/tidwall/btree v1.8.1 + go.opentelemetry.io/otel v1.38.0 + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.37.0 + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0 + go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.38.0 + go.opentelemetry.io/otel/sdk v1.38.0 + go.opentelemetry.io/otel/trace v1.38.0 go.uber.org/mock v0.6.0 golang.org/x/crypto v0.43.0 golang.org/x/sync v0.17.0 - google.golang.org/genproto/googleapis/api v0.0.0-20250818200422-3122310a409c + google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5 google.golang.org/grpc v1.76.0 google.golang.org/protobuf v1.36.10 gotest.tools/v3 v3.5.2 @@ -110,6 +117,7 @@ require ( github.com/bytedance/sonic v1.14.2 // indirect github.com/bytedance/sonic/loader v0.4.0 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect + github.com/cenkalti/backoff/v5 v5.0.3 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/cloudwego/base64x v0.1.6 // indirect github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443 // indirect @@ -154,6 +162,7 @@ require ( github.com/googleapis/enterprise-certificate-proxy v0.3.6 // indirect github.com/googleapis/gax-go/v2 v2.15.0 // indirect github.com/gorilla/websocket v1.5.3 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 // indirect github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect github.com/hashicorp/aws-sdk-go-base/v2 v2.0.0-beta.65 // indirect github.com/hashicorp/go-hclog v1.6.3 // indirect @@ -208,11 +217,9 @@ require ( go.opentelemetry.io/contrib/detectors/gcp v1.36.0 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0 // indirect - go.opentelemetry.io/otel v1.37.0 // indirect - go.opentelemetry.io/otel/metric v1.37.0 // indirect - go.opentelemetry.io/otel/sdk v1.37.0 // indirect - go.opentelemetry.io/otel/sdk/metric v1.37.0 // indirect - go.opentelemetry.io/otel/trace v1.37.0 // indirect + go.opentelemetry.io/otel/metric v1.38.0 // indirect + go.opentelemetry.io/otel/sdk/metric v1.38.0 // indirect + go.opentelemetry.io/proto/otlp v1.7.1 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect go.yaml.in/yaml/v2 v2.4.3 // indirect @@ -227,7 +234,7 @@ require ( golang.org/x/time v0.13.0 // indirect google.golang.org/api v0.247.0 // indirect google.golang.org/genproto v0.0.0-20250603155806-513f23925822 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20250818200422-3122310a409c // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect nhooyr.io/websocket v1.8.17 // indirect rsc.io/qr v0.2.0 // indirect diff --git a/go.sum b/go.sum index 2ea9388c678b..693c2dcbb741 100644 --- a/go.sum +++ b/go.sum @@ -157,6 +157,8 @@ github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QH github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM= +github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= @@ -445,6 +447,8 @@ github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgf github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 h1:8Tjv8EJ+pM1xP8mK6egEbD1OgnVTyacbefKhmbLhIhU= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2/go.mod h1:pkJQ2tZHJ0aFOVEEot6oZmaVEZcRme73eIFmhiVuRWs= github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c h1:6rhixN/i8ZofjG1Y75iExal34USq5p+wiN1tpie8IrU= github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c/go.mod h1:NMPJylDgVpX0MLRlPy15sqSwOFv/U1GZ2m21JhFfek0= github.com/hashicorp/aws-sdk-go-base/v2 v2.0.0-beta.65 h1:81+kWbE1yErFBMjME0I5k3x3kojjKsWtPYHEAutoPow= @@ -835,19 +839,29 @@ go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.6 go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0/go.mod h1:snMWehoOh2wsEwnvvwtDyFCxVeDAODenXHtn5vzrKjo= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0 h1:Hf9xI/XLML9ElpiHVDNwvqI0hIFlzV8dgIr35kV1kRU= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0/go.mod h1:NfchwuyNoMcZ5MLHwPrODwUF1HWCXWrL31s8gSAdIKY= -go.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ= -go.opentelemetry.io/otel v1.37.0/go.mod h1:ehE/umFRLnuLa/vSccNq9oS1ErUlkkK71gMcN34UG8I= +go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= +go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 h1:GqRJVj7UmLjCVyVJ3ZFLdPRmhDUp2zFmQe3RHIOsw24= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0/go.mod h1:ri3aaHSmCTVYu2AWv44YMauwAQc0aqI9gHKIcSbI1pU= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.37.0 h1:EtFWSnwW9hGObjkIdmlnWSydO+Qs8OwzfzXLUPg4xOc= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.37.0/go.mod h1:QjUEoiGCPkvFZ/MjK6ZZfNOS6mfVEVKYE99dFhuN2LI= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0 h1:aTL7F04bJHUlztTsNGJ2l+6he8c+y/b//eR0jjjemT4= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0/go.mod h1:kldtb7jDTeol0l3ewcmd8SDvx3EmIE7lyvqbasU3QC4= go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.36.0 h1:rixTyDGXFxRy1xzhKrotaHy3/KXdPhlWARrCgK+eqUY= go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.36.0/go.mod h1:dowW6UsM9MKbJq5JTz2AMVp3/5iW5I/TStsk8S+CfHw= -go.opentelemetry.io/otel/metric v1.37.0 h1:mvwbQS5m0tbmqML4NqK+e3aDiO02vsf/WgbsdpcPoZE= -go.opentelemetry.io/otel/metric v1.37.0/go.mod h1:04wGrZurHYKOc+RKeye86GwKiTb9FKm1WHtO+4EVr2E= -go.opentelemetry.io/otel/sdk v1.37.0 h1:ItB0QUqnjesGRvNcmAcU0LyvkVyGJ2xftD29bWdDvKI= -go.opentelemetry.io/otel/sdk v1.37.0/go.mod h1:VredYzxUvuo2q3WRcDnKDjbdvmO0sCzOvVAiY+yUkAg= -go.opentelemetry.io/otel/sdk/metric v1.37.0 h1:90lI228XrB9jCMuSdA0673aubgRobVZFhbjxHHspCPc= -go.opentelemetry.io/otel/sdk/metric v1.37.0/go.mod h1:cNen4ZWfiD37l5NhS+Keb5RXVWZWpRE+9WyVCpbo5ps= -go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4= -go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0= +go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.38.0 h1:kJxSDN4SgWWTjG/hPp3O7LCGLcHXFlvS2/FFOrwL+SE= +go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.38.0/go.mod h1:mgIOzS7iZeKJdeB8/NYHrJ48fdGc71Llo5bJ1J4DWUE= +go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= +go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= +go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E= +go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg= +go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM= +go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA= +go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= +go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= +go.opentelemetry.io/proto/otlp v1.7.1 h1:gTOMpGDb0WTBOP8JaO72iL3auEZhVmAQg4ipjOVAtj4= +go.opentelemetry.io/proto/otlp v1.7.1/go.mod h1:b2rVh6rfI/s2pHWNlB7ILJcRALpcNDzKhACevjI+ZnE= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= @@ -1087,10 +1101,10 @@ google.golang.org/genproto v0.0.0-20210126160654-44e461bb6506/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20220314164441-57ef72a4c106/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E= google.golang.org/genproto v0.0.0-20250603155806-513f23925822 h1:rHWScKit0gvAPuOnu87KpaYtjK5zBMLcULh7gxkCXu4= google.golang.org/genproto v0.0.0-20250603155806-513f23925822/go.mod h1:HubltRL7rMh0LfnQPkMH4NPDFEWp0jw3vixw7jEM53s= -google.golang.org/genproto/googleapis/api v0.0.0-20250818200422-3122310a409c h1:AtEkQdl5b6zsybXcbz00j1LwNodDuH6hVifIaNqk7NQ= -google.golang.org/genproto/googleapis/api v0.0.0-20250818200422-3122310a409c/go.mod h1:ea2MjsO70ssTfCjiwHgI0ZFqcw45Ksuk2ckf9G468GA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250818200422-3122310a409c h1:qXWI/sQtv5UKboZ/zUk7h+mrf/lXORyI+n9DKDAusdg= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250818200422-3122310a409c/go.mod h1:gw1tLEfykwDz2ET4a12jcXt4couGAm7IwsVaTy0Sflo= +google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5 h1:BIRfGDEjiHRrk0QKZe3Xv2ieMhtgRGeLcZQ0mIVn4EY= +google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5/go.mod h1:j3QtIyytwqGr1JUDtYXwtMXWPKsEa5LtzIFN1Wn5WvE= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5 h1:eaY8u2EuxbRv7c3NiGK0/NedzVsCcV6hDuU5qPX5EGE= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5/go.mod h1:M4/wBTSeyLxupu3W3tJtOgB14jILAS/XWPSSa3TAlJc= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM= diff --git a/log/tracer.go b/log/tracer.go index cfb99eafdb57..00274bd2414a 100644 --- a/log/tracer.go +++ b/log/tracer.go @@ -2,13 +2,8 @@ package log import "context" -// Tracer is an interface for creating and managing spans. -// It may be backed by open telemetry or other tracing libraries, -// Spans may also be used for collecting timing metrics. -// It embeds the Logger interface. Log events may be associated with spans. -type Tracer interface { - Logger - +// TraceProvider is an interface for creating and managing tracing spans. +type TraceProvider interface { // StartSpan starts a new span with the given operation name and key-value pair attributes. // If there is a parent span, the new span will be a child of that span. // It is recommended to use a defer statement to end the span like this: @@ -34,6 +29,15 @@ type Tracer interface { StartRootSpan(ctx context.Context, operation string, kvs ...any) (context.Context, Span) } +// Tracer is an interface for creating and managing spans. +// It may be backed by open telemetry or other tracing libraries, +// Spans may also be used for collecting timing metrics. +// It embeds the Logger interface. Log events may be associated with spans. +type Tracer interface { + Logger + TraceProvider +} + // Span is an interface for managing spans and creating nested spans via the embedded Tracer interface. type Span interface { // Tracer is embedded to allow for the creation of nested spans. diff --git a/telemetry/config.go b/telemetry/config.go new file mode 100644 index 000000000000..e707a127251d --- /dev/null +++ b/telemetry/config.go @@ -0,0 +1,150 @@ +package telemetry + +import ( + "net/http" + + "github.com/hashicorp/go-metrics" + "github.com/prometheus/common/expfmt" +) + +// globalTelemetryEnabled is a private variable that stores the telemetry enabled state. +// It is set on initialization and does not change for the lifetime of the program. +var globalTelemetryEnabled bool + +// IsTelemetryEnabled provides controlled access to check if telemetry is enabled. +func IsTelemetryEnabled() bool { + return globalTelemetryEnabled +} + +// EnableTelemetry allows for the global telemetry enabled state to be set. +func EnableTelemetry() { + globalTelemetryEnabled = true +} + +// globalLabels defines the set of global labels that will be applied to all +// metrics emitted using the telemetry package function wrappers. +var globalLabels = []metrics.Label{} + +// Metrics supported format types. +const ( + FormatDefault = "" + FormatPrometheus = "prometheus" + FormatText = "text" + ContentTypeText = `text/plain; version=` + expfmt.TextVersion + `; charset=utf-8` + + MetricSinkInMem = "mem" + MetricSinkStatsd = "statsd" + MetricSinkDogsStatsd = "dogstatsd" + MetricSinkFile = "file" + + TraceSinkOtel = "otel" + TraceSinkNoop = "noop" +) + +// DisplayableSink is an interface that defines a method for displaying metrics. +type DisplayableSink interface { + DisplayMetrics(resp http.ResponseWriter, req *http.Request) (any, error) +} + +// Config defines the configuration options for application telemetry. +type Config struct { + // ServiceName is the identifier for this service, used as a prefix for all metric keys. + // Example: "cosmos-app" → metrics like "cosmos-app.tx.count" + ServiceName string `mapstructure:"service-name"` + + // Enabled controls whether telemetry is active. When false, all telemetry operations + // become no-ops with zero overhead. When true, metrics collection is activated. + Enabled bool `mapstructure:"enabled"` + + // EnableHostname prefixes gauge values with the hostname. + // Useful in multi-node deployments to identify which node emitted a metric. + EnableHostname bool `mapstructure:"enable-hostname"` + + // EnableHostnameLabel adds a "hostname" label to all metrics. + // Alternative to EnableHostname that works better with label-based systems like Prometheus. + EnableHostnameLabel bool `mapstructure:"enable-hostname-label"` + + // EnableServiceLabel adds a "service" label with the ServiceName to all metrics. + // Useful when aggregating metrics from multiple services in one monitoring system. + EnableServiceLabel bool `mapstructure:"enable-service-label"` + + // PrometheusRetentionTime, when positive, enables a Prometheus metrics sink. + // Defines how long (in seconds) metrics are retained in memory for scraping. + // The Prometheus sink is added to a FanoutSink alongside the primary sink. + // Recommended value: 60 seconds or more. + PrometheusRetentionTime int64 `mapstructure:"prometheus-retention-time"` + + // GlobalLabels defines a set of key-value label pairs applied to ALL metrics. + // These labels are automatically attached to every metric emission. + // Useful for static identifiers like chain ID, environment, region, etc. + // + // Example: [][]string{{"chain_id", "cosmoshub-1"}, {"env", "production"}} + // + // Note: The outer array contains label pairs, each inner array has exactly 2 elements [key, value]. + GlobalLabels [][]string `mapstructure:"global-labels"` + + // MetricsSink defines the metrics backend type. Supported values: + // - "mem" (default): In-memory sink with SIGUSR1 dump-to-stderr capability + // - "prometheus": Prometheus exposition format (use with PrometheusRetentionTime) + // - "statsd": StatsD protocol (push-based, requires StatsdAddr) + // - "dogstatsd": Datadog-enhanced StatsD with tags (requires StatsdAddr, DatadogHostname) + // - "file": JSON lines written to a file (requires MetricsFile) + // + // Multiple sinks can be active via FanoutSink (e.g., mem + prometheus). + MetricsSink string `mapstructure:"metrics-sink" default:"mem"` + + // StatsdAddr is the address of the StatsD or DogStatsD server (host:port). + // Only used when MetricsSink is "statsd" or "dogstatsd". + // Example: "localhost:8125" + StatsdAddr string `mapstructure:"statsd-addr"` + + // DatadogHostname is the hostname to report when using DogStatsD. + // Only used when MetricsSink is "dogstatsd". + // If empty, the system hostname is used. + DatadogHostname string `mapstructure:"datadog-hostname"` + + // MetricsFile is the file path to write metrics to in JSONL format. + // Only used when MetricsSink is "file". + // Each metric emission creates a JSON line: {"timestamp":"...","type":"counter","key":[...],"value":1.0} + // Example: "/tmp/metrics.jsonl" or "./metrics.jsonl" + MetricsFile string `mapstructure:"metrics-file"` + + // TraceSink is the sink for trace data. Supported values: + // - "otel": OpenTelemetry trace sink + // - "metrics": all spans will be redirected to emit invocation counter and timing histogram metrics + // - "noop": No-op trace sink (default) + TraceSink string `mapstructure:"trace-sink"` + + // OtelTraceExporters is a list of OTLP exporters to use for trace data. + // This is only used when trace sink is set to "otel". + OtelTraceExporters []OtelTraceExportConfig `mapstructure:"otel-trace-exporters"` +} + +type OtelTraceExportConfig struct { + // Type is the exporter type. + // Must be one of: + // - "stdout" + // - "otlp" + // + // OTLP exporters must set the endpoint URL and can optionally set the transport protocol. + Type string `mapstructure:"type"` + + // OTLPTransport is the transport protocol to use for OTLP. + // Must be one of: + // - "http" (default) + // - "grpc" + OTLPTransport string `mapstructure:"otlp-transport"` + + // Endpoint is the OTLP exporter endpoint URL (grpc or http). + Endpoint string `mapstructure:"endpoint"` + + // Insecure disables TLS certificate verification for OTLP exporters. + Insecure bool `mapstructure:"insecure"` + + // File is the file path to write trace data to when using the "stdout" exporter. + // If it is empty, the trace data is written to stdout. + File string `mapstructure:"file"` + + // PrettyPrint enables pretty-printing of JSON output when using the "stdout" exporter. + PrettyPrint bool `mapstructure:"pretty-print"` +} diff --git a/telemetry/doc.go b/telemetry/doc.go new file mode 100644 index 000000000000..98afc159ba42 --- /dev/null +++ b/telemetry/doc.go @@ -0,0 +1,39 @@ +// Package telemetry provides observability through metrics and distributed tracing. +// +// # Metrics Collection +// +// Metrics collection uses hashicorp/go-metrics with support for multiple sink backends: +// - mem: In-memory aggregation with SIGUSR1 signal dumping to stderr +// - prometheus: Prometheus registry for pull-based scraping via /metrics endpoint +// - statsd: Push-based metrics to StatsD daemon +// - dogstatsd: Push-based metrics to Datadog StatsD daemon with tagging +// - file: Write metrics to a file as JSON lines (useful for tests and debugging) +// +// Multiple sinks can be active simultaneously via FanoutSink (e.g., both in-memory and Prometheus). +// +// # Distributed Tracing +// +// Tracing support is provided via OtelSpan, which wraps OpenTelemetry for hierarchical span tracking. +// See otel.go for the log.Tracer implementation. +// +// # Usage +// +// Initialize metrics at application startup: +// +// m, err := telemetry.New(telemetry.Config{ +// Enabled: true, +// ServiceName: "cosmos-app", +// PrometheusRetentionTime: 60, +// GlobalLabels: [][]string{{"chain_id", "cosmoshub-1"}}, +// }) +// if err != nil { +// log.Fatal(err) +// } +// defer m.Close() +// +// Emit metrics from anywhere in the application: +// +// telemetry.IncrCounter(1, "tx", "processed") +// telemetry.SetGauge(1024, "mempool", "size") +// defer telemetry.MeasureSince(telemetry.Now(), "block", "execution") +package telemetry diff --git a/telemetry/file_sink_test.go b/telemetry/file_sink_test.go index 431bdfdbfd48..4a8feceb7e37 100644 --- a/telemetry/file_sink_test.go +++ b/telemetry/file_sink_test.go @@ -139,11 +139,16 @@ func TestFileSink_WritesAfterClose(t *testing.T) { data, err := os.ReadFile(tmpfile) require.NoError(t, err) - scanner := bufio.NewScanner(bufio.NewReader(os.Open(tmpfile))) + file3, err := os.Open(tmpfile) + require.NoError(t, err) + defer file3.Close() + + scanner := bufio.NewScanner(file3) lineCount := 0 for scanner.Scan() { lineCount++ } + require.NoError(t, scanner.Err()) require.Equal(t, 1, lineCount, "only metric before close should be written") require.Contains(t, string(data), `"key":["before"]`) require.NotContains(t, string(data), `"key":["after"]`) diff --git a/telemetry/metrics.go b/telemetry/metrics.go index cae3dd2d3701..405bb3bc7a59 100644 --- a/telemetry/metrics.go +++ b/telemetry/metrics.go @@ -1,50 +1,11 @@ -// Package telemetry provides observability through metrics and distributed tracing. -// -// # Metrics Collection -// -// Metrics collection uses hashicorp/go-metrics with support for multiple sink backends: -// - mem: In-memory aggregation with SIGUSR1 signal dumping to stderr -// - prometheus: Prometheus registry for pull-based scraping via /metrics endpoint -// - statsd: Push-based metrics to StatsD daemon -// - dogstatsd: Push-based metrics to Datadog StatsD daemon with tagging -// - file: Write metrics to a file as JSON lines (useful for tests and debugging) -// -// Multiple sinks can be active simultaneously via FanoutSink (e.g., both in-memory and Prometheus). -// -// # Distributed Tracing -// -// Tracing support is provided via OtelSpan, which wraps OpenTelemetry for hierarchical span tracking. -// See otel.go for the log.Tracer implementation. -// -// # Usage -// -// Initialize metrics at application startup: -// -// m, err := telemetry.New(telemetry.Config{ -// Enabled: true, -// ServiceName: "cosmos-app", -// PrometheusRetentionTime: 60, -// GlobalLabels: [][]string{{"chain_id", "cosmoshub-1"}}, -// }) -// if err != nil { -// log.Fatal(err) -// } -// defer m.Close() -// -// Emit metrics from anywhere in the application: -// -// telemetry.IncrCounter(1, "tx", "processed") -// telemetry.SetGauge(1024, "mempool", "size") -// defer telemetry.MeasureSince(telemetry.Now(), "block", "execution") package telemetry import ( "bytes" + "context" "encoding/json" "errors" "fmt" - "io" - "net/http" "os" "time" @@ -53,110 +14,15 @@ import ( metricsprom "github.com/hashicorp/go-metrics/prometheus" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/common/expfmt" -) - -// globalTelemetryEnabled is a private variable that stores the telemetry enabled state. -// It is set on initialization and does not change for the lifetime of the program. -var globalTelemetryEnabled bool - -// IsTelemetryEnabled provides controlled access to check if telemetry is enabled. -func IsTelemetryEnabled() bool { - return globalTelemetryEnabled -} - -// EnableTelemetry allows for the global telemetry enabled state to be set. -func EnableTelemetry() { - globalTelemetryEnabled = true -} + "go.opentelemetry.io/otel/exporters/otlp/otlptrace" + "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc" + "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp" + "go.opentelemetry.io/otel/exporters/stdout/stdouttrace" + otelsdktrace "go.opentelemetry.io/otel/sdk/trace" -// globalLabels defines the set of global labels that will be applied to all -// metrics emitted using the telemetry package function wrappers. -var globalLabels = []metrics.Label{} - -// Metrics supported format types. -const ( - FormatDefault = "" - FormatPrometheus = "prometheus" - FormatText = "text" - ContentTypeText = `text/plain; version=` + expfmt.TextVersion + `; charset=utf-8` - - MetricSinkInMem = "mem" - MetricSinkStatsd = "statsd" - MetricSinkDogsStatsd = "dogstatsd" - MetricSinkFile = "file" + "cosmossdk.io/log" ) -// DisplayableSink is an interface that defines a method for displaying metrics. -type DisplayableSink interface { - DisplayMetrics(resp http.ResponseWriter, req *http.Request) (any, error) -} - -// Config defines the configuration options for application telemetry. -type Config struct { - // ServiceName is the identifier for this service, used as a prefix for all metric keys. - // Example: "cosmos-app" → metrics like "cosmos-app.tx.count" - ServiceName string `mapstructure:"service-name"` - - // Enabled controls whether telemetry is active. When false, all telemetry operations - // become no-ops with zero overhead. When true, metrics collection is activated. - Enabled bool `mapstructure:"enabled"` - - // EnableHostname prefixes gauge values with the hostname. - // Useful in multi-node deployments to identify which node emitted a metric. - EnableHostname bool `mapstructure:"enable-hostname"` - - // EnableHostnameLabel adds a "hostname" label to all metrics. - // Alternative to EnableHostname that works better with label-based systems like Prometheus. - EnableHostnameLabel bool `mapstructure:"enable-hostname-label"` - - // EnableServiceLabel adds a "service" label with the ServiceName to all metrics. - // Useful when aggregating metrics from multiple services in one monitoring system. - EnableServiceLabel bool `mapstructure:"enable-service-label"` - - // PrometheusRetentionTime, when positive, enables a Prometheus metrics sink. - // Defines how long (in seconds) metrics are retained in memory for scraping. - // The Prometheus sink is added to a FanoutSink alongside the primary sink. - // Recommended value: 60 seconds or more. - PrometheusRetentionTime int64 `mapstructure:"prometheus-retention-time"` - - // GlobalLabels defines a set of key-value label pairs applied to ALL metrics. - // These labels are automatically attached to every metric emission. - // Useful for static identifiers like chain ID, environment, region, etc. - // - // Example: [][]string{{"chain_id", "cosmoshub-1"}, {"env", "production"}} - // - // Note: The outer array contains label pairs, each inner array has exactly 2 elements [key, value]. - GlobalLabels [][]string `mapstructure:"global-labels"` - - // MetricsSink defines the metrics backend type. Supported values: - // - "mem" (default): In-memory sink with SIGUSR1 dump-to-stderr capability - // - "prometheus": Prometheus exposition format (use with PrometheusRetentionTime) - // - "statsd": StatsD protocol (push-based, requires StatsdAddr) - // - "dogstatsd": Datadog-enhanced StatsD with tags (requires StatsdAddr, DatadogHostname) - // - "file": JSON lines written to a file (requires MetricsFile) - // - // Multiple sinks can be active via FanoutSink (e.g., mem + prometheus). - MetricsSink string `mapstructure:"metrics-sink" default:"mem"` - - // StatsdAddr is the address of the StatsD or DogStatsD server (host:port). - // Only used when MetricsSink is "statsd" or "dogstatsd". - // Example: "localhost:8125" - StatsdAddr string `mapstructure:"statsd-addr"` - - // DatadogHostname is the hostname to report when using DogStatsD. - // Only used when MetricsSink is "dogstatsd". - // If empty, the system hostname is used. - DatadogHostname string `mapstructure:"datadog-hostname"` - - // MetricsFile is the file path to write metrics to in JSONL format. - // Only used when MetricsSink is "file". - // Each metric emission creates a JSON line: {"timestamp":"...","type":"counter","key":[...],"value":1.0} - // Example: "/tmp/metrics.jsonl" or "./metrics.jsonl" - MetricsFile string `mapstructure:"metrics-file"` - - TraceSink string `mapstructure:"trace-sink"` -} - // Metrics provides access to the application's metrics collection system. // It wraps the go-metrics global registry and configured sinks. // @@ -171,9 +37,12 @@ type Config struct { // Note: go-metrics uses a singleton global registry. Only one Metrics instance // should be created per process. type Metrics struct { - sink metrics.MetricSink - prometheusEnabled bool - closer io.Closer // non-nil when using file sink + sink metrics.MetricSink + prometheusEnabled bool + startFuncs []func(ctx context.Context) error + shutdownFuncs []func(context.Context) error + traceProvider log.TraceProvider + metricsTraceProvider *MetricsTraceProvider } // GatherResponse contains collected metrics in the requested format. @@ -226,10 +95,12 @@ func New(cfg Config) (_ *Metrics, rerr error) { metricsConf.EnableHostname = cfg.EnableHostname metricsConf.EnableHostnameLabel = cfg.EnableHostnameLabel + var startFuncs []func(context.Context) error + var shutdownFuncs []func(context.Context) error + var ( - sink metrics.MetricSink - closer io.Closer - err error + sink metrics.MetricSink + err error ) switch cfg.MetricsSink { case MetricSinkStatsd: @@ -246,7 +117,9 @@ func New(cfg Config) (_ *Metrics, rerr error) { } fileSink := NewFileSink(file) sink = fileSink - closer = fileSink + shutdownFuncs = append(shutdownFuncs, func(ctx context.Context) error { + return fileSink.Close() + }) default: memSink := metrics.NewInmemSink(10*time.Second, time.Minute) sink = memSink @@ -258,11 +131,89 @@ func New(cfg Config) (_ *Metrics, rerr error) { }() } + metricsTraceProvider := NewMetricsTraceProvider(nil, globalLabels, metrics.Default()) + + var tracerBase log.TraceProvider + switch cfg.TraceSink { + case TraceSinkOtel: + var tracerProviderOpts []otelsdktrace.TracerProviderOption + for _, exporterOpts := range cfg.OtelTraceExporters { + switch exporterOpts.Type { + case "otlp": + endpoint := exporterOpts.Endpoint + if endpoint == "" { + return nil, fmt.Errorf("otlp endpoint must be set") + } + var client otlptrace.Client + switch exporterOpts.OTLPTransport { + case "grpc": + opts := []otlptracegrpc.Option{otlptracegrpc.WithEndpoint(endpoint)} + if exporterOpts.Insecure { + opts = append(opts, otlptracegrpc.WithInsecure()) + } + client = otlptracegrpc.NewClient(opts...) + default: + opts := []otlptracehttp.Option{otlptracehttp.WithEndpoint(endpoint)} + if exporterOpts.Insecure { + opts = append(opts, otlptracehttp.WithInsecure()) + } + client = otlptracehttp.NewClient(opts...) + } + exporter := otlptrace.NewUnstarted(client) + startFuncs = append(startFuncs, exporter.Start) + batcherOpt := otelsdktrace.WithBatcher(exporter) + tracerProviderOpts = append(tracerProviderOpts, batcherOpt) + case "stdout": + var opts []stdouttrace.Option + if exporterOpts.File != "" { + file, err := os.OpenFile(exporterOpts.File, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644) + if err != nil { + return nil, fmt.Errorf("failed to open stdout trace file %s: %w", exporterOpts.File, err) + } + opts = append(opts, stdouttrace.WithWriter(file)) + shutdownFuncs = append(shutdownFuncs, func(ctx context.Context) error { + return file.Close() + }) + } + if exporterOpts.PrettyPrint { + opts = append(opts, stdouttrace.WithPrettyPrint()) + } + exporter, err := stdouttrace.New(opts...) + if err != nil { + return nil, fmt.Errorf("failed to create stdout trace exporter: %w", err) + } + batcher := otelsdktrace.WithBatcher(exporter) + tracerProviderOpts = append(tracerProviderOpts, batcher) + default: + return nil, fmt.Errorf("unknown trace exporter type: %s", exporterOpts.Type) + } + } + + tracerProvider := otelsdktrace.NewTracerProvider(tracerProviderOpts...) + shutdownFuncs = append(shutdownFuncs, tracerProvider.Shutdown) + tracerName := cfg.ServiceName + if tracerName == "" { + tracerName = "cosmos-sdk" + } + tracerBase = NewOtelTraceProvider(tracerProvider.Tracer(tracerName)) + + case "metrics": + tracerBase = metricsTraceProvider + default: + tracerBase = log.NewNopTracer() + } + if err != nil { return nil, err } - m := &Metrics{sink: sink, closer: closer} + m := &Metrics{ + sink: sink, + startFuncs: startFuncs, + shutdownFuncs: shutdownFuncs, + traceProvider: tracerBase, + metricsTraceProvider: metricsTraceProvider, + } fanout := metrics.FanoutSink{sink} if cfg.PrometheusRetentionTime > 0 { @@ -351,22 +302,37 @@ func (m *Metrics) gatherGeneric() (GatherResponse, error) { return GatherResponse{ContentType: "application/json", Metrics: content}, nil } -// Close flushes any buffered data and closes resources associated with the metrics system. -// This is primarily needed when using the file sink to ensure all data is written to disk. -// It is safe to call Close() multiple times, and safe to call on a nil Metrics object. -// -// For other sink types (mem, statsd, prometheus), Close() is a no-op. -// -// Example: -// -// m, err := telemetry.New(cfg) -// if err != nil { -// return err -// } -// defer m.Close() -func (m *Metrics) Close() error { - if m == nil || m.closer == nil { - return nil +// TraceProvider returns the base trace provider for creating spans. +func (m *Metrics) TraceProvider() log.TraceProvider { + return m.traceProvider +} + +// MetricsTraceProvider returns a trace provider that only emits metrics for spans. +// Use this when you specifically want to configure a code path to only emit metrics +// and not actual logging spans (useful for benchmarking small operations such as store operations). +func (m *Metrics) MetricsTraceProvider() log.TraceProvider { + return m.traceProvider +} + +// Start starts all configured exporters. +// Start should be called after New() in order to ensure that all configured +// exporters are started. +func (m *Metrics) Start(ctx context.Context) error { + for _, f := range m.startFuncs { + if err := f(ctx); err != nil { + return err + } + } + return nil +} + +// Shutdown must be called before the application exits to shutdown any +// exporters and close any open files. +func (m *Metrics) Shutdown(ctx context.Context) error { + for _, f := range m.shutdownFuncs { + if err := f(ctx); err != nil { + return err + } } - return m.closer.Close() + return nil } diff --git a/telemetry/metrics_span.go b/telemetry/metrics_span.go index 859d004bff9a..48675b4e9af3 100644 --- a/telemetry/metrics_span.go +++ b/telemetry/metrics_span.go @@ -9,6 +9,41 @@ import ( "cosmossdk.io/log" ) +type MetricsTraceProvider struct { + rootPath []string // Base path set at tracer creation, preserved across all spans + rootLabels []metrics.Label // Labels applied to all metrics emitted by this tracer + metrics *metrics.Metrics +} + +func NewMetricsTraceProvider(rootPath []string, rootLabels []metrics.Label, metrics *metrics.Metrics) *MetricsTraceProvider { + return &MetricsTraceProvider{rootPath: rootPath, rootLabels: rootLabels, metrics: metrics} +} + +func (m *MetricsTraceProvider) startSpan(existingPath []string, operation string, _ ...any) log.Span { + path := make([]string, len(existingPath)+1) + copy(path, existingPath) + path[len(path)-1] = operation + return &MetricsSpan{ + MetricsTraceProvider: m, + path: []string{operation}, + start: time.Now(), + } +} + +func (m *MetricsTraceProvider) StartSpan(operation string, _ ...any) log.Span { + return m.startSpan(m.rootPath, operation) +} + +func (m *MetricsTraceProvider) StartSpanContext(ctx context.Context, operation string, kvs ...any) (context.Context, log.Span) { + return ctx, m.StartSpan(operation, kvs...) +} + +func (m *MetricsTraceProvider) StartRootSpan(ctx context.Context, operation string, kvs ...any) (context.Context, log.Span) { + return ctx, m.StartSpan(operation, kvs...) +} + +var _ log.TraceProvider = (*MetricsTraceProvider)(nil) + // MetricsSpan is a log.Span implementation that emits timing and count metrics // to go-metrics when the span ends. // @@ -24,11 +59,9 @@ import ( // Root path and labels are preserved across all spans created from this tracer, // ensuring consistent metric namespacing and labeling throughout the span hierarchy. type MetricsSpan struct { - metrics *metrics.Metrics - start time.Time - path []string - rootPath []string // Base path set at tracer creation, preserved across all spans - rootLabels []metrics.Label // Labels applied to all metrics emitted by this tracer + *MetricsTraceProvider + start time.Time + path []string } // NewMetricsTracer creates a new MetricsSpan that acts as a root tracer. @@ -44,11 +77,13 @@ type MetricsSpan struct { // // Emits: "app.tx.validate.time" and "app.tx.validate.count" with module=staking label func NewMetricsTracer(m *metrics.Metrics, rootPath []string, rootLabels []metrics.Label) *MetricsSpan { return &MetricsSpan{ - metrics: m, - path: rootPath, - rootPath: rootPath, - rootLabels: rootLabels, - start: time.Now(), + MetricsTraceProvider: &MetricsTraceProvider{ + metrics: m, + rootPath: rootPath, + rootLabels: rootLabels, + }, + path: rootPath, + start: time.Now(), } } @@ -64,22 +99,13 @@ func (m *MetricsSpan) Impl() any { return nil } // Root path and labels are preserved in the child span. // The kvs parameters are ignored (metrics don't support dynamic attributes). func (m *MetricsSpan) StartSpan(operation string, kvs ...any) log.Span { - path := make([]string, len(m.path)+1) - copy(path, m.path) - path[len(path)-1] = operation - return &MetricsSpan{ - metrics: m.metrics, - path: path, - rootPath: m.rootPath, - rootLabels: m.rootLabels, - start: time.Now(), - } + return m.startSpan(m.path, operation) } // StartSpanContext creates a child span and returns the context unchanged. // The span is not stored in the context. -func (m *MetricsSpan) StartSpanContext(ctx context.Context, operation string, kvs ...any) (context.Context, log.Span) { - return ctx, m.StartSpan(operation, kvs...) +func (m *MetricsSpan) StartSpanContext(ctx context.Context, operation string, _ ...any) (context.Context, log.Span) { + return ctx, m.startSpan(m.path, operation) } // StartRootSpan creates a new root span by combining the tracer's root path with the operation. @@ -93,30 +119,23 @@ func (m *MetricsSpan) StartSpanContext(ctx context.Context, operation string, kv // defer span.End() // // Emits: "app.process.time" and "app.process.count" func (m *MetricsSpan) StartRootSpan(ctx context.Context, operation string, kvs ...any) (context.Context, log.Span) { - // Preserve root path and add operation to it - rootPath := append([]string{}, m.rootPath...) - rootPath = append(rootPath, operation) - - return ctx, &MetricsSpan{ - metrics: m.metrics, - path: rootPath, - rootPath: m.rootPath, - rootLabels: m.rootLabels, - start: time.Now(), - } + return ctx, m.startSpan(m.rootPath, operation) } // SetAttrs is a no-op - metrics don't support dynamic attributes. -func (m *MetricsSpan) SetAttrs(kvs ...any) {} +func (m *MetricsSpan) SetAttrs(...any) {} // SetErr is a no-op but returns the error unchanged for convenience. -func (m *MetricsSpan) SetErr(err error, kvs ...any) error { return err } +func (m *MetricsSpan) SetErr(err error, _ ...any) error { return err } // End emits timing and count metrics with ".time" and ".count" suffixes. +// Root labels are applied to both metrics. // // For a span with path ["query", "get"], this emits: // - Timer: "query.get.time" with duration since start // - Counter: "query.get.count" incremented by 1 +// +// If root labels were set (e.g., module=staking), they are included in both metrics. func (m *MetricsSpan) End() { // Create paths with suffixes to avoid metric type conflicts timePath := make([]string, len(m.path)+1) @@ -127,8 +146,14 @@ func (m *MetricsSpan) End() { copy(countPath, m.path) countPath[len(countPath)-1] = "count" - m.metrics.MeasureSince(timePath, m.start) - m.metrics.IncrCounter(countPath, 1) + // Apply root labels to metrics + if len(m.rootLabels) > 0 { + m.metrics.MeasureSinceWithLabels(timePath, m.start, m.rootLabels) + m.metrics.IncrCounterWithLabels(countPath, 1, m.rootLabels) + } else { + m.metrics.MeasureSince(timePath, m.start) + m.metrics.IncrCounter(countPath, 1) + } } var _ log.Span = (*MetricsSpan)(nil) diff --git a/telemetry/metrics_test.go b/telemetry/metrics_test.go index b741f007db22..a0aa4690f81f 100644 --- a/telemetry/metrics_test.go +++ b/telemetry/metrics_test.go @@ -1,7 +1,9 @@ package telemetry import ( + "context" "encoding/json" + "os" "strings" "testing" "time" @@ -57,11 +59,40 @@ func TestMetrics_Prom(t *testing.T) { gr, err := m.Gather(FormatPrometheus) require.NoError(t, err) - require.Equal(t, gr.ContentType, string(ContentTypeText)) + require.Equal(t, gr.ContentType, ContentTypeText) require.True(t, strings.Contains(string(gr.Metrics), "test_dummy_counter 30")) } +func TestMetrics_FileSink(t *testing.T) { + tmpfile := t.TempDir() + "/metrics.jsonl" + + m, err := New(Config{ + MetricsSink: MetricSinkFile, + MetricsFile: tmpfile, + Enabled: true, + EnableHostname: false, + ServiceName: "test", + }) + require.NoError(t, err) + require.NotNil(t, m) + + // Emit a few metrics + metrics.IncrCounter([]string{"test_counter"}, 5.0) + metrics.SetGauge([]string{"test_gauge"}, 42.0) + + // Close to flush buffered data + require.NoError(t, m.Shutdown(context.Background())) + + // Verify file was created and contains metrics + data, err := os.ReadFile(tmpfile) + require.NoError(t, err) + require.NotEmpty(t, data) + require.Contains(t, string(data), `"type":"counter"`) + require.Contains(t, string(data), `"type":"gauge"`) + require.Contains(t, string(data), `"key":["test","test_counter"]`) +} + func emitMetrics() { ticker := time.NewTicker(time.Second) timeout := time.After(30 * time.Second) diff --git a/telemetry/otel_span.go b/telemetry/otel_span.go index b3172d39abb3..4b323105f9cb 100644 --- a/telemetry/otel_span.go +++ b/telemetry/otel_span.go @@ -11,22 +11,52 @@ import ( "cosmossdk.io/log" ) -type OtelSpan struct { - tracer oteltrace.Tracer - ctx context.Context - span oteltrace.Span - persistentAttrs []otelattr.KeyValue +type OtelTracerBase struct { + tracer oteltrace.Tracer } -func NewOtelSpan(tracer oteltrace.Tracer, ctx context.Context, operation string, kvs ...any) (context.Context, *OtelSpan) { - ctx, span := tracer.Start(ctx, operation, oteltrace.WithAttributes(toKVs(kvs)...)) - return ctx, &OtelSpan{ +func NewOtelTraceProvider(tracer oteltrace.Tracer) *OtelTracerBase { + return &OtelTracerBase{ tracer: tracer, + } +} + +func (o *OtelTracerBase) StartSpan(operation string, kvs ...any) log.Span { + ctx, span := o.tracer.Start(context.Background(), operation, oteltrace.WithAttributes(toKVs(kvs)...)) + return &OtelSpan{ + tracer: o.tracer, + ctx: ctx, + span: span, + } +} + +func (o *OtelTracerBase) StartSpanContext(ctx context.Context, operation string, kvs ...any) (context.Context, log.Span) { + ctx, span := o.tracer.Start(ctx, operation, oteltrace.WithAttributes(toKVs(kvs)...)) + return ctx, &OtelSpan{ + tracer: o.tracer, + ctx: ctx, + span: span, + } +} + +func (o *OtelTracerBase) StartRootSpan(ctx context.Context, operation string, kvs ...any) (context.Context, log.Span) { + ctx, span := o.tracer.Start(ctx, operation, oteltrace.WithAttributes(toKVs(kvs)...), oteltrace.WithNewRoot()) + return ctx, &OtelSpan{ + tracer: o.tracer, ctx: ctx, span: span, } } +var _ log.TraceProvider = (*OtelTracerBase)(nil) + +type OtelSpan struct { + tracer oteltrace.Tracer + ctx context.Context + span oteltrace.Span + persistentAttrs []otelattr.KeyValue +} + func (o *OtelSpan) addEvent(level, msg string, keyVals ...any) { o.span.AddEvent(msg, oteltrace.WithAttributes(o.persistentAttrs...), From 7fafce361c906a46bbcce0203bffee6b2d88d07f Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Thu, 30 Oct 2025 12:33:21 -0400 Subject: [PATCH 06/52] fixes --- client/v2/go.mod | 19 ++++++++++++----- client/v2/go.sum | 42 ++++++++++++++++++++++++------------- simapp/go.mod | 25 +++++++++++++--------- simapp/go.sum | 44 +++++++++++++++++++++++++-------------- systemtests/go.mod | 19 ++++++++++++----- systemtests/go.sum | 42 ++++++++++++++++++++++++------------- telemetry/metrics.go | 2 +- telemetry/metrics_span.go | 29 +++----------------------- telemetry/otel_span.go | 14 ++++++------- tests/go.mod | 21 ++++++++++++------- tests/go.sum | 42 ++++++++++++++++++++++++------------- tests/systemtests/go.mod | 19 ++++++++++++----- tests/systemtests/go.sum | 42 ++++++++++++++++++++++++------------- 13 files changed, 222 insertions(+), 138 deletions(-) diff --git a/client/v2/go.mod b/client/v2/go.mod index 6c630e66cc06..7d46f2c4ca34 100644 --- a/client/v2/go.mod +++ b/client/v2/go.mod @@ -38,6 +38,7 @@ require ( github.com/bytedance/sonic v1.14.2 // indirect github.com/bytedance/sonic/loader v0.4.0 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect + github.com/cenkalti/backoff/v5 v5.0.3 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/chzyer/readline v1.5.1 // indirect github.com/cloudwego/base64x v0.1.6 // indirect @@ -83,11 +84,13 @@ require ( github.com/google/flatbuffers v25.2.10+incompatible // indirect github.com/google/go-cmp v0.7.0 // indirect github.com/google/orderedcode v0.0.1 // indirect + github.com/google/uuid v1.6.0 // indirect github.com/gorilla/handlers v1.5.2 // indirect github.com/gorilla/mux v1.8.1 // indirect github.com/gorilla/websocket v1.5.3 // indirect github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 // indirect github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect github.com/hashicorp/go-hclog v1.6.3 // indirect github.com/hashicorp/go-immutable-radix v1.3.1 // indirect @@ -145,9 +148,15 @@ require ( github.com/zondax/ledger-go v1.0.1 // indirect go.etcd.io/bbolt v1.4.0 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect - go.opentelemetry.io/otel v1.37.0 // indirect - go.opentelemetry.io/otel/metric v1.37.0 // indirect - go.opentelemetry.io/otel/trace v1.37.0 // indirect + go.opentelemetry.io/otel v1.38.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.37.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0 // indirect + go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.38.0 // indirect + go.opentelemetry.io/otel/metric v1.38.0 // indirect + go.opentelemetry.io/otel/sdk v1.38.0 // indirect + go.opentelemetry.io/otel/trace v1.38.0 // indirect + go.opentelemetry.io/proto/otlp v1.7.1 // indirect go.uber.org/mock v0.6.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect @@ -162,8 +171,8 @@ require ( golang.org/x/term v0.36.0 // indirect golang.org/x/text v0.30.0 // indirect google.golang.org/genproto v0.0.0-20250603155806-513f23925822 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20250818200422-3122310a409c // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20250818200422-3122310a409c // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect nhooyr.io/websocket v1.8.17 // indirect pgregory.net/rapid v1.2.0 // indirect diff --git a/client/v2/go.sum b/client/v2/go.sum index 2a11b57d4188..58676ed6c45a 100644 --- a/client/v2/go.sum +++ b/client/v2/go.sum @@ -89,6 +89,8 @@ github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QH github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM= +github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= @@ -354,6 +356,8 @@ github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgf github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 h1:8Tjv8EJ+pM1xP8mK6egEbD1OgnVTyacbefKhmbLhIhU= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2/go.mod h1:pkJQ2tZHJ0aFOVEEot6oZmaVEZcRme73eIFmhiVuRWs= github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c h1:6rhixN/i8ZofjG1Y75iExal34USq5p+wiN1tpie8IrU= github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c/go.mod h1:NMPJylDgVpX0MLRlPy15sqSwOFv/U1GZ2m21JhFfek0= github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE= @@ -714,17 +718,27 @@ go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= -go.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ= -go.opentelemetry.io/otel v1.37.0/go.mod h1:ehE/umFRLnuLa/vSccNq9oS1ErUlkkK71gMcN34UG8I= -go.opentelemetry.io/otel/metric v1.37.0 h1:mvwbQS5m0tbmqML4NqK+e3aDiO02vsf/WgbsdpcPoZE= -go.opentelemetry.io/otel/metric v1.37.0/go.mod h1:04wGrZurHYKOc+RKeye86GwKiTb9FKm1WHtO+4EVr2E= -go.opentelemetry.io/otel/sdk v1.37.0 h1:ItB0QUqnjesGRvNcmAcU0LyvkVyGJ2xftD29bWdDvKI= -go.opentelemetry.io/otel/sdk v1.37.0/go.mod h1:VredYzxUvuo2q3WRcDnKDjbdvmO0sCzOvVAiY+yUkAg= -go.opentelemetry.io/otel/sdk/metric v1.37.0 h1:90lI228XrB9jCMuSdA0673aubgRobVZFhbjxHHspCPc= -go.opentelemetry.io/otel/sdk/metric v1.37.0/go.mod h1:cNen4ZWfiD37l5NhS+Keb5RXVWZWpRE+9WyVCpbo5ps= -go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4= -go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0= +go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= +go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 h1:GqRJVj7UmLjCVyVJ3ZFLdPRmhDUp2zFmQe3RHIOsw24= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0/go.mod h1:ri3aaHSmCTVYu2AWv44YMauwAQc0aqI9gHKIcSbI1pU= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.37.0 h1:EtFWSnwW9hGObjkIdmlnWSydO+Qs8OwzfzXLUPg4xOc= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.37.0/go.mod h1:QjUEoiGCPkvFZ/MjK6ZZfNOS6mfVEVKYE99dFhuN2LI= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0 h1:aTL7F04bJHUlztTsNGJ2l+6he8c+y/b//eR0jjjemT4= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0/go.mod h1:kldtb7jDTeol0l3ewcmd8SDvx3EmIE7lyvqbasU3QC4= +go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.38.0 h1:kJxSDN4SgWWTjG/hPp3O7LCGLcHXFlvS2/FFOrwL+SE= +go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.38.0/go.mod h1:mgIOzS7iZeKJdeB8/NYHrJ48fdGc71Llo5bJ1J4DWUE= +go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= +go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= +go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E= +go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg= +go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM= +go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA= +go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= +go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= +go.opentelemetry.io/proto/otlp v1.7.1 h1:gTOMpGDb0WTBOP8JaO72iL3auEZhVmAQg4ipjOVAtj4= +go.opentelemetry.io/proto/otlp v1.7.1/go.mod h1:b2rVh6rfI/s2pHWNlB7ILJcRALpcNDzKhACevjI+ZnE= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= @@ -935,10 +949,10 @@ google.golang.org/genproto v0.0.0-20210126160654-44e461bb6506/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20220314164441-57ef72a4c106/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E= google.golang.org/genproto v0.0.0-20250603155806-513f23925822 h1:rHWScKit0gvAPuOnu87KpaYtjK5zBMLcULh7gxkCXu4= google.golang.org/genproto v0.0.0-20250603155806-513f23925822/go.mod h1:HubltRL7rMh0LfnQPkMH4NPDFEWp0jw3vixw7jEM53s= -google.golang.org/genproto/googleapis/api v0.0.0-20250818200422-3122310a409c h1:AtEkQdl5b6zsybXcbz00j1LwNodDuH6hVifIaNqk7NQ= -google.golang.org/genproto/googleapis/api v0.0.0-20250818200422-3122310a409c/go.mod h1:ea2MjsO70ssTfCjiwHgI0ZFqcw45Ksuk2ckf9G468GA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250818200422-3122310a409c h1:qXWI/sQtv5UKboZ/zUk7h+mrf/lXORyI+n9DKDAusdg= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250818200422-3122310a409c/go.mod h1:gw1tLEfykwDz2ET4a12jcXt4couGAm7IwsVaTy0Sflo= +google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5 h1:BIRfGDEjiHRrk0QKZe3Xv2ieMhtgRGeLcZQ0mIVn4EY= +google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5/go.mod h1:j3QtIyytwqGr1JUDtYXwtMXWPKsEa5LtzIFN1Wn5WvE= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5 h1:eaY8u2EuxbRv7c3NiGK0/NedzVsCcV6hDuU5qPX5EGE= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5/go.mod h1:M4/wBTSeyLxupu3W3tJtOgB14jILAS/XWPSSa3TAlJc= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM= diff --git a/simapp/go.mod b/simapp/go.mod index ec751f171381..167548375072 100644 --- a/simapp/go.mod +++ b/simapp/go.mod @@ -72,6 +72,7 @@ require ( github.com/bytedance/sonic v1.14.2 // indirect github.com/bytedance/sonic/loader v0.4.0 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect + github.com/cenkalti/backoff/v5 v5.0.3 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/chzyer/readline v1.5.1 // indirect github.com/cloudwego/base64x v0.1.6 // indirect @@ -133,6 +134,7 @@ require ( github.com/gorilla/websocket v1.5.3 // indirect github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 // indirect github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect github.com/hashicorp/aws-sdk-go-base/v2 v2.0.0-beta.65 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect @@ -201,11 +203,16 @@ require ( go.opentelemetry.io/contrib/detectors/gcp v1.36.0 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0 // indirect - go.opentelemetry.io/otel v1.37.0 // indirect - go.opentelemetry.io/otel/metric v1.37.0 // indirect - go.opentelemetry.io/otel/sdk v1.37.0 // indirect - go.opentelemetry.io/otel/sdk/metric v1.37.0 // indirect - go.opentelemetry.io/otel/trace v1.37.0 // indirect + go.opentelemetry.io/otel v1.38.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.37.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0 // indirect + go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.38.0 // indirect + go.opentelemetry.io/otel/metric v1.38.0 // indirect + go.opentelemetry.io/otel/sdk v1.38.0 // indirect + go.opentelemetry.io/otel/sdk/metric v1.38.0 // indirect + go.opentelemetry.io/otel/trace v1.38.0 // indirect + go.opentelemetry.io/proto/otlp v1.7.1 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect go.yaml.in/yaml/v2 v2.4.3 // indirect @@ -222,8 +229,8 @@ require ( golang.org/x/time v0.13.0 // indirect google.golang.org/api v0.247.0 // indirect google.golang.org/genproto v0.0.0-20250603155806-513f23925822 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20250818200422-3122310a409c // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20250818200422-3122310a409c // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5 // indirect google.golang.org/grpc v1.76.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect gotest.tools/v3 v3.5.2 // indirect @@ -233,9 +240,7 @@ require ( sigs.k8s.io/yaml v1.6.0 // indirect ) -replace ( - cosmossdk.io/log => ../log -) +replace cosmossdk.io/log => ../log // Below are the long-lived replace of the SimApp replace ( diff --git a/simapp/go.sum b/simapp/go.sum index 5d1407fd10c2..462724459d82 100644 --- a/simapp/go.sum +++ b/simapp/go.sum @@ -34,8 +34,6 @@ cosmossdk.io/depinject v1.2.1 h1:eD6FxkIjlVaNZT+dXTQuwQTKZrFZ4UrfCq1RKgzyhMw= cosmossdk.io/depinject v1.2.1/go.mod h1:lqQEycz0H2JXqvOgVwTsjEdMI0plswI7p6KX+MVqFOM= cosmossdk.io/errors v1.0.2 h1:wcYiJz08HThbWxd/L4jObeLaLySopyyuUFB5w4AGpCo= cosmossdk.io/errors v1.0.2/go.mod h1:0rjgiHkftRYPj//3DrD6y8hcm40HcPv/dR4R/4efr0k= -cosmossdk.io/log v1.6.1 h1:YXNwAgbDwMEKwDlCdH8vPcoggma48MgZrTQXCfmMBeI= -cosmossdk.io/log v1.6.1/go.mod h1:gMwsWyyDBjpdG9u2avCFdysXqxq28WJapJvu+vF1y+E= cosmossdk.io/math v1.5.3 h1:WH6tu6Z3AUCeHbeOSHg2mt9rnoiUWVWaQ2t6Gkll96U= cosmossdk.io/math v1.5.3/go.mod h1:uqcZv7vexnhMFJF+6zh9EWdm/+Ylyln34IvPnBauPCQ= cosmossdk.io/schema v1.1.0 h1:mmpuz3dzouCoyjjcMcA/xHBEmMChN+EHh8EHxHRHhzE= @@ -163,6 +161,8 @@ github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QH github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM= +github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= @@ -457,6 +457,8 @@ github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgf github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 h1:8Tjv8EJ+pM1xP8mK6egEbD1OgnVTyacbefKhmbLhIhU= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2/go.mod h1:pkJQ2tZHJ0aFOVEEot6oZmaVEZcRme73eIFmhiVuRWs= github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c h1:6rhixN/i8ZofjG1Y75iExal34USq5p+wiN1tpie8IrU= github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c/go.mod h1:NMPJylDgVpX0MLRlPy15sqSwOFv/U1GZ2m21JhFfek0= github.com/hashicorp/aws-sdk-go-base/v2 v2.0.0-beta.65 h1:81+kWbE1yErFBMjME0I5k3x3kojjKsWtPYHEAutoPow= @@ -845,19 +847,29 @@ go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.6 go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0/go.mod h1:snMWehoOh2wsEwnvvwtDyFCxVeDAODenXHtn5vzrKjo= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0 h1:Hf9xI/XLML9ElpiHVDNwvqI0hIFlzV8dgIr35kV1kRU= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0/go.mod h1:NfchwuyNoMcZ5MLHwPrODwUF1HWCXWrL31s8gSAdIKY= -go.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ= -go.opentelemetry.io/otel v1.37.0/go.mod h1:ehE/umFRLnuLa/vSccNq9oS1ErUlkkK71gMcN34UG8I= +go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= +go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 h1:GqRJVj7UmLjCVyVJ3ZFLdPRmhDUp2zFmQe3RHIOsw24= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0/go.mod h1:ri3aaHSmCTVYu2AWv44YMauwAQc0aqI9gHKIcSbI1pU= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.37.0 h1:EtFWSnwW9hGObjkIdmlnWSydO+Qs8OwzfzXLUPg4xOc= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.37.0/go.mod h1:QjUEoiGCPkvFZ/MjK6ZZfNOS6mfVEVKYE99dFhuN2LI= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0 h1:aTL7F04bJHUlztTsNGJ2l+6he8c+y/b//eR0jjjemT4= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0/go.mod h1:kldtb7jDTeol0l3ewcmd8SDvx3EmIE7lyvqbasU3QC4= go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.36.0 h1:rixTyDGXFxRy1xzhKrotaHy3/KXdPhlWARrCgK+eqUY= go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.36.0/go.mod h1:dowW6UsM9MKbJq5JTz2AMVp3/5iW5I/TStsk8S+CfHw= -go.opentelemetry.io/otel/metric v1.37.0 h1:mvwbQS5m0tbmqML4NqK+e3aDiO02vsf/WgbsdpcPoZE= -go.opentelemetry.io/otel/metric v1.37.0/go.mod h1:04wGrZurHYKOc+RKeye86GwKiTb9FKm1WHtO+4EVr2E= -go.opentelemetry.io/otel/sdk v1.37.0 h1:ItB0QUqnjesGRvNcmAcU0LyvkVyGJ2xftD29bWdDvKI= -go.opentelemetry.io/otel/sdk v1.37.0/go.mod h1:VredYzxUvuo2q3WRcDnKDjbdvmO0sCzOvVAiY+yUkAg= -go.opentelemetry.io/otel/sdk/metric v1.37.0 h1:90lI228XrB9jCMuSdA0673aubgRobVZFhbjxHHspCPc= -go.opentelemetry.io/otel/sdk/metric v1.37.0/go.mod h1:cNen4ZWfiD37l5NhS+Keb5RXVWZWpRE+9WyVCpbo5ps= -go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4= -go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0= +go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.38.0 h1:kJxSDN4SgWWTjG/hPp3O7LCGLcHXFlvS2/FFOrwL+SE= +go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.38.0/go.mod h1:mgIOzS7iZeKJdeB8/NYHrJ48fdGc71Llo5bJ1J4DWUE= +go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= +go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= +go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E= +go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg= +go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM= +go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA= +go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= +go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= +go.opentelemetry.io/proto/otlp v1.7.1 h1:gTOMpGDb0WTBOP8JaO72iL3auEZhVmAQg4ipjOVAtj4= +go.opentelemetry.io/proto/otlp v1.7.1/go.mod h1:b2rVh6rfI/s2pHWNlB7ILJcRALpcNDzKhACevjI+ZnE= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= @@ -1097,10 +1109,10 @@ google.golang.org/genproto v0.0.0-20210126160654-44e461bb6506/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20220314164441-57ef72a4c106/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E= google.golang.org/genproto v0.0.0-20250603155806-513f23925822 h1:rHWScKit0gvAPuOnu87KpaYtjK5zBMLcULh7gxkCXu4= google.golang.org/genproto v0.0.0-20250603155806-513f23925822/go.mod h1:HubltRL7rMh0LfnQPkMH4NPDFEWp0jw3vixw7jEM53s= -google.golang.org/genproto/googleapis/api v0.0.0-20250818200422-3122310a409c h1:AtEkQdl5b6zsybXcbz00j1LwNodDuH6hVifIaNqk7NQ= -google.golang.org/genproto/googleapis/api v0.0.0-20250818200422-3122310a409c/go.mod h1:ea2MjsO70ssTfCjiwHgI0ZFqcw45Ksuk2ckf9G468GA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250818200422-3122310a409c h1:qXWI/sQtv5UKboZ/zUk7h+mrf/lXORyI+n9DKDAusdg= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250818200422-3122310a409c/go.mod h1:gw1tLEfykwDz2ET4a12jcXt4couGAm7IwsVaTy0Sflo= +google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5 h1:BIRfGDEjiHRrk0QKZe3Xv2ieMhtgRGeLcZQ0mIVn4EY= +google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5/go.mod h1:j3QtIyytwqGr1JUDtYXwtMXWPKsEa5LtzIFN1Wn5WvE= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5 h1:eaY8u2EuxbRv7c3NiGK0/NedzVsCcV6hDuU5qPX5EGE= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5/go.mod h1:M4/wBTSeyLxupu3W3tJtOgB14jILAS/XWPSSa3TAlJc= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM= diff --git a/systemtests/go.mod b/systemtests/go.mod index f8ed7b71fed4..8fd0c16fb18a 100644 --- a/systemtests/go.mod +++ b/systemtests/go.mod @@ -34,6 +34,7 @@ require ( github.com/bytedance/sonic v1.14.2 // indirect github.com/bytedance/sonic/loader v0.4.0 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect + github.com/cenkalti/backoff/v5 v5.0.3 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/cloudwego/base64x v0.1.6 // indirect github.com/cockroachdb/errors v1.12.0 // indirect @@ -80,11 +81,13 @@ require ( github.com/google/flatbuffers v25.2.10+incompatible // indirect github.com/google/go-cmp v0.7.0 // indirect github.com/google/orderedcode v0.0.1 // indirect + github.com/google/uuid v1.6.0 // indirect github.com/gorilla/handlers v1.5.2 // indirect github.com/gorilla/mux v1.8.1 // indirect github.com/gorilla/websocket v1.5.3 // indirect github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 // indirect github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect github.com/hashicorp/go-hclog v1.6.3 // indirect github.com/hashicorp/go-immutable-radix v1.3.1 // indirect @@ -145,9 +148,15 @@ require ( github.com/zondax/ledger-go v1.0.1 // indirect go.etcd.io/bbolt v1.4.0 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect - go.opentelemetry.io/otel v1.37.0 // indirect - go.opentelemetry.io/otel/metric v1.37.0 // indirect - go.opentelemetry.io/otel/trace v1.37.0 // indirect + go.opentelemetry.io/otel v1.38.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.37.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0 // indirect + go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.38.0 // indirect + go.opentelemetry.io/otel/metric v1.38.0 // indirect + go.opentelemetry.io/otel/sdk v1.38.0 // indirect + go.opentelemetry.io/otel/trace v1.38.0 // indirect + go.opentelemetry.io/proto/otlp v1.7.1 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect go.yaml.in/yaml/v2 v2.4.3 // indirect @@ -161,8 +170,8 @@ require ( golang.org/x/term v0.36.0 // indirect golang.org/x/text v0.30.0 // indirect google.golang.org/genproto v0.0.0-20250603155806-513f23925822 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20250818200422-3122310a409c // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20250818200422-3122310a409c // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5 // indirect google.golang.org/protobuf v1.36.10 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect gotest.tools/v3 v3.5.2 // indirect diff --git a/systemtests/go.sum b/systemtests/go.sum index 4cfa4ee4d84e..ae9b36f2df21 100644 --- a/systemtests/go.sum +++ b/systemtests/go.sum @@ -91,6 +91,8 @@ github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QH github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM= +github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= @@ -354,6 +356,8 @@ github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgf github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 h1:8Tjv8EJ+pM1xP8mK6egEbD1OgnVTyacbefKhmbLhIhU= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2/go.mod h1:pkJQ2tZHJ0aFOVEEot6oZmaVEZcRme73eIFmhiVuRWs= github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c h1:6rhixN/i8ZofjG1Y75iExal34USq5p+wiN1tpie8IrU= github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c/go.mod h1:NMPJylDgVpX0MLRlPy15sqSwOFv/U1GZ2m21JhFfek0= github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE= @@ -723,17 +727,27 @@ go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= -go.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ= -go.opentelemetry.io/otel v1.37.0/go.mod h1:ehE/umFRLnuLa/vSccNq9oS1ErUlkkK71gMcN34UG8I= -go.opentelemetry.io/otel/metric v1.37.0 h1:mvwbQS5m0tbmqML4NqK+e3aDiO02vsf/WgbsdpcPoZE= -go.opentelemetry.io/otel/metric v1.37.0/go.mod h1:04wGrZurHYKOc+RKeye86GwKiTb9FKm1WHtO+4EVr2E= -go.opentelemetry.io/otel/sdk v1.37.0 h1:ItB0QUqnjesGRvNcmAcU0LyvkVyGJ2xftD29bWdDvKI= -go.opentelemetry.io/otel/sdk v1.37.0/go.mod h1:VredYzxUvuo2q3WRcDnKDjbdvmO0sCzOvVAiY+yUkAg= -go.opentelemetry.io/otel/sdk/metric v1.37.0 h1:90lI228XrB9jCMuSdA0673aubgRobVZFhbjxHHspCPc= -go.opentelemetry.io/otel/sdk/metric v1.37.0/go.mod h1:cNen4ZWfiD37l5NhS+Keb5RXVWZWpRE+9WyVCpbo5ps= -go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4= -go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0= +go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= +go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 h1:GqRJVj7UmLjCVyVJ3ZFLdPRmhDUp2zFmQe3RHIOsw24= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0/go.mod h1:ri3aaHSmCTVYu2AWv44YMauwAQc0aqI9gHKIcSbI1pU= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.37.0 h1:EtFWSnwW9hGObjkIdmlnWSydO+Qs8OwzfzXLUPg4xOc= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.37.0/go.mod h1:QjUEoiGCPkvFZ/MjK6ZZfNOS6mfVEVKYE99dFhuN2LI= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0 h1:aTL7F04bJHUlztTsNGJ2l+6he8c+y/b//eR0jjjemT4= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0/go.mod h1:kldtb7jDTeol0l3ewcmd8SDvx3EmIE7lyvqbasU3QC4= +go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.38.0 h1:kJxSDN4SgWWTjG/hPp3O7LCGLcHXFlvS2/FFOrwL+SE= +go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.38.0/go.mod h1:mgIOzS7iZeKJdeB8/NYHrJ48fdGc71Llo5bJ1J4DWUE= +go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= +go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= +go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E= +go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg= +go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM= +go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA= +go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= +go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= +go.opentelemetry.io/proto/otlp v1.7.1 h1:gTOMpGDb0WTBOP8JaO72iL3auEZhVmAQg4ipjOVAtj4= +go.opentelemetry.io/proto/otlp v1.7.1/go.mod h1:b2rVh6rfI/s2pHWNlB7ILJcRALpcNDzKhACevjI+ZnE= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= @@ -943,10 +957,10 @@ google.golang.org/genproto v0.0.0-20210126160654-44e461bb6506/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20220314164441-57ef72a4c106/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E= google.golang.org/genproto v0.0.0-20250603155806-513f23925822 h1:rHWScKit0gvAPuOnu87KpaYtjK5zBMLcULh7gxkCXu4= google.golang.org/genproto v0.0.0-20250603155806-513f23925822/go.mod h1:HubltRL7rMh0LfnQPkMH4NPDFEWp0jw3vixw7jEM53s= -google.golang.org/genproto/googleapis/api v0.0.0-20250818200422-3122310a409c h1:AtEkQdl5b6zsybXcbz00j1LwNodDuH6hVifIaNqk7NQ= -google.golang.org/genproto/googleapis/api v0.0.0-20250818200422-3122310a409c/go.mod h1:ea2MjsO70ssTfCjiwHgI0ZFqcw45Ksuk2ckf9G468GA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250818200422-3122310a409c h1:qXWI/sQtv5UKboZ/zUk7h+mrf/lXORyI+n9DKDAusdg= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250818200422-3122310a409c/go.mod h1:gw1tLEfykwDz2ET4a12jcXt4couGAm7IwsVaTy0Sflo= +google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5 h1:BIRfGDEjiHRrk0QKZe3Xv2ieMhtgRGeLcZQ0mIVn4EY= +google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5/go.mod h1:j3QtIyytwqGr1JUDtYXwtMXWPKsEa5LtzIFN1Wn5WvE= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5 h1:eaY8u2EuxbRv7c3NiGK0/NedzVsCcV6hDuU5qPX5EGE= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5/go.mod h1:M4/wBTSeyLxupu3W3tJtOgB14jILAS/XWPSSa3TAlJc= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM= diff --git a/telemetry/metrics.go b/telemetry/metrics.go index 405bb3bc7a59..e20ecf600058 100644 --- a/telemetry/metrics.go +++ b/telemetry/metrics.go @@ -311,7 +311,7 @@ func (m *Metrics) TraceProvider() log.TraceProvider { // Use this when you specifically want to configure a code path to only emit metrics // and not actual logging spans (useful for benchmarking small operations such as store operations). func (m *Metrics) MetricsTraceProvider() log.TraceProvider { - return m.traceProvider + return m.metricsTraceProvider } // Start starts all configured exporters. diff --git a/telemetry/metrics_span.go b/telemetry/metrics_span.go index 48675b4e9af3..933c5948c323 100644 --- a/telemetry/metrics_span.go +++ b/telemetry/metrics_span.go @@ -25,7 +25,7 @@ func (m *MetricsTraceProvider) startSpan(existingPath []string, operation string path[len(path)-1] = operation return &MetricsSpan{ MetricsTraceProvider: m, - path: []string{operation}, + path: path, start: time.Now(), } } @@ -35,11 +35,11 @@ func (m *MetricsTraceProvider) StartSpan(operation string, _ ...any) log.Span { } func (m *MetricsTraceProvider) StartSpanContext(ctx context.Context, operation string, kvs ...any) (context.Context, log.Span) { - return ctx, m.StartSpan(operation, kvs...) + return ctx, m.startSpan(m.rootPath, operation) } func (m *MetricsTraceProvider) StartRootSpan(ctx context.Context, operation string, kvs ...any) (context.Context, log.Span) { - return ctx, m.StartSpan(operation, kvs...) + return ctx, m.startSpan(m.rootPath, operation) } var _ log.TraceProvider = (*MetricsTraceProvider)(nil) @@ -64,29 +64,6 @@ type MetricsSpan struct { path []string } -// NewMetricsTracer creates a new MetricsSpan that acts as a root tracer. -// The rootPath defines the base metric name. If empty, metrics start from the root. -// The rootLabels are applied to all metrics emitted by this tracer and its children. -// -// Example: -// -// labels := []metrics.Label{{Name: "module", Value: "staking"}} -// tracer := NewMetricsTracer(metrics, []string{"app", "tx"}, labels) -// span := tracer.StartSpan("validate") -// defer span.End() -// // Emits: "app.tx.validate.time" and "app.tx.validate.count" with module=staking label -func NewMetricsTracer(m *metrics.Metrics, rootPath []string, rootLabels []metrics.Label) *MetricsSpan { - return &MetricsSpan{ - MetricsTraceProvider: &MetricsTraceProvider{ - metrics: m, - rootPath: rootPath, - rootLabels: rootLabels, - }, - path: rootPath, - start: time.Now(), - } -} - // Logger methods are no-ops - MetricsSpan does not support logging. func (m *MetricsSpan) Info(msg string, keyVals ...any) {} func (m *MetricsSpan) Warn(msg string, keyVals ...any) {} diff --git a/telemetry/otel_span.go b/telemetry/otel_span.go index 4b323105f9cb..e7c6aea9231f 100644 --- a/telemetry/otel_span.go +++ b/telemetry/otel_span.go @@ -11,17 +11,17 @@ import ( "cosmossdk.io/log" ) -type OtelTracerBase struct { +type OtelTraceProvider struct { tracer oteltrace.Tracer } -func NewOtelTraceProvider(tracer oteltrace.Tracer) *OtelTracerBase { - return &OtelTracerBase{ +func NewOtelTraceProvider(tracer oteltrace.Tracer) *OtelTraceProvider { + return &OtelTraceProvider{ tracer: tracer, } } -func (o *OtelTracerBase) StartSpan(operation string, kvs ...any) log.Span { +func (o *OtelTraceProvider) StartSpan(operation string, kvs ...any) log.Span { ctx, span := o.tracer.Start(context.Background(), operation, oteltrace.WithAttributes(toKVs(kvs)...)) return &OtelSpan{ tracer: o.tracer, @@ -30,7 +30,7 @@ func (o *OtelTracerBase) StartSpan(operation string, kvs ...any) log.Span { } } -func (o *OtelTracerBase) StartSpanContext(ctx context.Context, operation string, kvs ...any) (context.Context, log.Span) { +func (o *OtelTraceProvider) StartSpanContext(ctx context.Context, operation string, kvs ...any) (context.Context, log.Span) { ctx, span := o.tracer.Start(ctx, operation, oteltrace.WithAttributes(toKVs(kvs)...)) return ctx, &OtelSpan{ tracer: o.tracer, @@ -39,7 +39,7 @@ func (o *OtelTracerBase) StartSpanContext(ctx context.Context, operation string, } } -func (o *OtelTracerBase) StartRootSpan(ctx context.Context, operation string, kvs ...any) (context.Context, log.Span) { +func (o *OtelTraceProvider) StartRootSpan(ctx context.Context, operation string, kvs ...any) (context.Context, log.Span) { ctx, span := o.tracer.Start(ctx, operation, oteltrace.WithAttributes(toKVs(kvs)...), oteltrace.WithNewRoot()) return ctx, &OtelSpan{ tracer: o.tracer, @@ -48,7 +48,7 @@ func (o *OtelTracerBase) StartRootSpan(ctx context.Context, operation string, kv } } -var _ log.TraceProvider = (*OtelTracerBase)(nil) +var _ log.TraceProvider = (*OtelTraceProvider)(nil) type OtelSpan struct { tracer oteltrace.Tracer diff --git a/tests/go.mod b/tests/go.mod index 8c13fa6ff2f4..fff27db9c449 100644 --- a/tests/go.mod +++ b/tests/go.mod @@ -75,6 +75,7 @@ require ( github.com/bytedance/sonic v1.14.2 // indirect github.com/bytedance/sonic/loader v0.4.0 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect + github.com/cenkalti/backoff/v5 v5.0.3 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/chzyer/readline v1.5.1 // indirect github.com/cloudwego/base64x v0.1.6 // indirect @@ -132,6 +133,7 @@ require ( github.com/gorilla/websocket v1.5.3 // indirect github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 // indirect github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect github.com/hashicorp/aws-sdk-go-base/v2 v2.0.0-beta.65 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect @@ -201,11 +203,16 @@ require ( go.opentelemetry.io/contrib/detectors/gcp v1.36.0 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0 // indirect - go.opentelemetry.io/otel v1.37.0 // indirect - go.opentelemetry.io/otel/metric v1.37.0 // indirect - go.opentelemetry.io/otel/sdk v1.37.0 // indirect - go.opentelemetry.io/otel/sdk/metric v1.37.0 // indirect - go.opentelemetry.io/otel/trace v1.37.0 // indirect + go.opentelemetry.io/otel v1.38.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.37.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0 // indirect + go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.38.0 // indirect + go.opentelemetry.io/otel/metric v1.38.0 // indirect + go.opentelemetry.io/otel/sdk v1.38.0 // indirect + go.opentelemetry.io/otel/sdk/metric v1.38.0 // indirect + go.opentelemetry.io/otel/trace v1.38.0 // indirect + go.opentelemetry.io/proto/otlp v1.7.1 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect go.yaml.in/yaml/v2 v2.4.3 // indirect @@ -222,8 +229,8 @@ require ( golang.org/x/time v0.13.0 // indirect google.golang.org/api v0.247.0 // indirect google.golang.org/genproto v0.0.0-20250603155806-513f23925822 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20250818200422-3122310a409c // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20250818200422-3122310a409c // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect nhooyr.io/websocket v1.8.17 // indirect sigs.k8s.io/yaml v1.6.0 // indirect diff --git a/tests/go.sum b/tests/go.sum index 416fb05e6ede..b7404e7f61e8 100644 --- a/tests/go.sum +++ b/tests/go.sum @@ -161,6 +161,8 @@ github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QH github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM= +github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= @@ -452,6 +454,8 @@ github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgf github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 h1:8Tjv8EJ+pM1xP8mK6egEbD1OgnVTyacbefKhmbLhIhU= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2/go.mod h1:pkJQ2tZHJ0aFOVEEot6oZmaVEZcRme73eIFmhiVuRWs= github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c h1:6rhixN/i8ZofjG1Y75iExal34USq5p+wiN1tpie8IrU= github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c/go.mod h1:NMPJylDgVpX0MLRlPy15sqSwOFv/U1GZ2m21JhFfek0= github.com/hashicorp/aws-sdk-go-base/v2 v2.0.0-beta.65 h1:81+kWbE1yErFBMjME0I5k3x3kojjKsWtPYHEAutoPow= @@ -844,19 +848,29 @@ go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.6 go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0/go.mod h1:snMWehoOh2wsEwnvvwtDyFCxVeDAODenXHtn5vzrKjo= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0 h1:Hf9xI/XLML9ElpiHVDNwvqI0hIFlzV8dgIr35kV1kRU= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0/go.mod h1:NfchwuyNoMcZ5MLHwPrODwUF1HWCXWrL31s8gSAdIKY= -go.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ= -go.opentelemetry.io/otel v1.37.0/go.mod h1:ehE/umFRLnuLa/vSccNq9oS1ErUlkkK71gMcN34UG8I= +go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= +go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 h1:GqRJVj7UmLjCVyVJ3ZFLdPRmhDUp2zFmQe3RHIOsw24= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0/go.mod h1:ri3aaHSmCTVYu2AWv44YMauwAQc0aqI9gHKIcSbI1pU= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.37.0 h1:EtFWSnwW9hGObjkIdmlnWSydO+Qs8OwzfzXLUPg4xOc= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.37.0/go.mod h1:QjUEoiGCPkvFZ/MjK6ZZfNOS6mfVEVKYE99dFhuN2LI= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0 h1:aTL7F04bJHUlztTsNGJ2l+6he8c+y/b//eR0jjjemT4= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0/go.mod h1:kldtb7jDTeol0l3ewcmd8SDvx3EmIE7lyvqbasU3QC4= go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.36.0 h1:rixTyDGXFxRy1xzhKrotaHy3/KXdPhlWARrCgK+eqUY= go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.36.0/go.mod h1:dowW6UsM9MKbJq5JTz2AMVp3/5iW5I/TStsk8S+CfHw= -go.opentelemetry.io/otel/metric v1.37.0 h1:mvwbQS5m0tbmqML4NqK+e3aDiO02vsf/WgbsdpcPoZE= -go.opentelemetry.io/otel/metric v1.37.0/go.mod h1:04wGrZurHYKOc+RKeye86GwKiTb9FKm1WHtO+4EVr2E= -go.opentelemetry.io/otel/sdk v1.37.0 h1:ItB0QUqnjesGRvNcmAcU0LyvkVyGJ2xftD29bWdDvKI= -go.opentelemetry.io/otel/sdk v1.37.0/go.mod h1:VredYzxUvuo2q3WRcDnKDjbdvmO0sCzOvVAiY+yUkAg= -go.opentelemetry.io/otel/sdk/metric v1.37.0 h1:90lI228XrB9jCMuSdA0673aubgRobVZFhbjxHHspCPc= -go.opentelemetry.io/otel/sdk/metric v1.37.0/go.mod h1:cNen4ZWfiD37l5NhS+Keb5RXVWZWpRE+9WyVCpbo5ps= -go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4= -go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0= +go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.38.0 h1:kJxSDN4SgWWTjG/hPp3O7LCGLcHXFlvS2/FFOrwL+SE= +go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.38.0/go.mod h1:mgIOzS7iZeKJdeB8/NYHrJ48fdGc71Llo5bJ1J4DWUE= +go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= +go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= +go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E= +go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg= +go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM= +go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA= +go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= +go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= +go.opentelemetry.io/proto/otlp v1.7.1 h1:gTOMpGDb0WTBOP8JaO72iL3auEZhVmAQg4ipjOVAtj4= +go.opentelemetry.io/proto/otlp v1.7.1/go.mod h1:b2rVh6rfI/s2pHWNlB7ILJcRALpcNDzKhACevjI+ZnE= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= @@ -1100,10 +1114,10 @@ google.golang.org/genproto v0.0.0-20210126160654-44e461bb6506/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20220314164441-57ef72a4c106/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E= google.golang.org/genproto v0.0.0-20250603155806-513f23925822 h1:rHWScKit0gvAPuOnu87KpaYtjK5zBMLcULh7gxkCXu4= google.golang.org/genproto v0.0.0-20250603155806-513f23925822/go.mod h1:HubltRL7rMh0LfnQPkMH4NPDFEWp0jw3vixw7jEM53s= -google.golang.org/genproto/googleapis/api v0.0.0-20250818200422-3122310a409c h1:AtEkQdl5b6zsybXcbz00j1LwNodDuH6hVifIaNqk7NQ= -google.golang.org/genproto/googleapis/api v0.0.0-20250818200422-3122310a409c/go.mod h1:ea2MjsO70ssTfCjiwHgI0ZFqcw45Ksuk2ckf9G468GA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250818200422-3122310a409c h1:qXWI/sQtv5UKboZ/zUk7h+mrf/lXORyI+n9DKDAusdg= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250818200422-3122310a409c/go.mod h1:gw1tLEfykwDz2ET4a12jcXt4couGAm7IwsVaTy0Sflo= +google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5 h1:BIRfGDEjiHRrk0QKZe3Xv2ieMhtgRGeLcZQ0mIVn4EY= +google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5/go.mod h1:j3QtIyytwqGr1JUDtYXwtMXWPKsEa5LtzIFN1Wn5WvE= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5 h1:eaY8u2EuxbRv7c3NiGK0/NedzVsCcV6hDuU5qPX5EGE= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5/go.mod h1:M4/wBTSeyLxupu3W3tJtOgB14jILAS/XWPSSa3TAlJc= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM= diff --git a/tests/systemtests/go.mod b/tests/systemtests/go.mod index d91bf94d9312..7c9b858c29da 100644 --- a/tests/systemtests/go.mod +++ b/tests/systemtests/go.mod @@ -38,6 +38,7 @@ require ( github.com/bytedance/sonic v1.14.2 // indirect github.com/bytedance/sonic/loader v0.4.0 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect + github.com/cenkalti/backoff/v5 v5.0.3 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/cloudwego/base64x v0.1.6 // indirect github.com/cockroachdb/errors v1.12.0 // indirect @@ -86,11 +87,13 @@ require ( github.com/google/flatbuffers v25.2.10+incompatible // indirect github.com/google/go-cmp v0.7.0 // indirect github.com/google/orderedcode v0.0.1 // indirect + github.com/google/uuid v1.6.0 // indirect github.com/gorilla/handlers v1.5.2 // indirect github.com/gorilla/mux v1.8.1 // indirect github.com/gorilla/websocket v1.5.3 // indirect github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 // indirect github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect github.com/hashicorp/go-hclog v1.6.3 // indirect github.com/hashicorp/go-immutable-radix v1.3.1 // indirect @@ -151,9 +154,15 @@ require ( github.com/zondax/ledger-go v1.0.1 // indirect go.etcd.io/bbolt v1.4.0 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect - go.opentelemetry.io/otel v1.37.0 // indirect - go.opentelemetry.io/otel/metric v1.37.0 // indirect - go.opentelemetry.io/otel/trace v1.37.0 // indirect + go.opentelemetry.io/otel v1.38.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.37.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0 // indirect + go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.38.0 // indirect + go.opentelemetry.io/otel/metric v1.38.0 // indirect + go.opentelemetry.io/otel/sdk v1.38.0 // indirect + go.opentelemetry.io/otel/trace v1.38.0 // indirect + go.opentelemetry.io/proto/otlp v1.7.1 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect go.yaml.in/yaml/v2 v2.4.3 // indirect @@ -167,8 +176,8 @@ require ( golang.org/x/term v0.36.0 // indirect golang.org/x/text v0.30.0 // indirect google.golang.org/genproto v0.0.0-20250603155806-513f23925822 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20250818200422-3122310a409c // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20250818200422-3122310a409c // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5 // indirect google.golang.org/grpc v1.76.0 // indirect google.golang.org/protobuf v1.36.10 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/tests/systemtests/go.sum b/tests/systemtests/go.sum index 90428e129f04..f3ec451282a3 100644 --- a/tests/systemtests/go.sum +++ b/tests/systemtests/go.sum @@ -89,6 +89,8 @@ github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QH github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM= +github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= @@ -352,6 +354,8 @@ github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgf github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 h1:8Tjv8EJ+pM1xP8mK6egEbD1OgnVTyacbefKhmbLhIhU= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2/go.mod h1:pkJQ2tZHJ0aFOVEEot6oZmaVEZcRme73eIFmhiVuRWs= github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c h1:6rhixN/i8ZofjG1Y75iExal34USq5p+wiN1tpie8IrU= github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c/go.mod h1:NMPJylDgVpX0MLRlPy15sqSwOFv/U1GZ2m21JhFfek0= github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE= @@ -721,17 +725,27 @@ go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= -go.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ= -go.opentelemetry.io/otel v1.37.0/go.mod h1:ehE/umFRLnuLa/vSccNq9oS1ErUlkkK71gMcN34UG8I= -go.opentelemetry.io/otel/metric v1.37.0 h1:mvwbQS5m0tbmqML4NqK+e3aDiO02vsf/WgbsdpcPoZE= -go.opentelemetry.io/otel/metric v1.37.0/go.mod h1:04wGrZurHYKOc+RKeye86GwKiTb9FKm1WHtO+4EVr2E= -go.opentelemetry.io/otel/sdk v1.37.0 h1:ItB0QUqnjesGRvNcmAcU0LyvkVyGJ2xftD29bWdDvKI= -go.opentelemetry.io/otel/sdk v1.37.0/go.mod h1:VredYzxUvuo2q3WRcDnKDjbdvmO0sCzOvVAiY+yUkAg= -go.opentelemetry.io/otel/sdk/metric v1.37.0 h1:90lI228XrB9jCMuSdA0673aubgRobVZFhbjxHHspCPc= -go.opentelemetry.io/otel/sdk/metric v1.37.0/go.mod h1:cNen4ZWfiD37l5NhS+Keb5RXVWZWpRE+9WyVCpbo5ps= -go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4= -go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0= +go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= +go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 h1:GqRJVj7UmLjCVyVJ3ZFLdPRmhDUp2zFmQe3RHIOsw24= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0/go.mod h1:ri3aaHSmCTVYu2AWv44YMauwAQc0aqI9gHKIcSbI1pU= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.37.0 h1:EtFWSnwW9hGObjkIdmlnWSydO+Qs8OwzfzXLUPg4xOc= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.37.0/go.mod h1:QjUEoiGCPkvFZ/MjK6ZZfNOS6mfVEVKYE99dFhuN2LI= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0 h1:aTL7F04bJHUlztTsNGJ2l+6he8c+y/b//eR0jjjemT4= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0/go.mod h1:kldtb7jDTeol0l3ewcmd8SDvx3EmIE7lyvqbasU3QC4= +go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.38.0 h1:kJxSDN4SgWWTjG/hPp3O7LCGLcHXFlvS2/FFOrwL+SE= +go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.38.0/go.mod h1:mgIOzS7iZeKJdeB8/NYHrJ48fdGc71Llo5bJ1J4DWUE= +go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= +go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= +go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E= +go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg= +go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM= +go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA= +go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= +go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= +go.opentelemetry.io/proto/otlp v1.7.1 h1:gTOMpGDb0WTBOP8JaO72iL3auEZhVmAQg4ipjOVAtj4= +go.opentelemetry.io/proto/otlp v1.7.1/go.mod h1:b2rVh6rfI/s2pHWNlB7ILJcRALpcNDzKhACevjI+ZnE= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= @@ -941,10 +955,10 @@ google.golang.org/genproto v0.0.0-20210126160654-44e461bb6506/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20220314164441-57ef72a4c106/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E= google.golang.org/genproto v0.0.0-20250603155806-513f23925822 h1:rHWScKit0gvAPuOnu87KpaYtjK5zBMLcULh7gxkCXu4= google.golang.org/genproto v0.0.0-20250603155806-513f23925822/go.mod h1:HubltRL7rMh0LfnQPkMH4NPDFEWp0jw3vixw7jEM53s= -google.golang.org/genproto/googleapis/api v0.0.0-20250818200422-3122310a409c h1:AtEkQdl5b6zsybXcbz00j1LwNodDuH6hVifIaNqk7NQ= -google.golang.org/genproto/googleapis/api v0.0.0-20250818200422-3122310a409c/go.mod h1:ea2MjsO70ssTfCjiwHgI0ZFqcw45Ksuk2ckf9G468GA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250818200422-3122310a409c h1:qXWI/sQtv5UKboZ/zUk7h+mrf/lXORyI+n9DKDAusdg= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250818200422-3122310a409c/go.mod h1:gw1tLEfykwDz2ET4a12jcXt4couGAm7IwsVaTy0Sflo= +google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5 h1:BIRfGDEjiHRrk0QKZe3Xv2ieMhtgRGeLcZQ0mIVn4EY= +google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5/go.mod h1:j3QtIyytwqGr1JUDtYXwtMXWPKsEa5LtzIFN1Wn5WvE= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5 h1:eaY8u2EuxbRv7c3NiGK0/NedzVsCcV6hDuU5qPX5EGE= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5/go.mod h1:M4/wBTSeyLxupu3W3tJtOgB14jILAS/XWPSSa3TAlJc= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM= From bdba035644d3924b9af2fd3b345c8610b9da8761 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Thu, 30 Oct 2025 13:45:26 -0400 Subject: [PATCH 07/52] simapp setup, make tracers wrap loggers --- baseapp/baseapp.go | 4 +- baseapp/test_helpers.go | 8 ++-- log/tracer.go | 34 ++++++++-------- simapp/app_di.go | 41 ++++++++++++++++++- telemetry/config.go | 38 ++++++++--------- telemetry/metrics.go | 86 ++++++++++++++++++--------------------- telemetry/metrics_span.go | 42 ++++++++++--------- telemetry/options.go | 14 +++++++ telemetry/otel_span.go | 19 +++++---- 9 files changed, 169 insertions(+), 117 deletions(-) create mode 100644 telemetry/options.go diff --git a/baseapp/baseapp.go b/baseapp/baseapp.go index 14b42770af07..9de5a9dcaff4 100644 --- a/baseapp/baseapp.go +++ b/baseapp/baseapp.go @@ -191,7 +191,7 @@ func NewBaseApp( // initialize tracer tracer, ok := app.logger.(log.Tracer) if !ok { - tracer = log.NewNopTracer() + tracer = log.NewNopTracer(app.logger) } app.tracer = tracer @@ -992,7 +992,7 @@ func (app *BaseApp) runMsgs(ctx sdk.Context, msgs []sdk.Msg, msgsV2 []protov2.Me // extract the tracer from the context tracer, ok := ctx.Logger().(log.Tracer) if !ok { - tracer = log.NewNopTracer() + tracer = log.NewNopTracer(app.logger) } span := tracer.StartSpan("runMsgs") defer span.End() diff --git a/baseapp/test_helpers.go b/baseapp/test_helpers.go index 560f96e61834..12695792d659 100644 --- a/baseapp/test_helpers.go +++ b/baseapp/test_helpers.go @@ -20,13 +20,13 @@ func (app *BaseApp) SimCheck(txEncoder sdk.TxEncoder, tx sdk.Tx) (sdk.GasInfo, * return sdk.GasInfo{}, nil, errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, "%s", err) } - gasInfo, result, _, err := app.RunTx(execModeCheck, bz, tx, -1, nil, nil, log.NewNopTracer()) + gasInfo, result, _, err := app.RunTx(execModeCheck, bz, tx, -1, nil, nil, log.NewNopTracer(log.NewNopLogger())) return gasInfo, result, err } // Simulate executes a tx in simulate mode to get result and gas info. func (app *BaseApp) Simulate(txBytes []byte) (sdk.GasInfo, *sdk.Result, error) { - gasInfo, result, _, err := app.RunTx(execModeSimulate, txBytes, nil, -1, nil, nil, log.NewNopTracer()) + gasInfo, result, _, err := app.RunTx(execModeSimulate, txBytes, nil, -1, nil, nil, log.NewNopTracer(log.NewNopLogger())) return gasInfo, result, err } @@ -37,7 +37,7 @@ func (app *BaseApp) SimDeliver(txEncoder sdk.TxEncoder, tx sdk.Tx) (sdk.GasInfo, return sdk.GasInfo{}, nil, errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, "%s", err) } - gasInfo, result, _, err := app.RunTx(execModeFinalize, bz, tx, -1, nil, nil, log.NewNopTracer()) + gasInfo, result, _, err := app.RunTx(execModeFinalize, bz, tx, -1, nil, nil, log.NewNopTracer(log.NewNopLogger())) return gasInfo, result, err } @@ -48,7 +48,7 @@ func (app *BaseApp) SimTxFinalizeBlock(txEncoder sdk.TxEncoder, tx sdk.Tx) (sdk. return sdk.GasInfo{}, nil, errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, "%s", err) } - gasInfo, result, _, err := app.RunTx(execModeFinalize, bz, tx, -1, nil, nil, log.NewNopTracer()) + gasInfo, result, _, err := app.RunTx(execModeFinalize, bz, tx, -1, nil, nil, log.NewNopTracer(log.NewNopLogger())) return gasInfo, result, err } diff --git a/log/tracer.go b/log/tracer.go index 00274bd2414a..ac304b1a5e41 100644 --- a/log/tracer.go +++ b/log/tracer.go @@ -2,8 +2,13 @@ package log import "context" -// TraceProvider is an interface for creating and managing tracing spans. -type TraceProvider interface { +// Tracer is an interface for creating and managing spans. +// It may be backed by open telemetry or other tracing libraries, +// Spans may also be used for collecting timing metrics. +// It embeds the Logger interface. Log events may be associated with spans. +type Tracer interface { + Logger + // StartSpan starts a new span with the given operation name and key-value pair attributes. // If there is a parent span, the new span will be a child of that span. // It is recommended to use a defer statement to end the span like this: @@ -29,15 +34,6 @@ type TraceProvider interface { StartRootSpan(ctx context.Context, operation string, kvs ...any) (context.Context, Span) } -// Tracer is an interface for creating and managing spans. -// It may be backed by open telemetry or other tracing libraries, -// Spans may also be used for collecting timing metrics. -// It embeds the Logger interface. Log events may be associated with spans. -type Tracer interface { - Logger - TraceProvider -} - // Span is an interface for managing spans and creating nested spans via the embedded Tracer interface. type Span interface { // Tracer is embedded to allow for the creation of nested spans. @@ -66,25 +62,27 @@ type Span interface { End() } -// NewNopTracer returns a Tracer that does nothing. -func NewNopTracer() Tracer { - return nopTracer{} +// NewNopTracer returns a Tracer that wraps a logger for logging methods but does not emit any spans. +func NewNopTracer(logger Logger) Tracer { + return nopTracer{ + Logger: logger, + } } type nopTracer struct { - nopLogger + Logger } func (n nopTracer) StartRootSpan(ctx context.Context, operation string, kvs ...any) (context.Context, Span) { - return ctx, nopSpan{} + return ctx, nopSpan{n} } func (n nopTracer) StartSpanContext(ctx context.Context, _ string, _ ...any) (context.Context, Span) { - return ctx, nopSpan{} + return ctx, nopSpan{n} } func (n nopTracer) StartSpan(string, ...any) Span { - return nopSpan{} + return nopSpan{n} } type nopSpan struct { diff --git a/simapp/app_di.go b/simapp/app_di.go index 3e8e010d0acb..d9516de47564 100644 --- a/simapp/app_di.go +++ b/simapp/app_di.go @@ -3,15 +3,23 @@ package simapp import ( + "context" + "encoding/json" + "fmt" "io" + "os" + "os/signal" + "syscall" dbm "github.com/cosmos/cosmos-db" clienthelpers "cosmossdk.io/client/v2/helpers" "cosmossdk.io/depinject" - "cosmossdk.io/log" storetypes "cosmossdk.io/store/types" + "cosmossdk.io/log" + "github.com/cosmos/cosmos-sdk/telemetry" + "github.com/cosmos/cosmos-sdk/baseapp" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/codec" @@ -100,6 +108,37 @@ func NewSimApp( appOpts servertypes.AppOptions, baseAppOptions ...func(*baseapp.BaseApp), ) *SimApp { + // configure metrics and tracing for testing + telemetryCfgJson, ok := os.LookupEnv("SIMAPP_TELEMETRY") + if ok && telemetryCfgJson != "" { + var telemetryCfg telemetry.Config + err := json.Unmarshal([]byte(telemetryCfgJson), &telemetryCfg) + if err != nil { + panic(fmt.Errorf("failed to parse simapp telemetry config: %v\n", err)) + } else { + fmt.Printf("\nConfiguring telemetry for simapp: %+v\n", telemetryCfg) + metrics, err := telemetry.New(telemetryCfg, telemetry.WithLogger(logger)) + if err != nil { + panic(fmt.Errorf("failed to initialize simapp telemetry: %v\n", err)) + } + logger = metrics.Tracer() + err = metrics.Start(context.Background()) + if err != nil { + panic(fmt.Errorf("failed to start simapp telemetry: %v\n", err)) + } + shutdownChan := make(chan os.Signal, 1) + signal.Notify(shutdownChan, os.Interrupt, syscall.SIGTERM) + go func() { + // shutdown when there's a shutdown signal + <-shutdownChan + err := metrics.Shutdown(context.Background()) + if err != nil { + fmt.Printf("failed to shutdown simapp telemetry: %v\n", err) + } + }() + } + } + var ( app = &SimApp{} appBuilder *runtime.AppBuilder diff --git a/telemetry/config.go b/telemetry/config.go index e707a127251d..1e9eeb52ac97 100644 --- a/telemetry/config.go +++ b/telemetry/config.go @@ -50,29 +50,29 @@ type DisplayableSink interface { type Config struct { // ServiceName is the identifier for this service, used as a prefix for all metric keys. // Example: "cosmos-app" → metrics like "cosmos-app.tx.count" - ServiceName string `mapstructure:"service-name"` + ServiceName string `mapstructure:"service-name" json:"service-name"` // Enabled controls whether telemetry is active. When false, all telemetry operations // become no-ops with zero overhead. When true, metrics collection is activated. - Enabled bool `mapstructure:"enabled"` + Enabled bool `mapstructure:"enabled" json:"enabled"` // EnableHostname prefixes gauge values with the hostname. // Useful in multi-node deployments to identify which node emitted a metric. - EnableHostname bool `mapstructure:"enable-hostname"` + EnableHostname bool `mapstructure:"enable-hostname" json:"enable-hostname"` // EnableHostnameLabel adds a "hostname" label to all metrics. // Alternative to EnableHostname that works better with label-based systems like Prometheus. - EnableHostnameLabel bool `mapstructure:"enable-hostname-label"` + EnableHostnameLabel bool `mapstructure:"enable-hostname-label" json:"enable-hostname-label"` // EnableServiceLabel adds a "service" label with the ServiceName to all metrics. // Useful when aggregating metrics from multiple services in one monitoring system. - EnableServiceLabel bool `mapstructure:"enable-service-label"` + EnableServiceLabel bool `mapstructure:"enable-service-label" json:"enable-service-label"` // PrometheusRetentionTime, when positive, enables a Prometheus metrics sink. // Defines how long (in seconds) metrics are retained in memory for scraping. // The Prometheus sink is added to a FanoutSink alongside the primary sink. // Recommended value: 60 seconds or more. - PrometheusRetentionTime int64 `mapstructure:"prometheus-retention-time"` + PrometheusRetentionTime int64 `mapstructure:"prometheus-retention-time" json:"prometheus-retention-time"` // GlobalLabels defines a set of key-value label pairs applied to ALL metrics. // These labels are automatically attached to every metric emission. @@ -81,7 +81,7 @@ type Config struct { // Example: [][]string{{"chain_id", "cosmoshub-1"}, {"env", "production"}} // // Note: The outer array contains label pairs, each inner array has exactly 2 elements [key, value]. - GlobalLabels [][]string `mapstructure:"global-labels"` + GlobalLabels [][]string `mapstructure:"global-labels" json:"global-labels"` // MetricsSink defines the metrics backend type. Supported values: // - "mem" (default): In-memory sink with SIGUSR1 dump-to-stderr capability @@ -91,33 +91,33 @@ type Config struct { // - "file": JSON lines written to a file (requires MetricsFile) // // Multiple sinks can be active via FanoutSink (e.g., mem + prometheus). - MetricsSink string `mapstructure:"metrics-sink" default:"mem"` + MetricsSink string `mapstructure:"metrics-sink" json:"metrics-sink" default:"mem"` // StatsdAddr is the address of the StatsD or DogStatsD server (host:port). // Only used when MetricsSink is "statsd" or "dogstatsd". // Example: "localhost:8125" - StatsdAddr string `mapstructure:"statsd-addr"` + StatsdAddr string `mapstructure:"statsd-addr" json:"statsd-addr"` // DatadogHostname is the hostname to report when using DogStatsD. // Only used when MetricsSink is "dogstatsd". // If empty, the system hostname is used. - DatadogHostname string `mapstructure:"datadog-hostname"` + DatadogHostname string `mapstructure:"datadog-hostname" json:"datadog-hostname"` // MetricsFile is the file path to write metrics to in JSONL format. // Only used when MetricsSink is "file". // Each metric emission creates a JSON line: {"timestamp":"...","type":"counter","key":[...],"value":1.0} // Example: "/tmp/metrics.jsonl" or "./metrics.jsonl" - MetricsFile string `mapstructure:"metrics-file"` + MetricsFile string `mapstructure:"metrics-file" json:"metrics-file"` // TraceSink is the sink for trace data. Supported values: // - "otel": OpenTelemetry trace sink // - "metrics": all spans will be redirected to emit invocation counter and timing histogram metrics // - "noop": No-op trace sink (default) - TraceSink string `mapstructure:"trace-sink"` + TraceSink string `mapstructure:"trace-sink" json:"trace-sink"` // OtelTraceExporters is a list of OTLP exporters to use for trace data. // This is only used when trace sink is set to "otel". - OtelTraceExporters []OtelTraceExportConfig `mapstructure:"otel-trace-exporters"` + OtelTraceExporters []OtelTraceExportConfig `mapstructure:"otel-trace-exporters" json:"otel-trace-exporters"` } type OtelTraceExportConfig struct { @@ -127,24 +127,24 @@ type OtelTraceExportConfig struct { // - "otlp" // // OTLP exporters must set the endpoint URL and can optionally set the transport protocol. - Type string `mapstructure:"type"` + Type string `mapstructure:"type" json:"type"` // OTLPTransport is the transport protocol to use for OTLP. // Must be one of: // - "http" (default) // - "grpc" - OTLPTransport string `mapstructure:"otlp-transport"` + OTLPTransport string `mapstructure:"otlp-transport" json:"otlp-transport"` // Endpoint is the OTLP exporter endpoint URL (grpc or http). - Endpoint string `mapstructure:"endpoint"` + Endpoint string `mapstructure:"endpoint" json:"endpoint"` // Insecure disables TLS certificate verification for OTLP exporters. - Insecure bool `mapstructure:"insecure"` + Insecure bool `mapstructure:"insecure" json:"insecure"` // File is the file path to write trace data to when using the "stdout" exporter. // If it is empty, the trace data is written to stdout. - File string `mapstructure:"file"` + File string `mapstructure:"file" json:"file"` // PrettyPrint enables pretty-printing of JSON output when using the "stdout" exporter. - PrettyPrint bool `mapstructure:"pretty-print"` + PrettyPrint bool `mapstructure:"pretty-print" json:"pretty-print"` } diff --git a/telemetry/metrics.go b/telemetry/metrics.go index e20ecf600058..3bcb777918bb 100644 --- a/telemetry/metrics.go +++ b/telemetry/metrics.go @@ -37,12 +37,13 @@ import ( // Note: go-metrics uses a singleton global registry. Only one Metrics instance // should be created per process. type Metrics struct { - sink metrics.MetricSink - prometheusEnabled bool - startFuncs []func(ctx context.Context) error - shutdownFuncs []func(context.Context) error - traceProvider log.TraceProvider - metricsTraceProvider *MetricsTraceProvider + sink metrics.MetricSink + prometheusEnabled bool + startFuncs []func(ctx context.Context) error + shutdownFuncs []func(context.Context) error + logger log.Logger + tracer log.Tracer + metricsTracer *MetricsTracer } // GatherResponse contains collected metrics in the requested format. @@ -77,7 +78,7 @@ type GatherResponse struct { // return err // } // defer m.Close() -func New(cfg Config) (_ *Metrics, rerr error) { +func New(cfg Config, opts ...Option) (_ *Metrics, rerr error) { globalTelemetryEnabled = cfg.Enabled if !cfg.Enabled { return nil, nil @@ -95,18 +96,21 @@ func New(cfg Config) (_ *Metrics, rerr error) { metricsConf.EnableHostname = cfg.EnableHostname metricsConf.EnableHostnameLabel = cfg.EnableHostnameLabel - var startFuncs []func(context.Context) error - var shutdownFuncs []func(context.Context) error + // Initialize Metrics struct early with default logger + m := &Metrics{ + logger: log.NewNopLogger(), // Default to nop logger + } + // Apply functional options to set logger + for _, opt := range opts { + opt(m) + } - var ( - sink metrics.MetricSink - err error - ) + var err error switch cfg.MetricsSink { case MetricSinkStatsd: - sink, err = metrics.NewStatsdSink(cfg.StatsdAddr) + m.sink, err = metrics.NewStatsdSink(cfg.StatsdAddr) case MetricSinkDogsStatsd: - sink, err = datadog.NewDogStatsdSink(cfg.StatsdAddr, cfg.DatadogHostname) + m.sink, err = datadog.NewDogStatsdSink(cfg.StatsdAddr, cfg.DatadogHostname) case MetricSinkFile: if cfg.MetricsFile == "" { return nil, errors.New("metrics-file must be set when metrics-sink is 'file'") @@ -116,13 +120,13 @@ func New(cfg Config) (_ *Metrics, rerr error) { return nil, fmt.Errorf("failed to open metrics file: %w", err) } fileSink := NewFileSink(file) - sink = fileSink - shutdownFuncs = append(shutdownFuncs, func(ctx context.Context) error { - return fileSink.Close() + m.shutdownFuncs = append(m.shutdownFuncs, func(ctx context.Context) error { + return file.Close() }) + m.sink = fileSink default: memSink := metrics.NewInmemSink(10*time.Second, time.Minute) - sink = memSink + m.sink = memSink inMemSig := metrics.DefaultInmemSignal(memSink) defer func() { if rerr != nil { @@ -130,10 +134,13 @@ func New(cfg Config) (_ *Metrics, rerr error) { } }() } + if err != nil { + return nil, err + } - metricsTraceProvider := NewMetricsTraceProvider(nil, globalLabels, metrics.Default()) + m.tracer = log.NewNopTracer(m.logger) + m.metricsTracer = NewMetricsTracer(metrics.Default(), nil, globalLabels, m.logger) - var tracerBase log.TraceProvider switch cfg.TraceSink { case TraceSinkOtel: var tracerProviderOpts []otelsdktrace.TracerProviderOption @@ -160,7 +167,7 @@ func New(cfg Config) (_ *Metrics, rerr error) { client = otlptracehttp.NewClient(opts...) } exporter := otlptrace.NewUnstarted(client) - startFuncs = append(startFuncs, exporter.Start) + m.startFuncs = append(m.startFuncs, exporter.Start) batcherOpt := otelsdktrace.WithBatcher(exporter) tracerProviderOpts = append(tracerProviderOpts, batcherOpt) case "stdout": @@ -171,7 +178,7 @@ func New(cfg Config) (_ *Metrics, rerr error) { return nil, fmt.Errorf("failed to open stdout trace file %s: %w", exporterOpts.File, err) } opts = append(opts, stdouttrace.WithWriter(file)) - shutdownFuncs = append(shutdownFuncs, func(ctx context.Context) error { + m.shutdownFuncs = append(m.shutdownFuncs, func(ctx context.Context) error { return file.Close() }) } @@ -190,31 +197,18 @@ func New(cfg Config) (_ *Metrics, rerr error) { } tracerProvider := otelsdktrace.NewTracerProvider(tracerProviderOpts...) - shutdownFuncs = append(shutdownFuncs, tracerProvider.Shutdown) + m.shutdownFuncs = append(m.shutdownFuncs, tracerProvider.Shutdown) tracerName := cfg.ServiceName if tracerName == "" { tracerName = "cosmos-sdk" } - tracerBase = NewOtelTraceProvider(tracerProvider.Tracer(tracerName)) - + m.tracer = NewOtelTracer(tracerProvider.Tracer(tracerName), m.logger) case "metrics": - tracerBase = metricsTraceProvider + m.tracer = m.metricsTracer default: - tracerBase = log.NewNopTracer() } - if err != nil { - return nil, err - } - - m := &Metrics{ - sink: sink, - startFuncs: startFuncs, - shutdownFuncs: shutdownFuncs, - traceProvider: tracerBase, - metricsTraceProvider: metricsTraceProvider, - } - fanout := metrics.FanoutSink{sink} + fanout := metrics.FanoutSink{m.sink} if cfg.PrometheusRetentionTime > 0 { m.prometheusEnabled = true @@ -302,16 +296,16 @@ func (m *Metrics) gatherGeneric() (GatherResponse, error) { return GatherResponse{ContentType: "application/json", Metrics: content}, nil } -// TraceProvider returns the base trace provider for creating spans. -func (m *Metrics) TraceProvider() log.TraceProvider { - return m.traceProvider +// Tracer returns the base tracer for creating spans and logging. +func (m *Metrics) Tracer() log.Tracer { + return m.tracer } -// MetricsTraceProvider returns a trace provider that only emits metrics for spans. +// MetricsTracer returns a tracer that only emits metrics for spans. // Use this when you specifically want to configure a code path to only emit metrics // and not actual logging spans (useful for benchmarking small operations such as store operations). -func (m *Metrics) MetricsTraceProvider() log.TraceProvider { - return m.metricsTraceProvider +func (m *Metrics) MetricsTracer() log.Tracer { + return m.metricsTracer } // Start starts all configured exporters. diff --git a/telemetry/metrics_span.go b/telemetry/metrics_span.go index 933c5948c323..407c91708ae1 100644 --- a/telemetry/metrics_span.go +++ b/telemetry/metrics_span.go @@ -9,40 +9,50 @@ import ( "cosmossdk.io/log" ) -type MetricsTraceProvider struct { +// MetricsTracer is a log.Tracer implementation that emits metrics for span operations. +// It wraps a logger and forwards all log calls to it, while creating MetricsSpan instances +// that emit timing and count metrics. +type MetricsTracer struct { + log.Logger // Logger to forward log calls to rootPath []string // Base path set at tracer creation, preserved across all spans rootLabels []metrics.Label // Labels applied to all metrics emitted by this tracer metrics *metrics.Metrics } -func NewMetricsTraceProvider(rootPath []string, rootLabels []metrics.Label, metrics *metrics.Metrics) *MetricsTraceProvider { - return &MetricsTraceProvider{rootPath: rootPath, rootLabels: rootLabels, metrics: metrics} +// NewMetricsTracer creates a new MetricsTracer with the given configuration. +func NewMetricsTracer(metrics *metrics.Metrics, rootPath []string, rootLabels []metrics.Label, logger log.Logger) *MetricsTracer { + return &MetricsTracer{ + Logger: logger, + rootPath: rootPath, + rootLabels: rootLabels, + metrics: metrics, + } } -func (m *MetricsTraceProvider) startSpan(existingPath []string, operation string, _ ...any) log.Span { +func (m *MetricsTracer) startSpan(existingPath []string, operation string, _ ...any) log.Span { path := make([]string, len(existingPath)+1) copy(path, existingPath) path[len(path)-1] = operation return &MetricsSpan{ - MetricsTraceProvider: m, - path: path, - start: time.Now(), + MetricsTracer: m, + path: path, + start: time.Now(), } } -func (m *MetricsTraceProvider) StartSpan(operation string, _ ...any) log.Span { +func (m *MetricsTracer) StartSpan(operation string, _ ...any) log.Span { return m.startSpan(m.rootPath, operation) } -func (m *MetricsTraceProvider) StartSpanContext(ctx context.Context, operation string, kvs ...any) (context.Context, log.Span) { +func (m *MetricsTracer) StartSpanContext(ctx context.Context, operation string, kvs ...any) (context.Context, log.Span) { return ctx, m.startSpan(m.rootPath, operation) } -func (m *MetricsTraceProvider) StartRootSpan(ctx context.Context, operation string, kvs ...any) (context.Context, log.Span) { +func (m *MetricsTracer) StartRootSpan(ctx context.Context, operation string, kvs ...any) (context.Context, log.Span) { return ctx, m.startSpan(m.rootPath, operation) } -var _ log.TraceProvider = (*MetricsTraceProvider)(nil) +var _ log.Tracer = (*MetricsTracer)(nil) // MetricsSpan is a log.Span implementation that emits timing and count metrics // to go-metrics when the span ends. @@ -59,19 +69,11 @@ var _ log.TraceProvider = (*MetricsTraceProvider)(nil) // Root path and labels are preserved across all spans created from this tracer, // ensuring consistent metric namespacing and labeling throughout the span hierarchy. type MetricsSpan struct { - *MetricsTraceProvider + *MetricsTracer start time.Time path []string } -// Logger methods are no-ops - MetricsSpan does not support logging. -func (m *MetricsSpan) Info(msg string, keyVals ...any) {} -func (m *MetricsSpan) Warn(msg string, keyVals ...any) {} -func (m *MetricsSpan) Error(msg string, keyVals ...any) {} -func (m *MetricsSpan) Debug(msg string, keyVals ...any) {} -func (m *MetricsSpan) With(keyVals ...any) log.Logger { return m } -func (m *MetricsSpan) Impl() any { return nil } - // StartSpan creates a child span by appending the operation name to the current path. // Root path and labels are preserved in the child span. // The kvs parameters are ignored (metrics don't support dynamic attributes). diff --git a/telemetry/options.go b/telemetry/options.go new file mode 100644 index 000000000000..b48fe041ecd3 --- /dev/null +++ b/telemetry/options.go @@ -0,0 +1,14 @@ +package telemetry + +import "cosmossdk.io/log" + +// Option is a functional option for configuring Metrics. +type Option func(*Metrics) + +// WithLogger sets the default logger to use for tracers. +// If not provided, a nop logger will be used. +func WithLogger(logger log.Logger) Option { + return func(m *Metrics) { + m.logger = logger + } +} diff --git a/telemetry/otel_span.go b/telemetry/otel_span.go index e7c6aea9231f..cfdd9ac6d6de 100644 --- a/telemetry/otel_span.go +++ b/telemetry/otel_span.go @@ -11,17 +11,22 @@ import ( "cosmossdk.io/log" ) -type OtelTraceProvider struct { +// OtelTracer is a log.Tracer implementation that uses OpenTelemetry for distributed tracing. +// It wraps a logger and forwards all log calls to it, while creating OtelSpan instances +// that emit trace spans. +type OtelTracer struct { + log.Logger tracer oteltrace.Tracer } -func NewOtelTraceProvider(tracer oteltrace.Tracer) *OtelTraceProvider { - return &OtelTraceProvider{ +func NewOtelTracer(tracer oteltrace.Tracer, logger log.Logger) *OtelTracer { + return &OtelTracer{ + Logger: logger, tracer: tracer, } } -func (o *OtelTraceProvider) StartSpan(operation string, kvs ...any) log.Span { +func (o *OtelTracer) StartSpan(operation string, kvs ...any) log.Span { ctx, span := o.tracer.Start(context.Background(), operation, oteltrace.WithAttributes(toKVs(kvs)...)) return &OtelSpan{ tracer: o.tracer, @@ -30,7 +35,7 @@ func (o *OtelTraceProvider) StartSpan(operation string, kvs ...any) log.Span { } } -func (o *OtelTraceProvider) StartSpanContext(ctx context.Context, operation string, kvs ...any) (context.Context, log.Span) { +func (o *OtelTracer) StartSpanContext(ctx context.Context, operation string, kvs ...any) (context.Context, log.Span) { ctx, span := o.tracer.Start(ctx, operation, oteltrace.WithAttributes(toKVs(kvs)...)) return ctx, &OtelSpan{ tracer: o.tracer, @@ -39,7 +44,7 @@ func (o *OtelTraceProvider) StartSpanContext(ctx context.Context, operation stri } } -func (o *OtelTraceProvider) StartRootSpan(ctx context.Context, operation string, kvs ...any) (context.Context, log.Span) { +func (o *OtelTracer) StartRootSpan(ctx context.Context, operation string, kvs ...any) (context.Context, log.Span) { ctx, span := o.tracer.Start(ctx, operation, oteltrace.WithAttributes(toKVs(kvs)...), oteltrace.WithNewRoot()) return ctx, &OtelSpan{ tracer: o.tracer, @@ -48,7 +53,7 @@ func (o *OtelTraceProvider) StartRootSpan(ctx context.Context, operation string, } } -var _ log.TraceProvider = (*OtelTraceProvider)(nil) +var _ log.Tracer = (*OtelTracer)(nil) type OtelSpan struct { tracer oteltrace.Tracer From 25e3135feb5e3b1b6d358ca8ba4b1e2632c5db46 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Thu, 30 Oct 2025 14:32:28 -0400 Subject: [PATCH 08/52] add test setup --- baseapp/baseapp.go | 10 +++++----- simapp/app_di.go | 39 -------------------------------------- simapp/sim_test.go | 8 +++++++- telemetry/otel_span.go | 12 ++++++------ telemetry/testing.go | 43 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 61 insertions(+), 51 deletions(-) create mode 100644 telemetry/testing.go diff --git a/baseapp/baseapp.go b/baseapp/baseapp.go index 9de5a9dcaff4..e1de0596ae48 100644 --- a/baseapp/baseapp.go +++ b/baseapp/baseapp.go @@ -174,8 +174,13 @@ type BaseApp struct { func NewBaseApp( name string, logger log.Logger, db dbm.DB, txDecoder sdk.TxDecoder, options ...func(*BaseApp), ) *BaseApp { + tracer, ok := logger.(log.Tracer) + if !ok { + tracer = log.NewNopTracer(logger) + } app := &BaseApp{ logger: logger.With(log.ModuleKey, "baseapp"), + tracer: tracer, name: name, db: db, cms: store.NewCommitMultiStore(db, logger, storemetrics.NewNoOpMetrics()), // by default, we use a no-op metric gather in store @@ -189,11 +194,6 @@ func NewBaseApp( } // initialize tracer - tracer, ok := app.logger.(log.Tracer) - if !ok { - tracer = log.NewNopTracer(app.logger) - } - app.tracer = tracer for _, option := range options { option(app) diff --git a/simapp/app_di.go b/simapp/app_di.go index d9516de47564..5e6e9cf26a28 100644 --- a/simapp/app_di.go +++ b/simapp/app_di.go @@ -3,13 +3,7 @@ package simapp import ( - "context" - "encoding/json" - "fmt" "io" - "os" - "os/signal" - "syscall" dbm "github.com/cosmos/cosmos-db" @@ -18,8 +12,6 @@ import ( storetypes "cosmossdk.io/store/types" "cosmossdk.io/log" - "github.com/cosmos/cosmos-sdk/telemetry" - "github.com/cosmos/cosmos-sdk/baseapp" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/codec" @@ -108,37 +100,6 @@ func NewSimApp( appOpts servertypes.AppOptions, baseAppOptions ...func(*baseapp.BaseApp), ) *SimApp { - // configure metrics and tracing for testing - telemetryCfgJson, ok := os.LookupEnv("SIMAPP_TELEMETRY") - if ok && telemetryCfgJson != "" { - var telemetryCfg telemetry.Config - err := json.Unmarshal([]byte(telemetryCfgJson), &telemetryCfg) - if err != nil { - panic(fmt.Errorf("failed to parse simapp telemetry config: %v\n", err)) - } else { - fmt.Printf("\nConfiguring telemetry for simapp: %+v\n", telemetryCfg) - metrics, err := telemetry.New(telemetryCfg, telemetry.WithLogger(logger)) - if err != nil { - panic(fmt.Errorf("failed to initialize simapp telemetry: %v\n", err)) - } - logger = metrics.Tracer() - err = metrics.Start(context.Background()) - if err != nil { - panic(fmt.Errorf("failed to start simapp telemetry: %v\n", err)) - } - shutdownChan := make(chan os.Signal, 1) - signal.Notify(shutdownChan, os.Interrupt, syscall.SIGTERM) - go func() { - // shutdown when there's a shutdown signal - <-shutdownChan - err := metrics.Shutdown(context.Background()) - if err != nil { - fmt.Printf("failed to shutdown simapp telemetry: %v\n", err) - } - }() - } - } - var ( app = &SimApp{} appBuilder *runtime.AppBuilder diff --git a/simapp/sim_test.go b/simapp/sim_test.go index 55ead7b3ce7f..c1dd2e43bafc 100644 --- a/simapp/sim_test.go +++ b/simapp/sim_test.go @@ -19,6 +19,8 @@ import ( "github.com/stretchr/testify/require" "cosmossdk.io/log" + "github.com/cosmos/cosmos-sdk/telemetry" + "cosmossdk.io/store" storetypes "cosmossdk.io/store/types" @@ -189,7 +191,11 @@ func TestAppStateDeterminism(t *testing.T) { return others.Get(k) }) } - return NewSimApp(logger, db, nil, true, appOpts, append(baseAppOptions, interBlockCacheOpt())...) + metrics := telemetry.TestingInit(t, nil, logger) + span := metrics.Tracer().StartSpan("test-span") + span.Info("test span created") + span.End() + return NewSimApp(metrics.Tracer(), db, nil, true, appOpts, append(baseAppOptions, interBlockCacheOpt())...) } var mx sync.Mutex appHashResults := make(map[int64][][]byte) diff --git a/telemetry/otel_span.go b/telemetry/otel_span.go index cfdd9ac6d6de..3a7db06a24dc 100644 --- a/telemetry/otel_span.go +++ b/telemetry/otel_span.go @@ -65,7 +65,7 @@ type OtelSpan struct { func (o *OtelSpan) addEvent(level, msg string, keyVals ...any) { o.span.AddEvent(msg, oteltrace.WithAttributes(o.persistentAttrs...), - oteltrace.WithAttributes(toKVs(keyVals...)...), + oteltrace.WithAttributes(toKVs(keyVals)...), oteltrace.WithAttributes(otelattr.String("level", level)), ) } @@ -87,7 +87,7 @@ func (o *OtelSpan) Debug(msg string, keyVals ...any) { } func (o *OtelSpan) With(keyVals ...any) log.Logger { - attrs := toKVs(keyVals...) + attrs := toKVs(keyVals) persistentAttrs := make([]otelattr.KeyValue, 0, len(o.persistentAttrs)+len(attrs)) persistentAttrs = append(persistentAttrs, o.persistentAttrs...) persistentAttrs = append(persistentAttrs, attrs...) @@ -107,7 +107,7 @@ func (o *OtelSpan) startSpan(ctx context.Context, operation string, kvs []any, o if len(o.persistentAttrs) > 0 { opts = append(opts, oteltrace.WithAttributes(o.persistentAttrs...)) } - opts = append(opts, oteltrace.WithAttributes(toKVs(kvs...)...)) + opts = append(opts, oteltrace.WithAttributes(toKVs(kvs)...)) ctx, span := o.tracer.Start(ctx, operation, opts...) return &OtelSpan{ tracer: o.tracer, @@ -136,7 +136,7 @@ func (o *OtelSpan) StartRootSpan(ctx context.Context, operation string, kvs ...a } func (o *OtelSpan) SetAttrs(kvs ...any) { - o.span.SetAttributes(toKVs(kvs...)...) + o.span.SetAttributes(toKVs(kvs)...) } func (o *OtelSpan) SetErr(err error, kvs ...any) error { @@ -147,7 +147,7 @@ func (o *OtelSpan) SetErr(err error, kvs ...any) error { o.span.SetStatus(otelcodes.Error, err.Error()) } if len(kvs) > 0 { - o.span.SetAttributes(toKVs(kvs...)...) + o.span.SetAttributes(toKVs(kvs)...) } return err } @@ -158,7 +158,7 @@ func (o *OtelSpan) End() { var _ log.Span = (*OtelSpan)(nil) -func toKVs(kvs ...any) []otelattr.KeyValue { +func toKVs(kvs []any) []otelattr.KeyValue { if len(kvs)%2 != 0 { panic(fmt.Sprintf("kvs must have even length, got %d", len(kvs))) } diff --git a/telemetry/testing.go b/telemetry/testing.go new file mode 100644 index 000000000000..551068088ccd --- /dev/null +++ b/telemetry/testing.go @@ -0,0 +1,43 @@ +package telemetry + +import ( + "context" + "encoding/json" + "os" + "testing" + + "github.com/stretchr/testify/require" + + "cosmossdk.io/log" +) + +// TestingInit initializes telemetry for testing. +// If ctx is nil, context.Background() is used. +// If logger is nil, a new test logger is created. +func TestingInit(t *testing.T, ctx context.Context, logger log.Logger) *Metrics { + t.Helper() + if ctx == nil { + ctx = context.Background() + } + if logger == nil { + logger = log.NewTestLogger(t) + } + + // configure metrics and tracing for testing + telemetryCfg := Config{Enabled: true} + telemetryCfgJson, ok := os.LookupEnv("COSMOS_TELEMETRY") + if ok && telemetryCfgJson != "" { + err := json.Unmarshal([]byte(telemetryCfgJson), &telemetryCfg) + require.NoError(t, err, "failed to parse telemetry config", telemetryCfgJson) + } + + t.Logf("Configuring telemetry with: %+v", telemetryCfg) + metrics, err := New(telemetryCfg, WithLogger(logger)) + require.NoError(t, err, "failed to initialize telemetry") + err = metrics.Start(ctx) + require.NoError(t, err, "failed to start telemetry") + t.Cleanup(func() { + require.NoError(t, metrics.Shutdown(ctx), "failed to shutdown telemetry") + }) + return metrics +} From 5c7e464a797680cd6e5f113f9ab6f5287493fba3 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Thu, 30 Oct 2025 16:56:47 -0400 Subject: [PATCH 09/52] fix shutdown order --- telemetry/metrics.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/telemetry/metrics.go b/telemetry/metrics.go index 3bcb777918bb..db56cd76535a 100644 --- a/telemetry/metrics.go +++ b/telemetry/metrics.go @@ -323,8 +323,10 @@ func (m *Metrics) Start(ctx context.Context) error { // Shutdown must be called before the application exits to shutdown any // exporters and close any open files. func (m *Metrics) Shutdown(ctx context.Context) error { - for _, f := range m.shutdownFuncs { - if err := f(ctx); err != nil { + n := len(m.shutdownFuncs) + // shutdown in reverse order because some exporters may depend on others + for i := n - 1; i >= 0; i-- { + if err := m.shutdownFuncs[i](ctx); err != nil { return err } } From d71f7c15086307a903b2d4bddd12764f9923a080 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Thu, 30 Oct 2025 17:18:52 -0400 Subject: [PATCH 10/52] block trace nesting --- baseapp/abci.go | 24 ++++++++++++++---------- baseapp/baseapp.go | 2 ++ simapp/sim_test.go | 7 +++---- telemetry/metrics.go | 2 +- 4 files changed, 20 insertions(+), 15 deletions(-) diff --git a/baseapp/abci.go b/baseapp/abci.go index dd4999af0334..5254a2c7d60a 100644 --- a/baseapp/abci.go +++ b/baseapp/abci.go @@ -39,7 +39,7 @@ const ( ) func (app *BaseApp) InitChain(req *abci.RequestInitChain) (*abci.ResponseInitChain, error) { - span := app.tracer.StartSpan("InitChain") + span := app.blockSpan.StartSpan("InitChain") defer span.End() if req.ChainId != app.chainID { @@ -401,7 +401,7 @@ func (app *BaseApp) CheckTx(req *abci.RequestCheckTx) (*abci.ResponseCheckTx, er // Ref: https://github.com/cosmos/cosmos-sdk/blob/main/docs/architecture/adr-060-abci-1.0.md // Ref: https://github.com/cometbft/cometbft/blob/main/spec/abci/abci%2B%2B_basic_concepts.md func (app *BaseApp) PrepareProposal(req *abci.RequestPrepareProposal) (resp *abci.ResponsePrepareProposal, err error) { - span := app.tracer.StartSpan("PrepareProposal") + span := app.blockSpan.StartSpan("PrepareProposal") defer span.End() if app.abciHandlers.PrepareProposalHandler == nil { @@ -491,7 +491,7 @@ func (app *BaseApp) PrepareProposal(req *abci.RequestPrepareProposal) (resp *abc // Ref: https://github.com/cosmos/cosmos-sdk/blob/main/docs/architecture/adr-060-abci-1.0.md // Ref: https://github.com/cometbft/cometbft/blob/main/spec/abci/abci%2B%2B_basic_concepts.md func (app *BaseApp) ProcessProposal(req *abci.RequestProcessProposal) (resp *abci.ResponseProcessProposal, err error) { - span := app.tracer.StartSpan("ProcessProposal") + span := app.blockSpan.StartSpan("ProcessProposal") defer span.End() if app.abciHandlers.ProcessProposalHandler == nil { @@ -591,7 +591,7 @@ func (app *BaseApp) ProcessProposal(req *abci.RequestProcessProposal) (resp *abc // height and are committed in the subsequent height, i.e. H+2. An error is // returned if vote extensions are not enabled or if extendVote fails or panics. func (app *BaseApp) ExtendVote(_ context.Context, req *abci.RequestExtendVote) (resp *abci.ResponseExtendVote, err error) { - span := app.tracer.StartSpan("ExtendVote") + span := app.blockSpan.StartSpan("ExtendVote") defer span.End() // Always reset state given that ExtendVote and VerifyVoteExtension can timeout @@ -667,7 +667,7 @@ func (app *BaseApp) ExtendVote(_ context.Context, req *abci.RequestExtendVote) ( // phase. The response MUST be deterministic. An error is returned if vote // extensions are not enabled or if verifyVoteExt fails or panics. func (app *BaseApp) VerifyVoteExtension(req *abci.RequestVerifyVoteExtension) (resp *abci.ResponseVerifyVoteExtension, err error) { - span := app.tracer.StartSpan("VerifyVoteExtension") + span := app.blockSpan.StartSpan("VerifyVoteExtension") defer span.End() if app.abciHandlers.VerifyVoteExtensionHandler == nil { @@ -738,7 +738,7 @@ func (app *BaseApp) VerifyVoteExtension(req *abci.RequestVerifyVoteExtension) (r // only used to handle early cancellation, for anything related to state app.stateManager.GetState(execModeFinalize).Context() // must be used. func (app *BaseApp) internalFinalizeBlock(ctx context.Context, req *abci.RequestFinalizeBlock) (*abci.ResponseFinalizeBlock, error) { - span := app.tracer.StartSpan("internalFinalizeBlock") + ctx, span := app.tracer.StartSpanContext(ctx, "internalFinalizeBlock") defer span.End() var events []abci.Event @@ -916,7 +916,7 @@ func (app *BaseApp) executeTxsWithExecutor(ctx context.Context, ms storetypes.Mu // extensions into the proposal, which should not themselves be executed in cases // where they adhere to the sdk.Tx interface. func (app *BaseApp) FinalizeBlock(req *abci.RequestFinalizeBlock) (res *abci.ResponseFinalizeBlock, err error) { - span := app.tracer.StartSpan("FinalizeBlock") + ctx, span := app.blockSpan.StartSpanContext(context.Background(), "FinalizeBlock") defer span.End() defer func() { @@ -952,7 +952,7 @@ func (app *BaseApp) FinalizeBlock(req *abci.RequestFinalizeBlock) (res *abci.Res } // if no OE is running, just run the block (this is either a block replay or a OE that got aborted) - res, err = app.internalFinalizeBlock(context.Background(), req) + res, err = app.internalFinalizeBlock(ctx, req) if res != nil { res.AppHash = app.workingHash() } @@ -986,8 +986,12 @@ func (app *BaseApp) checkHalt(height int64, time time.Time) error { // against that height and gracefully halt if it matches the latest committed // height. func (app *BaseApp) Commit() (*abci.ResponseCommit, error) { - span := app.tracer.StartSpan("Commit") - defer span.End() + span := app.blockSpan.StartSpan("Commit") + defer func() { + span.End() + app.blockSpan.End() + app.blockSpan = app.tracer.StartSpan("block") + }() finalizeState := app.stateManager.GetState(execModeFinalize) header := finalizeState.Context().BlockHeader() diff --git a/baseapp/baseapp.go b/baseapp/baseapp.go index e1de0596ae48..4cc51ae8c3da 100644 --- a/baseapp/baseapp.go +++ b/baseapp/baseapp.go @@ -66,6 +66,7 @@ type BaseApp struct { mu sync.Mutex // mu protects the fields below. logger log.Logger tracer log.Tracer + blockSpan log.Span name string // application name from abci.BlockInfo db dbm.DB // common DB backend cms storetypes.CommitMultiStore // Main (uncached) state @@ -181,6 +182,7 @@ func NewBaseApp( app := &BaseApp{ logger: logger.With(log.ModuleKey, "baseapp"), tracer: tracer, + blockSpan: tracer.StartSpan("block"), name: name, db: db, cms: store.NewCommitMultiStore(db, logger, storemetrics.NewNoOpMetrics()), // by default, we use a no-op metric gather in store diff --git a/simapp/sim_test.go b/simapp/sim_test.go index c1dd2e43bafc..848911ef2ffd 100644 --- a/simapp/sim_test.go +++ b/simapp/sim_test.go @@ -192,10 +192,9 @@ func TestAppStateDeterminism(t *testing.T) { }) } metrics := telemetry.TestingInit(t, nil, logger) - span := metrics.Tracer().StartSpan("test-span") - span.Info("test span created") - span.End() - return NewSimApp(metrics.Tracer(), db, nil, true, appOpts, append(baseAppOptions, interBlockCacheOpt())...) + baseAppSpan := metrics.Tracer().StartSpan("baseapp") + t.Cleanup(baseAppSpan.End) + return NewSimApp(baseAppSpan, db, nil, true, appOpts, append(baseAppOptions, interBlockCacheOpt())...) } var mx sync.Mutex appHashResults := make(map[int64][][]byte) diff --git a/telemetry/metrics.go b/telemetry/metrics.go index db56cd76535a..0d47e63ccb55 100644 --- a/telemetry/metrics.go +++ b/telemetry/metrics.go @@ -324,7 +324,7 @@ func (m *Metrics) Start(ctx context.Context) error { // exporters and close any open files. func (m *Metrics) Shutdown(ctx context.Context) error { n := len(m.shutdownFuncs) - // shutdown in reverse order because some exporters may depend on others + // shutdown in reverse order because we can't close files until after the exporter is stopped for i := n - 1; i >= 0; i-- { if err := m.shutdownFuncs[i](ctx); err != nil { return err From 56b215a47725894396df66385b74b32dc12305e1 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Thu, 30 Oct 2025 19:50:44 -0400 Subject: [PATCH 11/52] update metrics config and instrumentation --- .gitignore | 2 ++ baseapp/test_helpers.go | 4 +++- telemetry/config.go | 5 +++++ telemetry/metrics.go | 32 +++++++++++++++++++++++++++----- telemetry/testing.go | 5 ++++- 5 files changed, 41 insertions(+), 7 deletions(-) diff --git a/.gitignore b/.gitignore index 4ce3ebf35d58..621132f18ff3 100644 --- a/.gitignore +++ b/.gitignore @@ -65,3 +65,5 @@ debug_container.log *.synctex.gz /x/genutil/config/priv_validator_key.json /x/genutil/data/priv_validator_state.json +/.envrc +/.env diff --git a/baseapp/test_helpers.go b/baseapp/test_helpers.go index 12695792d659..f303bb4d8efa 100644 --- a/baseapp/test_helpers.go +++ b/baseapp/test_helpers.go @@ -31,13 +31,15 @@ func (app *BaseApp) Simulate(txBytes []byte) (sdk.GasInfo, *sdk.Result, error) { } func (app *BaseApp) SimDeliver(txEncoder sdk.TxEncoder, tx sdk.Tx) (sdk.GasInfo, *sdk.Result, error) { + span := app.blockSpan.StartSpan("SimDeliver") + defer span.End() // See comment for Check(). bz, err := txEncoder(tx) if err != nil { return sdk.GasInfo{}, nil, errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, "%s", err) } - gasInfo, result, _, err := app.RunTx(execModeFinalize, bz, tx, -1, nil, nil, log.NewNopTracer(log.NewNopLogger())) + gasInfo, result, _, err := app.RunTx(execModeFinalize, bz, tx, -1, nil, nil, span) return gasInfo, result, err } diff --git a/telemetry/config.go b/telemetry/config.go index 1e9eeb52ac97..6e68a832a27d 100644 --- a/telemetry/config.go +++ b/telemetry/config.go @@ -141,6 +141,11 @@ type OtelTraceExportConfig struct { // Insecure disables TLS certificate verification for OTLP exporters. Insecure bool `mapstructure:"insecure" json:"insecure"` + // Headers is a map of HTTP headers to send with each request to the OTLP exporter. + // Useful for authentication, authorization, or custom metadata. + // Example: {"Authorization": "Bearer token123", "X-Custom-Header": "value"} + Headers map[string]string `mapstructure:"headers" json:"headers"` + // File is the file path to write trace data to when using the "stdout" exporter. // If it is empty, the trace data is written to stdout. File string `mapstructure:"file" json:"file"` diff --git a/telemetry/metrics.go b/telemetry/metrics.go index 0d47e63ccb55..b668d32f4982 100644 --- a/telemetry/metrics.go +++ b/telemetry/metrics.go @@ -18,7 +18,9 @@ import ( "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc" "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp" "go.opentelemetry.io/otel/exporters/stdout/stdouttrace" + "go.opentelemetry.io/otel/sdk/resource" otelsdktrace "go.opentelemetry.io/otel/sdk/trace" + semconv "go.opentelemetry.io/otel/semconv/v1.17.0" "cosmossdk.io/log" ) @@ -158,12 +160,18 @@ func New(cfg Config, opts ...Option) (_ *Metrics, rerr error) { if exporterOpts.Insecure { opts = append(opts, otlptracegrpc.WithInsecure()) } + if len(exporterOpts.Headers) > 0 { + opts = append(opts, otlptracegrpc.WithHeaders(exporterOpts.Headers)) + } client = otlptracegrpc.NewClient(opts...) default: opts := []otlptracehttp.Option{otlptracehttp.WithEndpoint(endpoint)} if exporterOpts.Insecure { opts = append(opts, otlptracehttp.WithInsecure()) } + if len(exporterOpts.Headers) > 0 { + opts = append(opts, otlptracehttp.WithHeaders(exporterOpts.Headers)) + } client = otlptracehttp.NewClient(opts...) } exporter := otlptrace.NewUnstarted(client) @@ -196,13 +204,27 @@ func New(cfg Config, opts ...Option) (_ *Metrics, rerr error) { } } + // Determine service name for both resource and tracer + serviceName := cfg.ServiceName + if serviceName == "" { + serviceName = "cosmos-sdk" + } + + // Create OpenTelemetry resource with service name + res, err := resource.New(context.Background(), + resource.WithAttributes( + semconv.ServiceName(serviceName), + ), + ) + if err != nil { + return nil, fmt.Errorf("failed to create trace resource: %w", err) + } + + // Add resource to tracer provider options + tracerProviderOpts = append(tracerProviderOpts, otelsdktrace.WithResource(res)) tracerProvider := otelsdktrace.NewTracerProvider(tracerProviderOpts...) m.shutdownFuncs = append(m.shutdownFuncs, tracerProvider.Shutdown) - tracerName := cfg.ServiceName - if tracerName == "" { - tracerName = "cosmos-sdk" - } - m.tracer = NewOtelTracer(tracerProvider.Tracer(tracerName), m.logger) + m.tracer = NewOtelTracer(tracerProvider.Tracer(serviceName), m.logger) case "metrics": m.tracer = m.metricsTracer default: diff --git a/telemetry/testing.go b/telemetry/testing.go index 551068088ccd..f259e978e293 100644 --- a/telemetry/testing.go +++ b/telemetry/testing.go @@ -24,7 +24,10 @@ func TestingInit(t *testing.T, ctx context.Context, logger log.Logger) *Metrics } // configure metrics and tracing for testing - telemetryCfg := Config{Enabled: true} + telemetryCfg := Config{ + Enabled: true, + ServiceName: "cosmos-sdk-test", + } telemetryCfgJson, ok := os.LookupEnv("COSMOS_TELEMETRY") if ok && telemetryCfgJson != "" { err := json.Unmarshal([]byte(telemetryCfgJson), &telemetryCfg) From f9ce55cb6fb9e6c68610434a096dcab0a649addc Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Fri, 31 Oct 2025 10:07:51 -0400 Subject: [PATCH 12/52] start adding otel metric config --- go.mod | 16 ++++++++++++++-- go.sum | 28 ++++++++++++++++++++++++++++ telemetry/config.go | 37 +++++++++++++++++++++++++++---------- telemetry/metrics.go | 10 ++++++++++ 4 files changed, 79 insertions(+), 12 deletions(-) diff --git a/go.mod b/go.mod index d696ee4f4640..c53a80266aad 100644 --- a/go.mod +++ b/go.mod @@ -59,7 +59,7 @@ require ( github.com/tidwall/btree v1.8.1 go.opentelemetry.io/otel v1.38.0 go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.37.0 + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0 go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0 go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.38.0 go.opentelemetry.io/otel/sdk v1.38.0 @@ -162,6 +162,7 @@ require ( github.com/googleapis/enterprise-certificate-proxy v0.3.6 // indirect github.com/googleapis/gax-go/v2 v2.15.0 // indirect github.com/gorilla/websocket v1.5.3 // indirect + github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 // indirect github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect github.com/hashicorp/aws-sdk-go-base/v2 v2.0.0-beta.65 // indirect @@ -194,7 +195,8 @@ require ( github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/prometheus/client_model v0.6.2 // indirect - github.com/prometheus/procfs v0.16.1 // indirect + github.com/prometheus/otlptranslator v0.0.2 // indirect + github.com/prometheus/procfs v0.17.0 // indirect github.com/rcrowley/go-metrics v0.0.0-20250401214520-65e299d6c5c9 // indirect github.com/rogpeppe/go-internal v1.14.1 // indirect github.com/rs/cors v1.11.1 // indirect @@ -217,7 +219,17 @@ require ( go.opentelemetry.io/contrib/detectors/gcp v1.36.0 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0 // indirect + go.opentelemetry.io/contrib/otelconf v0.18.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.14.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.14.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.38.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.38.0 // indirect + go.opentelemetry.io/otel/exporters/prometheus v0.60.0 // indirect + go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.14.0 // indirect + go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.38.0 // indirect + go.opentelemetry.io/otel/log v0.14.0 // indirect go.opentelemetry.io/otel/metric v1.38.0 // indirect + go.opentelemetry.io/otel/sdk/log v0.14.0 // indirect go.opentelemetry.io/otel/sdk/metric v1.38.0 // indirect go.opentelemetry.io/proto/otlp v1.7.1 // indirect go.uber.org/multierr v1.11.0 // indirect diff --git a/go.sum b/go.sum index 693c2dcbb741..0df3549e96fa 100644 --- a/go.sum +++ b/go.sum @@ -439,6 +439,8 @@ github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc h1:GN2Lv3MGO7AS6PrRoT6yV5+wkrOpcszoIsO4+4ds248= +github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc/go.mod h1:+JKpmjMGhpgPL+rXZ5nsZieVzvarn86asRlBg4uNGnk= github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-middleware v1.2.2/go.mod h1:EaizFBKfUKtMIF5iaDEhniwNedqGo9FuLFzppDr3uwI= github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDaL56wXCB/5+wF6uHfaI= @@ -706,6 +708,8 @@ github.com/prometheus/common v0.15.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16 github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= github.com/prometheus/common v0.67.1 h1:OTSON1P4DNxzTg4hmKCc37o4ZAZDv0cfXLkOt0oEowI= github.com/prometheus/common v0.67.1/go.mod h1:RpmT9v35q2Y+lsieQsdOh5sXZ6ajUGC8NjZAmr8vb0Q= +github.com/prometheus/otlptranslator v0.0.2 h1:+1CdeLVrRQ6Psmhnobldo0kTp96Rj80DRXRd5OSnMEQ= +github.com/prometheus/otlptranslator v0.0.2/go.mod h1:P8AwMgdD7XEr6QRUJ2QWLpiAZTgTE2UYgjlu3svompI= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= @@ -715,6 +719,8 @@ github.com/prometheus/procfs v0.3.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4O github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg= github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is= +github.com/prometheus/procfs v0.17.0 h1:FuLQ+05u4ZI+SS/w9+BWEM2TXiHKsUQ9TADiRH7DuK0= +github.com/prometheus/procfs v0.17.0/go.mod h1:oPQLaDAMRbA+u8H5Pbfq+dl3VDAvHxMUOVhe0wYB2zw= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rcrowley/go-metrics v0.0.0-20250401214520-65e299d6c5c9 h1:bsUq1dX0N8AOIL7EB/X911+m4EHsnWEHeJ0c+3TTBrg= github.com/rcrowley/go-metrics v0.0.0-20250401214520-65e299d6c5c9/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= @@ -839,22 +845,44 @@ go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.6 go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0/go.mod h1:snMWehoOh2wsEwnvvwtDyFCxVeDAODenXHtn5vzrKjo= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0 h1:Hf9xI/XLML9ElpiHVDNwvqI0hIFlzV8dgIr35kV1kRU= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0/go.mod h1:NfchwuyNoMcZ5MLHwPrODwUF1HWCXWrL31s8gSAdIKY= +go.opentelemetry.io/contrib/otelconf v0.18.0 h1:ciF2Gf00BWs0DnexKFZXcxg9kJ8r3SUW1LOzW3CsKA8= +go.opentelemetry.io/contrib/otelconf v0.18.0/go.mod h1:FcP7k+JLwBLdOxS6qY6VQ/4b5VBntI6L6o80IMwhAeI= go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= +go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.14.0 h1:OMqPldHt79PqWKOMYIAQs3CxAi7RLgPxwfFSwr4ZxtM= +go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.14.0/go.mod h1:1biG4qiqTxKiUCtoWDPpL3fB3KxVwCiGw81j3nKMuHE= +go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.14.0 h1:QQqYw3lkrzwVsoEX0w//EhH/TCnpRdEenKBOOEIMjWc= +go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.14.0/go.mod h1:gSVQcr17jk2ig4jqJ2DX30IdWH251JcNAecvrqTxH1s= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.38.0 h1:vl9obrcoWVKp/lwl8tRE33853I8Xru9HFbw/skNeLs8= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.38.0/go.mod h1:GAXRxmLJcVM3u22IjTg74zWBrRCKq8BnOqUVLodpcpw= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.38.0 h1:Oe2z/BCg5q7k4iXC3cqJxKYg0ieRiOqF0cecFYdPTwk= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.38.0/go.mod h1:ZQM5lAJpOsKnYagGg/zV2krVqTtaVdYdDkhMoX6Oalg= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 h1:GqRJVj7UmLjCVyVJ3ZFLdPRmhDUp2zFmQe3RHIOsw24= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0/go.mod h1:ri3aaHSmCTVYu2AWv44YMauwAQc0aqI9gHKIcSbI1pU= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.37.0 h1:EtFWSnwW9hGObjkIdmlnWSydO+Qs8OwzfzXLUPg4xOc= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.37.0/go.mod h1:QjUEoiGCPkvFZ/MjK6ZZfNOS6mfVEVKYE99dFhuN2LI= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0 h1:lwI4Dc5leUqENgGuQImwLo4WnuXFPetmPpkLi2IrX54= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0/go.mod h1:Kz/oCE7z5wuyhPxsXDuaPteSWqjSBD5YaSdbxZYGbGk= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0 h1:aTL7F04bJHUlztTsNGJ2l+6he8c+y/b//eR0jjjemT4= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0/go.mod h1:kldtb7jDTeol0l3ewcmd8SDvx3EmIE7lyvqbasU3QC4= +go.opentelemetry.io/otel/exporters/prometheus v0.60.0 h1:cGtQxGvZbnrWdC2GyjZi0PDKVSLWP/Jocix3QWfXtbo= +go.opentelemetry.io/otel/exporters/prometheus v0.60.0/go.mod h1:hkd1EekxNo69PTV4OWFGZcKQiIqg0RfuWExcPKFvepk= +go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.14.0 h1:B/g+qde6Mkzxbry5ZZag0l7QrQBCtVm7lVjaLgmpje8= +go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.14.0/go.mod h1:mOJK8eMmgW6ocDJn6Bn11CcZ05gi3P8GylBXEkZtbgA= go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.36.0 h1:rixTyDGXFxRy1xzhKrotaHy3/KXdPhlWARrCgK+eqUY= go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.36.0/go.mod h1:dowW6UsM9MKbJq5JTz2AMVp3/5iW5I/TStsk8S+CfHw= +go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.38.0 h1:wm/Q0GAAykXv83wzcKzGGqAnnfLFyFe7RslekZuv+VI= +go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.38.0/go.mod h1:ra3Pa40+oKjvYh+ZD3EdxFZZB0xdMfuileHAm4nNN7w= go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.38.0 h1:kJxSDN4SgWWTjG/hPp3O7LCGLcHXFlvS2/FFOrwL+SE= go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.38.0/go.mod h1:mgIOzS7iZeKJdeB8/NYHrJ48fdGc71Llo5bJ1J4DWUE= +go.opentelemetry.io/otel/log v0.14.0 h1:2rzJ+pOAZ8qmZ3DDHg73NEKzSZkhkGIua9gXtxNGgrM= +go.opentelemetry.io/otel/log v0.14.0/go.mod h1:5jRG92fEAgx0SU/vFPxmJvhIuDU9E1SUnEQrMlJpOno= go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E= go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg= +go.opentelemetry.io/otel/sdk/log v0.14.0 h1:JU/U3O7N6fsAXj0+CXz21Czg532dW2V4gG1HE/e8Zrg= +go.opentelemetry.io/otel/sdk/log v0.14.0/go.mod h1:imQvII+0ZylXfKU7/wtOND8Hn4OpT3YUoIgqJVksUkM= go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM= go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA= go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= diff --git a/telemetry/config.go b/telemetry/config.go index 6e68a832a27d..42b78413e73e 100644 --- a/telemetry/config.go +++ b/telemetry/config.go @@ -5,6 +5,7 @@ import ( "github.com/hashicorp/go-metrics" "github.com/prometheus/common/expfmt" + otelconf "go.opentelemetry.io/contrib/otelconf/v0.3.0" ) // globalTelemetryEnabled is a private variable that stores the telemetry enabled state. @@ -115,41 +116,57 @@ type Config struct { // - "noop": No-op trace sink (default) TraceSink string `mapstructure:"trace-sink" json:"trace-sink"` - // OtelTraceExporters is a list of OTLP exporters to use for trace data. + // OtelTraceExporters is a list of exporters to use for trace data. // This is only used when trace sink is set to "otel". - OtelTraceExporters []OtelTraceExportConfig `mapstructure:"otel-trace-exporters" json:"otel-trace-exporters"` + OtelTraceExporters []OtelExportConfig `mapstructure:"otel-trace-exporters" json:"otel-trace-exporters"` + + // OtelMetricsExporters is a list of exporters to use for metrics data via OpenTelemetry. + // When configured, wrapper functions (IncrCounter, SetGauge, etc.) will use OTel instruments + // instead of go-metrics, and metrics will be exported through these exporters. + OtelMetricsExporters []OtelExportConfig `mapstructure:"otel-metrics-exporters" json:"otel-metrics-exporters"` } -type OtelTraceExportConfig struct { +// OtelExportConfig defines configuration for an OpenTelemetry exporter. +// This is used for both traces and metrics exporters. +type OtelExportConfig struct { // Type is the exporter type. - // Must be one of: - // - "stdout" - // - "otlp" - // - // OTLP exporters must set the endpoint URL and can optionally set the transport protocol. + // For traces: "stdout", "otlp" + // For metrics: "stdout", "otlp", "prometheus" Type string `mapstructure:"type" json:"type"` // OTLPTransport is the transport protocol to use for OTLP. // Must be one of: // - "http" (default) // - "grpc" + // Only used when Type is "otlp". OTLPTransport string `mapstructure:"otlp-transport" json:"otlp-transport"` // Endpoint is the OTLP exporter endpoint URL (grpc or http). + // Only used when Type is "otlp". + // Example: "localhost:4318" for HTTP, "localhost:4317" for gRPC Endpoint string `mapstructure:"endpoint" json:"endpoint"` // Insecure disables TLS certificate verification for OTLP exporters. + // Only used when Type is "otlp". Insecure bool `mapstructure:"insecure" json:"insecure"` // Headers is a map of HTTP headers to send with each request to the OTLP exporter. // Useful for authentication, authorization, or custom metadata. + // Only used when Type is "otlp". // Example: {"Authorization": "Bearer token123", "X-Custom-Header": "value"} Headers map[string]string `mapstructure:"headers" json:"headers"` - // File is the file path to write trace data to when using the "stdout" exporter. - // If it is empty, the trace data is written to stdout. + // File is the file path to write data to when using the "stdout" exporter. + // If empty, data is written to stdout. + // Only used when Type is "stdout". File string `mapstructure:"file" json:"file"` // PrettyPrint enables pretty-printing of JSON output when using the "stdout" exporter. + // Only used when Type is "stdout" for traces. PrettyPrint bool `mapstructure:"pretty-print" json:"pretty-print"` + + // ListenAddress is the address to listen on for Prometheus scraping. + // Only used when Type is "prometheus" for metrics. + // Example: ":8080" or "localhost:9090" + ListenAddress string `mapstructure:"listen-address" json:"listen-address"` } diff --git a/telemetry/metrics.go b/telemetry/metrics.go index b668d32f4982..eb4491099e65 100644 --- a/telemetry/metrics.go +++ b/telemetry/metrics.go @@ -46,6 +46,16 @@ type Metrics struct { logger log.Logger tracer log.Tracer metricsTracer *MetricsTracer + + // OpenTelemetry metrics (when OtelMetricsExporters is configured) + meterProvider *sdkmetric.MeterProvider + meter metric.Meter + + // Instrument cache for wrapper functions + counters map[string]metric.Int64Counter + gauges map[string]metric.Float64Gauge + histograms map[string]metric.Float64Histogram + mu sync.RWMutex } // GatherResponse contains collected metrics in the requested format. From 3fff00f53ee6ef9949247ffad9c090a8ef4c8421 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Fri, 31 Oct 2025 13:32:49 -0400 Subject: [PATCH 13/52] migrate to pure otel setup --- baseapp/abci.go | 75 ++++--- baseapp/baseapp.go | 72 +++---- baseapp/genesis.go | 2 +- baseapp/test_helpers.go | 11 +- baseapp/txnrunner/default.go | 7 +- blockstm/executor.go | 4 +- blockstm/txnrunner.go | 5 +- blockstm/types.go | 4 +- client/v2/go.mod | 18 +- client/v2/go.sum | 35 +++- go.mod | 17 +- go.sum | 9 +- log/tracer.go | 99 ---------- server/api/server.go | 28 --- server/config/config.go | 19 +- server/start.go | 28 +-- simapp/go.mod | 17 +- simapp/go.sum | 37 +++- simapp/sim_test.go | 11 +- systemtests/go.mod | 18 +- systemtests/go.sum | 35 +++- telemetry/config.go | 192 ++++-------------- telemetry/doc.go | 39 +--- telemetry/file_sink.go | 157 --------------- telemetry/file_sink_test.go | 182 ----------------- telemetry/metrics.go | 366 ----------------------------------- telemetry/metrics_span.go | 139 ------------- telemetry/metrics_test.go | 108 ----------- telemetry/options.go | 14 -- telemetry/otel_span.go | 203 ------------------- telemetry/testing.go | 37 +--- telemetry/wrapper.go | 2 + tests/go.mod | 17 +- tests/go.sum | 37 +++- tests/systemtests/go.mod | 18 +- tests/systemtests/go.sum | 35 +++- testutil/network/network.go | 4 +- types/abci.go | 4 +- types/context.go | 9 +- 39 files changed, 391 insertions(+), 1723 deletions(-) delete mode 100644 log/tracer.go delete mode 100644 telemetry/file_sink.go delete mode 100644 telemetry/file_sink_test.go delete mode 100644 telemetry/metrics.go delete mode 100644 telemetry/metrics_span.go delete mode 100644 telemetry/metrics_test.go delete mode 100644 telemetry/options.go delete mode 100644 telemetry/otel_span.go diff --git a/baseapp/abci.go b/baseapp/abci.go index 5254a2c7d60a..e1aabdc64216 100644 --- a/baseapp/abci.go +++ b/baseapp/abci.go @@ -39,7 +39,7 @@ const ( ) func (app *BaseApp) InitChain(req *abci.RequestInitChain) (*abci.ResponseInitChain, error) { - span := app.blockSpan.StartSpan("InitChain") + _, span := tracer.Start(context.Background(), "InitChain") defer span.End() if req.ChainId != app.chainID { @@ -155,8 +155,8 @@ func (app *BaseApp) Info(_ *abci.RequestInfo) (*abci.ResponseInfo, error) { // Query implements the ABCI interface. It delegates to CommitMultiStore if it // implements Queryable. -func (app *BaseApp) Query(_ context.Context, req *abci.RequestQuery) (resp *abci.ResponseQuery, err error) { - span := app.tracer.StartSpan("Query") +func (app *BaseApp) Query(ctx context.Context, req *abci.RequestQuery) (resp *abci.ResponseQuery, err error) { + ctx, span := tracer.Start(ctx, "Query") defer span.End() // add panic recovery for all queries @@ -348,7 +348,7 @@ func (app *BaseApp) ApplySnapshotChunk(req *abci.RequestApplySnapshotChunk) (*ab // will contain relevant error information. Regardless of tx execution outcome, // the ResponseCheckTx will contain the relevant gas execution context. func (app *BaseApp) CheckTx(req *abci.RequestCheckTx) (*abci.ResponseCheckTx, error) { - span := app.tracer.StartSpan("CheckTx") + _, span := tracer.Start(context.Background(), "CheckTx") defer span.End() var mode sdk.ExecMode @@ -365,7 +365,7 @@ func (app *BaseApp) CheckTx(req *abci.RequestCheckTx) (*abci.ResponseCheckTx, er } if app.abciHandlers.CheckTxHandler == nil { - gasInfo, result, anteEvents, err := app.RunTx(mode, req.Tx, nil, -1, nil, nil, span) + gasInfo, result, anteEvents, err := app.RunTx(mode, req.Tx, nil, -1, nil, nil) if err != nil { return sdkerrors.ResponseCheckTxWithEvents(err, gasInfo.GasWanted, gasInfo.GasUsed, anteEvents, app.trace), nil } @@ -381,7 +381,7 @@ func (app *BaseApp) CheckTx(req *abci.RequestCheckTx) (*abci.ResponseCheckTx, er // Create wrapper to avoid users overriding the execution mode runTx := func(txBytes []byte, tx sdk.Tx) (gInfo sdk.GasInfo, result *sdk.Result, anteEvents []abci.Event, err error) { - return app.RunTx(mode, txBytes, tx, -1, nil, nil, span) + return app.RunTx(mode, txBytes, tx, -1, nil, nil) } return app.abciHandlers.CheckTxHandler(runTx, req) @@ -401,9 +401,6 @@ func (app *BaseApp) CheckTx(req *abci.RequestCheckTx) (*abci.ResponseCheckTx, er // Ref: https://github.com/cosmos/cosmos-sdk/blob/main/docs/architecture/adr-060-abci-1.0.md // Ref: https://github.com/cometbft/cometbft/blob/main/spec/abci/abci%2B%2B_basic_concepts.md func (app *BaseApp) PrepareProposal(req *abci.RequestPrepareProposal) (resp *abci.ResponsePrepareProposal, err error) { - span := app.blockSpan.StartSpan("PrepareProposal") - defer span.End() - if app.abciHandlers.PrepareProposalHandler == nil { return nil, errors.New("PrepareProposal handler not set") } @@ -466,7 +463,10 @@ func (app *BaseApp) PrepareProposal(req *abci.RequestPrepareProposal) (resp *abc } }() - resp, err = app.abciHandlers.PrepareProposalHandler(prepareProposalState.Context(), req) + ctx := prepareProposalState.Context() + ctx, span := ctx.StartSpan(tracer, "PrepareProposal") + defer span.End() + resp, err = app.abciHandlers.PrepareProposalHandler(ctx, req) if err != nil { app.logger.Error("failed to prepare proposal", "height", req.Height, "time", req.Time, "err", err) return &abci.ResponsePrepareProposal{Txs: req.Txs}, nil @@ -491,9 +491,6 @@ func (app *BaseApp) PrepareProposal(req *abci.RequestPrepareProposal) (resp *abc // Ref: https://github.com/cosmos/cosmos-sdk/blob/main/docs/architecture/adr-060-abci-1.0.md // Ref: https://github.com/cometbft/cometbft/blob/main/spec/abci/abci%2B%2B_basic_concepts.md func (app *BaseApp) ProcessProposal(req *abci.RequestProcessProposal) (resp *abci.ResponseProcessProposal, err error) { - span := app.blockSpan.StartSpan("ProcessProposal") - defer span.End() - if app.abciHandlers.ProcessProposalHandler == nil { return nil, errors.New("ProcessProposal handler not set") } @@ -528,7 +525,10 @@ func (app *BaseApp) ProcessProposal(req *abci.RequestProcessProposal) (resp *abc } processProposalState := app.stateManager.GetState(execModeProcessProposal) - processProposalState.SetContext(app.getContextForProposal(processProposalState.Context(), req.Height). + ctx := processProposalState.Context() + ctx, span := ctx.StartSpan(tracer, "ProcessProposal") + defer span.End() + processProposalState.SetContext(app.getContextForProposal(ctx, req.Height). WithVoteInfos(req.ProposedLastCommit.Votes). // this is a set of votes that are not finalized yet, wait for commit WithBlockHeight(req.Height). WithBlockTime(req.Time). @@ -591,9 +591,6 @@ func (app *BaseApp) ProcessProposal(req *abci.RequestProcessProposal) (resp *abc // height and are committed in the subsequent height, i.e. H+2. An error is // returned if vote extensions are not enabled or if extendVote fails or panics. func (app *BaseApp) ExtendVote(_ context.Context, req *abci.RequestExtendVote) (resp *abci.ResponseExtendVote, err error) { - span := app.blockSpan.StartSpan("ExtendVote") - defer span.End() - // Always reset state given that ExtendVote and VerifyVoteExtension can timeout // and be called again in a subsequent round. var ctx sdk.Context @@ -613,6 +610,9 @@ func (app *BaseApp) ExtendVote(_ context.Context, req *abci.RequestExtendVote) ( return nil, errors.New("application ExtendVote handler not set") } + ctx, span := ctx.StartSpan(tracer, "ExtendVote") + defer span.End() + // If vote extensions are not enabled, as a safety precaution, we return an // error. cp := app.GetConsensusParams(ctx) @@ -667,9 +667,6 @@ func (app *BaseApp) ExtendVote(_ context.Context, req *abci.RequestExtendVote) ( // phase. The response MUST be deterministic. An error is returned if vote // extensions are not enabled or if verifyVoteExt fails or panics. func (app *BaseApp) VerifyVoteExtension(req *abci.RequestVerifyVoteExtension) (resp *abci.ResponseVerifyVoteExtension, err error) { - span := app.blockSpan.StartSpan("VerifyVoteExtension") - defer span.End() - if app.abciHandlers.VerifyVoteExtensionHandler == nil { return nil, errors.New("application VerifyVoteExtension handler not set") } @@ -687,6 +684,9 @@ func (app *BaseApp) VerifyVoteExtension(req *abci.RequestVerifyVoteExtension) (r ctx = sdk.NewContext(ms, emptyHeader, false, app.logger).WithStreamingManager(app.streamingManager) } + ctx, span := ctx.StartSpan(tracer, "VerifyVoteExtension") + defer span.End() + // If vote extensions are not enabled, as a safety precaution, we return an // error. cp := app.GetConsensusParams(ctx) @@ -737,10 +737,7 @@ func (app *BaseApp) VerifyVoteExtension(req *abci.RequestVerifyVoteExtension) (r // Execution flow or by the FinalizeBlock ABCI method. The context received is // only used to handle early cancellation, for anything related to state app.stateManager.GetState(execModeFinalize).Context() // must be used. -func (app *BaseApp) internalFinalizeBlock(ctx context.Context, req *abci.RequestFinalizeBlock) (*abci.ResponseFinalizeBlock, error) { - ctx, span := app.tracer.StartSpanContext(ctx, "internalFinalizeBlock") - defer span.End() - +func (app *BaseApp) internalFinalizeBlock(goCtx context.Context, req *abci.RequestFinalizeBlock) (*abci.ResponseFinalizeBlock, error) { var events []abci.Event if err := app.checkHalt(req.Height, req.Time); err != nil { @@ -774,9 +771,12 @@ func (app *BaseApp) internalFinalizeBlock(ctx context.Context, req *abci.Request app.stateManager.SetState(execModeFinalize, app.cms, header, app.logger, app.streamingManager) finalizeState = app.stateManager.GetState(execModeFinalize) } + ctx := finalizeState.Context().WithContext(goCtx) + ctx, span := ctx.StartSpan(tracer, "internalFinalizeBlock") + defer span.End() // Context is now updated with Header information. - finalizeState.SetContext(finalizeState.Context(). + finalizeState.SetContext(ctx. WithBlockHeader(header). WithHeaderHash(req.Hash). WithHeaderInfo(coreheader.Info{ @@ -806,14 +806,14 @@ func (app *BaseApp) internalFinalizeBlock(ctx context.Context, req *abci.Request WithHeaderHash(req.Hash)) } - preblockEvents, err := app.preBlock(span, req) + preblockEvents, err := app.preBlock(req) if err != nil { return nil, err } events = append(events, preblockEvents...) - beginBlock, err := app.beginBlock(span, req) + beginBlock, err := app.beginBlock(req) if err != nil { return nil, err } @@ -870,7 +870,7 @@ func (app *BaseApp) internalFinalizeBlock(ctx context.Context, req *abci.Request WithBlockGasUsed(blockGasUsed). WithBlockGasWanted(blockGasWanted), ) - endBlock, err := app.endBlock(span, finalizeState.Context()) + endBlock, err := app.endBlock() if err != nil { return nil, err } @@ -898,7 +898,6 @@ func (app *BaseApp) executeTxsWithExecutor(ctx context.Context, ms storetypes.Mu if app.txRunner == nil { app.txRunner = txnrunner.NewDefaultRunner( app.txDecoder, - app.tracer, ) } @@ -916,9 +915,6 @@ func (app *BaseApp) executeTxsWithExecutor(ctx context.Context, ms storetypes.Mu // extensions into the proposal, which should not themselves be executed in cases // where they adhere to the sdk.Tx interface. func (app *BaseApp) FinalizeBlock(req *abci.RequestFinalizeBlock) (res *abci.ResponseFinalizeBlock, err error) { - ctx, span := app.blockSpan.StartSpanContext(context.Background(), "FinalizeBlock") - defer span.End() - defer func() { if res == nil { return @@ -952,7 +948,7 @@ func (app *BaseApp) FinalizeBlock(req *abci.RequestFinalizeBlock) (res *abci.Res } // if no OE is running, just run the block (this is either a block replay or a OE that got aborted) - res, err = app.internalFinalizeBlock(ctx, req) + res, err = app.internalFinalizeBlock(context.Background(), req) if res != nil { res.AppHash = app.workingHash() } @@ -986,15 +982,12 @@ func (app *BaseApp) checkHalt(height int64, time time.Time) error { // against that height and gracefully halt if it matches the latest committed // height. func (app *BaseApp) Commit() (*abci.ResponseCommit, error) { - span := app.blockSpan.StartSpan("Commit") - defer func() { - span.End() - app.blockSpan.End() - app.blockSpan = app.tracer.StartSpan("block") - }() - finalizeState := app.stateManager.GetState(execModeFinalize) - header := finalizeState.Context().BlockHeader() + ctx := finalizeState.Context() + ctx, span := ctx.StartSpan(tracer, "Commit") + defer span.End() + + header := ctx.BlockHeader() retainHeight := app.GetBlockRetentionHeight(header.Height) if app.abciHandlers.Precommiter != nil { diff --git a/baseapp/baseapp.go b/baseapp/baseapp.go index 4cc51ae8c3da..fb502333e6f6 100644 --- a/baseapp/baseapp.go +++ b/baseapp/baseapp.go @@ -1,7 +1,6 @@ package baseapp import ( - "context" "fmt" "maps" "math" @@ -15,6 +14,9 @@ import ( cmtproto "github.com/cometbft/cometbft/proto/tendermint/types" dbm "github.com/cosmos/cosmos-db" "github.com/cosmos/gogoproto/proto" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/trace" protov2 "google.golang.org/protobuf/proto" errorsmod "cosmossdk.io/errors" @@ -32,6 +34,7 @@ import ( codectypes "github.com/cosmos/cosmos-sdk/codec/types" servertypes "github.com/cosmos/cosmos-sdk/server/types" "github.com/cosmos/cosmos-sdk/telemetry" + _ "github.com/cosmos/cosmos-sdk/telemetry" // need to initialize telemetry before we declare tracer and metrics sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/types/mempool" @@ -60,13 +63,15 @@ const ( var _ servertypes.ABCI = (*BaseApp)(nil) +var ( + tracer trace.Tracer = otel.Tracer("baseapp") +) + // BaseApp reflects the ABCI application implementation. type BaseApp struct { // initialized on creation mu sync.Mutex // mu protects the fields below. logger log.Logger - tracer log.Tracer - blockSpan log.Span name string // application name from abci.BlockInfo db dbm.DB // common DB backend cms storetypes.CommitMultiStore // Main (uncached) state @@ -175,14 +180,8 @@ type BaseApp struct { func NewBaseApp( name string, logger log.Logger, db dbm.DB, txDecoder sdk.TxDecoder, options ...func(*BaseApp), ) *BaseApp { - tracer, ok := logger.(log.Tracer) - if !ok { - tracer = log.NewNopTracer(logger) - } app := &BaseApp{ logger: logger.With(log.ModuleKey, "baseapp"), - tracer: tracer, - blockSpan: tracer.StartSpan("block"), name: name, db: db, cms: store.NewCommitMultiStore(db, logger, storemetrics.NewNoOpMetrics()), // by default, we use a no-op metric gather in store @@ -662,14 +661,13 @@ func (app *BaseApp) cacheTxContext(ctx sdk.Context, txBytes []byte) (sdk.Context return ctx.WithMultiStore(msCache), msCache } -func (app *BaseApp) preBlock(tracer log.Tracer, req *abci.RequestFinalizeBlock) ([]abci.Event, error) { - span := tracer.StartSpan("preBlock") - defer span.End() - +func (app *BaseApp) preBlock(req *abci.RequestFinalizeBlock) ([]abci.Event, error) { var events []abci.Event if app.abciHandlers.PreBlocker != nil { finalizeState := app.stateManager.GetState(execModeFinalize) ctx := finalizeState.Context().WithEventManager(sdk.NewEventManager()) + ctx, span := ctx.StartSpan(tracer, "preBlock") + defer span.End() rsp, err := app.abciHandlers.PreBlocker(ctx, req) if err != nil { return nil, err @@ -688,14 +686,17 @@ func (app *BaseApp) preBlock(tracer log.Tracer, req *abci.RequestFinalizeBlock) return events, nil } -func (app *BaseApp) beginBlock(tracer log.Tracer, _ *abci.RequestFinalizeBlock) (sdk.BeginBlock, error) { +func (app *BaseApp) beginBlock(_ *abci.RequestFinalizeBlock) (sdk.BeginBlock, error) { var ( resp sdk.BeginBlock err error ) if app.abciHandlers.BeginBlocker != nil { - resp, err = app.abciHandlers.BeginBlocker(app.stateManager.GetState(execModeFinalize).Context()) + ctx := app.stateManager.GetState(execModeFinalize).Context() + ctx, span := ctx.StartSpan(tracer, "beginBlock") + defer span.End() + resp, err = app.abciHandlers.BeginBlocker(ctx) if err != nil { return resp, err } @@ -714,7 +715,7 @@ func (app *BaseApp) beginBlock(tracer log.Tracer, _ *abci.RequestFinalizeBlock) return resp, nil } -func (app *BaseApp) deliverTx(tx []byte, txMultiStore storetypes.MultiStore, txIndex int, incarnationCache map[string]any, tracer log.Tracer) *abci.ExecTxResult { +func (app *BaseApp) deliverTx(tx []byte, txMultiStore storetypes.MultiStore, txIndex int, incarnationCache map[string]any) *abci.ExecTxResult { gInfo := sdk.GasInfo{} resultStr := "successful" @@ -727,7 +728,7 @@ func (app *BaseApp) deliverTx(tx []byte, txMultiStore storetypes.MultiStore, txI telemetry.SetGauge(float32(gInfo.GasWanted), "tx", "gas", "wanted") }() - gInfo, result, anteEvents, err := app.RunTx(execModeFinalize, tx, nil, txIndex, txMultiStore, incarnationCache, tracer) + gInfo, result, anteEvents, err := app.RunTx(execModeFinalize, tx, nil, txIndex, txMultiStore, incarnationCache) if err != nil { resultStr = "failed" resp = sdkerrors.ResponseExecTxResultWithEvents( @@ -753,14 +754,14 @@ func (app *BaseApp) deliverTx(tx []byte, txMultiStore storetypes.MultiStore, txI // endBlock is an application-defined function that is called after transactions // have been processed in FinalizeBlock. -func (app *BaseApp) endBlock(tracer log.Tracer, _ context.Context) (sdk.EndBlock, error) { - span := tracer.StartSpan("endBlock") - defer span.End() - +func (app *BaseApp) endBlock() (sdk.EndBlock, error) { var endblock sdk.EndBlock if app.abciHandlers.EndBlocker != nil { - eb, err := app.abciHandlers.EndBlocker(app.stateManager.GetState(execModeFinalize).Context()) + ctx := app.stateManager.GetState(execModeFinalize).Context() + ctx, span := ctx.StartSpan(tracer, "endBlock") + defer span.End() + eb, err := app.abciHandlers.EndBlocker(ctx) if err != nil { return endblock, err } @@ -789,8 +790,9 @@ func (app *BaseApp) endBlock(tracer log.Tracer, _ context.Context) (sdk.EndBlock // and execute successfully. An error is returned otherwise. // both txbytes and the decoded tx are passed to runTx to avoid the state machine encoding the tx and decoding the transaction twice // passing the decoded tx to runTX is optional, it will be decoded if the tx is nil -func (app *BaseApp) RunTx(mode sdk.ExecMode, txBytes []byte, tx sdk.Tx, txIndex int, txMultiStore storetypes.MultiStore, incarnationCache map[string]any, tracer log.Tracer) (gInfo sdk.GasInfo, result *sdk.Result, anteEvents []abci.Event, err error) { - span := tracer.StartSpan("RunTx", "txBytes", txBytes, "txIndex", txIndex, "mode", mode) +func (app *BaseApp) RunTx(mode sdk.ExecMode, txBytes []byte, tx sdk.Tx, txIndex int, txMultiStore storetypes.MultiStore, incarnationCache map[string]any) (gInfo sdk.GasInfo, result *sdk.Result, anteEvents []abci.Event, err error) { + ctx := app.getContextForTx(mode, txBytes, txIndex) + ctx, span := ctx.StartSpan(tracer, "runTx") defer span.End() // NOTE: GasWanted should be returned by the AnteHandler. GasUsed is @@ -798,7 +800,6 @@ func (app *BaseApp) RunTx(mode sdk.ExecMode, txBytes []byte, tx sdk.Tx, txIndex // meter, so we initialize upfront. var gasWanted uint64 - ctx := app.getContextForTx(mode, txBytes, txIndex) if incarnationCache != nil { ctx = ctx.WithIncarnationCache(incarnationCache) } @@ -881,7 +882,7 @@ func (app *BaseApp) RunTx(mode sdk.ExecMode, txBytes []byte, tx sdk.Tx, txIndex // performance benefits, but it'll be more difficult to get right. anteCtx, msCache = app.cacheTxContext(ctx, txBytes) anteCtx = anteCtx.WithEventManager(sdk.NewEventManager()) - anteSpan := tracer.StartSpan("anteHandler") + anteCtx, anteSpan := anteCtx.StartSpan(tracer, "anteHandler") newCtx, err := app.anteHandler(anteCtx, tx, mode == execModeSimulate) anteSpan.End() @@ -932,7 +933,6 @@ func (app *BaseApp) RunTx(mode sdk.ExecMode, txBytes []byte, tx sdk.Tx, txIndex // in case message processing fails. At this point, the MultiStore // is a branch of a branch. runMsgCtx, msCache := app.cacheTxContext(ctx, txBytes) - runMsgCtx = runMsgCtx.WithLogger(tracer) // attach the tracer to the context as the logger // Attempt to execute all messages and only update state if all messages pass // and we're in DeliverTx. Note, runMsgs will never return a reference to a @@ -991,12 +991,7 @@ func (app *BaseApp) RunTx(mode sdk.ExecMode, txBytes []byte, tx sdk.Tx, txIndex // Handler does not exist for a given message route. Otherwise, a reference to a // Result is returned. The caller must not commit state if an error is returned. func (app *BaseApp) runMsgs(ctx sdk.Context, msgs []sdk.Msg, msgsV2 []protov2.Message, mode sdk.ExecMode) (*sdk.Result, error) { - // extract the tracer from the context - tracer, ok := ctx.Logger().(log.Tracer) - if !ok { - tracer = log.NewNopTracer(app.logger) - } - span := tracer.StartSpan("runMsgs") + ctx, span := ctx.StartSpan(tracer, "runMsgs") defer span.End() events := sdk.EmptyEvents() @@ -1015,7 +1010,12 @@ func (app *BaseApp) runMsgs(ctx sdk.Context, msgs []sdk.Msg, msgsV2 []protov2.Me return nil, errorsmod.Wrapf(sdkerrors.ErrUnknownRequest, "no message handler found for %T", msg) } - msgSpan := span.StartSpan("msgHandler", "msgType", sdk.MsgTypeURL(msg), "msgIndex", i) + ctx, msgSpan := ctx.StartSpan(tracer, "msgHandler", + trace.WithAttributes( + attribute.String("msg_type", sdk.MsgTypeURL(msg)), + attribute.Int("msg_index", i), + ), + ) // ADR 031 request type routing msgResult, err := handler(ctx, msg) if err != nil { @@ -1110,7 +1110,7 @@ func (app *BaseApp) PrepareProposalVerifyTx(tx sdk.Tx) ([]byte, error) { return nil, err } - _, _, _, err = app.RunTx(execModePrepareProposal, bz, tx, -1, nil, nil, app.tracer) + _, _, _, err = app.RunTx(execModePrepareProposal, bz, tx, -1, nil, nil) if err != nil { return nil, err } @@ -1129,7 +1129,7 @@ func (app *BaseApp) ProcessProposalVerifyTx(txBz []byte) (sdk.Tx, error) { return nil, err } - _, _, _, err = app.RunTx(execModeProcessProposal, txBz, tx, -1, nil, nil, app.tracer) + _, _, _, err = app.RunTx(execModeProcessProposal, txBz, tx, -1, nil, nil) if err != nil { return nil, err } diff --git a/baseapp/genesis.go b/baseapp/genesis.go index cbc1adc5d709..547a1322d8a7 100644 --- a/baseapp/genesis.go +++ b/baseapp/genesis.go @@ -13,7 +13,7 @@ var _ genesis.TxHandler = (*BaseApp)(nil) // ExecuteGenesisTx implements genesis.GenesisState from // cosmossdk.io/core/genesis to set initial state in genesis func (ba *BaseApp) ExecuteGenesisTx(tx []byte) error { - res := ba.deliverTx(tx, nil, -1, nil, ba.tracer) + res := ba.deliverTx(tx, nil, -1, nil) if res.Code != types.CodeTypeOK { return errors.New(res.Log) diff --git a/baseapp/test_helpers.go b/baseapp/test_helpers.go index f303bb4d8efa..6144552490b2 100644 --- a/baseapp/test_helpers.go +++ b/baseapp/test_helpers.go @@ -5,7 +5,6 @@ import ( errorsmod "cosmossdk.io/errors" - "cosmossdk.io/log" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) @@ -20,26 +19,24 @@ func (app *BaseApp) SimCheck(txEncoder sdk.TxEncoder, tx sdk.Tx) (sdk.GasInfo, * return sdk.GasInfo{}, nil, errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, "%s", err) } - gasInfo, result, _, err := app.RunTx(execModeCheck, bz, tx, -1, nil, nil, log.NewNopTracer(log.NewNopLogger())) + gasInfo, result, _, err := app.RunTx(execModeCheck, bz, tx, -1, nil, nil) return gasInfo, result, err } // Simulate executes a tx in simulate mode to get result and gas info. func (app *BaseApp) Simulate(txBytes []byte) (sdk.GasInfo, *sdk.Result, error) { - gasInfo, result, _, err := app.RunTx(execModeSimulate, txBytes, nil, -1, nil, nil, log.NewNopTracer(log.NewNopLogger())) + gasInfo, result, _, err := app.RunTx(execModeSimulate, txBytes, nil, -1, nil, nil) return gasInfo, result, err } func (app *BaseApp) SimDeliver(txEncoder sdk.TxEncoder, tx sdk.Tx) (sdk.GasInfo, *sdk.Result, error) { - span := app.blockSpan.StartSpan("SimDeliver") - defer span.End() // See comment for Check(). bz, err := txEncoder(tx) if err != nil { return sdk.GasInfo{}, nil, errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, "%s", err) } - gasInfo, result, _, err := app.RunTx(execModeFinalize, bz, tx, -1, nil, nil, span) + gasInfo, result, _, err := app.RunTx(execModeFinalize, bz, tx, -1, nil, nil) return gasInfo, result, err } @@ -50,7 +47,7 @@ func (app *BaseApp) SimTxFinalizeBlock(txEncoder sdk.TxEncoder, tx sdk.Tx) (sdk. return sdk.GasInfo{}, nil, errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, "%s", err) } - gasInfo, result, _, err := app.RunTx(execModeFinalize, bz, tx, -1, nil, nil, log.NewNopTracer(log.NewNopLogger())) + gasInfo, result, _, err := app.RunTx(execModeFinalize, bz, tx, -1, nil, nil) return gasInfo, result, err } diff --git a/baseapp/txnrunner/default.go b/baseapp/txnrunner/default.go index 01b9921fc512..d92f8099d4dd 100644 --- a/baseapp/txnrunner/default.go +++ b/baseapp/txnrunner/default.go @@ -7,24 +7,21 @@ import ( storetypes "cosmossdk.io/store/types" - "cosmossdk.io/log" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) var _ sdk.TxRunner = DefaultRunner{} -func NewDefaultRunner(txDecoder sdk.TxDecoder, tracer log.Tracer) *DefaultRunner { +func NewDefaultRunner(txDecoder sdk.TxDecoder) *DefaultRunner { return &DefaultRunner{ txDecoder: txDecoder, - tracer: tracer, } } // DefaultRunner is the default TxnRunner implementation which executes the transactions in a block sequentially. type DefaultRunner struct { txDecoder sdk.TxDecoder - tracer log.Tracer } func (d DefaultRunner) Run(ctx context.Context, _ storetypes.MultiStore, txs [][]byte, deliverTx sdk.DeliverTxFunc) ([]*abci.ExecTxResult, error) { @@ -34,7 +31,7 @@ func (d DefaultRunner) Run(ctx context.Context, _ storetypes.MultiStore, txs [][ var response *abci.ExecTxResult if _, err := d.txDecoder(rawTx); err == nil { - response = deliverTx(rawTx, nil, i, nil, d.tracer) + response = deliverTx(rawTx, nil, i, nil) } else { // In the case where a transaction included in a block proposal is malformed, // we still want to return a default response to comet. This is because comet diff --git a/blockstm/executor.go b/blockstm/executor.go index 8ee790c486b9..4014c4ead966 100644 --- a/blockstm/executor.go +++ b/blockstm/executor.go @@ -3,8 +3,6 @@ package blockstm import ( "context" "fmt" - - "cosmossdk.io/log" ) // Executor fields are not mutated during execution. @@ -86,6 +84,6 @@ func (e *Executor) NeedsReexecution(version TxnVersion) (TxnVersion, TaskKind) { func (e *Executor) execute(txn TxnIndex) *MultiMVMemoryView { view := e.mvMemory.View(txn) - e.txExecutor(txn, view, log.TracerFromContext(e.ctx)) + e.txExecutor(txn, view) return view } diff --git a/blockstm/txnrunner.go b/blockstm/txnrunner.go index eb3461e93a8a..9e50c60522ea 100644 --- a/blockstm/txnrunner.go +++ b/blockstm/txnrunner.go @@ -10,7 +10,6 @@ import ( "cosmossdk.io/collections" storetypes "cosmossdk.io/store/types" - "cosmossdk.io/log" sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -79,7 +78,7 @@ func (e STMRunner) Run(ctx context.Context, ms storetypes.MultiStore, txs [][]by stmMultiStoreWrapper{ms}, e.workers, estimates, - func(txn TxnIndex, ms MultiStore, tracer log.Tracer) { + func(txn TxnIndex, ms MultiStore) { var cache map[string]any // only one of the concurrent incarnations gets the cache if there are any, otherwise execute without @@ -93,7 +92,7 @@ func (e STMRunner) Run(ctx context.Context, ms storetypes.MultiStore, txs [][]by if memTxs != nil { memTx = memTxs[txn] } - results[txn] = deliverTx(memTx, msWrapper{ms}, int(txn), cache, tracer) + results[txn] = deliverTx(memTx, msWrapper{ms}, int(txn), cache) if v != nil { incarnationCache[txn].Store(v) diff --git a/blockstm/types.go b/blockstm/types.go index fa533dfdfefc..873647b2f077 100644 --- a/blockstm/types.go +++ b/blockstm/types.go @@ -2,8 +2,6 @@ package blockstm import ( storetypes "cosmossdk.io/store/types" - - "cosmossdk.io/log" ) const ( @@ -61,7 +59,7 @@ type ReadSet struct { type MultiReadSet = map[int]*ReadSet // TxExecutor executes transactions on top of a multi-version memory view. -type TxExecutor func(TxnIndex, MultiStore, log.Tracer) +type TxExecutor func(TxnIndex, MultiStore) type MultiStore interface { GetStore(storetypes.StoreKey) storetypes.Store diff --git a/client/v2/go.mod b/client/v2/go.mod index 7d46f2c4ca34..1f1aeb58a265 100644 --- a/client/v2/go.mod +++ b/client/v2/go.mod @@ -30,7 +30,6 @@ require ( filippo.io/edwards25519 v1.1.0 // indirect github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect github.com/99designs/keyring v1.2.1 // indirect - github.com/DataDog/datadog-go v3.2.0+incompatible // indirect github.com/DataDog/zstd v1.5.7 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bgentry/speakeasy v0.2.0 // indirect @@ -88,6 +87,7 @@ require ( github.com/gorilla/handlers v1.5.2 // indirect github.com/gorilla/mux v1.8.1 // indirect github.com/gorilla/websocket v1.5.3 // indirect + github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc // indirect github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 // indirect @@ -126,7 +126,8 @@ require ( github.com/prometheus/client_golang v1.23.2 // indirect github.com/prometheus/client_model v0.6.2 // indirect github.com/prometheus/common v0.67.1 // indirect - github.com/prometheus/procfs v0.16.1 // indirect + github.com/prometheus/otlptranslator v0.0.2 // indirect + github.com/prometheus/procfs v0.17.0 // indirect github.com/rcrowley/go-metrics v0.0.0-20250401214520-65e299d6c5c9 // indirect github.com/rogpeppe/go-internal v1.14.1 // indirect github.com/rs/cors v1.11.1 // indirect @@ -148,13 +149,24 @@ require ( github.com/zondax/ledger-go v1.0.1 // indirect go.etcd.io/bbolt v1.4.0 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect + go.opentelemetry.io/contrib/otelconf v0.18.0 // indirect go.opentelemetry.io/otel v1.38.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.14.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.14.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.38.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.38.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.37.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0 // indirect + go.opentelemetry.io/otel/exporters/prometheus v0.60.0 // indirect + go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.14.0 // indirect + go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.38.0 // indirect go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.38.0 // indirect + go.opentelemetry.io/otel/log v0.14.0 // indirect go.opentelemetry.io/otel/metric v1.38.0 // indirect go.opentelemetry.io/otel/sdk v1.38.0 // indirect + go.opentelemetry.io/otel/sdk/log v0.14.0 // indirect + go.opentelemetry.io/otel/sdk/metric v1.38.0 // indirect go.opentelemetry.io/otel/trace v1.38.0 // indirect go.opentelemetry.io/proto/otlp v1.7.1 // indirect go.uber.org/mock v0.6.0 // indirect diff --git a/client/v2/go.sum b/client/v2/go.sum index 58676ed6c45a..a26eb6a85ec5 100644 --- a/client/v2/go.sum +++ b/client/v2/go.sum @@ -29,7 +29,6 @@ github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25 github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/DataDog/datadog-go v3.2.0+incompatible h1:qSG2N4FghB1He/r2mFrWKCaL7dXCilEuNEeAn20fdD4= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/DataDog/zstd v1.5.7 h1:ybO8RBeh29qrxIhCA9E8gKY6xfONU9T6G6aP9DTKfLE= github.com/DataDog/zstd v1.5.7/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= @@ -348,6 +347,8 @@ github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc h1:GN2Lv3MGO7AS6PrRoT6yV5+wkrOpcszoIsO4+4ds248= +github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc/go.mod h1:+JKpmjMGhpgPL+rXZ5nsZieVzvarn86asRlBg4uNGnk= github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-middleware v1.2.2/go.mod h1:EaizFBKfUKtMIF5iaDEhniwNedqGo9FuLFzppDr3uwI= github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDaL56wXCB/5+wF6uHfaI= @@ -602,6 +603,8 @@ github.com/prometheus/common v0.15.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16 github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= github.com/prometheus/common v0.67.1 h1:OTSON1P4DNxzTg4hmKCc37o4ZAZDv0cfXLkOt0oEowI= github.com/prometheus/common v0.67.1/go.mod h1:RpmT9v35q2Y+lsieQsdOh5sXZ6ajUGC8NjZAmr8vb0Q= +github.com/prometheus/otlptranslator v0.0.2 h1:+1CdeLVrRQ6Psmhnobldo0kTp96Rj80DRXRd5OSnMEQ= +github.com/prometheus/otlptranslator v0.0.2/go.mod h1:P8AwMgdD7XEr6QRUJ2QWLpiAZTgTE2UYgjlu3svompI= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= @@ -609,8 +612,8 @@ github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+Gx github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.3.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg= -github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is= +github.com/prometheus/procfs v0.17.0 h1:FuLQ+05u4ZI+SS/w9+BWEM2TXiHKsUQ9TADiRH7DuK0= +github.com/prometheus/procfs v0.17.0/go.mod h1:oPQLaDAMRbA+u8H5Pbfq+dl3VDAvHxMUOVhe0wYB2zw= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rcrowley/go-metrics v0.0.0-20250401214520-65e299d6c5c9 h1:bsUq1dX0N8AOIL7EB/X911+m4EHsnWEHeJ0c+3TTBrg= github.com/rcrowley/go-metrics v0.0.0-20250401214520-65e299d6c5c9/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= @@ -718,20 +721,42 @@ go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= +go.opentelemetry.io/contrib/otelconf v0.18.0 h1:ciF2Gf00BWs0DnexKFZXcxg9kJ8r3SUW1LOzW3CsKA8= +go.opentelemetry.io/contrib/otelconf v0.18.0/go.mod h1:FcP7k+JLwBLdOxS6qY6VQ/4b5VBntI6L6o80IMwhAeI= go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= +go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.14.0 h1:OMqPldHt79PqWKOMYIAQs3CxAi7RLgPxwfFSwr4ZxtM= +go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.14.0/go.mod h1:1biG4qiqTxKiUCtoWDPpL3fB3KxVwCiGw81j3nKMuHE= +go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.14.0 h1:QQqYw3lkrzwVsoEX0w//EhH/TCnpRdEenKBOOEIMjWc= +go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.14.0/go.mod h1:gSVQcr17jk2ig4jqJ2DX30IdWH251JcNAecvrqTxH1s= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.38.0 h1:vl9obrcoWVKp/lwl8tRE33853I8Xru9HFbw/skNeLs8= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.38.0/go.mod h1:GAXRxmLJcVM3u22IjTg74zWBrRCKq8BnOqUVLodpcpw= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.38.0 h1:Oe2z/BCg5q7k4iXC3cqJxKYg0ieRiOqF0cecFYdPTwk= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.38.0/go.mod h1:ZQM5lAJpOsKnYagGg/zV2krVqTtaVdYdDkhMoX6Oalg= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 h1:GqRJVj7UmLjCVyVJ3ZFLdPRmhDUp2zFmQe3RHIOsw24= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0/go.mod h1:ri3aaHSmCTVYu2AWv44YMauwAQc0aqI9gHKIcSbI1pU= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.37.0 h1:EtFWSnwW9hGObjkIdmlnWSydO+Qs8OwzfzXLUPg4xOc= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.37.0/go.mod h1:QjUEoiGCPkvFZ/MjK6ZZfNOS6mfVEVKYE99dFhuN2LI= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0 h1:lwI4Dc5leUqENgGuQImwLo4WnuXFPetmPpkLi2IrX54= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0/go.mod h1:Kz/oCE7z5wuyhPxsXDuaPteSWqjSBD5YaSdbxZYGbGk= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0 h1:aTL7F04bJHUlztTsNGJ2l+6he8c+y/b//eR0jjjemT4= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0/go.mod h1:kldtb7jDTeol0l3ewcmd8SDvx3EmIE7lyvqbasU3QC4= +go.opentelemetry.io/otel/exporters/prometheus v0.60.0 h1:cGtQxGvZbnrWdC2GyjZi0PDKVSLWP/Jocix3QWfXtbo= +go.opentelemetry.io/otel/exporters/prometheus v0.60.0/go.mod h1:hkd1EekxNo69PTV4OWFGZcKQiIqg0RfuWExcPKFvepk= +go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.14.0 h1:B/g+qde6Mkzxbry5ZZag0l7QrQBCtVm7lVjaLgmpje8= +go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.14.0/go.mod h1:mOJK8eMmgW6ocDJn6Bn11CcZ05gi3P8GylBXEkZtbgA= +go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.38.0 h1:wm/Q0GAAykXv83wzcKzGGqAnnfLFyFe7RslekZuv+VI= +go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.38.0/go.mod h1:ra3Pa40+oKjvYh+ZD3EdxFZZB0xdMfuileHAm4nNN7w= go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.38.0 h1:kJxSDN4SgWWTjG/hPp3O7LCGLcHXFlvS2/FFOrwL+SE= go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.38.0/go.mod h1:mgIOzS7iZeKJdeB8/NYHrJ48fdGc71Llo5bJ1J4DWUE= +go.opentelemetry.io/otel/log v0.14.0 h1:2rzJ+pOAZ8qmZ3DDHg73NEKzSZkhkGIua9gXtxNGgrM= +go.opentelemetry.io/otel/log v0.14.0/go.mod h1:5jRG92fEAgx0SU/vFPxmJvhIuDU9E1SUnEQrMlJpOno= go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E= go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg= +go.opentelemetry.io/otel/sdk/log v0.14.0 h1:JU/U3O7N6fsAXj0+CXz21Czg532dW2V4gG1HE/e8Zrg= +go.opentelemetry.io/otel/sdk/log v0.14.0/go.mod h1:imQvII+0ZylXfKU7/wtOND8Hn4OpT3YUoIgqJVksUkM= +go.opentelemetry.io/otel/sdk/log/logtest v0.14.0 h1:Ijbtz+JKXl8T2MngiwqBlPaHqc4YCaP/i13Qrow6gAM= +go.opentelemetry.io/otel/sdk/log/logtest v0.14.0/go.mod h1:dCU8aEL6q+L9cYTqcVOk8rM9Tp8WdnHOPLiBgp0SGOA= go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM= go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA= go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= diff --git a/go.mod b/go.mod index c53a80266aad..9f4d8319c8ae 100644 --- a/go.mod +++ b/go.mod @@ -46,8 +46,6 @@ require ( github.com/manifoldco/promptui v0.9.0 github.com/mattn/go-isatty v0.0.20 github.com/mdp/qrterminal/v3 v3.2.1 - github.com/prometheus/client_golang v1.23.2 - github.com/prometheus/common v0.67.1 github.com/rs/zerolog v1.34.0 github.com/spf13/cast v1.10.0 github.com/spf13/cobra v1.10.1 @@ -57,12 +55,8 @@ require ( github.com/tendermint/go-amino v0.16.0 github.com/test-go/testify v1.1.4 github.com/tidwall/btree v1.8.1 + go.opentelemetry.io/contrib/otelconf v0.18.0 go.opentelemetry.io/otel v1.38.0 - go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0 - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0 - go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.38.0 - go.opentelemetry.io/otel/sdk v1.38.0 go.opentelemetry.io/otel/trace v1.38.0 go.uber.org/mock v0.6.0 golang.org/x/crypto v0.43.0 @@ -87,7 +81,6 @@ require ( cosmossdk.io/schema v1.1.0 // indirect filippo.io/edwards25519 v1.1.0 // indirect github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect - github.com/DataDog/datadog-go v3.2.0+incompatible // indirect github.com/DataDog/zstd v1.5.7 // indirect github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.29.0 // indirect github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.53.0 // indirect @@ -194,7 +187,9 @@ require ( github.com/pkg/errors v0.9.1 // indirect github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/prometheus/client_golang v1.23.2 // indirect github.com/prometheus/client_model v0.6.2 // indirect + github.com/prometheus/common v0.67.1 // indirect github.com/prometheus/otlptranslator v0.0.2 // indirect github.com/prometheus/procfs v0.17.0 // indirect github.com/rcrowley/go-metrics v0.0.0-20250401214520-65e299d6c5c9 // indirect @@ -219,16 +214,20 @@ require ( go.opentelemetry.io/contrib/detectors/gcp v1.36.0 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0 // indirect - go.opentelemetry.io/contrib/otelconf v0.18.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.14.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.14.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.38.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.38.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0 // indirect go.opentelemetry.io/otel/exporters/prometheus v0.60.0 // indirect go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.14.0 // indirect go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.38.0 // indirect + go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.38.0 // indirect go.opentelemetry.io/otel/log v0.14.0 // indirect go.opentelemetry.io/otel/metric v1.38.0 // indirect + go.opentelemetry.io/otel/sdk v1.38.0 // indirect go.opentelemetry.io/otel/sdk/log v0.14.0 // indirect go.opentelemetry.io/otel/sdk/metric v1.38.0 // indirect go.opentelemetry.io/proto/otlp v1.7.1 // indirect diff --git a/go.sum b/go.sum index 0df3549e96fa..a090e17f9037 100644 --- a/go.sum +++ b/go.sum @@ -49,7 +49,6 @@ github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25 github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/DataDog/datadog-go v3.2.0+incompatible h1:qSG2N4FghB1He/r2mFrWKCaL7dXCilEuNEeAn20fdD4= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/DataDog/zstd v1.5.7 h1:ybO8RBeh29qrxIhCA9E8gKY6xfONU9T6G6aP9DTKfLE= github.com/DataDog/zstd v1.5.7/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= @@ -717,8 +716,6 @@ github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+Gx github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.3.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg= -github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is= github.com/prometheus/procfs v0.17.0 h1:FuLQ+05u4ZI+SS/w9+BWEM2TXiHKsUQ9TADiRH7DuK0= github.com/prometheus/procfs v0.17.0/go.mod h1:oPQLaDAMRbA+u8H5Pbfq+dl3VDAvHxMUOVhe0wYB2zw= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= @@ -859,8 +856,6 @@ go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.38.0 h1:Oe2 go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.38.0/go.mod h1:ZQM5lAJpOsKnYagGg/zV2krVqTtaVdYdDkhMoX6Oalg= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 h1:GqRJVj7UmLjCVyVJ3ZFLdPRmhDUp2zFmQe3RHIOsw24= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0/go.mod h1:ri3aaHSmCTVYu2AWv44YMauwAQc0aqI9gHKIcSbI1pU= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.37.0 h1:EtFWSnwW9hGObjkIdmlnWSydO+Qs8OwzfzXLUPg4xOc= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.37.0/go.mod h1:QjUEoiGCPkvFZ/MjK6ZZfNOS6mfVEVKYE99dFhuN2LI= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0 h1:lwI4Dc5leUqENgGuQImwLo4WnuXFPetmPpkLi2IrX54= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0/go.mod h1:Kz/oCE7z5wuyhPxsXDuaPteSWqjSBD5YaSdbxZYGbGk= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0 h1:aTL7F04bJHUlztTsNGJ2l+6he8c+y/b//eR0jjjemT4= @@ -869,8 +864,6 @@ go.opentelemetry.io/otel/exporters/prometheus v0.60.0 h1:cGtQxGvZbnrWdC2GyjZi0PD go.opentelemetry.io/otel/exporters/prometheus v0.60.0/go.mod h1:hkd1EekxNo69PTV4OWFGZcKQiIqg0RfuWExcPKFvepk= go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.14.0 h1:B/g+qde6Mkzxbry5ZZag0l7QrQBCtVm7lVjaLgmpje8= go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.14.0/go.mod h1:mOJK8eMmgW6ocDJn6Bn11CcZ05gi3P8GylBXEkZtbgA= -go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.36.0 h1:rixTyDGXFxRy1xzhKrotaHy3/KXdPhlWARrCgK+eqUY= -go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.36.0/go.mod h1:dowW6UsM9MKbJq5JTz2AMVp3/5iW5I/TStsk8S+CfHw= go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.38.0 h1:wm/Q0GAAykXv83wzcKzGGqAnnfLFyFe7RslekZuv+VI= go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.38.0/go.mod h1:ra3Pa40+oKjvYh+ZD3EdxFZZB0xdMfuileHAm4nNN7w= go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.38.0 h1:kJxSDN4SgWWTjG/hPp3O7LCGLcHXFlvS2/FFOrwL+SE= @@ -883,6 +876,8 @@ go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5 go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg= go.opentelemetry.io/otel/sdk/log v0.14.0 h1:JU/U3O7N6fsAXj0+CXz21Czg532dW2V4gG1HE/e8Zrg= go.opentelemetry.io/otel/sdk/log v0.14.0/go.mod h1:imQvII+0ZylXfKU7/wtOND8Hn4OpT3YUoIgqJVksUkM= +go.opentelemetry.io/otel/sdk/log/logtest v0.14.0 h1:Ijbtz+JKXl8T2MngiwqBlPaHqc4YCaP/i13Qrow6gAM= +go.opentelemetry.io/otel/sdk/log/logtest v0.14.0/go.mod h1:dCU8aEL6q+L9cYTqcVOk8rM9Tp8WdnHOPLiBgp0SGOA= go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM= go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA= go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= diff --git a/log/tracer.go b/log/tracer.go deleted file mode 100644 index ac304b1a5e41..000000000000 --- a/log/tracer.go +++ /dev/null @@ -1,99 +0,0 @@ -package log - -import "context" - -// Tracer is an interface for creating and managing spans. -// It may be backed by open telemetry or other tracing libraries, -// Spans may also be used for collecting timing metrics. -// It embeds the Logger interface. Log events may be associated with spans. -type Tracer interface { - Logger - - // StartSpan starts a new span with the given operation name and key-value pair attributes. - // If there is a parent span, the new span will be a child of that span. - // It is recommended to use a defer statement to end the span like this: - // span := tracer.StartSpan("my-span") - // defer span.End() - StartSpan(operation string, kvs ...any) Span - - // StartSpanContext attempts to retrieve an existing tracer from the context and then starts a new span - // as a child of that span. - // If no tracer is found, it returns a new span that is a child of this tracer instance. - // This is useful if a span may have been set in the context, but we are not sure. - // The function also returns a context with the span added to it. - StartSpanContext(ctx context.Context, operation string, kvs ...any) (context.Context, Span) - - // StartRootSpan returns a root-level span that doesn't have a parent. - // Use this when starting async work to ensure its spans are not timed as part of the current span. - // Example usage: - // go func() { - // ctx, span := outerSpan.StartRootSpan(ctx, "my-go-routine") - // defer span.End() - // doSomething() - // }() - StartRootSpan(ctx context.Context, operation string, kvs ...any) (context.Context, Span) -} - -// Span is an interface for managing spans and creating nested spans via the embedded Tracer interface. -type Span interface { - // Tracer is embedded to allow for the creation of nested spans. - Tracer - - // SetAttrs sets additional key-value attributes on the span. - SetAttrs(kvs ...any) - - // SetErr records an optional error on the span and optionally adds additional key-value pair attributes. - // It returns the error value unchanged, allowing use in return statements. - // If err is nil, the span is marked as successful. - // If err is not nil, the span is marked as failed. - // This does NOT end the span, you must still call End. - // Example usage: - // span := tracer.StartSpan("my-span") - // defer span.End() - // err := doSomething() - // return span.SetErr(err, "additional", "info") // okay to call with a nil error - SetErr(err error, kvs ...any) error - - // End marks the end of a span and is designed to be used in a defer statement right after the span is created. - // Calling End on a span that has already ended is a no-op. - // Example usage: - // span := tracer.StartSpan("my-span") - // defer span.End() - End() -} - -// NewNopTracer returns a Tracer that wraps a logger for logging methods but does not emit any spans. -func NewNopTracer(logger Logger) Tracer { - return nopTracer{ - Logger: logger, - } -} - -type nopTracer struct { - Logger -} - -func (n nopTracer) StartRootSpan(ctx context.Context, operation string, kvs ...any) (context.Context, Span) { - return ctx, nopSpan{n} -} - -func (n nopTracer) StartSpanContext(ctx context.Context, _ string, _ ...any) (context.Context, Span) { - return ctx, nopSpan{n} -} - -func (n nopTracer) StartSpan(string, ...any) Span { - return nopSpan{n} -} - -type nopSpan struct { - nopTracer -} - -func (n nopSpan) SetAttrs(...any) {} - -func (n nopSpan) SetErr(err error, _ ...any) error { return err } - -func (n nopSpan) End() {} - -var _ Tracer = nopTracer{} -var _ Span = nopSpan{} diff --git a/server/api/server.go b/server/api/server.go index 0aa1cf170956..3cb276871cec 100644 --- a/server/api/server.go +++ b/server/api/server.go @@ -2,7 +2,6 @@ package api import ( "context" - "fmt" "net" "net/http" "strings" @@ -24,7 +23,6 @@ import ( "github.com/cosmos/cosmos-sdk/codec/legacy" "github.com/cosmos/cosmos-sdk/server/config" cmtlogwrapper "github.com/cosmos/cosmos-sdk/server/log" - "github.com/cosmos/cosmos-sdk/telemetry" grpctypes "github.com/cosmos/cosmos-sdk/types/grpc" ) @@ -35,7 +33,6 @@ type Server struct { ClientCtx client.Context GRPCSrv *grpc.Server logger log.Logger - metrics *telemetry.Metrics // Start() is blocking and generally called from a separate goroutine. // Close() can be called asynchronously and access shared memory @@ -191,31 +188,6 @@ func (s *Server) Close() error { return s.listener.Close() } -func (s *Server) SetTelemetry(m *telemetry.Metrics) { - s.mtx.Lock() - s.registerMetrics(m) - s.mtx.Unlock() -} - -func (s *Server) registerMetrics(m *telemetry.Metrics) { - s.metrics = m - - metricsHandler := func(w http.ResponseWriter, r *http.Request) { - format := strings.TrimSpace(r.FormValue("format")) - - gr, err := s.metrics.Gather(format) - if err != nil { - writeErrorResponse(w, http.StatusBadRequest, fmt.Sprintf("failed to gather metrics: %s", err)) - return - } - - w.Header().Set("Content-Type", gr.ContentType) - _, _ = w.Write(gr.Metrics) - } - - s.Router.HandleFunc("/metrics", metricsHandler).Methods("GET") -} - // errorResponse defines the attributes of a JSON error response. type errorResponse struct { Code int `json:"code,omitempty"` diff --git a/server/config/config.go b/server/config/config.go index a50893e850c1..c9fa4351a087 100644 --- a/server/config/config.go +++ b/server/config/config.go @@ -8,7 +8,7 @@ import ( pruningtypes "cosmossdk.io/store/pruning/types" - "github.com/cosmos/cosmos-sdk/telemetry" + _ "github.com/cosmos/cosmos-sdk/telemetry" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) @@ -190,13 +190,12 @@ type Config struct { BaseConfig `mapstructure:",squash"` // Telemetry defines the application telemetry configuration - Telemetry telemetry.Config `mapstructure:"telemetry"` - API APIConfig `mapstructure:"api"` - GRPC GRPCConfig `mapstructure:"grpc"` - GRPCWeb GRPCWebConfig `mapstructure:"grpc-web"` - StateSync StateSyncConfig `mapstructure:"state-sync"` - Streaming StreamingConfig `mapstructure:"streaming"` - Mempool MempoolConfig `mapstructure:"mempool"` + API APIConfig `mapstructure:"api"` + GRPC GRPCConfig `mapstructure:"grpc"` + GRPCWeb GRPCWebConfig `mapstructure:"grpc-web"` + StateSync StateSyncConfig `mapstructure:"state-sync"` + Streaming StreamingConfig `mapstructure:"streaming"` + Mempool MempoolConfig `mapstructure:"mempool"` } // SetMinGasPrices sets the validator's minimum gas prices. @@ -234,10 +233,6 @@ func DefaultConfig() *Config { IAVLDisableFastNode: false, AppDBBackend: "", }, - Telemetry: telemetry.Config{ - Enabled: false, - GlobalLabels: [][]string{}, - }, API: APIConfig{ Enable: false, Swagger: false, diff --git a/server/start.go b/server/start.go index aab620b27548..4bb4c29b1e0d 100644 --- a/server/start.go +++ b/server/start.go @@ -230,20 +230,15 @@ func start(svrCtx *Context, clientCtx client.Context, appCreator types.AppCreato } defer appCleanupFn() - metrics, err := startTelemetry(svrCfg) - if err != nil { - return fmt.Errorf("failed to start telemetry: %w", err) - } - emitServerInfoMetrics() if !withCmt { - return startStandAlone(svrCtx, svrCfg, clientCtx, app, metrics, opts) + return startStandAlone(svrCtx, svrCfg, clientCtx, app, opts) } - return startInProcess(svrCtx, svrCfg, clientCtx, app, metrics, opts) + return startInProcess(svrCtx, svrCfg, clientCtx, app, opts) } -func startStandAlone(svrCtx *Context, svrCfg serverconfig.Config, clientCtx client.Context, app types.Application, metrics *telemetry.Metrics, opts StartCmdOptions) error { +func startStandAlone(svrCtx *Context, svrCfg serverconfig.Config, clientCtx client.Context, app types.Application, opts StartCmdOptions) error { addr := svrCtx.Viper.GetString(flagAddress) transport := svrCtx.Viper.GetString(flagTransport) @@ -282,7 +277,7 @@ func startStandAlone(svrCtx *Context, svrCfg serverconfig.Config, clientCtx clie return err } - err = startAPIServer(ctx, g, svrCfg, clientCtx, svrCtx, app, svrCtx.Config.RootDir, grpcSrv, metrics) + err = startAPIServer(ctx, g, svrCfg, clientCtx, svrCtx, app, svrCtx.Config.RootDir, grpcSrv) if err != nil { return err } @@ -309,9 +304,7 @@ func startStandAlone(svrCtx *Context, svrCfg serverconfig.Config, clientCtx clie return g.Wait() } -func startInProcess(svrCtx *Context, svrCfg serverconfig.Config, clientCtx client.Context, app types.Application, - metrics *telemetry.Metrics, opts StartCmdOptions, -) error { +func startInProcess(svrCtx *Context, svrCfg serverconfig.Config, clientCtx client.Context, app types.Application, opts StartCmdOptions) error { cmtCfg := svrCtx.Config gRPCOnly := svrCtx.Viper.GetBool(flagGRPCOnly) @@ -348,7 +341,7 @@ func startInProcess(svrCtx *Context, svrCfg serverconfig.Config, clientCtx clien return fmt.Errorf("failed to start grpc server: %w", err) } - err = startAPIServer(ctx, g, svrCfg, clientCtx, svrCtx, app, cmtCfg.RootDir, grpcSrv, metrics) + err = startAPIServer(ctx, g, svrCfg, clientCtx, svrCtx, app, cmtCfg.RootDir, grpcSrv) if err != nil { return fmt.Errorf("failed to start api server: %w", err) } @@ -517,7 +510,6 @@ func startAPIServer( app types.Application, home string, grpcSrv *grpc.Server, - metrics *telemetry.Metrics, ) error { if !svrCfg.API.Enable { return nil @@ -528,20 +520,12 @@ func startAPIServer( apiSrv := api.New(clientCtx, svrCtx.Logger.With("module", "api-server"), grpcSrv) app.RegisterAPIRoutes(apiSrv, svrCfg.API) - if svrCfg.Telemetry.Enabled { - apiSrv.SetTelemetry(metrics) - } - g.Go(func() error { return apiSrv.Start(ctx, svrCfg) }) return nil } -func startTelemetry(cfg serverconfig.Config) (*telemetry.Metrics, error) { - return telemetry.New(cfg.Telemetry) -} - // wrapCPUProfile starts CPU profiling, if enabled, and executes the provided // callbackFn in a separate goroutine, then will wait for that callback to // return. diff --git a/simapp/go.mod b/simapp/go.mod index 167548375072..f3b7f18f7733 100644 --- a/simapp/go.mod +++ b/simapp/go.mod @@ -41,7 +41,6 @@ require ( filippo.io/edwards25519 v1.1.0 // indirect github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect github.com/99designs/keyring v1.2.2 // indirect - github.com/DataDog/datadog-go v3.2.0+incompatible // indirect github.com/DataDog/zstd v1.5.7 // indirect github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.29.0 // indirect github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.53.0 // indirect @@ -132,6 +131,7 @@ require ( github.com/gorilla/handlers v1.5.2 // indirect github.com/gorilla/mux v1.8.1 // indirect github.com/gorilla/websocket v1.5.3 // indirect + github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc // indirect github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 // indirect @@ -177,7 +177,8 @@ require ( github.com/prometheus/client_golang v1.23.2 // indirect github.com/prometheus/client_model v0.6.2 // indirect github.com/prometheus/common v0.67.1 // indirect - github.com/prometheus/procfs v0.16.1 // indirect + github.com/prometheus/otlptranslator v0.0.2 // indirect + github.com/prometheus/procfs v0.17.0 // indirect github.com/rcrowley/go-metrics v0.0.0-20250401214520-65e299d6c5c9 // indirect github.com/rogpeppe/go-internal v1.14.1 // indirect github.com/rs/cors v1.11.1 // indirect @@ -203,13 +204,23 @@ require ( go.opentelemetry.io/contrib/detectors/gcp v1.36.0 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0 // indirect + go.opentelemetry.io/contrib/otelconf v0.18.0 // indirect go.opentelemetry.io/otel v1.38.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.14.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.14.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.38.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.38.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.37.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0 // indirect + go.opentelemetry.io/otel/exporters/prometheus v0.60.0 // indirect + go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.14.0 // indirect + go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.38.0 // indirect go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.38.0 // indirect + go.opentelemetry.io/otel/log v0.14.0 // indirect go.opentelemetry.io/otel/metric v1.38.0 // indirect go.opentelemetry.io/otel/sdk v1.38.0 // indirect + go.opentelemetry.io/otel/sdk/log v0.14.0 // indirect go.opentelemetry.io/otel/sdk/metric v1.38.0 // indirect go.opentelemetry.io/otel/trace v1.38.0 // indirect go.opentelemetry.io/proto/otlp v1.7.1 // indirect diff --git a/simapp/go.sum b/simapp/go.sum index 462724459d82..016a7cbf300d 100644 --- a/simapp/go.sum +++ b/simapp/go.sum @@ -53,7 +53,6 @@ github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25 github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/DataDog/datadog-go v3.2.0+incompatible h1:qSG2N4FghB1He/r2mFrWKCaL7dXCilEuNEeAn20fdD4= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/DataDog/zstd v1.5.7 h1:ybO8RBeh29qrxIhCA9E8gKY6xfONU9T6G6aP9DTKfLE= github.com/DataDog/zstd v1.5.7/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= @@ -449,6 +448,8 @@ github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc h1:GN2Lv3MGO7AS6PrRoT6yV5+wkrOpcszoIsO4+4ds248= +github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc/go.mod h1:+JKpmjMGhpgPL+rXZ5nsZieVzvarn86asRlBg4uNGnk= github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-middleware v1.2.2/go.mod h1:EaizFBKfUKtMIF5iaDEhniwNedqGo9FuLFzppDr3uwI= github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDaL56wXCB/5+wF6uHfaI= @@ -716,6 +717,8 @@ github.com/prometheus/common v0.15.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16 github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= github.com/prometheus/common v0.67.1 h1:OTSON1P4DNxzTg4hmKCc37o4ZAZDv0cfXLkOt0oEowI= github.com/prometheus/common v0.67.1/go.mod h1:RpmT9v35q2Y+lsieQsdOh5sXZ6ajUGC8NjZAmr8vb0Q= +github.com/prometheus/otlptranslator v0.0.2 h1:+1CdeLVrRQ6Psmhnobldo0kTp96Rj80DRXRd5OSnMEQ= +github.com/prometheus/otlptranslator v0.0.2/go.mod h1:P8AwMgdD7XEr6QRUJ2QWLpiAZTgTE2UYgjlu3svompI= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= @@ -723,8 +726,8 @@ github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+Gx github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.3.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg= -github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is= +github.com/prometheus/procfs v0.17.0 h1:FuLQ+05u4ZI+SS/w9+BWEM2TXiHKsUQ9TADiRH7DuK0= +github.com/prometheus/procfs v0.17.0/go.mod h1:oPQLaDAMRbA+u8H5Pbfq+dl3VDAvHxMUOVhe0wYB2zw= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rcrowley/go-metrics v0.0.0-20250401214520-65e299d6c5c9 h1:bsUq1dX0N8AOIL7EB/X911+m4EHsnWEHeJ0c+3TTBrg= github.com/rcrowley/go-metrics v0.0.0-20250401214520-65e299d6c5c9/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= @@ -847,22 +850,42 @@ go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.6 go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0/go.mod h1:snMWehoOh2wsEwnvvwtDyFCxVeDAODenXHtn5vzrKjo= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0 h1:Hf9xI/XLML9ElpiHVDNwvqI0hIFlzV8dgIr35kV1kRU= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0/go.mod h1:NfchwuyNoMcZ5MLHwPrODwUF1HWCXWrL31s8gSAdIKY= +go.opentelemetry.io/contrib/otelconf v0.18.0 h1:ciF2Gf00BWs0DnexKFZXcxg9kJ8r3SUW1LOzW3CsKA8= +go.opentelemetry.io/contrib/otelconf v0.18.0/go.mod h1:FcP7k+JLwBLdOxS6qY6VQ/4b5VBntI6L6o80IMwhAeI= go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= +go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.14.0 h1:OMqPldHt79PqWKOMYIAQs3CxAi7RLgPxwfFSwr4ZxtM= +go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.14.0/go.mod h1:1biG4qiqTxKiUCtoWDPpL3fB3KxVwCiGw81j3nKMuHE= +go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.14.0 h1:QQqYw3lkrzwVsoEX0w//EhH/TCnpRdEenKBOOEIMjWc= +go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.14.0/go.mod h1:gSVQcr17jk2ig4jqJ2DX30IdWH251JcNAecvrqTxH1s= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.38.0 h1:vl9obrcoWVKp/lwl8tRE33853I8Xru9HFbw/skNeLs8= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.38.0/go.mod h1:GAXRxmLJcVM3u22IjTg74zWBrRCKq8BnOqUVLodpcpw= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.38.0 h1:Oe2z/BCg5q7k4iXC3cqJxKYg0ieRiOqF0cecFYdPTwk= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.38.0/go.mod h1:ZQM5lAJpOsKnYagGg/zV2krVqTtaVdYdDkhMoX6Oalg= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 h1:GqRJVj7UmLjCVyVJ3ZFLdPRmhDUp2zFmQe3RHIOsw24= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0/go.mod h1:ri3aaHSmCTVYu2AWv44YMauwAQc0aqI9gHKIcSbI1pU= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.37.0 h1:EtFWSnwW9hGObjkIdmlnWSydO+Qs8OwzfzXLUPg4xOc= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.37.0/go.mod h1:QjUEoiGCPkvFZ/MjK6ZZfNOS6mfVEVKYE99dFhuN2LI= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0 h1:lwI4Dc5leUqENgGuQImwLo4WnuXFPetmPpkLi2IrX54= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0/go.mod h1:Kz/oCE7z5wuyhPxsXDuaPteSWqjSBD5YaSdbxZYGbGk= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0 h1:aTL7F04bJHUlztTsNGJ2l+6he8c+y/b//eR0jjjemT4= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0/go.mod h1:kldtb7jDTeol0l3ewcmd8SDvx3EmIE7lyvqbasU3QC4= -go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.36.0 h1:rixTyDGXFxRy1xzhKrotaHy3/KXdPhlWARrCgK+eqUY= -go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.36.0/go.mod h1:dowW6UsM9MKbJq5JTz2AMVp3/5iW5I/TStsk8S+CfHw= +go.opentelemetry.io/otel/exporters/prometheus v0.60.0 h1:cGtQxGvZbnrWdC2GyjZi0PDKVSLWP/Jocix3QWfXtbo= +go.opentelemetry.io/otel/exporters/prometheus v0.60.0/go.mod h1:hkd1EekxNo69PTV4OWFGZcKQiIqg0RfuWExcPKFvepk= +go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.14.0 h1:B/g+qde6Mkzxbry5ZZag0l7QrQBCtVm7lVjaLgmpje8= +go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.14.0/go.mod h1:mOJK8eMmgW6ocDJn6Bn11CcZ05gi3P8GylBXEkZtbgA= +go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.38.0 h1:wm/Q0GAAykXv83wzcKzGGqAnnfLFyFe7RslekZuv+VI= +go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.38.0/go.mod h1:ra3Pa40+oKjvYh+ZD3EdxFZZB0xdMfuileHAm4nNN7w= go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.38.0 h1:kJxSDN4SgWWTjG/hPp3O7LCGLcHXFlvS2/FFOrwL+SE= go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.38.0/go.mod h1:mgIOzS7iZeKJdeB8/NYHrJ48fdGc71Llo5bJ1J4DWUE= +go.opentelemetry.io/otel/log v0.14.0 h1:2rzJ+pOAZ8qmZ3DDHg73NEKzSZkhkGIua9gXtxNGgrM= +go.opentelemetry.io/otel/log v0.14.0/go.mod h1:5jRG92fEAgx0SU/vFPxmJvhIuDU9E1SUnEQrMlJpOno= go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E= go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg= +go.opentelemetry.io/otel/sdk/log v0.14.0 h1:JU/U3O7N6fsAXj0+CXz21Czg532dW2V4gG1HE/e8Zrg= +go.opentelemetry.io/otel/sdk/log v0.14.0/go.mod h1:imQvII+0ZylXfKU7/wtOND8Hn4OpT3YUoIgqJVksUkM= +go.opentelemetry.io/otel/sdk/log/logtest v0.14.0 h1:Ijbtz+JKXl8T2MngiwqBlPaHqc4YCaP/i13Qrow6gAM= +go.opentelemetry.io/otel/sdk/log/logtest v0.14.0/go.mod h1:dCU8aEL6q+L9cYTqcVOk8rM9Tp8WdnHOPLiBgp0SGOA= go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM= go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA= go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= diff --git a/simapp/sim_test.go b/simapp/sim_test.go index 848911ef2ffd..ae9607fc386f 100644 --- a/simapp/sim_test.go +++ b/simapp/sim_test.go @@ -3,6 +3,7 @@ package simapp import ( + "context" "encoding/binary" "encoding/json" "flag" @@ -17,6 +18,7 @@ import ( dbm "github.com/cosmos/cosmos-db" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "go.opentelemetry.io/otel" "cosmossdk.io/log" "github.com/cosmos/cosmos-sdk/telemetry" @@ -159,6 +161,10 @@ func IsEmptyValidatorSetErr(err error) bool { } func TestAppStateDeterminism(t *testing.T) { + telemetry.TestingInit(t, context.Background()) + tracer := otel.Tracer("test") + _, span := tracer.Start(context.Background(), "TestAppStateDeterminism") + defer span.End() const numTimesToRunPerSeed = 1 var seeds []int64 if s := simcli.NewConfigFromFlags().Seed; s != simcli.DefaultSeedValue { @@ -191,10 +197,7 @@ func TestAppStateDeterminism(t *testing.T) { return others.Get(k) }) } - metrics := telemetry.TestingInit(t, nil, logger) - baseAppSpan := metrics.Tracer().StartSpan("baseapp") - t.Cleanup(baseAppSpan.End) - return NewSimApp(baseAppSpan, db, nil, true, appOpts, append(baseAppOptions, interBlockCacheOpt())...) + return NewSimApp(logger, db, nil, true, appOpts, append(baseAppOptions, interBlockCacheOpt())...) } var mx sync.Mutex appHashResults := make(map[int64][][]byte) diff --git a/systemtests/go.mod b/systemtests/go.mod index 8fd0c16fb18a..9affc6f367c3 100644 --- a/systemtests/go.mod +++ b/systemtests/go.mod @@ -26,7 +26,6 @@ require ( filippo.io/edwards25519 v1.1.0 // indirect github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect github.com/99designs/keyring v1.2.1 // indirect - github.com/DataDog/datadog-go v3.2.0+incompatible // indirect github.com/DataDog/zstd v1.5.7 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bgentry/speakeasy v0.2.0 // indirect @@ -85,6 +84,7 @@ require ( github.com/gorilla/handlers v1.5.2 // indirect github.com/gorilla/mux v1.8.1 // indirect github.com/gorilla/websocket v1.5.3 // indirect + github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc // indirect github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 // indirect @@ -122,7 +122,8 @@ require ( github.com/prometheus/client_golang v1.23.2 // indirect github.com/prometheus/client_model v0.6.2 // indirect github.com/prometheus/common v0.67.1 // indirect - github.com/prometheus/procfs v0.16.1 // indirect + github.com/prometheus/otlptranslator v0.0.2 // indirect + github.com/prometheus/procfs v0.17.0 // indirect github.com/rcrowley/go-metrics v0.0.0-20250401214520-65e299d6c5c9 // indirect github.com/rogpeppe/go-internal v1.14.1 // indirect github.com/rs/cors v1.11.1 // indirect @@ -148,13 +149,24 @@ require ( github.com/zondax/ledger-go v1.0.1 // indirect go.etcd.io/bbolt v1.4.0 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect + go.opentelemetry.io/contrib/otelconf v0.18.0 // indirect go.opentelemetry.io/otel v1.38.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.14.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.14.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.38.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.38.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.37.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0 // indirect + go.opentelemetry.io/otel/exporters/prometheus v0.60.0 // indirect + go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.14.0 // indirect + go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.38.0 // indirect go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.38.0 // indirect + go.opentelemetry.io/otel/log v0.14.0 // indirect go.opentelemetry.io/otel/metric v1.38.0 // indirect go.opentelemetry.io/otel/sdk v1.38.0 // indirect + go.opentelemetry.io/otel/sdk/log v0.14.0 // indirect + go.opentelemetry.io/otel/sdk/metric v1.38.0 // indirect go.opentelemetry.io/otel/trace v1.38.0 // indirect go.opentelemetry.io/proto/otlp v1.7.1 // indirect go.uber.org/multierr v1.11.0 // indirect diff --git a/systemtests/go.sum b/systemtests/go.sum index ae9b36f2df21..7e5dfcf655aa 100644 --- a/systemtests/go.sum +++ b/systemtests/go.sum @@ -31,7 +31,6 @@ github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25 github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/DataDog/datadog-go v3.2.0+incompatible h1:qSG2N4FghB1He/r2mFrWKCaL7dXCilEuNEeAn20fdD4= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/DataDog/zstd v1.5.7 h1:ybO8RBeh29qrxIhCA9E8gKY6xfONU9T6G6aP9DTKfLE= github.com/DataDog/zstd v1.5.7/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= @@ -348,6 +347,8 @@ github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc h1:GN2Lv3MGO7AS6PrRoT6yV5+wkrOpcszoIsO4+4ds248= +github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc/go.mod h1:+JKpmjMGhpgPL+rXZ5nsZieVzvarn86asRlBg4uNGnk= github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-middleware v1.2.2/go.mod h1:EaizFBKfUKtMIF5iaDEhniwNedqGo9FuLFzppDr3uwI= github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDaL56wXCB/5+wF6uHfaI= @@ -602,6 +603,8 @@ github.com/prometheus/common v0.15.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16 github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= github.com/prometheus/common v0.67.1 h1:OTSON1P4DNxzTg4hmKCc37o4ZAZDv0cfXLkOt0oEowI= github.com/prometheus/common v0.67.1/go.mod h1:RpmT9v35q2Y+lsieQsdOh5sXZ6ajUGC8NjZAmr8vb0Q= +github.com/prometheus/otlptranslator v0.0.2 h1:+1CdeLVrRQ6Psmhnobldo0kTp96Rj80DRXRd5OSnMEQ= +github.com/prometheus/otlptranslator v0.0.2/go.mod h1:P8AwMgdD7XEr6QRUJ2QWLpiAZTgTE2UYgjlu3svompI= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= @@ -609,8 +612,8 @@ github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+Gx github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.3.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg= -github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is= +github.com/prometheus/procfs v0.17.0 h1:FuLQ+05u4ZI+SS/w9+BWEM2TXiHKsUQ9TADiRH7DuK0= +github.com/prometheus/procfs v0.17.0/go.mod h1:oPQLaDAMRbA+u8H5Pbfq+dl3VDAvHxMUOVhe0wYB2zw= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rcrowley/go-metrics v0.0.0-20250401214520-65e299d6c5c9 h1:bsUq1dX0N8AOIL7EB/X911+m4EHsnWEHeJ0c+3TTBrg= github.com/rcrowley/go-metrics v0.0.0-20250401214520-65e299d6c5c9/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= @@ -727,20 +730,42 @@ go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= +go.opentelemetry.io/contrib/otelconf v0.18.0 h1:ciF2Gf00BWs0DnexKFZXcxg9kJ8r3SUW1LOzW3CsKA8= +go.opentelemetry.io/contrib/otelconf v0.18.0/go.mod h1:FcP7k+JLwBLdOxS6qY6VQ/4b5VBntI6L6o80IMwhAeI= go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= +go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.14.0 h1:OMqPldHt79PqWKOMYIAQs3CxAi7RLgPxwfFSwr4ZxtM= +go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.14.0/go.mod h1:1biG4qiqTxKiUCtoWDPpL3fB3KxVwCiGw81j3nKMuHE= +go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.14.0 h1:QQqYw3lkrzwVsoEX0w//EhH/TCnpRdEenKBOOEIMjWc= +go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.14.0/go.mod h1:gSVQcr17jk2ig4jqJ2DX30IdWH251JcNAecvrqTxH1s= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.38.0 h1:vl9obrcoWVKp/lwl8tRE33853I8Xru9HFbw/skNeLs8= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.38.0/go.mod h1:GAXRxmLJcVM3u22IjTg74zWBrRCKq8BnOqUVLodpcpw= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.38.0 h1:Oe2z/BCg5q7k4iXC3cqJxKYg0ieRiOqF0cecFYdPTwk= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.38.0/go.mod h1:ZQM5lAJpOsKnYagGg/zV2krVqTtaVdYdDkhMoX6Oalg= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 h1:GqRJVj7UmLjCVyVJ3ZFLdPRmhDUp2zFmQe3RHIOsw24= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0/go.mod h1:ri3aaHSmCTVYu2AWv44YMauwAQc0aqI9gHKIcSbI1pU= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.37.0 h1:EtFWSnwW9hGObjkIdmlnWSydO+Qs8OwzfzXLUPg4xOc= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.37.0/go.mod h1:QjUEoiGCPkvFZ/MjK6ZZfNOS6mfVEVKYE99dFhuN2LI= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0 h1:lwI4Dc5leUqENgGuQImwLo4WnuXFPetmPpkLi2IrX54= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0/go.mod h1:Kz/oCE7z5wuyhPxsXDuaPteSWqjSBD5YaSdbxZYGbGk= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0 h1:aTL7F04bJHUlztTsNGJ2l+6he8c+y/b//eR0jjjemT4= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0/go.mod h1:kldtb7jDTeol0l3ewcmd8SDvx3EmIE7lyvqbasU3QC4= +go.opentelemetry.io/otel/exporters/prometheus v0.60.0 h1:cGtQxGvZbnrWdC2GyjZi0PDKVSLWP/Jocix3QWfXtbo= +go.opentelemetry.io/otel/exporters/prometheus v0.60.0/go.mod h1:hkd1EekxNo69PTV4OWFGZcKQiIqg0RfuWExcPKFvepk= +go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.14.0 h1:B/g+qde6Mkzxbry5ZZag0l7QrQBCtVm7lVjaLgmpje8= +go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.14.0/go.mod h1:mOJK8eMmgW6ocDJn6Bn11CcZ05gi3P8GylBXEkZtbgA= +go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.38.0 h1:wm/Q0GAAykXv83wzcKzGGqAnnfLFyFe7RslekZuv+VI= +go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.38.0/go.mod h1:ra3Pa40+oKjvYh+ZD3EdxFZZB0xdMfuileHAm4nNN7w= go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.38.0 h1:kJxSDN4SgWWTjG/hPp3O7LCGLcHXFlvS2/FFOrwL+SE= go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.38.0/go.mod h1:mgIOzS7iZeKJdeB8/NYHrJ48fdGc71Llo5bJ1J4DWUE= +go.opentelemetry.io/otel/log v0.14.0 h1:2rzJ+pOAZ8qmZ3DDHg73NEKzSZkhkGIua9gXtxNGgrM= +go.opentelemetry.io/otel/log v0.14.0/go.mod h1:5jRG92fEAgx0SU/vFPxmJvhIuDU9E1SUnEQrMlJpOno= go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E= go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg= +go.opentelemetry.io/otel/sdk/log v0.14.0 h1:JU/U3O7N6fsAXj0+CXz21Czg532dW2V4gG1HE/e8Zrg= +go.opentelemetry.io/otel/sdk/log v0.14.0/go.mod h1:imQvII+0ZylXfKU7/wtOND8Hn4OpT3YUoIgqJVksUkM= +go.opentelemetry.io/otel/sdk/log/logtest v0.14.0 h1:Ijbtz+JKXl8T2MngiwqBlPaHqc4YCaP/i13Qrow6gAM= +go.opentelemetry.io/otel/sdk/log/logtest v0.14.0/go.mod h1:dCU8aEL6q+L9cYTqcVOk8rM9Tp8WdnHOPLiBgp0SGOA= go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM= go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA= go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= diff --git a/telemetry/config.go b/telemetry/config.go index 42b78413e73e..440b7002227d 100644 --- a/telemetry/config.go +++ b/telemetry/config.go @@ -1,172 +1,58 @@ package telemetry import ( - "net/http" + "context" + "encoding/json" + "fmt" + "os" - "github.com/hashicorp/go-metrics" - "github.com/prometheus/common/expfmt" - otelconf "go.opentelemetry.io/contrib/otelconf/v0.3.0" + "go.opentelemetry.io/contrib/otelconf/v0.3.0" ) -// globalTelemetryEnabled is a private variable that stores the telemetry enabled state. -// It is set on initialization and does not change for the lifetime of the program. -var globalTelemetryEnabled bool +var sdk otelconf.SDK -// IsTelemetryEnabled provides controlled access to check if telemetry is enabled. -func IsTelemetryEnabled() bool { - return globalTelemetryEnabled -} - -// EnableTelemetry allows for the global telemetry enabled state to be set. -func EnableTelemetry() { - globalTelemetryEnabled = true -} - -// globalLabels defines the set of global labels that will be applied to all -// metrics emitted using the telemetry package function wrappers. -var globalLabels = []metrics.Label{} - -// Metrics supported format types. -const ( - FormatDefault = "" - FormatPrometheus = "prometheus" - FormatText = "text" - ContentTypeText = `text/plain; version=` + expfmt.TextVersion + `; charset=utf-8` - - MetricSinkInMem = "mem" - MetricSinkStatsd = "statsd" - MetricSinkDogsStatsd = "dogstatsd" - MetricSinkFile = "file" - - TraceSinkOtel = "otel" - TraceSinkNoop = "noop" -) - -// DisplayableSink is an interface that defines a method for displaying metrics. -type DisplayableSink interface { - DisplayMetrics(resp http.ResponseWriter, req *http.Request) (any, error) -} - -// Config defines the configuration options for application telemetry. -type Config struct { - // ServiceName is the identifier for this service, used as a prefix for all metric keys. - // Example: "cosmos-app" → metrics like "cosmos-app.tx.count" - ServiceName string `mapstructure:"service-name" json:"service-name"` - - // Enabled controls whether telemetry is active. When false, all telemetry operations - // become no-ops with zero overhead. When true, metrics collection is activated. - Enabled bool `mapstructure:"enabled" json:"enabled"` +var isTelemetryEnabled = true - // EnableHostname prefixes gauge values with the hostname. - // Useful in multi-node deployments to identify which node emitted a metric. - EnableHostname bool `mapstructure:"enable-hostname" json:"enable-hostname"` +func init() { + var err error - // EnableHostnameLabel adds a "hostname" label to all metrics. - // Alternative to EnableHostname that works better with label-based systems like Prometheus. - EnableHostnameLabel bool `mapstructure:"enable-hostname-label" json:"enable-hostname-label"` + var opts []otelconf.ConfigurationOption - // EnableServiceLabel adds a "service" label with the ServiceName to all metrics. - // Useful when aggregating metrics from multiple services in one monitoring system. - EnableServiceLabel bool `mapstructure:"enable-service-label" json:"enable-service-label"` + confFilename := os.Getenv("COSMOS_TELEMETRY") + if confFilename != "" { + bz, err := os.ReadFile(confFilename) + if err != nil { + panic(fmt.Sprintf("failed to read telemetry config file: %v", err)) + } - // PrometheusRetentionTime, when positive, enables a Prometheus metrics sink. - // Defines how long (in seconds) metrics are retained in memory for scraping. - // The Prometheus sink is added to a FanoutSink alongside the primary sink. - // Recommended value: 60 seconds or more. - PrometheusRetentionTime int64 `mapstructure:"prometheus-retention-time" json:"prometheus-retention-time"` + cfg, err := otelconf.ParseYAML(bz) + if err != nil { + panic(fmt.Sprintf("failed to parse telemetry config file: %v", err)) + } - // GlobalLabels defines a set of key-value label pairs applied to ALL metrics. - // These labels are automatically attached to every metric emission. - // Useful for static identifiers like chain ID, environment, region, etc. - // - // Example: [][]string{{"chain_id", "cosmoshub-1"}, {"env", "production"}} - // - // Note: The outer array contains label pairs, each inner array has exactly 2 elements [key, value]. - GlobalLabels [][]string `mapstructure:"global-labels" json:"global-labels"` + cfgJson, err := json.Marshal(cfg) + if err != nil { + panic(fmt.Sprintf("failed to marshal telemetry config file: %v", err)) + } + fmt.Printf("\nInitializing telemetry with config:\n%s\n\n", cfgJson) - // MetricsSink defines the metrics backend type. Supported values: - // - "mem" (default): In-memory sink with SIGUSR1 dump-to-stderr capability - // - "prometheus": Prometheus exposition format (use with PrometheusRetentionTime) - // - "statsd": StatsD protocol (push-based, requires StatsdAddr) - // - "dogstatsd": Datadog-enhanced StatsD with tags (requires StatsdAddr, DatadogHostname) - // - "file": JSON lines written to a file (requires MetricsFile) - // - // Multiple sinks can be active via FanoutSink (e.g., mem + prometheus). - MetricsSink string `mapstructure:"metrics-sink" json:"metrics-sink" default:"mem"` + opts = append(opts, otelconf.WithOpenTelemetryConfiguration(*cfg)) + } - // StatsdAddr is the address of the StatsD or DogStatsD server (host:port). - // Only used when MetricsSink is "statsd" or "dogstatsd". - // Example: "localhost:8125" - StatsdAddr string `mapstructure:"statsd-addr" json:"statsd-addr"` - - // DatadogHostname is the hostname to report when using DogStatsD. - // Only used when MetricsSink is "dogstatsd". - // If empty, the system hostname is used. - DatadogHostname string `mapstructure:"datadog-hostname" json:"datadog-hostname"` - - // MetricsFile is the file path to write metrics to in JSONL format. - // Only used when MetricsSink is "file". - // Each metric emission creates a JSON line: {"timestamp":"...","type":"counter","key":[...],"value":1.0} - // Example: "/tmp/metrics.jsonl" or "./metrics.jsonl" - MetricsFile string `mapstructure:"metrics-file" json:"metrics-file"` - - // TraceSink is the sink for trace data. Supported values: - // - "otel": OpenTelemetry trace sink - // - "metrics": all spans will be redirected to emit invocation counter and timing histogram metrics - // - "noop": No-op trace sink (default) - TraceSink string `mapstructure:"trace-sink" json:"trace-sink"` - - // OtelTraceExporters is a list of exporters to use for trace data. - // This is only used when trace sink is set to "otel". - OtelTraceExporters []OtelExportConfig `mapstructure:"otel-trace-exporters" json:"otel-trace-exporters"` - - // OtelMetricsExporters is a list of exporters to use for metrics data via OpenTelemetry. - // When configured, wrapper functions (IncrCounter, SetGauge, etc.) will use OTel instruments - // instead of go-metrics, and metrics will be exported through these exporters. - OtelMetricsExporters []OtelExportConfig `mapstructure:"otel-metrics-exporters" json:"otel-metrics-exporters"` + sdk, err = otelconf.NewSDK(opts...) + if err != nil { + panic(fmt.Sprintf("failed to initialize telemetry: %v", err)) + } } -// OtelExportConfig defines configuration for an OpenTelemetry exporter. -// This is used for both traces and metrics exporters. -type OtelExportConfig struct { - // Type is the exporter type. - // For traces: "stdout", "otlp" - // For metrics: "stdout", "otlp", "prometheus" - Type string `mapstructure:"type" json:"type"` - - // OTLPTransport is the transport protocol to use for OTLP. - // Must be one of: - // - "http" (default) - // - "grpc" - // Only used when Type is "otlp". - OTLPTransport string `mapstructure:"otlp-transport" json:"otlp-transport"` - - // Endpoint is the OTLP exporter endpoint URL (grpc or http). - // Only used when Type is "otlp". - // Example: "localhost:4318" for HTTP, "localhost:4317" for gRPC - Endpoint string `mapstructure:"endpoint" json:"endpoint"` - - // Insecure disables TLS certificate verification for OTLP exporters. - // Only used when Type is "otlp". - Insecure bool `mapstructure:"insecure" json:"insecure"` - - // Headers is a map of HTTP headers to send with each request to the OTLP exporter. - // Useful for authentication, authorization, or custom metadata. - // Only used when Type is "otlp". - // Example: {"Authorization": "Bearer token123", "X-Custom-Header": "value"} - Headers map[string]string `mapstructure:"headers" json:"headers"` - - // File is the file path to write data to when using the "stdout" exporter. - // If empty, data is written to stdout. - // Only used when Type is "stdout". - File string `mapstructure:"file" json:"file"` +func Shutdown(ctx context.Context) error { + return sdk.Shutdown(ctx) +} - // PrettyPrint enables pretty-printing of JSON output when using the "stdout" exporter. - // Only used when Type is "stdout" for traces. - PrettyPrint bool `mapstructure:"pretty-print" json:"pretty-print"` +func IsTelemetryEnabled() bool { + return isTelemetryEnabled +} - // ListenAddress is the address to listen on for Prometheus scraping. - // Only used when Type is "prometheus" for metrics. - // Example: ":8080" or "localhost:9090" - ListenAddress string `mapstructure:"listen-address" json:"listen-address"` +func SetTelemetryEnabled(v bool) { + isTelemetryEnabled = v } diff --git a/telemetry/doc.go b/telemetry/doc.go index 98afc159ba42..7019bd9a9563 100644 --- a/telemetry/doc.go +++ b/telemetry/doc.go @@ -1,39 +1,2 @@ -// Package telemetry provides observability through metrics and distributed tracing. -// -// # Metrics Collection -// -// Metrics collection uses hashicorp/go-metrics with support for multiple sink backends: -// - mem: In-memory aggregation with SIGUSR1 signal dumping to stderr -// - prometheus: Prometheus registry for pull-based scraping via /metrics endpoint -// - statsd: Push-based metrics to StatsD daemon -// - dogstatsd: Push-based metrics to Datadog StatsD daemon with tagging -// - file: Write metrics to a file as JSON lines (useful for tests and debugging) -// -// Multiple sinks can be active simultaneously via FanoutSink (e.g., both in-memory and Prometheus). -// -// # Distributed Tracing -// -// Tracing support is provided via OtelSpan, which wraps OpenTelemetry for hierarchical span tracking. -// See otel.go for the log.Tracer implementation. -// -// # Usage -// -// Initialize metrics at application startup: -// -// m, err := telemetry.New(telemetry.Config{ -// Enabled: true, -// ServiceName: "cosmos-app", -// PrometheusRetentionTime: 60, -// GlobalLabels: [][]string{{"chain_id", "cosmoshub-1"}}, -// }) -// if err != nil { -// log.Fatal(err) -// } -// defer m.Close() -// -// Emit metrics from anywhere in the application: -// -// telemetry.IncrCounter(1, "tx", "processed") -// telemetry.SetGauge(1024, "mempool", "size") -// defer telemetry.MeasureSince(telemetry.Now(), "block", "execution") +// Package telemetry initialize OpenTelemetry and provides metrics wrapper functions. package telemetry diff --git a/telemetry/file_sink.go b/telemetry/file_sink.go deleted file mode 100644 index 4c653558fd6d..000000000000 --- a/telemetry/file_sink.go +++ /dev/null @@ -1,157 +0,0 @@ -package telemetry - -import ( - "bufio" - "encoding/json" - "fmt" - "io" - "sync" - "time" - - "github.com/hashicorp/go-metrics" -) - -// FileSink writes metrics to a file as JSON lines (JSONL format). -// Each metric emission creates a single JSON line with timestamp, type, key, value, and labels. -// -// This sink is particularly useful for: -// - Test environments where metrics need to be inspected after execution -// - CI/CD pipelines where metrics should be logged for analysis -// - Debugging and local development -// -// The sink is thread-safe and buffers writes for performance. -// Call Close() to flush buffered data and close the underlying writer. -type FileSink struct { - writer *bufio.Writer - closer io.Closer - mu sync.Mutex - closed bool -} - -// metricLine represents a single metric emission in JSON format. -type metricLine struct { - Timestamp time.Time `json:"timestamp"` - Type string `json:"type"` - Key []string `json:"key"` - Value float32 `json:"value"` - Labels []metrics.Label `json:"labels,omitempty"` -} - -// NewFileSink creates a new FileSink that writes to the given io.WriteCloser. -// The sink buffers writes for performance. Call Close() to flush and close. -func NewFileSink(w io.WriteCloser) *FileSink { - return &FileSink{ - writer: bufio.NewWriter(w), - closer: w, - closed: false, - } -} - -// SetGauge implements metrics.MetricSink. -func (f *FileSink) SetGauge(key []string, val float32) { - f.SetGaugeWithLabels(key, val, nil) -} - -// SetGaugeWithLabels implements metrics.MetricSink. -func (f *FileSink) SetGaugeWithLabels(key []string, val float32, labels []metrics.Label) { - f.writeLine(metricLine{ - Timestamp: time.Now().UTC(), - Type: "gauge", - Key: key, - Value: val, - Labels: labels, - }) -} - -// EmitKey implements metrics.MetricSink. -func (f *FileSink) EmitKey(key []string, val float32) { - f.writeLine(metricLine{ - Timestamp: time.Now().UTC(), - Type: "kv", - Key: key, - Value: val, - }) -} - -// IncrCounter implements metrics.MetricSink. -func (f *FileSink) IncrCounter(key []string, val float32) { - f.IncrCounterWithLabels(key, val, nil) -} - -// IncrCounterWithLabels implements metrics.MetricSink. -func (f *FileSink) IncrCounterWithLabels(key []string, val float32, labels []metrics.Label) { - f.writeLine(metricLine{ - Timestamp: time.Now().UTC(), - Type: "counter", - Key: key, - Value: val, - Labels: labels, - }) -} - -// AddSample implements metrics.MetricSink. -func (f *FileSink) AddSample(key []string, val float32) { - f.AddSampleWithLabels(key, val, nil) -} - -// AddSampleWithLabels implements metrics.MetricSink. -func (f *FileSink) AddSampleWithLabels(key []string, val float32, labels []metrics.Label) { - f.writeLine(metricLine{ - Timestamp: time.Now().UTC(), - Type: "sample", - Key: key, - Value: val, - Labels: labels, - }) -} - -// writeLine writes a metric line to the file as JSON. -func (f *FileSink) writeLine(line metricLine) { - f.mu.Lock() - defer f.mu.Unlock() - - if f.closed { - return - } - - data, err := json.Marshal(line) - if err != nil { - // If JSON marshaling fails, write error to stderr but don't crash - fmt.Fprintf(io.Discard, "failed to marshal metric: %v\n", err) - return - } - - // Write JSON line with newline - if _, err := f.writer.Write(data); err != nil { - return - } - if err := f.writer.WriteByte('\n'); err != nil { - return - } -} - -// Close flushes any buffered data and closes the underlying writer. -// It is safe to call Close multiple times. -func (f *FileSink) Close() error { - f.mu.Lock() - defer f.mu.Unlock() - - if f.closed { - return nil - } - - f.closed = true - - // Flush buffered data - if err := f.writer.Flush(); err != nil { - f.closer.Close() // Try to close anyway - return fmt.Errorf("failed to flush metrics file: %w", err) - } - - // Close the underlying file - if err := f.closer.Close(); err != nil { - return fmt.Errorf("failed to close metrics file: %w", err) - } - - return nil -} diff --git a/telemetry/file_sink_test.go b/telemetry/file_sink_test.go deleted file mode 100644 index 4a8feceb7e37..000000000000 --- a/telemetry/file_sink_test.go +++ /dev/null @@ -1,182 +0,0 @@ -package telemetry - -import ( - "bufio" - "encoding/json" - "os" - "path/filepath" - "sync" - "testing" - - "github.com/hashicorp/go-metrics" - "github.com/stretchr/testify/require" -) - -func TestFileSink_BasicOperations(t *testing.T) { - tmpfile := filepath.Join(t.TempDir(), "metrics.jsonl") - file, err := os.Create(tmpfile) - require.NoError(t, err) - - sink := NewFileSink(file) - - // Emit various metric types - sink.IncrCounter([]string{"test", "counter"}, 1.5) - sink.SetGauge([]string{"test", "gauge"}, 42.0) - sink.AddSample([]string{"test", "sample"}, 100.0) - sink.EmitKey([]string{"test", "kv"}, 3.14) - - // Emit metrics with labels - labels := []metrics.Label{ - {Name: "module", Value: "bank"}, - {Name: "operation", Value: "send"}, - } - sink.IncrCounterWithLabels([]string{"test", "counter_labeled"}, 2.0, labels) - sink.SetGaugeWithLabels([]string{"test", "gauge_labeled"}, 99.0, labels) - sink.AddSampleWithLabels([]string{"test", "sample_labeled"}, 50.0, labels) - - // Close to flush - require.NoError(t, sink.Close()) - - // Read and verify file contents - data, err := os.ReadFile(tmpfile) - require.NoError(t, err) - - file2, err := os.Open(tmpfile) - require.NoError(t, err) - defer file2.Close() - - scanner := bufio.NewScanner(file2) - lineCount := 0 - for scanner.Scan() { - lineCount++ - var metric metricLine - err := json.Unmarshal(scanner.Bytes(), &metric) - require.NoError(t, err, "line %d should be valid JSON", lineCount) - require.NotZero(t, metric.Timestamp, "line %d should have timestamp", lineCount) - require.NotEmpty(t, metric.Type, "line %d should have type", lineCount) - require.NotEmpty(t, metric.Key, "line %d should have key", lineCount) - } - require.NoError(t, scanner.Err()) - require.Equal(t, 7, lineCount, "should have 7 metrics") - - // Verify specific metric formats - require.Contains(t, string(data), `"type":"counter"`) - require.Contains(t, string(data), `"type":"gauge"`) - require.Contains(t, string(data), `"type":"sample"`) - require.Contains(t, string(data), `"type":"kv"`) - require.Contains(t, string(data), `"key":["test","counter"]`) - require.Contains(t, string(data), `"value":1.5`) - require.Contains(t, string(data), `"labels":[{"Name":"module","Value":"bank"}`) -} - -func TestFileSink_ConcurrentWrites(t *testing.T) { - tmpfile := filepath.Join(t.TempDir(), "metrics_concurrent.jsonl") - file, err := os.Create(tmpfile) - require.NoError(t, err) - - sink := NewFileSink(file) - - // Spawn multiple goroutines writing metrics concurrently - const numGoroutines = 10 - const metricsPerGoroutine = 100 - - var wg sync.WaitGroup - wg.Add(numGoroutines) - - for i := 0; i < numGoroutines; i++ { - go func(id int) { - defer wg.Done() - for j := 0; j < metricsPerGoroutine; j++ { - sink.IncrCounter([]string{"concurrent", "test"}, float32(id)) - } - }(i) - } - - wg.Wait() - require.NoError(t, sink.Close()) - - // Count lines in file - file, err = os.Open(tmpfile) - require.NoError(t, err) - defer file.Close() - - scanner := bufio.NewScanner(file) - lineCount := 0 - for scanner.Scan() { - lineCount++ - } - require.NoError(t, scanner.Err()) - require.Equal(t, numGoroutines*metricsPerGoroutine, lineCount, "all metrics should be written") -} - -func TestFileSink_CloseIdempotent(t *testing.T) { - tmpfile := filepath.Join(t.TempDir(), "metrics_close.jsonl") - file, err := os.Create(tmpfile) - require.NoError(t, err) - - sink := NewFileSink(file) - sink.IncrCounter([]string{"test"}, 1.0) - - // Close multiple times should not error - require.NoError(t, sink.Close()) - require.NoError(t, sink.Close()) - require.NoError(t, sink.Close()) -} - -func TestFileSink_WritesAfterClose(t *testing.T) { - tmpfile := filepath.Join(t.TempDir(), "metrics_after_close.jsonl") - file, err := os.Create(tmpfile) - require.NoError(t, err) - - sink := NewFileSink(file) - sink.IncrCounter([]string{"before"}, 1.0) - require.NoError(t, sink.Close()) - - // Writes after close should be silently ignored (no panic) - sink.IncrCounter([]string{"after"}, 1.0) - - // File should only contain one metric - data, err := os.ReadFile(tmpfile) - require.NoError(t, err) - - file3, err := os.Open(tmpfile) - require.NoError(t, err) - defer file3.Close() - - scanner := bufio.NewScanner(file3) - lineCount := 0 - for scanner.Scan() { - lineCount++ - } - require.NoError(t, scanner.Err()) - require.Equal(t, 1, lineCount, "only metric before close should be written") - require.Contains(t, string(data), `"key":["before"]`) - require.NotContains(t, string(data), `"key":["after"]`) -} - -func TestFileSink_JSONFormat(t *testing.T) { - tmpfile := filepath.Join(t.TempDir(), "metrics_json.jsonl") - file, err := os.Create(tmpfile) - require.NoError(t, err) - - sink := NewFileSink(file) - labels := []metrics.Label{{Name: "env", Value: "test"}} - sink.IncrCounterWithLabels([]string{"api", "requests"}, 5.0, labels) - require.NoError(t, sink.Close()) - - // Parse JSON and verify structure - data, err := os.ReadFile(tmpfile) - require.NoError(t, err) - - var metric metricLine - err = json.Unmarshal(data[:len(data)-1], &metric) // Remove trailing newline - require.NoError(t, err) - - require.Equal(t, "counter", metric.Type) - require.Equal(t, []string{"api", "requests"}, metric.Key) - require.Equal(t, float32(5.0), metric.Value) - require.Len(t, metric.Labels, 1) - require.Equal(t, "env", metric.Labels[0].Name) - require.Equal(t, "test", metric.Labels[0].Value) - require.NotZero(t, metric.Timestamp) -} diff --git a/telemetry/metrics.go b/telemetry/metrics.go deleted file mode 100644 index eb4491099e65..000000000000 --- a/telemetry/metrics.go +++ /dev/null @@ -1,366 +0,0 @@ -package telemetry - -import ( - "bytes" - "context" - "encoding/json" - "errors" - "fmt" - "os" - "time" - - "github.com/hashicorp/go-metrics" - "github.com/hashicorp/go-metrics/datadog" - metricsprom "github.com/hashicorp/go-metrics/prometheus" - "github.com/prometheus/client_golang/prometheus" - "github.com/prometheus/common/expfmt" - "go.opentelemetry.io/otel/exporters/otlp/otlptrace" - "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc" - "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp" - "go.opentelemetry.io/otel/exporters/stdout/stdouttrace" - "go.opentelemetry.io/otel/sdk/resource" - otelsdktrace "go.opentelemetry.io/otel/sdk/trace" - semconv "go.opentelemetry.io/otel/semconv/v1.17.0" - - "cosmossdk.io/log" -) - -// Metrics provides access to the application's metrics collection system. -// It wraps the go-metrics global registry and configured sinks. -// -// When using the in-memory sink, sending SIGUSR1 to the process (kill -USR1 ) -// will dump current metrics to stderr for debugging. -// -// The Metrics object maintains references to configured sinks and provides -// a Gather() method for pull-based metric retrieval (useful for testing and monitoring). -// -// When using the file sink, call Close() to flush buffered data and close the file. -// -// Note: go-metrics uses a singleton global registry. Only one Metrics instance -// should be created per process. -type Metrics struct { - sink metrics.MetricSink - prometheusEnabled bool - startFuncs []func(ctx context.Context) error - shutdownFuncs []func(context.Context) error - logger log.Logger - tracer log.Tracer - metricsTracer *MetricsTracer - - // OpenTelemetry metrics (when OtelMetricsExporters is configured) - meterProvider *sdkmetric.MeterProvider - meter metric.Meter - - // Instrument cache for wrapper functions - counters map[string]metric.Int64Counter - gauges map[string]metric.Float64Gauge - histograms map[string]metric.Float64Histogram - mu sync.RWMutex -} - -// GatherResponse contains collected metrics in the requested format. -// The Metrics field holds the serialized metric data, and ContentType -// indicates how it's encoded ("application/json" or prometheus text format). -type GatherResponse struct { - Metrics []byte - ContentType string -} - -// New creates and initializes the metrics system with the given configuration. -// -// Returns nil if telemetry is disabled (cfg.Enabled == false), which allows -// callers to safely ignore the Metrics object. -// -// The function: -// - Initializes the go-metrics global registry -// - Configures the specified sink(s) (mem, prometheus, statsd, dogstatsd, file) -// - Sets up global labels to be applied to all metrics -// - Enables SIGUSR1 signal handling for in-memory sink dumps -// - Creates a FanoutSink if multiple sinks are needed (e.g., mem + prometheus) -// -// Example: -// -// m, err := telemetry.New(telemetry.Config{ -// Enabled: true, -// ServiceName: "cosmos-app", -// MetricsSink: telemetry.MetricSinkInMem, -// PrometheusRetentionTime: 60, -// }) -// if err != nil { -// return err -// } -// defer m.Close() -func New(cfg Config, opts ...Option) (_ *Metrics, rerr error) { - globalTelemetryEnabled = cfg.Enabled - if !cfg.Enabled { - return nil, nil - } - - if numGlobalLabels := len(cfg.GlobalLabels); numGlobalLabels > 0 { - parsedGlobalLabels := make([]metrics.Label, numGlobalLabels) - for i, gl := range cfg.GlobalLabels { - parsedGlobalLabels[i] = NewLabel(gl[0], gl[1]) - } - globalLabels = parsedGlobalLabels - } - - metricsConf := metrics.DefaultConfig(cfg.ServiceName) - metricsConf.EnableHostname = cfg.EnableHostname - metricsConf.EnableHostnameLabel = cfg.EnableHostnameLabel - - // Initialize Metrics struct early with default logger - m := &Metrics{ - logger: log.NewNopLogger(), // Default to nop logger - } - // Apply functional options to set logger - for _, opt := range opts { - opt(m) - } - - var err error - switch cfg.MetricsSink { - case MetricSinkStatsd: - m.sink, err = metrics.NewStatsdSink(cfg.StatsdAddr) - case MetricSinkDogsStatsd: - m.sink, err = datadog.NewDogStatsdSink(cfg.StatsdAddr, cfg.DatadogHostname) - case MetricSinkFile: - if cfg.MetricsFile == "" { - return nil, errors.New("metrics-file must be set when metrics-sink is 'file'") - } - file, err := os.OpenFile(cfg.MetricsFile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644) - if err != nil { - return nil, fmt.Errorf("failed to open metrics file: %w", err) - } - fileSink := NewFileSink(file) - m.shutdownFuncs = append(m.shutdownFuncs, func(ctx context.Context) error { - return file.Close() - }) - m.sink = fileSink - default: - memSink := metrics.NewInmemSink(10*time.Second, time.Minute) - m.sink = memSink - inMemSig := metrics.DefaultInmemSignal(memSink) - defer func() { - if rerr != nil { - inMemSig.Stop() - } - }() - } - if err != nil { - return nil, err - } - - m.tracer = log.NewNopTracer(m.logger) - m.metricsTracer = NewMetricsTracer(metrics.Default(), nil, globalLabels, m.logger) - - switch cfg.TraceSink { - case TraceSinkOtel: - var tracerProviderOpts []otelsdktrace.TracerProviderOption - for _, exporterOpts := range cfg.OtelTraceExporters { - switch exporterOpts.Type { - case "otlp": - endpoint := exporterOpts.Endpoint - if endpoint == "" { - return nil, fmt.Errorf("otlp endpoint must be set") - } - var client otlptrace.Client - switch exporterOpts.OTLPTransport { - case "grpc": - opts := []otlptracegrpc.Option{otlptracegrpc.WithEndpoint(endpoint)} - if exporterOpts.Insecure { - opts = append(opts, otlptracegrpc.WithInsecure()) - } - if len(exporterOpts.Headers) > 0 { - opts = append(opts, otlptracegrpc.WithHeaders(exporterOpts.Headers)) - } - client = otlptracegrpc.NewClient(opts...) - default: - opts := []otlptracehttp.Option{otlptracehttp.WithEndpoint(endpoint)} - if exporterOpts.Insecure { - opts = append(opts, otlptracehttp.WithInsecure()) - } - if len(exporterOpts.Headers) > 0 { - opts = append(opts, otlptracehttp.WithHeaders(exporterOpts.Headers)) - } - client = otlptracehttp.NewClient(opts...) - } - exporter := otlptrace.NewUnstarted(client) - m.startFuncs = append(m.startFuncs, exporter.Start) - batcherOpt := otelsdktrace.WithBatcher(exporter) - tracerProviderOpts = append(tracerProviderOpts, batcherOpt) - case "stdout": - var opts []stdouttrace.Option - if exporterOpts.File != "" { - file, err := os.OpenFile(exporterOpts.File, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644) - if err != nil { - return nil, fmt.Errorf("failed to open stdout trace file %s: %w", exporterOpts.File, err) - } - opts = append(opts, stdouttrace.WithWriter(file)) - m.shutdownFuncs = append(m.shutdownFuncs, func(ctx context.Context) error { - return file.Close() - }) - } - if exporterOpts.PrettyPrint { - opts = append(opts, stdouttrace.WithPrettyPrint()) - } - exporter, err := stdouttrace.New(opts...) - if err != nil { - return nil, fmt.Errorf("failed to create stdout trace exporter: %w", err) - } - batcher := otelsdktrace.WithBatcher(exporter) - tracerProviderOpts = append(tracerProviderOpts, batcher) - default: - return nil, fmt.Errorf("unknown trace exporter type: %s", exporterOpts.Type) - } - } - - // Determine service name for both resource and tracer - serviceName := cfg.ServiceName - if serviceName == "" { - serviceName = "cosmos-sdk" - } - - // Create OpenTelemetry resource with service name - res, err := resource.New(context.Background(), - resource.WithAttributes( - semconv.ServiceName(serviceName), - ), - ) - if err != nil { - return nil, fmt.Errorf("failed to create trace resource: %w", err) - } - - // Add resource to tracer provider options - tracerProviderOpts = append(tracerProviderOpts, otelsdktrace.WithResource(res)) - tracerProvider := otelsdktrace.NewTracerProvider(tracerProviderOpts...) - m.shutdownFuncs = append(m.shutdownFuncs, tracerProvider.Shutdown) - m.tracer = NewOtelTracer(tracerProvider.Tracer(serviceName), m.logger) - case "metrics": - m.tracer = m.metricsTracer - default: - } - - fanout := metrics.FanoutSink{m.sink} - - if cfg.PrometheusRetentionTime > 0 { - m.prometheusEnabled = true - prometheusOpts := metricsprom.PrometheusOpts{ - Expiration: time.Duration(cfg.PrometheusRetentionTime) * time.Second, - } - - promSink, err := metricsprom.NewPrometheusSinkFrom(prometheusOpts) - if err != nil { - return nil, err - } - - fanout = append(fanout, promSink) - } - - if _, err := metrics.NewGlobal(metricsConf, fanout); err != nil { - return nil, err - } - - return m, nil -} - -// Gather collects all registered metrics and returns a GatherResponse where the -// metrics are encoded depending on the type. Metrics are either encoded via -// Prometheus or JSON if in-memory. -func (m *Metrics) Gather(format string) (GatherResponse, error) { - switch format { - case FormatPrometheus: - return m.gatherPrometheus() - - case FormatText: - return m.gatherGeneric() - - case FormatDefault: - return m.gatherGeneric() - - default: - return GatherResponse{}, fmt.Errorf("unsupported metrics format: %s", format) - } -} - -// gatherPrometheus collects Prometheus metrics and returns a GatherResponse. -// If Prometheus metrics are not enabled, it returns an error. -func (m *Metrics) gatherPrometheus() (GatherResponse, error) { - if !m.prometheusEnabled { - return GatherResponse{}, errors.New("prometheus metrics are not enabled") - } - - metricsFamilies, err := prometheus.DefaultGatherer.Gather() - if err != nil { - return GatherResponse{}, fmt.Errorf("failed to gather prometheus metrics: %w", err) - } - - buf := &bytes.Buffer{} - defer buf.Reset() - - e := expfmt.NewEncoder(buf, expfmt.NewFormat(expfmt.TypeTextPlain)) - - for _, mf := range metricsFamilies { - if err := e.Encode(mf); err != nil { - return GatherResponse{}, fmt.Errorf("failed to encode prometheus metrics: %w", err) - } - } - - return GatherResponse{ContentType: ContentTypeText, Metrics: buf.Bytes()}, nil -} - -// gatherGeneric collects generic metrics and returns a GatherResponse. -func (m *Metrics) gatherGeneric() (GatherResponse, error) { - gm, ok := m.sink.(DisplayableSink) - if !ok { - return GatherResponse{}, errors.New("non in-memory metrics sink does not support generic format") - } - - summary, err := gm.DisplayMetrics(nil, nil) - if err != nil { - return GatherResponse{}, fmt.Errorf("failed to gather in-memory metrics: %w", err) - } - - content, err := json.Marshal(summary) - if err != nil { - return GatherResponse{}, fmt.Errorf("failed to encode in-memory metrics: %w", err) - } - - return GatherResponse{ContentType: "application/json", Metrics: content}, nil -} - -// Tracer returns the base tracer for creating spans and logging. -func (m *Metrics) Tracer() log.Tracer { - return m.tracer -} - -// MetricsTracer returns a tracer that only emits metrics for spans. -// Use this when you specifically want to configure a code path to only emit metrics -// and not actual logging spans (useful for benchmarking small operations such as store operations). -func (m *Metrics) MetricsTracer() log.Tracer { - return m.metricsTracer -} - -// Start starts all configured exporters. -// Start should be called after New() in order to ensure that all configured -// exporters are started. -func (m *Metrics) Start(ctx context.Context) error { - for _, f := range m.startFuncs { - if err := f(ctx); err != nil { - return err - } - } - return nil -} - -// Shutdown must be called before the application exits to shutdown any -// exporters and close any open files. -func (m *Metrics) Shutdown(ctx context.Context) error { - n := len(m.shutdownFuncs) - // shutdown in reverse order because we can't close files until after the exporter is stopped - for i := n - 1; i >= 0; i-- { - if err := m.shutdownFuncs[i](ctx); err != nil { - return err - } - } - return nil -} diff --git a/telemetry/metrics_span.go b/telemetry/metrics_span.go deleted file mode 100644 index 407c91708ae1..000000000000 --- a/telemetry/metrics_span.go +++ /dev/null @@ -1,139 +0,0 @@ -package telemetry - -import ( - "context" - "time" - - "github.com/hashicorp/go-metrics" - - "cosmossdk.io/log" -) - -// MetricsTracer is a log.Tracer implementation that emits metrics for span operations. -// It wraps a logger and forwards all log calls to it, while creating MetricsSpan instances -// that emit timing and count metrics. -type MetricsTracer struct { - log.Logger // Logger to forward log calls to - rootPath []string // Base path set at tracer creation, preserved across all spans - rootLabels []metrics.Label // Labels applied to all metrics emitted by this tracer - metrics *metrics.Metrics -} - -// NewMetricsTracer creates a new MetricsTracer with the given configuration. -func NewMetricsTracer(metrics *metrics.Metrics, rootPath []string, rootLabels []metrics.Label, logger log.Logger) *MetricsTracer { - return &MetricsTracer{ - Logger: logger, - rootPath: rootPath, - rootLabels: rootLabels, - metrics: metrics, - } -} - -func (m *MetricsTracer) startSpan(existingPath []string, operation string, _ ...any) log.Span { - path := make([]string, len(existingPath)+1) - copy(path, existingPath) - path[len(path)-1] = operation - return &MetricsSpan{ - MetricsTracer: m, - path: path, - start: time.Now(), - } -} - -func (m *MetricsTracer) StartSpan(operation string, _ ...any) log.Span { - return m.startSpan(m.rootPath, operation) -} - -func (m *MetricsTracer) StartSpanContext(ctx context.Context, operation string, kvs ...any) (context.Context, log.Span) { - return ctx, m.startSpan(m.rootPath, operation) -} - -func (m *MetricsTracer) StartRootSpan(ctx context.Context, operation string, kvs ...any) (context.Context, log.Span) { - return ctx, m.startSpan(m.rootPath, operation) -} - -var _ log.Tracer = (*MetricsTracer)(nil) - -// MetricsSpan is a log.Span implementation that emits timing and count metrics -// to go-metrics when the span ends. -// -// Unlike distributed tracing spans, MetricsSpan: -// - Does not support logging (Info/Warn/Error/Debug are no-ops) -// - Ignores span attributes (kvs parameters) -// - Emits aggregated metrics rather than individual trace events -// -// When End() is called, two metrics are emitted: -// - A timer metric with ".time" suffix (e.g., "query.get.time") -// - A counter metric with ".count" suffix (e.g., "query.get.count") -// -// Root path and labels are preserved across all spans created from this tracer, -// ensuring consistent metric namespacing and labeling throughout the span hierarchy. -type MetricsSpan struct { - *MetricsTracer - start time.Time - path []string -} - -// StartSpan creates a child span by appending the operation name to the current path. -// Root path and labels are preserved in the child span. -// The kvs parameters are ignored (metrics don't support dynamic attributes). -func (m *MetricsSpan) StartSpan(operation string, kvs ...any) log.Span { - return m.startSpan(m.path, operation) -} - -// StartSpanContext creates a child span and returns the context unchanged. -// The span is not stored in the context. -func (m *MetricsSpan) StartSpanContext(ctx context.Context, operation string, _ ...any) (context.Context, log.Span) { - return ctx, m.startSpan(m.path, operation) -} - -// StartRootSpan creates a new root span by combining the tracer's root path with the operation. -// Unlike StartSpan, this does not extend the current span's path - it starts fresh from the root path. -// Root labels are preserved in the new span. -// -// Example: -// -// tracer := NewMetricsTracer(metrics, []string{"app"}, nil) -// _, span := tracer.StartRootSpan(ctx, "process") -// defer span.End() -// // Emits: "app.process.time" and "app.process.count" -func (m *MetricsSpan) StartRootSpan(ctx context.Context, operation string, kvs ...any) (context.Context, log.Span) { - return ctx, m.startSpan(m.rootPath, operation) -} - -// SetAttrs is a no-op - metrics don't support dynamic attributes. -func (m *MetricsSpan) SetAttrs(...any) {} - -// SetErr is a no-op but returns the error unchanged for convenience. -func (m *MetricsSpan) SetErr(err error, _ ...any) error { return err } - -// End emits timing and count metrics with ".time" and ".count" suffixes. -// Root labels are applied to both metrics. -// -// For a span with path ["query", "get"], this emits: -// - Timer: "query.get.time" with duration since start -// - Counter: "query.get.count" incremented by 1 -// -// If root labels were set (e.g., module=staking), they are included in both metrics. -func (m *MetricsSpan) End() { - // Create paths with suffixes to avoid metric type conflicts - timePath := make([]string, len(m.path)+1) - copy(timePath, m.path) - timePath[len(timePath)-1] = "time" - - countPath := make([]string, len(m.path)+1) - copy(countPath, m.path) - countPath[len(countPath)-1] = "count" - - // Apply root labels to metrics - if len(m.rootLabels) > 0 { - m.metrics.MeasureSinceWithLabels(timePath, m.start, m.rootLabels) - m.metrics.IncrCounterWithLabels(countPath, 1, m.rootLabels) - } else { - m.metrics.MeasureSince(timePath, m.start) - m.metrics.IncrCounter(countPath, 1) - } -} - -var _ log.Span = (*MetricsSpan)(nil) -var _ log.Tracer = (*MetricsSpan)(nil) diff --git a/telemetry/metrics_test.go b/telemetry/metrics_test.go deleted file mode 100644 index a0aa4690f81f..000000000000 --- a/telemetry/metrics_test.go +++ /dev/null @@ -1,108 +0,0 @@ -package telemetry - -import ( - "context" - "encoding/json" - "os" - "strings" - "testing" - "time" - - "github.com/hashicorp/go-metrics" - "github.com/stretchr/testify/require" -) - -func TestMetrics_Disabled(t *testing.T) { - m, err := New(Config{Enabled: false}) - require.Nil(t, m) - require.Nil(t, err) -} - -func TestMetrics_InMem(t *testing.T) { - m, err := New(Config{ - MetricsSink: MetricSinkInMem, - Enabled: true, - EnableHostname: false, - ServiceName: "test", - }) - require.NoError(t, err) - require.NotNil(t, m) - - emitMetrics() - - gr, err := m.Gather(FormatText) - require.NoError(t, err) - require.Equal(t, gr.ContentType, "application/json") - - jsonMetrics := make(map[string]any) - require.NoError(t, json.Unmarshal(gr.Metrics, &jsonMetrics)) - - counters := jsonMetrics["Counters"].([]any) - require.Equal(t, counters[0].(map[string]any)["Count"].(float64), 10.0) - require.Equal(t, counters[0].(map[string]any)["Name"].(string), "test.dummy_counter") -} - -func TestMetrics_Prom(t *testing.T) { - m, err := New(Config{ - MetricsSink: MetricSinkInMem, - Enabled: true, - EnableHostname: false, - ServiceName: "test", - PrometheusRetentionTime: 60, - EnableHostnameLabel: false, - }) - require.NoError(t, err) - require.NotNil(t, m) - require.True(t, m.prometheusEnabled) - - emitMetrics() - - gr, err := m.Gather(FormatPrometheus) - require.NoError(t, err) - require.Equal(t, gr.ContentType, ContentTypeText) - - require.True(t, strings.Contains(string(gr.Metrics), "test_dummy_counter 30")) -} - -func TestMetrics_FileSink(t *testing.T) { - tmpfile := t.TempDir() + "/metrics.jsonl" - - m, err := New(Config{ - MetricsSink: MetricSinkFile, - MetricsFile: tmpfile, - Enabled: true, - EnableHostname: false, - ServiceName: "test", - }) - require.NoError(t, err) - require.NotNil(t, m) - - // Emit a few metrics - metrics.IncrCounter([]string{"test_counter"}, 5.0) - metrics.SetGauge([]string{"test_gauge"}, 42.0) - - // Close to flush buffered data - require.NoError(t, m.Shutdown(context.Background())) - - // Verify file was created and contains metrics - data, err := os.ReadFile(tmpfile) - require.NoError(t, err) - require.NotEmpty(t, data) - require.Contains(t, string(data), `"type":"counter"`) - require.Contains(t, string(data), `"type":"gauge"`) - require.Contains(t, string(data), `"key":["test","test_counter"]`) -} - -func emitMetrics() { - ticker := time.NewTicker(time.Second) - timeout := time.After(30 * time.Second) - - for { - select { - case <-ticker.C: - metrics.IncrCounter([]string{"dummy_counter"}, 1.0) - case <-timeout: - return - } - } -} diff --git a/telemetry/options.go b/telemetry/options.go deleted file mode 100644 index b48fe041ecd3..000000000000 --- a/telemetry/options.go +++ /dev/null @@ -1,14 +0,0 @@ -package telemetry - -import "cosmossdk.io/log" - -// Option is a functional option for configuring Metrics. -type Option func(*Metrics) - -// WithLogger sets the default logger to use for tracers. -// If not provided, a nop logger will be used. -func WithLogger(logger log.Logger) Option { - return func(m *Metrics) { - m.logger = logger - } -} diff --git a/telemetry/otel_span.go b/telemetry/otel_span.go deleted file mode 100644 index 3a7db06a24dc..000000000000 --- a/telemetry/otel_span.go +++ /dev/null @@ -1,203 +0,0 @@ -package telemetry - -import ( - "context" - "fmt" - - otelattr "go.opentelemetry.io/otel/attribute" - otelcodes "go.opentelemetry.io/otel/codes" - oteltrace "go.opentelemetry.io/otel/trace" - - "cosmossdk.io/log" -) - -// OtelTracer is a log.Tracer implementation that uses OpenTelemetry for distributed tracing. -// It wraps a logger and forwards all log calls to it, while creating OtelSpan instances -// that emit trace spans. -type OtelTracer struct { - log.Logger - tracer oteltrace.Tracer -} - -func NewOtelTracer(tracer oteltrace.Tracer, logger log.Logger) *OtelTracer { - return &OtelTracer{ - Logger: logger, - tracer: tracer, - } -} - -func (o *OtelTracer) StartSpan(operation string, kvs ...any) log.Span { - ctx, span := o.tracer.Start(context.Background(), operation, oteltrace.WithAttributes(toKVs(kvs)...)) - return &OtelSpan{ - tracer: o.tracer, - ctx: ctx, - span: span, - } -} - -func (o *OtelTracer) StartSpanContext(ctx context.Context, operation string, kvs ...any) (context.Context, log.Span) { - ctx, span := o.tracer.Start(ctx, operation, oteltrace.WithAttributes(toKVs(kvs)...)) - return ctx, &OtelSpan{ - tracer: o.tracer, - ctx: ctx, - span: span, - } -} - -func (o *OtelTracer) StartRootSpan(ctx context.Context, operation string, kvs ...any) (context.Context, log.Span) { - ctx, span := o.tracer.Start(ctx, operation, oteltrace.WithAttributes(toKVs(kvs)...), oteltrace.WithNewRoot()) - return ctx, &OtelSpan{ - tracer: o.tracer, - ctx: ctx, - span: span, - } -} - -var _ log.Tracer = (*OtelTracer)(nil) - -type OtelSpan struct { - tracer oteltrace.Tracer - ctx context.Context - span oteltrace.Span - persistentAttrs []otelattr.KeyValue -} - -func (o *OtelSpan) addEvent(level, msg string, keyVals ...any) { - o.span.AddEvent(msg, - oteltrace.WithAttributes(o.persistentAttrs...), - oteltrace.WithAttributes(toKVs(keyVals)...), - oteltrace.WithAttributes(otelattr.String("level", level)), - ) -} - -func (o *OtelSpan) Info(msg string, keyVals ...any) { - o.addEvent("info", msg, keyVals...) -} - -func (o *OtelSpan) Warn(msg string, keyVals ...any) { - o.addEvent("warn", msg, keyVals...) -} - -func (o *OtelSpan) Error(msg string, keyVals ...any) { - o.addEvent("error", msg, keyVals...) -} - -func (o *OtelSpan) Debug(msg string, keyVals ...any) { - o.addEvent("debug", msg, keyVals...) -} - -func (o *OtelSpan) With(keyVals ...any) log.Logger { - attrs := toKVs(keyVals) - persistentAttrs := make([]otelattr.KeyValue, 0, len(o.persistentAttrs)+len(attrs)) - persistentAttrs = append(persistentAttrs, o.persistentAttrs...) - persistentAttrs = append(persistentAttrs, attrs...) - return &OtelSpan{ - tracer: o.tracer, - ctx: o.ctx, - span: o.span, - persistentAttrs: persistentAttrs, - } -} - -func (o *OtelSpan) Impl() any { - return o.span -} - -func (o *OtelSpan) startSpan(ctx context.Context, operation string, kvs []any, opts ...oteltrace.SpanStartOption) *OtelSpan { - if len(o.persistentAttrs) > 0 { - opts = append(opts, oteltrace.WithAttributes(o.persistentAttrs...)) - } - opts = append(opts, oteltrace.WithAttributes(toKVs(kvs)...)) - ctx, span := o.tracer.Start(ctx, operation, opts...) - return &OtelSpan{ - tracer: o.tracer, - ctx: ctx, - span: span, - persistentAttrs: o.persistentAttrs, - } -} - -func (o *OtelSpan) StartSpan(operation string, kvs ...any) log.Span { - return o.startSpan(o.ctx, operation, kvs) -} - -func (o *OtelSpan) StartSpanContext(ctx context.Context, operation string, kvs ...any) (context.Context, log.Span) { - if !oteltrace.SpanContextFromContext(ctx).IsValid() { - // if we don't have a valid span in the context, use the one from the tracer - ctx = o.ctx - } - span := o.startSpan(ctx, operation, kvs) - return span.ctx, span -} - -func (o *OtelSpan) StartRootSpan(ctx context.Context, operation string, kvs ...any) (context.Context, log.Span) { - span := o.startSpan(ctx, operation, kvs, oteltrace.WithNewRoot()) - return span.ctx, span -} - -func (o *OtelSpan) SetAttrs(kvs ...any) { - o.span.SetAttributes(toKVs(kvs)...) -} - -func (o *OtelSpan) SetErr(err error, kvs ...any) error { - if err == nil { - o.span.SetStatus(otelcodes.Ok, "OK") - } else { - o.span.RecordError(err) - o.span.SetStatus(otelcodes.Error, err.Error()) - } - if len(kvs) > 0 { - o.span.SetAttributes(toKVs(kvs)...) - } - return err -} - -func (o *OtelSpan) End() { - o.span.End() -} - -var _ log.Span = (*OtelSpan)(nil) - -func toKVs(kvs []any) []otelattr.KeyValue { - if len(kvs)%2 != 0 { - panic(fmt.Sprintf("kvs must have even length, got %d", len(kvs))) - } - res := make([]otelattr.KeyValue, 0, len(kvs)/2) - for i := 0; i < len(kvs); i += 2 { - key, ok := kvs[i].(string) - if !ok { - panic("key must be string") - } - res = append(res, otelattr.KeyValue{ - Key: otelattr.Key(key), - Value: toValue(kvs[i+1]), - }) - } - return res -} - -func toValue(value any) otelattr.Value { - switch v := value.(type) { - case bool: - return otelattr.BoolValue(v) - case string: - return otelattr.StringValue(v) - case int64: - return otelattr.Int64Value(v) - case int: - return otelattr.IntValue(v) - case float64: - return otelattr.Float64Value(v) - case []string: - return otelattr.StringSliceValue(v) - case []int64: - return otelattr.Int64SliceValue(v) - case []int: - return otelattr.IntSliceValue(v) - case []float64: - return otelattr.Float64SliceValue(v) - default: - return otelattr.StringValue(fmt.Sprintf("%+v", value)) - } - -} diff --git a/telemetry/testing.go b/telemetry/testing.go index f259e978e293..02868632e972 100644 --- a/telemetry/testing.go +++ b/telemetry/testing.go @@ -2,45 +2,16 @@ package telemetry import ( "context" - "encoding/json" - "os" "testing" - - "github.com/stretchr/testify/require" - - "cosmossdk.io/log" ) // TestingInit initializes telemetry for testing. // If ctx is nil, context.Background() is used. // If logger is nil, a new test logger is created. -func TestingInit(t *testing.T, ctx context.Context, logger log.Logger) *Metrics { - t.Helper() - if ctx == nil { - ctx = context.Background() - } - if logger == nil { - logger = log.NewTestLogger(t) - } - - // configure metrics and tracing for testing - telemetryCfg := Config{ - Enabled: true, - ServiceName: "cosmos-sdk-test", - } - telemetryCfgJson, ok := os.LookupEnv("COSMOS_TELEMETRY") - if ok && telemetryCfgJson != "" { - err := json.Unmarshal([]byte(telemetryCfgJson), &telemetryCfg) - require.NoError(t, err, "failed to parse telemetry config", telemetryCfgJson) - } - - t.Logf("Configuring telemetry with: %+v", telemetryCfg) - metrics, err := New(telemetryCfg, WithLogger(logger)) - require.NoError(t, err, "failed to initialize telemetry") - err = metrics.Start(ctx) - require.NoError(t, err, "failed to start telemetry") +func TestingInit(t *testing.T, ctx context.Context) { t.Cleanup(func() { - require.NoError(t, metrics.Shutdown(ctx), "failed to shutdown telemetry") + if err := Shutdown(ctx); err != nil { + t.Fatalf("failed to shutdown telemetry: %v", err) + } }) - return metrics } diff --git a/telemetry/wrapper.go b/telemetry/wrapper.go index 8445ed823830..12d3f43c6875 100644 --- a/telemetry/wrapper.go +++ b/telemetry/wrapper.go @@ -6,6 +6,8 @@ import ( "github.com/hashicorp/go-metrics" ) +var globalLabels []metrics.Label + // Common metric key constants const ( MetricKeyPreBlocker = "pre_blocker" diff --git a/tests/go.mod b/tests/go.mod index fff27db9c449..c7129097442e 100644 --- a/tests/go.mod +++ b/tests/go.mod @@ -44,7 +44,6 @@ require ( filippo.io/edwards25519 v1.1.0 // indirect github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect github.com/99designs/keyring v1.2.2 // indirect - github.com/DataDog/datadog-go v3.2.0+incompatible // indirect github.com/DataDog/zstd v1.5.7 // indirect github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.29.0 // indirect github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.53.0 // indirect @@ -131,6 +130,7 @@ require ( github.com/gorilla/handlers v1.5.2 // indirect github.com/gorilla/mux v1.8.1 // indirect github.com/gorilla/websocket v1.5.3 // indirect + github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc // indirect github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 // indirect @@ -175,7 +175,8 @@ require ( github.com/prometheus/client_golang v1.23.2 // indirect github.com/prometheus/client_model v0.6.2 // indirect github.com/prometheus/common v0.67.1 // indirect - github.com/prometheus/procfs v0.16.1 // indirect + github.com/prometheus/otlptranslator v0.0.2 // indirect + github.com/prometheus/procfs v0.17.0 // indirect github.com/rcrowley/go-metrics v0.0.0-20250401214520-65e299d6c5c9 // indirect github.com/rogpeppe/go-internal v1.14.1 // indirect github.com/rs/cors v1.11.1 // indirect @@ -203,13 +204,23 @@ require ( go.opentelemetry.io/contrib/detectors/gcp v1.36.0 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0 // indirect + go.opentelemetry.io/contrib/otelconf v0.18.0 // indirect go.opentelemetry.io/otel v1.38.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.14.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.14.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.38.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.38.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.37.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0 // indirect + go.opentelemetry.io/otel/exporters/prometheus v0.60.0 // indirect + go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.14.0 // indirect + go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.38.0 // indirect go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.38.0 // indirect + go.opentelemetry.io/otel/log v0.14.0 // indirect go.opentelemetry.io/otel/metric v1.38.0 // indirect go.opentelemetry.io/otel/sdk v1.38.0 // indirect + go.opentelemetry.io/otel/sdk/log v0.14.0 // indirect go.opentelemetry.io/otel/sdk/metric v1.38.0 // indirect go.opentelemetry.io/otel/trace v1.38.0 // indirect go.opentelemetry.io/proto/otlp v1.7.1 // indirect diff --git a/tests/go.sum b/tests/go.sum index b7404e7f61e8..c5aef41227f0 100644 --- a/tests/go.sum +++ b/tests/go.sum @@ -53,7 +53,6 @@ github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25 github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/DataDog/datadog-go v3.2.0+incompatible h1:qSG2N4FghB1He/r2mFrWKCaL7dXCilEuNEeAn20fdD4= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/DataDog/zstd v1.5.7 h1:ybO8RBeh29qrxIhCA9E8gKY6xfONU9T6G6aP9DTKfLE= github.com/DataDog/zstd v1.5.7/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= @@ -446,6 +445,8 @@ github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc h1:GN2Lv3MGO7AS6PrRoT6yV5+wkrOpcszoIsO4+4ds248= +github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc/go.mod h1:+JKpmjMGhpgPL+rXZ5nsZieVzvarn86asRlBg4uNGnk= github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-middleware v1.2.2/go.mod h1:EaizFBKfUKtMIF5iaDEhniwNedqGo9FuLFzppDr3uwI= github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDaL56wXCB/5+wF6uHfaI= @@ -717,6 +718,8 @@ github.com/prometheus/common v0.15.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16 github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= github.com/prometheus/common v0.67.1 h1:OTSON1P4DNxzTg4hmKCc37o4ZAZDv0cfXLkOt0oEowI= github.com/prometheus/common v0.67.1/go.mod h1:RpmT9v35q2Y+lsieQsdOh5sXZ6ajUGC8NjZAmr8vb0Q= +github.com/prometheus/otlptranslator v0.0.2 h1:+1CdeLVrRQ6Psmhnobldo0kTp96Rj80DRXRd5OSnMEQ= +github.com/prometheus/otlptranslator v0.0.2/go.mod h1:P8AwMgdD7XEr6QRUJ2QWLpiAZTgTE2UYgjlu3svompI= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= @@ -724,8 +727,8 @@ github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+Gx github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.3.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg= -github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is= +github.com/prometheus/procfs v0.17.0 h1:FuLQ+05u4ZI+SS/w9+BWEM2TXiHKsUQ9TADiRH7DuK0= +github.com/prometheus/procfs v0.17.0/go.mod h1:oPQLaDAMRbA+u8H5Pbfq+dl3VDAvHxMUOVhe0wYB2zw= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rcrowley/go-metrics v0.0.0-20250401214520-65e299d6c5c9 h1:bsUq1dX0N8AOIL7EB/X911+m4EHsnWEHeJ0c+3TTBrg= github.com/rcrowley/go-metrics v0.0.0-20250401214520-65e299d6c5c9/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= @@ -848,22 +851,42 @@ go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.6 go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0/go.mod h1:snMWehoOh2wsEwnvvwtDyFCxVeDAODenXHtn5vzrKjo= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0 h1:Hf9xI/XLML9ElpiHVDNwvqI0hIFlzV8dgIr35kV1kRU= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0/go.mod h1:NfchwuyNoMcZ5MLHwPrODwUF1HWCXWrL31s8gSAdIKY= +go.opentelemetry.io/contrib/otelconf v0.18.0 h1:ciF2Gf00BWs0DnexKFZXcxg9kJ8r3SUW1LOzW3CsKA8= +go.opentelemetry.io/contrib/otelconf v0.18.0/go.mod h1:FcP7k+JLwBLdOxS6qY6VQ/4b5VBntI6L6o80IMwhAeI= go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= +go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.14.0 h1:OMqPldHt79PqWKOMYIAQs3CxAi7RLgPxwfFSwr4ZxtM= +go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.14.0/go.mod h1:1biG4qiqTxKiUCtoWDPpL3fB3KxVwCiGw81j3nKMuHE= +go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.14.0 h1:QQqYw3lkrzwVsoEX0w//EhH/TCnpRdEenKBOOEIMjWc= +go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.14.0/go.mod h1:gSVQcr17jk2ig4jqJ2DX30IdWH251JcNAecvrqTxH1s= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.38.0 h1:vl9obrcoWVKp/lwl8tRE33853I8Xru9HFbw/skNeLs8= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.38.0/go.mod h1:GAXRxmLJcVM3u22IjTg74zWBrRCKq8BnOqUVLodpcpw= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.38.0 h1:Oe2z/BCg5q7k4iXC3cqJxKYg0ieRiOqF0cecFYdPTwk= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.38.0/go.mod h1:ZQM5lAJpOsKnYagGg/zV2krVqTtaVdYdDkhMoX6Oalg= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 h1:GqRJVj7UmLjCVyVJ3ZFLdPRmhDUp2zFmQe3RHIOsw24= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0/go.mod h1:ri3aaHSmCTVYu2AWv44YMauwAQc0aqI9gHKIcSbI1pU= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.37.0 h1:EtFWSnwW9hGObjkIdmlnWSydO+Qs8OwzfzXLUPg4xOc= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.37.0/go.mod h1:QjUEoiGCPkvFZ/MjK6ZZfNOS6mfVEVKYE99dFhuN2LI= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0 h1:lwI4Dc5leUqENgGuQImwLo4WnuXFPetmPpkLi2IrX54= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0/go.mod h1:Kz/oCE7z5wuyhPxsXDuaPteSWqjSBD5YaSdbxZYGbGk= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0 h1:aTL7F04bJHUlztTsNGJ2l+6he8c+y/b//eR0jjjemT4= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0/go.mod h1:kldtb7jDTeol0l3ewcmd8SDvx3EmIE7lyvqbasU3QC4= -go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.36.0 h1:rixTyDGXFxRy1xzhKrotaHy3/KXdPhlWARrCgK+eqUY= -go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.36.0/go.mod h1:dowW6UsM9MKbJq5JTz2AMVp3/5iW5I/TStsk8S+CfHw= +go.opentelemetry.io/otel/exporters/prometheus v0.60.0 h1:cGtQxGvZbnrWdC2GyjZi0PDKVSLWP/Jocix3QWfXtbo= +go.opentelemetry.io/otel/exporters/prometheus v0.60.0/go.mod h1:hkd1EekxNo69PTV4OWFGZcKQiIqg0RfuWExcPKFvepk= +go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.14.0 h1:B/g+qde6Mkzxbry5ZZag0l7QrQBCtVm7lVjaLgmpje8= +go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.14.0/go.mod h1:mOJK8eMmgW6ocDJn6Bn11CcZ05gi3P8GylBXEkZtbgA= +go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.38.0 h1:wm/Q0GAAykXv83wzcKzGGqAnnfLFyFe7RslekZuv+VI= +go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.38.0/go.mod h1:ra3Pa40+oKjvYh+ZD3EdxFZZB0xdMfuileHAm4nNN7w= go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.38.0 h1:kJxSDN4SgWWTjG/hPp3O7LCGLcHXFlvS2/FFOrwL+SE= go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.38.0/go.mod h1:mgIOzS7iZeKJdeB8/NYHrJ48fdGc71Llo5bJ1J4DWUE= +go.opentelemetry.io/otel/log v0.14.0 h1:2rzJ+pOAZ8qmZ3DDHg73NEKzSZkhkGIua9gXtxNGgrM= +go.opentelemetry.io/otel/log v0.14.0/go.mod h1:5jRG92fEAgx0SU/vFPxmJvhIuDU9E1SUnEQrMlJpOno= go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E= go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg= +go.opentelemetry.io/otel/sdk/log v0.14.0 h1:JU/U3O7N6fsAXj0+CXz21Czg532dW2V4gG1HE/e8Zrg= +go.opentelemetry.io/otel/sdk/log v0.14.0/go.mod h1:imQvII+0ZylXfKU7/wtOND8Hn4OpT3YUoIgqJVksUkM= +go.opentelemetry.io/otel/sdk/log/logtest v0.14.0 h1:Ijbtz+JKXl8T2MngiwqBlPaHqc4YCaP/i13Qrow6gAM= +go.opentelemetry.io/otel/sdk/log/logtest v0.14.0/go.mod h1:dCU8aEL6q+L9cYTqcVOk8rM9Tp8WdnHOPLiBgp0SGOA= go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM= go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA= go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= diff --git a/tests/systemtests/go.mod b/tests/systemtests/go.mod index 7c9b858c29da..e0bb7f0f279d 100644 --- a/tests/systemtests/go.mod +++ b/tests/systemtests/go.mod @@ -30,7 +30,6 @@ require ( filippo.io/edwards25519 v1.1.0 // indirect github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect github.com/99designs/keyring v1.2.2 // indirect - github.com/DataDog/datadog-go v3.2.0+incompatible // indirect github.com/DataDog/zstd v1.5.7 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bgentry/speakeasy v0.2.0 // indirect @@ -91,6 +90,7 @@ require ( github.com/gorilla/handlers v1.5.2 // indirect github.com/gorilla/mux v1.8.1 // indirect github.com/gorilla/websocket v1.5.3 // indirect + github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc // indirect github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 // indirect @@ -128,7 +128,8 @@ require ( github.com/prometheus/client_golang v1.23.2 // indirect github.com/prometheus/client_model v0.6.2 // indirect github.com/prometheus/common v0.67.1 // indirect - github.com/prometheus/procfs v0.16.1 // indirect + github.com/prometheus/otlptranslator v0.0.2 // indirect + github.com/prometheus/procfs v0.17.0 // indirect github.com/rcrowley/go-metrics v0.0.0-20250401214520-65e299d6c5c9 // indirect github.com/rogpeppe/go-internal v1.14.1 // indirect github.com/rs/cors v1.11.1 // indirect @@ -154,13 +155,24 @@ require ( github.com/zondax/ledger-go v1.0.1 // indirect go.etcd.io/bbolt v1.4.0 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect + go.opentelemetry.io/contrib/otelconf v0.18.0 // indirect go.opentelemetry.io/otel v1.38.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.14.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.14.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.38.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.38.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.37.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0 // indirect + go.opentelemetry.io/otel/exporters/prometheus v0.60.0 // indirect + go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.14.0 // indirect + go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.38.0 // indirect go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.38.0 // indirect + go.opentelemetry.io/otel/log v0.14.0 // indirect go.opentelemetry.io/otel/metric v1.38.0 // indirect go.opentelemetry.io/otel/sdk v1.38.0 // indirect + go.opentelemetry.io/otel/sdk/log v0.14.0 // indirect + go.opentelemetry.io/otel/sdk/metric v1.38.0 // indirect go.opentelemetry.io/otel/trace v1.38.0 // indirect go.opentelemetry.io/proto/otlp v1.7.1 // indirect go.uber.org/multierr v1.11.0 // indirect diff --git a/tests/systemtests/go.sum b/tests/systemtests/go.sum index f3ec451282a3..ea7b7b02107d 100644 --- a/tests/systemtests/go.sum +++ b/tests/systemtests/go.sum @@ -29,7 +29,6 @@ github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25 github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/DataDog/datadog-go v3.2.0+incompatible h1:qSG2N4FghB1He/r2mFrWKCaL7dXCilEuNEeAn20fdD4= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/DataDog/zstd v1.5.7 h1:ybO8RBeh29qrxIhCA9E8gKY6xfONU9T6G6aP9DTKfLE= github.com/DataDog/zstd v1.5.7/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= @@ -346,6 +345,8 @@ github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc h1:GN2Lv3MGO7AS6PrRoT6yV5+wkrOpcszoIsO4+4ds248= +github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc/go.mod h1:+JKpmjMGhpgPL+rXZ5nsZieVzvarn86asRlBg4uNGnk= github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-middleware v1.2.2/go.mod h1:EaizFBKfUKtMIF5iaDEhniwNedqGo9FuLFzppDr3uwI= github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDaL56wXCB/5+wF6uHfaI= @@ -600,6 +601,8 @@ github.com/prometheus/common v0.15.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16 github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= github.com/prometheus/common v0.67.1 h1:OTSON1P4DNxzTg4hmKCc37o4ZAZDv0cfXLkOt0oEowI= github.com/prometheus/common v0.67.1/go.mod h1:RpmT9v35q2Y+lsieQsdOh5sXZ6ajUGC8NjZAmr8vb0Q= +github.com/prometheus/otlptranslator v0.0.2 h1:+1CdeLVrRQ6Psmhnobldo0kTp96Rj80DRXRd5OSnMEQ= +github.com/prometheus/otlptranslator v0.0.2/go.mod h1:P8AwMgdD7XEr6QRUJ2QWLpiAZTgTE2UYgjlu3svompI= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= @@ -607,8 +610,8 @@ github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+Gx github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.3.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg= -github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is= +github.com/prometheus/procfs v0.17.0 h1:FuLQ+05u4ZI+SS/w9+BWEM2TXiHKsUQ9TADiRH7DuK0= +github.com/prometheus/procfs v0.17.0/go.mod h1:oPQLaDAMRbA+u8H5Pbfq+dl3VDAvHxMUOVhe0wYB2zw= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rcrowley/go-metrics v0.0.0-20250401214520-65e299d6c5c9 h1:bsUq1dX0N8AOIL7EB/X911+m4EHsnWEHeJ0c+3TTBrg= github.com/rcrowley/go-metrics v0.0.0-20250401214520-65e299d6c5c9/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= @@ -725,20 +728,42 @@ go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= +go.opentelemetry.io/contrib/otelconf v0.18.0 h1:ciF2Gf00BWs0DnexKFZXcxg9kJ8r3SUW1LOzW3CsKA8= +go.opentelemetry.io/contrib/otelconf v0.18.0/go.mod h1:FcP7k+JLwBLdOxS6qY6VQ/4b5VBntI6L6o80IMwhAeI= go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= +go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.14.0 h1:OMqPldHt79PqWKOMYIAQs3CxAi7RLgPxwfFSwr4ZxtM= +go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.14.0/go.mod h1:1biG4qiqTxKiUCtoWDPpL3fB3KxVwCiGw81j3nKMuHE= +go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.14.0 h1:QQqYw3lkrzwVsoEX0w//EhH/TCnpRdEenKBOOEIMjWc= +go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.14.0/go.mod h1:gSVQcr17jk2ig4jqJ2DX30IdWH251JcNAecvrqTxH1s= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.38.0 h1:vl9obrcoWVKp/lwl8tRE33853I8Xru9HFbw/skNeLs8= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.38.0/go.mod h1:GAXRxmLJcVM3u22IjTg74zWBrRCKq8BnOqUVLodpcpw= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.38.0 h1:Oe2z/BCg5q7k4iXC3cqJxKYg0ieRiOqF0cecFYdPTwk= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.38.0/go.mod h1:ZQM5lAJpOsKnYagGg/zV2krVqTtaVdYdDkhMoX6Oalg= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 h1:GqRJVj7UmLjCVyVJ3ZFLdPRmhDUp2zFmQe3RHIOsw24= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0/go.mod h1:ri3aaHSmCTVYu2AWv44YMauwAQc0aqI9gHKIcSbI1pU= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.37.0 h1:EtFWSnwW9hGObjkIdmlnWSydO+Qs8OwzfzXLUPg4xOc= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.37.0/go.mod h1:QjUEoiGCPkvFZ/MjK6ZZfNOS6mfVEVKYE99dFhuN2LI= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0 h1:lwI4Dc5leUqENgGuQImwLo4WnuXFPetmPpkLi2IrX54= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0/go.mod h1:Kz/oCE7z5wuyhPxsXDuaPteSWqjSBD5YaSdbxZYGbGk= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0 h1:aTL7F04bJHUlztTsNGJ2l+6he8c+y/b//eR0jjjemT4= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0/go.mod h1:kldtb7jDTeol0l3ewcmd8SDvx3EmIE7lyvqbasU3QC4= +go.opentelemetry.io/otel/exporters/prometheus v0.60.0 h1:cGtQxGvZbnrWdC2GyjZi0PDKVSLWP/Jocix3QWfXtbo= +go.opentelemetry.io/otel/exporters/prometheus v0.60.0/go.mod h1:hkd1EekxNo69PTV4OWFGZcKQiIqg0RfuWExcPKFvepk= +go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.14.0 h1:B/g+qde6Mkzxbry5ZZag0l7QrQBCtVm7lVjaLgmpje8= +go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.14.0/go.mod h1:mOJK8eMmgW6ocDJn6Bn11CcZ05gi3P8GylBXEkZtbgA= +go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.38.0 h1:wm/Q0GAAykXv83wzcKzGGqAnnfLFyFe7RslekZuv+VI= +go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.38.0/go.mod h1:ra3Pa40+oKjvYh+ZD3EdxFZZB0xdMfuileHAm4nNN7w= go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.38.0 h1:kJxSDN4SgWWTjG/hPp3O7LCGLcHXFlvS2/FFOrwL+SE= go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.38.0/go.mod h1:mgIOzS7iZeKJdeB8/NYHrJ48fdGc71Llo5bJ1J4DWUE= +go.opentelemetry.io/otel/log v0.14.0 h1:2rzJ+pOAZ8qmZ3DDHg73NEKzSZkhkGIua9gXtxNGgrM= +go.opentelemetry.io/otel/log v0.14.0/go.mod h1:5jRG92fEAgx0SU/vFPxmJvhIuDU9E1SUnEQrMlJpOno= go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E= go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg= +go.opentelemetry.io/otel/sdk/log v0.14.0 h1:JU/U3O7N6fsAXj0+CXz21Czg532dW2V4gG1HE/e8Zrg= +go.opentelemetry.io/otel/sdk/log v0.14.0/go.mod h1:imQvII+0ZylXfKU7/wtOND8Hn4OpT3YUoIgqJVksUkM= +go.opentelemetry.io/otel/sdk/log/logtest v0.14.0 h1:Ijbtz+JKXl8T2MngiwqBlPaHqc4YCaP/i13Qrow6gAM= +go.opentelemetry.io/otel/sdk/log/logtest v0.14.0/go.mod h1:dCU8aEL6q+L9cYTqcVOk8rM9Tp8WdnHOPLiBgp0SGOA= go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM= go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA= go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= diff --git a/testutil/network/network.go b/testutil/network/network.go index 138b94bf77de..d4a0dfc9efee 100644 --- a/testutil/network/network.go +++ b/testutil/network/network.go @@ -25,11 +25,12 @@ import ( "google.golang.org/grpc" "cosmossdk.io/depinject" - "cosmossdk.io/log" sdkmath "cosmossdk.io/math" "cosmossdk.io/math/unsafe" pruningtypes "cosmossdk.io/store/pruning/types" + "cosmossdk.io/log" + "github.com/cosmos/cosmos-sdk/baseapp" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/flags" @@ -377,7 +378,6 @@ func New(l Logger, baseDir string, cfg Config) (*Network, error) { appCfg.MinGasPrices = cfg.MinGasPrices appCfg.API.Enable = true appCfg.API.Swagger = false - appCfg.Telemetry.Enabled = false ctx := server.NewDefaultContext() cmtCfg := ctx.Config diff --git a/types/abci.go b/types/abci.go index d80439ed8ac0..06ca95d7b620 100644 --- a/types/abci.go +++ b/types/abci.go @@ -6,8 +6,6 @@ import ( abci "github.com/cometbft/cometbft/abci/types" storetypes "cosmossdk.io/store/types" - - "cosmossdk.io/log" ) // ABCIHandlers aggregates all ABCI handlers needed for an application. @@ -101,7 +99,7 @@ func (r ResponsePreBlock) IsConsensusParamsChanged() bool { type RunTx = func(txBytes []byte, tx Tx) (gInfo GasInfo, result *Result, anteEvents []abci.Event, err error) // DeliverTxFunc is the function called for each transaction in order to produce a single ExecTxResult -type DeliverTxFunc func(tx []byte, ms storetypes.MultiStore, txIndex int, incarnationCache map[string]any, tracer log.Tracer) *abci.ExecTxResult +type DeliverTxFunc func(tx []byte, ms storetypes.MultiStore, txIndex int, incarnationCache map[string]any) *abci.ExecTxResult // TxRunner defines an interface for types which can be used to execute the DeliverTxFunc. // It should return an array of *abci.ExecTxResult corresponding to the result of executing each transaction diff --git a/types/context.go b/types/context.go index 4e762cc15943..7247783be320 100644 --- a/types/context.go +++ b/types/context.go @@ -6,12 +6,14 @@ import ( abci "github.com/cometbft/cometbft/abci/types" cmtproto "github.com/cometbft/cometbft/proto/tendermint/types" + "go.opentelemetry.io/otel/trace" "cosmossdk.io/core/comet" "cosmossdk.io/core/header" - "cosmossdk.io/log" "cosmossdk.io/store/gaskv" storetypes "cosmossdk.io/store/types" + + "cosmossdk.io/log" ) // ExecMode defines the execution mode which can be set on a Context. @@ -439,6 +441,11 @@ func (c Context) WithIncarnationCache(cache map[string]any) Context { return c } +func (c Context) StartSpan(tracer trace.Tracer, spanName string, opts ...trace.SpanStartOption) (Context, trace.Span) { + goCtx, span := tracer.Start(c.baseCtx, spanName, opts...) + return c.WithContext(goCtx), span +} + var ( _ context.Context = Context{} _ storetypes.Context = Context{} From 50775674c9a7b863401cb6daedc3794a436a9e69 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Fri, 31 Oct 2025 13:43:39 -0400 Subject: [PATCH 14/52] fixes --- simapp/sim_test.go | 4 ---- telemetry/config.go | 6 ++++++ 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/simapp/sim_test.go b/simapp/sim_test.go index ae9607fc386f..4336d2aaf3b5 100644 --- a/simapp/sim_test.go +++ b/simapp/sim_test.go @@ -18,7 +18,6 @@ import ( dbm "github.com/cosmos/cosmos-db" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "go.opentelemetry.io/otel" "cosmossdk.io/log" "github.com/cosmos/cosmos-sdk/telemetry" @@ -162,9 +161,6 @@ func IsEmptyValidatorSetErr(err error) bool { func TestAppStateDeterminism(t *testing.T) { telemetry.TestingInit(t, context.Background()) - tracer := otel.Tracer("test") - _, span := tracer.Start(context.Background(), "TestAppStateDeterminism") - defer span.End() const numTimesToRunPerSeed = 1 var seeds []int64 if s := simcli.NewConfigFromFlags().Seed; s != simcli.DefaultSeedValue { diff --git a/telemetry/config.go b/telemetry/config.go index 440b7002227d..81a5a7ca58c3 100644 --- a/telemetry/config.go +++ b/telemetry/config.go @@ -7,6 +7,8 @@ import ( "os" "go.opentelemetry.io/contrib/otelconf/v0.3.0" + "go.opentelemetry.io/otel" + logglobal "go.opentelemetry.io/otel/log/global" ) var sdk otelconf.SDK @@ -43,6 +45,10 @@ func init() { if err != nil { panic(fmt.Sprintf("failed to initialize telemetry: %v", err)) } + + otel.SetTracerProvider(sdk.TracerProvider()) + otel.SetMeterProvider(sdk.MeterProvider()) + logglobal.SetLoggerProvider(sdk.LoggerProvider()) } func Shutdown(ctx context.Context) error { From 31536b6cdb61e71a9bc59e0af82d50f3144136b7 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Fri, 31 Oct 2025 14:13:39 -0400 Subject: [PATCH 15/52] add basic metrics --- baseapp/abci.go | 4 ++++ baseapp/baseapp.go | 42 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/baseapp/abci.go b/baseapp/abci.go index e1aabdc64216..ae5f6f888818 100644 --- a/baseapp/abci.go +++ b/baseapp/abci.go @@ -1033,6 +1033,10 @@ func (app *BaseApp) Commit() (*abci.ResponseCommit, error) { // The SnapshotIfApplicable method will create the snapshot by starting the goroutine app.snapshotManager.SnapshotIfApplicable(header.Height) + blockCnt.Add(ctx, 1) + blockTime.Record(ctx, time.Since(app.blockStartTime).Seconds()) + app.blockStartTime = time.Now() + return resp, nil } diff --git a/baseapp/baseapp.go b/baseapp/baseapp.go index fb502333e6f6..1b1df303cdef 100644 --- a/baseapp/baseapp.go +++ b/baseapp/baseapp.go @@ -7,6 +7,7 @@ import ( "slices" "strconv" "sync" + "time" "github.com/cockroachdb/errors" abci "github.com/cometbft/cometbft/abci/types" @@ -16,6 +17,7 @@ import ( "github.com/cosmos/gogoproto/proto" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/metric" "go.opentelemetry.io/otel/trace" protov2 "google.golang.org/protobuf/proto" @@ -64,9 +66,40 @@ const ( var _ servertypes.ABCI = (*BaseApp)(nil) var ( - tracer trace.Tracer = otel.Tracer("baseapp") + tracer = otel.Tracer("baseapp") + meter = otel.Meter("baseapp") + blockCnt metric.Int64Counter + txCnt metric.Int64Counter + blockTime metric.Float64Histogram + txTime metric.Int64Histogram ) +func init() { + var err error + blockCnt, err = meter.Int64Counter("block.count") + if err != nil { + panic(err) + } + txCnt, err = meter.Int64Counter("tx.count") + if err != nil { + panic(err) + } + blockTime, err = meter.Float64Histogram("block.time", + metric.WithUnit("s"), + metric.WithDescription("Block time in seconds"), + ) + if err != nil { + panic(err) + } + txTime, err = meter.Int64Histogram("tx.time", + metric.WithUnit("us"), + metric.WithDescription("Transaction time in microseconds"), + ) + if err != nil { + panic(err) + } +} + // BaseApp reflects the ABCI application implementation. type BaseApp struct { // initialized on creation @@ -172,6 +205,8 @@ type BaseApp struct { // Optional alternative tx runner, used for block-stm parallel transaction execution. If nil, default txRunner is used. txRunner sdk.TxRunner + + blockStartTime time.Time } // NewBaseApp returns a reference to an initialized BaseApp. It accepts a @@ -192,6 +227,7 @@ func NewBaseApp( fauxMerkleMode: false, sigverifyTx: true, gasConfig: config.GasConfig{QueryGasLimit: math.MaxUint64}, + blockStartTime: time.Now(), } // initialize tracer @@ -791,6 +827,7 @@ func (app *BaseApp) endBlock() (sdk.EndBlock, error) { // both txbytes and the decoded tx are passed to runTx to avoid the state machine encoding the tx and decoding the transaction twice // passing the decoded tx to runTX is optional, it will be decoded if the tx is nil func (app *BaseApp) RunTx(mode sdk.ExecMode, txBytes []byte, tx sdk.Tx, txIndex int, txMultiStore storetypes.MultiStore, incarnationCache map[string]any) (gInfo sdk.GasInfo, result *sdk.Result, anteEvents []abci.Event, err error) { + startTime := time.Now() ctx := app.getContextForTx(mode, txBytes, txIndex) ctx, span := ctx.StartSpan(tracer, "runTx") defer span.End() @@ -974,6 +1011,9 @@ func (app *BaseApp) RunTx(mode sdk.ExecMode, txBytes []byte, tx sdk.Tx, txIndex consumeBlockGas() msCache.Write() + + txCnt.Add(ctx, 1) + txTime.Record(ctx, time.Since(startTime).Microseconds()) } if len(anteEvents) > 0 && (mode == execModeFinalize || mode == execModeSimulate) { From c922688e2d08cb9458d6db457280c71af696d945 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Fri, 31 Oct 2025 14:30:38 -0400 Subject: [PATCH 16/52] add telemetry shutdown hook --- server/start.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/server/start.go b/server/start.go index 4bb4c29b1e0d..36e874ea2ab4 100644 --- a/server/start.go +++ b/server/start.go @@ -607,6 +607,12 @@ func startApp(svrCtx *Context, appCreator types.AppCreator, opts StartCmdOptions cleanupFn = func() { traceCleanupFn() + + shutdownCtx, _ := context.WithTimeout(context.Background(), 5*time.Second) + if err := telemetry.Shutdown(shutdownCtx); err != nil { + svrCtx.Logger.Error("failed to shutdown telemetry", "error", err) + } + if localErr := app.Close(); localErr != nil { svrCtx.Logger.Error(localErr.Error()) } From ed891ccc32a352d4f8e7d18adf44a546ef954c2d Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Fri, 31 Oct 2025 14:40:12 -0400 Subject: [PATCH 17/52] docs, cleanup --- go.mod | 6 ++---- go.sum | 2 ++ simapp/go.mod | 2 -- simapp/go.sum | 2 ++ telemetry/doc.go | 18 +++++++++++++++++- telemetry/testing.go | 7 +++++-- types/context.go | 3 +++ 7 files changed, 31 insertions(+), 9 deletions(-) diff --git a/go.mod b/go.mod index 9f4d8319c8ae..720a8f833b66 100644 --- a/go.mod +++ b/go.mod @@ -57,6 +57,8 @@ require ( github.com/tidwall/btree v1.8.1 go.opentelemetry.io/contrib/otelconf v0.18.0 go.opentelemetry.io/otel v1.38.0 + go.opentelemetry.io/otel/log v0.14.0 + go.opentelemetry.io/otel/metric v1.38.0 go.opentelemetry.io/otel/trace v1.38.0 go.uber.org/mock v0.6.0 golang.org/x/crypto v0.43.0 @@ -225,8 +227,6 @@ require ( go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.14.0 // indirect go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.38.0 // indirect go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.38.0 // indirect - go.opentelemetry.io/otel/log v0.14.0 // indirect - go.opentelemetry.io/otel/metric v1.38.0 // indirect go.opentelemetry.io/otel/sdk v1.38.0 // indirect go.opentelemetry.io/otel/sdk/log v0.14.0 // indirect go.opentelemetry.io/otel/sdk/metric v1.38.0 // indirect @@ -254,8 +254,6 @@ require ( // Here are the short-lived replace from the Cosmos SDK // Replace here are pending PRs, or version to be tagged -replace cosmossdk.io/log => ./log - // Below are the long-lived replace of the Cosmos SDK replace ( // use cosmos fork of keyring diff --git a/go.sum b/go.sum index a090e17f9037..b4025a518e6f 100644 --- a/go.sum +++ b/go.sum @@ -32,6 +32,8 @@ cosmossdk.io/depinject v1.2.1 h1:eD6FxkIjlVaNZT+dXTQuwQTKZrFZ4UrfCq1RKgzyhMw= cosmossdk.io/depinject v1.2.1/go.mod h1:lqQEycz0H2JXqvOgVwTsjEdMI0plswI7p6KX+MVqFOM= cosmossdk.io/errors v1.0.2 h1:wcYiJz08HThbWxd/L4jObeLaLySopyyuUFB5w4AGpCo= cosmossdk.io/errors v1.0.2/go.mod h1:0rjgiHkftRYPj//3DrD6y8hcm40HcPv/dR4R/4efr0k= +cosmossdk.io/log v1.6.1 h1:YXNwAgbDwMEKwDlCdH8vPcoggma48MgZrTQXCfmMBeI= +cosmossdk.io/log v1.6.1/go.mod h1:gMwsWyyDBjpdG9u2avCFdysXqxq28WJapJvu+vF1y+E= cosmossdk.io/math v1.5.3 h1:WH6tu6Z3AUCeHbeOSHg2mt9rnoiUWVWaQ2t6Gkll96U= cosmossdk.io/math v1.5.3/go.mod h1:uqcZv7vexnhMFJF+6zh9EWdm/+Ylyln34IvPnBauPCQ= cosmossdk.io/schema v1.1.0 h1:mmpuz3dzouCoyjjcMcA/xHBEmMChN+EHh8EHxHRHhzE= diff --git a/simapp/go.mod b/simapp/go.mod index f3b7f18f7733..1100e0357d99 100644 --- a/simapp/go.mod +++ b/simapp/go.mod @@ -251,8 +251,6 @@ require ( sigs.k8s.io/yaml v1.6.0 // indirect ) -replace cosmossdk.io/log => ../log - // Below are the long-lived replace of the SimApp replace ( // use cosmos fork of keyring diff --git a/simapp/go.sum b/simapp/go.sum index 016a7cbf300d..d26be9d2bbf0 100644 --- a/simapp/go.sum +++ b/simapp/go.sum @@ -34,6 +34,8 @@ cosmossdk.io/depinject v1.2.1 h1:eD6FxkIjlVaNZT+dXTQuwQTKZrFZ4UrfCq1RKgzyhMw= cosmossdk.io/depinject v1.2.1/go.mod h1:lqQEycz0H2JXqvOgVwTsjEdMI0plswI7p6KX+MVqFOM= cosmossdk.io/errors v1.0.2 h1:wcYiJz08HThbWxd/L4jObeLaLySopyyuUFB5w4AGpCo= cosmossdk.io/errors v1.0.2/go.mod h1:0rjgiHkftRYPj//3DrD6y8hcm40HcPv/dR4R/4efr0k= +cosmossdk.io/log v1.6.1 h1:YXNwAgbDwMEKwDlCdH8vPcoggma48MgZrTQXCfmMBeI= +cosmossdk.io/log v1.6.1/go.mod h1:gMwsWyyDBjpdG9u2avCFdysXqxq28WJapJvu+vF1y+E= cosmossdk.io/math v1.5.3 h1:WH6tu6Z3AUCeHbeOSHg2mt9rnoiUWVWaQ2t6Gkll96U= cosmossdk.io/math v1.5.3/go.mod h1:uqcZv7vexnhMFJF+6zh9EWdm/+Ylyln34IvPnBauPCQ= cosmossdk.io/schema v1.1.0 h1:mmpuz3dzouCoyjjcMcA/xHBEmMChN+EHh8EHxHRHhzE= diff --git a/telemetry/doc.go b/telemetry/doc.go index 7019bd9a9563..a56752fd3cc8 100644 --- a/telemetry/doc.go +++ b/telemetry/doc.go @@ -1,2 +1,18 @@ -// Package telemetry initialize OpenTelemetry and provides metrics wrapper functions. +// Package telemetry initializes OpenTelemetry and provides legacy metrics wrapper functions. +// End users only need to set the COSMOS_TELEMETRY environment variable to the path of +// an OpenTelemetry declarative configuration file: https://opentelemetry.io/docs/languages/sdk-configuration/declarative-configuration/ +// +// Developers need to do two things: +// 1. Import this package before declaring any otel Tracer, Meter or Logger instances. +// 2. Make sure Shutdown() is called when the application is shutting down. +// Tests can use the TestingInit function at startup to accomplish this. +// +// If these steps are followed, developers can follow the official golang otel conventions +// of declaring package-level tracer and meter instances using otel.Tracer() and otel.Meter(). +// NOTE: it is important to thread context.Context properly for spans, metrics and logs to be +// correlated correctly. +// When using the SDK's context type, spans must be started with Context.StartSpan to +// get an SDK context which has the span set correctly. +// For logging, go.opentelemetry.io/contrib/bridges/otelslog provides a way to do this with the standard +// library slog package. package telemetry diff --git a/telemetry/testing.go b/telemetry/testing.go index 02868632e972..df9ac2085a18 100644 --- a/telemetry/testing.go +++ b/telemetry/testing.go @@ -5,10 +5,13 @@ import ( "testing" ) -// TestingInit initializes telemetry for testing. +// TestingInit initializes telemetry for testing so that it is automatically +// shutdown after the test completes. // If ctx is nil, context.Background() is used. -// If logger is nil, a new test logger is created. func TestingInit(t *testing.T, ctx context.Context) { + if ctx == nil { + ctx = context.Background() + } t.Cleanup(func() { if err := Shutdown(ctx); err != nil { t.Fatalf("failed to shutdown telemetry: %v", err) diff --git a/types/context.go b/types/context.go index 7247783be320..34f4a85cfd2f 100644 --- a/types/context.go +++ b/types/context.go @@ -441,6 +441,9 @@ func (c Context) WithIncarnationCache(cache map[string]any) Context { return c } +// StartSpan starts an otel span and returns a new context with the span attached. +// Use this instead of calling tracer.Start directly to have the span correctly +// attached to this context type. func (c Context) StartSpan(tracer trace.Tracer, spanName string, opts ...trace.SpanStartOption) (Context, trace.Span) { goCtx, span := tracer.Start(c.baseCtx, spanName, opts...) return c.WithContext(goCtx), span From f685bd45c908b12feb962263554501407ff819f2 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Fri, 31 Oct 2025 14:45:15 -0400 Subject: [PATCH 18/52] WIP on removing go-metrics --- telemetry/wrapper.go | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/telemetry/wrapper.go b/telemetry/wrapper.go index 12d3f43c6875..1d28e8af4d73 100644 --- a/telemetry/wrapper.go +++ b/telemetry/wrapper.go @@ -1,9 +1,12 @@ package telemetry import ( + "sync" "time" "github.com/hashicorp/go-metrics" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/metric" ) var globalLabels []metrics.Label @@ -16,6 +19,17 @@ const ( MetricLabelNameModule = "module" ) +var meter = otel.Meter("cosmos-sdk") +var mtx sync.RWMutex +var counters map[string]metric.Float64Counter +var gauges map[string]metric.Float64Gauge +var histograms map[string]metric.Float64Histogram + +type Label struct { + Name string + Value string +} + // NewLabel creates a new instance of Label with name and value func NewLabel(name, value string) metrics.Label { return metrics.Label{Name: name, Value: value} From 699f5d31779bbf5b3316ca9fd39d133acad1e6d1 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Fri, 31 Oct 2025 15:48:04 -0400 Subject: [PATCH 19/52] setup sim test flag --- simapp/sim_test.go | 6 ++++-- types/simulation/config.go | 1 + x/simulation/client/cli/flags.go | 3 +++ 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/simapp/sim_test.go b/simapp/sim_test.go index 4336d2aaf3b5..9be125236cbf 100644 --- a/simapp/sim_test.go +++ b/simapp/sim_test.go @@ -20,6 +20,7 @@ import ( "github.com/stretchr/testify/require" "cosmossdk.io/log" + "github.com/cosmos/cosmos-sdk/telemetry" "cosmossdk.io/store" @@ -161,9 +162,10 @@ func IsEmptyValidatorSetErr(err error) bool { func TestAppStateDeterminism(t *testing.T) { telemetry.TestingInit(t, context.Background()) - const numTimesToRunPerSeed = 1 + cfg := simcli.NewConfigFromFlags() + numTimesToRunPerSeed := cfg.NumRuns var seeds []int64 - if s := simcli.NewConfigFromFlags().Seed; s != simcli.DefaultSeedValue { + if s := cfg.Seed; s != simcli.DefaultSeedValue { // We will be overriding the random seed and just run a single simulation on the provided seed value for j := 0; j < numTimesToRunPerSeed; j++ { // multiple rounds seeds = append(seeds, s) diff --git a/types/simulation/config.go b/types/simulation/config.go index 1e385fdfa1d6..b903ed3bc1f7 100644 --- a/types/simulation/config.go +++ b/types/simulation/config.go @@ -16,6 +16,7 @@ type Config struct { InitialBlockHeight int // initial block to start the simulation GenesisTime int64 // genesis time to start the simulation NumBlocks int // number of new blocks to simulate from the initial block height + NumRuns int // number of times to run the simulation for simulations that have multiple runs BlockSize int // operations per block ChainID string // chain-id used on the simulation diff --git a/x/simulation/client/cli/flags.go b/x/simulation/client/cli/flags.go index 8479b83f5e1c..c8552fec91bc 100644 --- a/x/simulation/client/cli/flags.go +++ b/x/simulation/client/cli/flags.go @@ -20,6 +20,7 @@ var ( FlagSeedValue int64 FlagInitialBlockHeightValue int FlagNumBlocksValue int + FlagNumRunsValue int FlagBlockSizeValue int FlagLeanValue bool FlagCommitValue bool @@ -51,6 +52,7 @@ func GetSimulatorFlags() { flag.StringVar(&FlagExportStatsPathValue, "ExportStatsPath", "", "custom file path to save the exported simulation statistics JSON") flag.Int64Var(&FlagSeedValue, "Seed", DefaultSeedValue, "simulation random seed") flag.IntVar(&FlagInitialBlockHeightValue, "InitialBlockHeight", 1, "initial block to start the simulation") + flag.IntVar(&FlagNumRunsValue, "NumRuns", 3, "number of runs to run for simulations that do multiple runs at once") flag.IntVar(&FlagNumBlocksValue, "NumBlocks", 500, "number of new blocks to simulate from the initial block height") flag.IntVar(&FlagBlockSizeValue, "BlockSize", 200, "operations per block") flag.BoolVar(&FlagLeanValue, "Lean", false, "lean simulation log output") @@ -81,6 +83,7 @@ func NewConfigFromFlags() simulation.Config { Seed: FlagSeedValue, InitialBlockHeight: FlagInitialBlockHeightValue, GenesisTime: FlagGenesisTimeValue, + NumRuns: FlagNumRunsValue, NumBlocks: FlagNumBlocksValue, BlockSize: FlagBlockSizeValue, Lean: FlagLeanValue, From 5df24604d0e409022e5691b11e742ee7d3ba5cb6 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Fri, 31 Oct 2025 16:32:34 -0400 Subject: [PATCH 20/52] integrate slog logging --- client/v2/go.mod | 1 + client/v2/go.sum | 2 ++ go.mod | 1 + go.sum | 2 ++ simapp/go.mod | 1 + simapp/go.sum | 2 ++ systemtests/go.mod | 1 + systemtests/go.sum | 2 ++ telemetry/config.go | 7 +++++++ tests/go.mod | 1 + tests/go.sum | 2 ++ tests/systemtests/go.mod | 1 + tests/systemtests/go.sum | 2 ++ 13 files changed, 25 insertions(+) diff --git a/client/v2/go.mod b/client/v2/go.mod index 1f1aeb58a265..6e8810501d61 100644 --- a/client/v2/go.mod +++ b/client/v2/go.mod @@ -149,6 +149,7 @@ require ( github.com/zondax/ledger-go v1.0.1 // indirect go.etcd.io/bbolt v1.4.0 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect + go.opentelemetry.io/contrib/bridges/otelslog v0.13.0 // indirect go.opentelemetry.io/contrib/otelconf v0.18.0 // indirect go.opentelemetry.io/otel v1.38.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.14.0 // indirect diff --git a/client/v2/go.sum b/client/v2/go.sum index a26eb6a85ec5..670ac1e03247 100644 --- a/client/v2/go.sum +++ b/client/v2/go.sum @@ -721,6 +721,8 @@ go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= +go.opentelemetry.io/contrib/bridges/otelslog v0.13.0 h1:bwnLpizECbPr1RrQ27waeY2SPIPeccCx/xLuoYADZ9s= +go.opentelemetry.io/contrib/bridges/otelslog v0.13.0/go.mod h1:3nWlOiiqA9UtUnrcNk82mYasNxD8ehOspL0gOfEo6Y4= go.opentelemetry.io/contrib/otelconf v0.18.0 h1:ciF2Gf00BWs0DnexKFZXcxg9kJ8r3SUW1LOzW3CsKA8= go.opentelemetry.io/contrib/otelconf v0.18.0/go.mod h1:FcP7k+JLwBLdOxS6qY6VQ/4b5VBntI6L6o80IMwhAeI= go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= diff --git a/go.mod b/go.mod index 720a8f833b66..8b41a692b3ec 100644 --- a/go.mod +++ b/go.mod @@ -55,6 +55,7 @@ require ( github.com/tendermint/go-amino v0.16.0 github.com/test-go/testify v1.1.4 github.com/tidwall/btree v1.8.1 + go.opentelemetry.io/contrib/bridges/otelslog v0.13.0 go.opentelemetry.io/contrib/otelconf v0.18.0 go.opentelemetry.io/otel v1.38.0 go.opentelemetry.io/otel/log v0.14.0 diff --git a/go.sum b/go.sum index b4025a518e6f..6cf83a395b8b 100644 --- a/go.sum +++ b/go.sum @@ -838,6 +838,8 @@ go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= +go.opentelemetry.io/contrib/bridges/otelslog v0.13.0 h1:bwnLpizECbPr1RrQ27waeY2SPIPeccCx/xLuoYADZ9s= +go.opentelemetry.io/contrib/bridges/otelslog v0.13.0/go.mod h1:3nWlOiiqA9UtUnrcNk82mYasNxD8ehOspL0gOfEo6Y4= go.opentelemetry.io/contrib/detectors/gcp v1.36.0 h1:F7q2tNlCaHY9nMKHR6XH9/qkp8FktLnIcy6jJNyOCQw= go.opentelemetry.io/contrib/detectors/gcp v1.36.0/go.mod h1:IbBN8uAIIx734PTonTPxAxnjc2pQTxWNkwfstZ+6H2k= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0 h1:q4XOmH/0opmeuJtPsbFNivyl7bCt7yRBbeEm2sC/XtQ= diff --git a/simapp/go.mod b/simapp/go.mod index 1100e0357d99..6168b1eafde7 100644 --- a/simapp/go.mod +++ b/simapp/go.mod @@ -201,6 +201,7 @@ require ( github.com/zondax/ledger-go v1.0.1 // indirect go.etcd.io/bbolt v1.4.0 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect + go.opentelemetry.io/contrib/bridges/otelslog v0.13.0 // indirect go.opentelemetry.io/contrib/detectors/gcp v1.36.0 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0 // indirect diff --git a/simapp/go.sum b/simapp/go.sum index d26be9d2bbf0..bca05daab254 100644 --- a/simapp/go.sum +++ b/simapp/go.sum @@ -846,6 +846,8 @@ go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= +go.opentelemetry.io/contrib/bridges/otelslog v0.13.0 h1:bwnLpizECbPr1RrQ27waeY2SPIPeccCx/xLuoYADZ9s= +go.opentelemetry.io/contrib/bridges/otelslog v0.13.0/go.mod h1:3nWlOiiqA9UtUnrcNk82mYasNxD8ehOspL0gOfEo6Y4= go.opentelemetry.io/contrib/detectors/gcp v1.36.0 h1:F7q2tNlCaHY9nMKHR6XH9/qkp8FktLnIcy6jJNyOCQw= go.opentelemetry.io/contrib/detectors/gcp v1.36.0/go.mod h1:IbBN8uAIIx734PTonTPxAxnjc2pQTxWNkwfstZ+6H2k= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0 h1:q4XOmH/0opmeuJtPsbFNivyl7bCt7yRBbeEm2sC/XtQ= diff --git a/systemtests/go.mod b/systemtests/go.mod index 9affc6f367c3..ac8cc478f354 100644 --- a/systemtests/go.mod +++ b/systemtests/go.mod @@ -149,6 +149,7 @@ require ( github.com/zondax/ledger-go v1.0.1 // indirect go.etcd.io/bbolt v1.4.0 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect + go.opentelemetry.io/contrib/bridges/otelslog v0.13.0 // indirect go.opentelemetry.io/contrib/otelconf v0.18.0 // indirect go.opentelemetry.io/otel v1.38.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.14.0 // indirect diff --git a/systemtests/go.sum b/systemtests/go.sum index 7e5dfcf655aa..aa4352f4a16e 100644 --- a/systemtests/go.sum +++ b/systemtests/go.sum @@ -730,6 +730,8 @@ go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= +go.opentelemetry.io/contrib/bridges/otelslog v0.13.0 h1:bwnLpizECbPr1RrQ27waeY2SPIPeccCx/xLuoYADZ9s= +go.opentelemetry.io/contrib/bridges/otelslog v0.13.0/go.mod h1:3nWlOiiqA9UtUnrcNk82mYasNxD8ehOspL0gOfEo6Y4= go.opentelemetry.io/contrib/otelconf v0.18.0 h1:ciF2Gf00BWs0DnexKFZXcxg9kJ8r3SUW1LOzW3CsKA8= go.opentelemetry.io/contrib/otelconf v0.18.0/go.mod h1:FcP7k+JLwBLdOxS6qY6VQ/4b5VBntI6L6o80IMwhAeI= go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= diff --git a/telemetry/config.go b/telemetry/config.go index 81a5a7ca58c3..461fc9d1f275 100644 --- a/telemetry/config.go +++ b/telemetry/config.go @@ -4,8 +4,10 @@ import ( "context" "encoding/json" "fmt" + "log/slog" "os" + "go.opentelemetry.io/contrib/bridges/otelslog" "go.opentelemetry.io/contrib/otelconf/v0.3.0" "go.opentelemetry.io/otel" logglobal "go.opentelemetry.io/otel/log/global" @@ -46,9 +48,14 @@ func init() { panic(fmt.Sprintf("failed to initialize telemetry: %v", err)) } + // setup otel global providers otel.SetTracerProvider(sdk.TracerProvider()) otel.SetMeterProvider(sdk.MeterProvider()) logglobal.SetLoggerProvider(sdk.LoggerProvider()) + // setup slog default provider so that any logs emitted the default slog will be traced + slog.SetDefault(otelslog.NewLogger("", otelslog.WithSource(true))) + // emit an initialized message which verifies basic telemetry is working + slog.Info("Telemetry initialized") } func Shutdown(ctx context.Context) error { diff --git a/tests/go.mod b/tests/go.mod index c7129097442e..6dc60d9ba6d8 100644 --- a/tests/go.mod +++ b/tests/go.mod @@ -201,6 +201,7 @@ require ( github.com/zondax/ledger-go v1.0.1 // indirect go.etcd.io/bbolt v1.4.0 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect + go.opentelemetry.io/contrib/bridges/otelslog v0.13.0 // indirect go.opentelemetry.io/contrib/detectors/gcp v1.36.0 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0 // indirect diff --git a/tests/go.sum b/tests/go.sum index c5aef41227f0..55cb1ce10c9a 100644 --- a/tests/go.sum +++ b/tests/go.sum @@ -845,6 +845,8 @@ go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= +go.opentelemetry.io/contrib/bridges/otelslog v0.13.0 h1:bwnLpizECbPr1RrQ27waeY2SPIPeccCx/xLuoYADZ9s= +go.opentelemetry.io/contrib/bridges/otelslog v0.13.0/go.mod h1:3nWlOiiqA9UtUnrcNk82mYasNxD8ehOspL0gOfEo6Y4= go.opentelemetry.io/contrib/detectors/gcp v1.36.0 h1:F7q2tNlCaHY9nMKHR6XH9/qkp8FktLnIcy6jJNyOCQw= go.opentelemetry.io/contrib/detectors/gcp v1.36.0/go.mod h1:IbBN8uAIIx734PTonTPxAxnjc2pQTxWNkwfstZ+6H2k= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0 h1:q4XOmH/0opmeuJtPsbFNivyl7bCt7yRBbeEm2sC/XtQ= diff --git a/tests/systemtests/go.mod b/tests/systemtests/go.mod index e0bb7f0f279d..fcff5d1ed271 100644 --- a/tests/systemtests/go.mod +++ b/tests/systemtests/go.mod @@ -155,6 +155,7 @@ require ( github.com/zondax/ledger-go v1.0.1 // indirect go.etcd.io/bbolt v1.4.0 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect + go.opentelemetry.io/contrib/bridges/otelslog v0.13.0 // indirect go.opentelemetry.io/contrib/otelconf v0.18.0 // indirect go.opentelemetry.io/otel v1.38.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.14.0 // indirect diff --git a/tests/systemtests/go.sum b/tests/systemtests/go.sum index ea7b7b02107d..e393aa40834a 100644 --- a/tests/systemtests/go.sum +++ b/tests/systemtests/go.sum @@ -728,6 +728,8 @@ go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= +go.opentelemetry.io/contrib/bridges/otelslog v0.13.0 h1:bwnLpizECbPr1RrQ27waeY2SPIPeccCx/xLuoYADZ9s= +go.opentelemetry.io/contrib/bridges/otelslog v0.13.0/go.mod h1:3nWlOiiqA9UtUnrcNk82mYasNxD8ehOspL0gOfEo6Y4= go.opentelemetry.io/contrib/otelconf v0.18.0 h1:ciF2Gf00BWs0DnexKFZXcxg9kJ8r3SUW1LOzW3CsKA8= go.opentelemetry.io/contrib/otelconf v0.18.0/go.mod h1:FcP7k+JLwBLdOxS6qY6VQ/4b5VBntI6L6o80IMwhAeI= go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= From 1c84edb805fb11210df5d3aeaff1f295db03017c Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Fri, 31 Oct 2025 16:40:11 -0400 Subject: [PATCH 21/52] update to use official env var --- telemetry/config.go | 2 +- telemetry/doc.go | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/telemetry/config.go b/telemetry/config.go index 461fc9d1f275..4689ad2fdfce 100644 --- a/telemetry/config.go +++ b/telemetry/config.go @@ -22,7 +22,7 @@ func init() { var opts []otelconf.ConfigurationOption - confFilename := os.Getenv("COSMOS_TELEMETRY") + confFilename := os.Getenv("OTEL_EXPERIMENTAL_CONFIG_FILE") if confFilename != "" { bz, err := os.ReadFile(confFilename) if err != nil { diff --git a/telemetry/doc.go b/telemetry/doc.go index a56752fd3cc8..c3c37264051f 100644 --- a/telemetry/doc.go +++ b/telemetry/doc.go @@ -1,6 +1,10 @@ // Package telemetry initializes OpenTelemetry and provides legacy metrics wrapper functions. -// End users only need to set the COSMOS_TELEMETRY environment variable to the path of -// an OpenTelemetry declarative configuration file: https://opentelemetry.io/docs/languages/sdk-configuration/declarative-configuration/ +// While manual OpenTelemetry initialization is still supported, this package provides a single +// point of initialization such that end users can just use the official +// OpenTelemetry declarative configuration spec: https://opentelemetry.io/docs/languages/sdk-configuration/declarative-configuration/ +// End users only need to set the OTEL_EXPERIMENTAL_CONFIG_FILE environment variable to the path of +// an OpenTelemetry configuration file and that's it. +// All the documentation necessary is provided in the OpenTelemetry documentation. // // Developers need to do two things: // 1. Import this package before declaring any otel Tracer, Meter or Logger instances. From 46e4bcb98dbb451167e3ebd1795a9d2b0ce671f3 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Mon, 3 Nov 2025 13:00:07 -0500 Subject: [PATCH 22/52] add README.md --- telemetry/README.md | 65 +++++++++++++++++++++++++++++++++++++++++++++ telemetry/doc.go | 20 -------------- 2 files changed, 65 insertions(+), 20 deletions(-) create mode 100644 telemetry/README.md diff --git a/telemetry/README.md b/telemetry/README.md new file mode 100644 index 000000000000..6dcf0ac9caa5 --- /dev/null +++ b/telemetry/README.md @@ -0,0 +1,65 @@ +## Quick Start For Local Telemetry + +To quickly setup a local telemetry environment where OpenTelemetry data is sent to a local instance of Grafana LGTM: +1. start the [Grafana LGTM docker image](https://hub.docker.com/r/grafana/otel-lgtm): + ```shell + docker run -p 3000:3000 -p 4317:4317 -p 4318:4318 --rm -ti grafana/otel-lgtm + ``` +2. create a basic OpenTelemetry configuration file which will send data to the local instance of Grafana LGTM: + ```yaml + resource: + attributes: + - name: service.name + value: my_app_name + tracer_provider: + processors: + - simple: # NOTE: you should use batch in production! + exporter: + otlp: + protocol: grpc + endpoint: http://localhost:4317 + meter_provider: + readers: + - periodic: + interval: 100 # 100 milliseconds, use something longer in production! + exporter: + otlp: + protocol: grpc + endpoint: http://localhost:4317 + logger_provider: + processors: + - simple: # NOTE: you should use batch in production! + exporter: + otlp: + protocol: grpc + endpoint: http://localhost:4317 + ``` +3. set the `OTEL_EXPERIMENTAL_CONFIG_FILE` environment variable to the path of the configuration file: +`export OTEL_EXPERIMENTAL_CONFIG_FILE=path/to/config.yaml` +4. start your application or tests +5. view the data in Grafana LGTM at http://localhost:3000/. The Drilldown views are suggested for getting started. + +## OpenTelemetry Initialization + +While manual OpenTelemetry initialization is still supported, this package provides a single +point of initialization such that end users can just use the official +OpenTelemetry declarative configuration spec: https://opentelemetry.io/docs/languages/sdk-configuration/declarative-configuration/ +End users only need to set the `OTEL_EXPERIMENTAL_CONFIG_FILE` environment variable to the path of +an OpenTelemetry configuration file and that's it. +All the documentation necessary is provided in the OpenTelemetry documentation. + +## Developer Usage + +Developers need to do two things to use this package properly: + 1. Import this package before declaring any otel Tracer, Meter or Logger instances. + 2. Make sure Shutdown() is called when the application is shutting down. + Tests can use the TestingInit function at startup to accomplish this. + +If these steps are followed, developers can follow the official golang otel conventions +of declaring package-level tracer and meter instances using otel.Tracer() and otel.Meter(). +NOTE: it is important to thread context.Context properly for spans, metrics and logs to be +correlated correctly. +When using the SDK's context type, spans must be started with Context.StartSpan to +get an SDK context which has the span set correctly. +For logging, go.opentelemetry.io/contrib/bridges/otelslog provides a way to do this with the standard +library slog package. diff --git a/telemetry/doc.go b/telemetry/doc.go index c3c37264051f..606ace81fdd8 100644 --- a/telemetry/doc.go +++ b/telemetry/doc.go @@ -1,22 +1,2 @@ // Package telemetry initializes OpenTelemetry and provides legacy metrics wrapper functions. -// While manual OpenTelemetry initialization is still supported, this package provides a single -// point of initialization such that end users can just use the official -// OpenTelemetry declarative configuration spec: https://opentelemetry.io/docs/languages/sdk-configuration/declarative-configuration/ -// End users only need to set the OTEL_EXPERIMENTAL_CONFIG_FILE environment variable to the path of -// an OpenTelemetry configuration file and that's it. -// All the documentation necessary is provided in the OpenTelemetry documentation. -// -// Developers need to do two things: -// 1. Import this package before declaring any otel Tracer, Meter or Logger instances. -// 2. Make sure Shutdown() is called when the application is shutting down. -// Tests can use the TestingInit function at startup to accomplish this. -// -// If these steps are followed, developers can follow the official golang otel conventions -// of declaring package-level tracer and meter instances using otel.Tracer() and otel.Meter(). -// NOTE: it is important to thread context.Context properly for spans, metrics and logs to be -// correlated correctly. -// When using the SDK's context type, spans must be started with Context.StartSpan to -// get an SDK context which has the span set correctly. -// For logging, go.opentelemetry.io/contrib/bridges/otelslog provides a way to do this with the standard -// library slog package. package telemetry From f0c3955550b030a879d88e08fe647037cb8db9c0 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Mon, 3 Nov 2025 13:01:50 -0500 Subject: [PATCH 23/52] delete spaces --- telemetry/README.md | 62 ++++++++++++++++++++++----------------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/telemetry/README.md b/telemetry/README.md index 6dcf0ac9caa5..9df20c3ec5fc 100644 --- a/telemetry/README.md +++ b/telemetry/README.md @@ -2,38 +2,38 @@ To quickly setup a local telemetry environment where OpenTelemetry data is sent to a local instance of Grafana LGTM: 1. start the [Grafana LGTM docker image](https://hub.docker.com/r/grafana/otel-lgtm): - ```shell - docker run -p 3000:3000 -p 4317:4317 -p 4318:4318 --rm -ti grafana/otel-lgtm - ``` +```shell +docker run -p 3000:3000 -p 4317:4317 -p 4318:4318 --rm -ti grafana/otel-lgtm +``` 2. create a basic OpenTelemetry configuration file which will send data to the local instance of Grafana LGTM: - ```yaml - resource: - attributes: - - name: service.name - value: my_app_name - tracer_provider: - processors: - - simple: # NOTE: you should use batch in production! - exporter: - otlp: - protocol: grpc - endpoint: http://localhost:4317 - meter_provider: - readers: - - periodic: - interval: 100 # 100 milliseconds, use something longer in production! - exporter: - otlp: - protocol: grpc - endpoint: http://localhost:4317 - logger_provider: - processors: - - simple: # NOTE: you should use batch in production! - exporter: - otlp: - protocol: grpc - endpoint: http://localhost:4317 - ``` +```yaml +resource: + attributes: + - name: service.name + value: my_app_name +tracer_provider: + processors: + - simple: # NOTE: you should use batch in production! + exporter: + otlp: + protocol: grpc + endpoint: http://localhost:4317 +meter_provider: + readers: + - periodic: + interval: 100 # 100 milliseconds, use something longer in production! + exporter: + otlp: + protocol: grpc + endpoint: http://localhost:4317 +logger_provider: + processors: + - simple: # NOTE: you should use batch in production! + exporter: + otlp: + protocol: grpc + endpoint: http://localhost:4317 +``` 3. set the `OTEL_EXPERIMENTAL_CONFIG_FILE` environment variable to the path of the configuration file: `export OTEL_EXPERIMENTAL_CONFIG_FILE=path/to/config.yaml` 4. start your application or tests From 7dfb754bf366e1e7aedc4414b081004075686233 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Mon, 3 Nov 2025 17:55:20 -0500 Subject: [PATCH 24/52] setup TestingMain --- simapp/sim_test.go | 9 +++++---- telemetry/testing.go | 23 +++++++++++++++-------- 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/simapp/sim_test.go b/simapp/sim_test.go index 9be125236cbf..4f2bf6ad95f0 100644 --- a/simapp/sim_test.go +++ b/simapp/sim_test.go @@ -3,7 +3,6 @@ package simapp import ( - "context" "encoding/binary" "encoding/json" "flag" @@ -21,13 +20,12 @@ import ( "cosmossdk.io/log" - "github.com/cosmos/cosmos-sdk/telemetry" - "cosmossdk.io/store" storetypes "cosmossdk.io/store/types" "github.com/cosmos/cosmos-sdk/baseapp" servertypes "github.com/cosmos/cosmos-sdk/server/types" + "github.com/cosmos/cosmos-sdk/telemetry" simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims" sims "github.com/cosmos/cosmos-sdk/testutil/simsx" sdk "github.com/cosmos/cosmos-sdk/types" @@ -48,6 +46,10 @@ func init() { flag.BoolVar(&FlagEnableStreamingValue, "EnableStreaming", false, "Enable streaming service") } +func TestMain(m *testing.M) { + telemetry.TestingMain(m, nil) +} + // interBlockCacheOpt returns a BaseApp option function that sets the persistent // inter-block write-through cache. func interBlockCacheOpt() func(*baseapp.BaseApp) { @@ -161,7 +163,6 @@ func IsEmptyValidatorSetErr(err error) bool { } func TestAppStateDeterminism(t *testing.T) { - telemetry.TestingInit(t, context.Background()) cfg := simcli.NewConfigFromFlags() numTimesToRunPerSeed := cfg.NumRuns var seeds []int64 diff --git a/telemetry/testing.go b/telemetry/testing.go index df9ac2085a18..623a7e93e7cf 100644 --- a/telemetry/testing.go +++ b/telemetry/testing.go @@ -2,19 +2,26 @@ package telemetry import ( "context" + "fmt" + "os" "testing" ) -// TestingInit initializes telemetry for testing so that it is automatically -// shutdown after the test completes. +// TestingMain should be used in tests where you want to run telemetry and need clean shutdown +// behavior at the end of the test, for instance to collect benchmark metrics. // If ctx is nil, context.Background() is used. -func TestingInit(t *testing.T, ctx context.Context) { +// Example: +// +// func TestMain(m *testing.M) { +// telemetry.TestingMain(m, nil) +// } +func TestingMain(m *testing.M, ctx context.Context) { + code := m.Run() if ctx == nil { ctx = context.Background() } - t.Cleanup(func() { - if err := Shutdown(ctx); err != nil { - t.Fatalf("failed to shutdown telemetry: %v", err) - } - }) + if err := Shutdown(ctx); err != nil { + fmt.Printf("failed to shutdown telemetry after test completion: %v\n", err) + } + os.Exit(code) } From 1ce344b3aa223f6484b4f528bebf27720a952a5e Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Mon, 3 Nov 2025 17:55:57 -0500 Subject: [PATCH 25/52] update suggested config in README.md --- telemetry/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/telemetry/README.md b/telemetry/README.md index 9df20c3ec5fc..bbaabbe34c01 100644 --- a/telemetry/README.md +++ b/telemetry/README.md @@ -13,7 +13,7 @@ resource: value: my_app_name tracer_provider: processors: - - simple: # NOTE: you should use batch in production! + - batch: # NOTE: you should use batch in production! exporter: otlp: protocol: grpc @@ -21,14 +21,14 @@ tracer_provider: meter_provider: readers: - periodic: - interval: 100 # 100 milliseconds, use something longer in production! + interval: 1000 # 1 second, maybe use something longer in production exporter: otlp: protocol: grpc endpoint: http://localhost:4317 logger_provider: processors: - - simple: # NOTE: you should use batch in production! + - batch: exporter: otlp: protocol: grpc From edbae924e5beb19d3192502cc0cd9f4fd57e6362 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Mon, 3 Nov 2025 18:31:52 -0500 Subject: [PATCH 26/52] add otel custom config options --- go.mod | 24 +++++-- go.sum | 24 +++++++ simapp/go.mod | 10 +++ simapp/go.sum | 24 +++++++ systemtests/go.mod | 10 +++ systemtests/go.sum | 24 +++++++ telemetry/config.go | 141 +++++++++++++++++++++++++++++++++++++-- tests/go.mod | 10 +++ tests/go.sum | 24 +++++++ tests/systemtests/go.mod | 10 +++ tests/systemtests/go.sum | 24 +++++++ 11 files changed, 313 insertions(+), 12 deletions(-) diff --git a/go.mod b/go.mod index 8b41a692b3ec..ec583f892f44 100644 --- a/go.mod +++ b/go.mod @@ -56,12 +56,21 @@ require ( github.com/test-go/testify v1.1.4 github.com/tidwall/btree v1.8.1 go.opentelemetry.io/contrib/bridges/otelslog v0.13.0 + go.opentelemetry.io/contrib/instrumentation/host v0.63.0 + go.opentelemetry.io/contrib/instrumentation/runtime v0.63.0 go.opentelemetry.io/contrib/otelconf v0.18.0 go.opentelemetry.io/otel v1.38.0 + go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.14.0 + go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.38.0 + go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.38.0 go.opentelemetry.io/otel/log v0.14.0 go.opentelemetry.io/otel/metric v1.38.0 + go.opentelemetry.io/otel/sdk v1.38.0 + go.opentelemetry.io/otel/sdk/log v0.14.0 + go.opentelemetry.io/otel/sdk/metric v1.38.0 go.opentelemetry.io/otel/trace v1.38.0 go.uber.org/mock v0.6.0 + go.yaml.in/yaml/v3 v3.0.4 golang.org/x/crypto v0.43.0 golang.org/x/sync v0.17.0 google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5 @@ -132,6 +141,7 @@ require ( github.com/dgraph-io/ristretto/v2 v2.1.0 // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/dvsekhvalnov/jose2go v1.6.0 // indirect + github.com/ebitengine/purego v0.8.4 // indirect github.com/emicklei/dot v1.8.0 // indirect github.com/envoyproxy/go-control-plane/envoy v1.32.4 // indirect github.com/envoyproxy/protoc-gen-validate v1.2.1 // indirect @@ -145,6 +155,7 @@ require ( github.com/go-logfmt/logfmt v0.6.1 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect + github.com/go-ole/go-ole v1.3.0 // indirect github.com/go-viper/mapstructure/v2 v2.4.0 // indirect github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect github.com/gogo/googleapis v1.4.1 // indirect @@ -177,6 +188,7 @@ require ( github.com/kr/text v0.2.0 // indirect github.com/lib/pq v1.10.9 // indirect github.com/linxGnu/grocksdb v1.10.3 // indirect + github.com/lufia/plan9stats v0.0.0-20250827001030-24949be3fa54 // indirect github.com/mattn/go-colorable v0.1.14 // indirect github.com/minio/highwayhash v1.0.3 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect @@ -190,6 +202,7 @@ require ( github.com/pkg/errors v0.9.1 // indirect github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect github.com/prometheus/client_golang v1.23.2 // indirect github.com/prometheus/client_model v0.6.2 // indirect github.com/prometheus/common v0.67.1 // indirect @@ -200,14 +213,18 @@ require ( github.com/rs/cors v1.11.1 // indirect github.com/sagikazarmark/locafero v0.11.0 // indirect github.com/sasha-s/go-deadlock v0.3.6 // indirect + github.com/shirou/gopsutil/v4 v4.25.7 // indirect github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect github.com/spf13/afero v1.15.0 // indirect github.com/spiffe/go-spiffe/v2 v2.5.0 // indirect github.com/subosito/gotenv v1.6.0 // indirect github.com/supranational/blst v0.3.16 // indirect github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d // indirect + github.com/tklauser/go-sysconf v0.3.15 // indirect + github.com/tklauser/numcpus v0.10.0 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ulikunitz/xz v0.5.15 // indirect + github.com/yusufpapurcu/wmi v1.2.4 // indirect github.com/zeebo/errs v1.4.0 // indirect github.com/zondax/golem v0.27.0 // indirect github.com/zondax/hid v0.9.2 // indirect @@ -225,17 +242,10 @@ require ( go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0 // indirect go.opentelemetry.io/otel/exporters/prometheus v0.60.0 // indirect - go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.14.0 // indirect - go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.38.0 // indirect - go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.38.0 // indirect - go.opentelemetry.io/otel/sdk v1.38.0 // indirect - go.opentelemetry.io/otel/sdk/log v0.14.0 // indirect - go.opentelemetry.io/otel/sdk/metric v1.38.0 // indirect go.opentelemetry.io/proto/otlp v1.7.1 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect go.yaml.in/yaml/v2 v2.4.3 // indirect - go.yaml.in/yaml/v3 v3.0.4 // indirect golang.org/x/arch v0.22.0 // indirect golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6 // indirect golang.org/x/net v0.46.0 // indirect diff --git a/go.sum b/go.sum index 6cf83a395b8b..92042504ea99 100644 --- a/go.sum +++ b/go.sum @@ -275,6 +275,8 @@ github.com/dvsekhvalnov/jose2go v1.6.0/go.mod h1:QsHjhyTlD/lAVqn/NSbVZmSCGeDehTB github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= +github.com/ebitengine/purego v0.8.4 h1:CF7LEKg5FFOsASUj0+QwaXf8Ht6TlFxg09+S9wz0omw= +github.com/ebitengine/purego v0.8.4/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= github.com/emicklei/dot v1.8.0 h1:HnD60yAKFAevNeT+TPYr9pb8VB9bqdeSo0nzwIW6IOI= github.com/emicklei/dot v1.8.0/go.mod h1:DeV7GvQtIw4h2u73RKBkkFdvVAz0D9fzeJrgPW6gy/s= @@ -339,6 +341,9 @@ github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= +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/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= @@ -564,6 +569,8 @@ github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-b github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= github.com/linxGnu/grocksdb v1.10.3 h1:0laII9AQ6kFxo5SjhdTfSh9EgF20piD6TMHK6YuDm+4= github.com/linxGnu/grocksdb v1.10.3/go.mod h1:OLQKZwiKwaJiAVCsOzWKvwiLwfZ5Vz8Md5TYR7t7pM8= +github.com/lufia/plan9stats v0.0.0-20250827001030-24949be3fa54 h1:mFWunSatvkQQDhpdyuFAYwyAan3hzCuma+Pz8sqvOfg= +github.com/lufia/plan9stats v0.0.0-20250827001030-24949be3fa54/go.mod h1:autxFIvghDt3jPTLoqZ9OZ7s9qTGNAWmYCjVFWPX/zg= github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= github.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE= github.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= @@ -683,6 +690,8 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU= +github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= @@ -744,6 +753,8 @@ github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0 github.com/sasha-s/go-deadlock v0.3.6 h1:TR7sfOnZ7x00tWPfD397Peodt57KzMDo+9Ae9rMiUmw= github.com/sasha-s/go-deadlock v0.3.6/go.mod h1:CUqNyyvMxTyjFqDT7MRg9mb4Dv/btmGTqSR+rky/UXo= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/shirou/gopsutil/v4 v4.25.7 h1:bNb2JuqKuAu3tRlPv5piSmBZyMfecwQ+t/ILq+1JqVM= +github.com/shirou/gopsutil/v4 v4.25.7/go.mod h1:XV/egmwJtd3ZQjBpJVY5kndsiOO4IRqy9TQnmm6VP7U= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= @@ -808,6 +819,10 @@ github.com/tendermint/go-amino v0.16.0 h1:GyhmgQKvqF82e2oZeuMSp9JTN0N09emoSZlb2l github.com/tendermint/go-amino v0.16.0/go.mod h1:TQU0M1i/ImAo+tYpZi73AU3V/dKeCoMC9Sphe2ZwGME= github.com/test-go/testify v1.1.4 h1:Tf9lntrKUMHiXQ07qBScBTSA0dhYQlu83hswqelv1iE= github.com/test-go/testify v1.1.4/go.mod h1:rH7cfJo/47vWGdi4GPj16x3/t1xGOj2YxzmNQzk2ghU= +github.com/tklauser/go-sysconf v0.3.15 h1:VE89k0criAymJ/Os65CSn1IXaol+1wrsFHEB8Ol49K4= +github.com/tklauser/go-sysconf v0.3.15/go.mod h1:Dmjwr6tYFIseJw7a3dRLJfsHAMXZ3nEnL/aZY+0IuI4= +github.com/tklauser/numcpus v0.10.0 h1:18njr6LDBk1zuna922MgdjQuJFjrdppsZG60sHGfjso= +github.com/tklauser/numcpus v0.10.0/go.mod h1:BiTKazU708GQTYF4mB+cmlpT2Is1gLk7XVuEeem8LsQ= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= @@ -821,6 +836,8 @@ github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= +github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= github.com/zeebo/errs v1.4.0 h1:XNdoD/RRMKP7HD0UhJnIzUy74ISdGGxURlYG8HSWSfM= github.com/zeebo/errs v1.4.0/go.mod h1:sgbWHsvVuTPHcqJJGQ1WhI5KbWlHYz+2+2C/LSEtCw4= github.com/zondax/golem v0.27.0 h1:IbBjGIXF3SoGOZHsILJvIM/F/ylwJzMcHAcggiqniPw= @@ -844,8 +861,12 @@ go.opentelemetry.io/contrib/detectors/gcp v1.36.0 h1:F7q2tNlCaHY9nMKHR6XH9/qkp8F go.opentelemetry.io/contrib/detectors/gcp v1.36.0/go.mod h1:IbBN8uAIIx734PTonTPxAxnjc2pQTxWNkwfstZ+6H2k= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0 h1:q4XOmH/0opmeuJtPsbFNivyl7bCt7yRBbeEm2sC/XtQ= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0/go.mod h1:snMWehoOh2wsEwnvvwtDyFCxVeDAODenXHtn5vzrKjo= +go.opentelemetry.io/contrib/instrumentation/host v0.63.0 h1:zsaUrWypCf0NtYSUby+/BS6QqhXVNxMQD5w4dLczKCQ= +go.opentelemetry.io/contrib/instrumentation/host v0.63.0/go.mod h1:Ru+kuFO+ToZqBKwI59rCStOhW6LWrbGisYrFaX61bJk= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0 h1:Hf9xI/XLML9ElpiHVDNwvqI0hIFlzV8dgIr35kV1kRU= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0/go.mod h1:NfchwuyNoMcZ5MLHwPrODwUF1HWCXWrL31s8gSAdIKY= +go.opentelemetry.io/contrib/instrumentation/runtime v0.63.0 h1:PeBoRj6af6xMI7qCupwFvTbbnd49V7n5YpG6pg8iDYQ= +go.opentelemetry.io/contrib/instrumentation/runtime v0.63.0/go.mod h1:ingqBCtMCe8I4vpz/UVzCW6sxoqgZB37nao91mLQ3Bw= go.opentelemetry.io/contrib/otelconf v0.18.0 h1:ciF2Gf00BWs0DnexKFZXcxg9kJ8r3SUW1LOzW3CsKA8= go.opentelemetry.io/contrib/otelconf v0.18.0/go.mod h1:FcP7k+JLwBLdOxS6qY6VQ/4b5VBntI6L6o80IMwhAeI= go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= @@ -1016,6 +1037,7 @@ golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1033,6 +1055,7 @@ golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1052,6 +1075,7 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= diff --git a/simapp/go.mod b/simapp/go.mod index 6168b1eafde7..e87d8b3b03c6 100644 --- a/simapp/go.mod +++ b/simapp/go.mod @@ -101,6 +101,7 @@ require ( github.com/dgraph-io/ristretto/v2 v2.1.0 // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/dvsekhvalnov/jose2go v1.8.0 // indirect + github.com/ebitengine/purego v0.8.4 // indirect github.com/emicklei/dot v1.8.0 // indirect github.com/envoyproxy/go-control-plane/envoy v1.32.4 // indirect github.com/envoyproxy/protoc-gen-validate v1.2.1 // indirect @@ -114,6 +115,7 @@ require ( github.com/go-logfmt/logfmt v0.6.1 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect + github.com/go-ole/go-ole v1.3.0 // indirect github.com/go-viper/mapstructure/v2 v2.4.0 // indirect github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect github.com/gogo/googleapis v1.4.1 // indirect @@ -159,6 +161,7 @@ require ( github.com/kr/text v0.2.0 // indirect github.com/lib/pq v1.10.9 // indirect github.com/linxGnu/grocksdb v1.10.3 // indirect + github.com/lufia/plan9stats v0.0.0-20250827001030-24949be3fa54 // indirect github.com/manifoldco/promptui v0.9.0 // indirect github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect @@ -174,6 +177,7 @@ require ( github.com/pkg/errors v0.9.1 // indirect github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect github.com/prometheus/client_golang v1.23.2 // indirect github.com/prometheus/client_model v0.6.2 // indirect github.com/prometheus/common v0.67.1 // indirect @@ -185,6 +189,7 @@ require ( github.com/rs/zerolog v1.34.0 // indirect github.com/sagikazarmark/locafero v0.11.0 // indirect github.com/sasha-s/go-deadlock v0.3.6 // indirect + github.com/shirou/gopsutil/v4 v4.25.7 // indirect github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect github.com/spf13/afero v1.15.0 // indirect github.com/spiffe/go-spiffe/v2 v2.5.0 // indirect @@ -193,8 +198,11 @@ require ( github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d // indirect github.com/tendermint/go-amino v0.16.0 // indirect github.com/tidwall/btree v1.8.1 // indirect + github.com/tklauser/go-sysconf v0.3.15 // indirect + github.com/tklauser/numcpus v0.10.0 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ulikunitz/xz v0.5.15 // indirect + github.com/yusufpapurcu/wmi v1.2.4 // indirect github.com/zeebo/errs v1.4.0 // indirect github.com/zondax/golem v0.27.0 // indirect github.com/zondax/hid v0.9.2 // indirect @@ -204,7 +212,9 @@ require ( go.opentelemetry.io/contrib/bridges/otelslog v0.13.0 // indirect go.opentelemetry.io/contrib/detectors/gcp v1.36.0 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0 // indirect + go.opentelemetry.io/contrib/instrumentation/host v0.63.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0 // indirect + go.opentelemetry.io/contrib/instrumentation/runtime v0.63.0 // indirect go.opentelemetry.io/contrib/otelconf v0.18.0 // indirect go.opentelemetry.io/otel v1.38.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.14.0 // indirect diff --git a/simapp/go.sum b/simapp/go.sum index bca05daab254..6521c07eb831 100644 --- a/simapp/go.sum +++ b/simapp/go.sum @@ -286,6 +286,8 @@ github.com/dvsekhvalnov/jose2go v1.8.0/go.mod h1:QsHjhyTlD/lAVqn/NSbVZmSCGeDehTB github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= +github.com/ebitengine/purego v0.8.4 h1:CF7LEKg5FFOsASUj0+QwaXf8Ht6TlFxg09+S9wz0omw= +github.com/ebitengine/purego v0.8.4/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= github.com/emicklei/dot v1.8.0 h1:HnD60yAKFAevNeT+TPYr9pb8VB9bqdeSo0nzwIW6IOI= github.com/emicklei/dot v1.8.0/go.mod h1:DeV7GvQtIw4h2u73RKBkkFdvVAz0D9fzeJrgPW6gy/s= @@ -350,6 +352,9 @@ github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= +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/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= @@ -574,6 +579,8 @@ github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-b github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= github.com/linxGnu/grocksdb v1.10.3 h1:0laII9AQ6kFxo5SjhdTfSh9EgF20piD6TMHK6YuDm+4= github.com/linxGnu/grocksdb v1.10.3/go.mod h1:OLQKZwiKwaJiAVCsOzWKvwiLwfZ5Vz8Md5TYR7t7pM8= +github.com/lufia/plan9stats v0.0.0-20250827001030-24949be3fa54 h1:mFWunSatvkQQDhpdyuFAYwyAan3hzCuma+Pz8sqvOfg= +github.com/lufia/plan9stats v0.0.0-20250827001030-24949be3fa54/go.mod h1:autxFIvghDt3jPTLoqZ9OZ7s9qTGNAWmYCjVFWPX/zg= github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= github.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE= github.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= @@ -693,6 +700,8 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU= +github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= @@ -754,6 +763,8 @@ github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0 github.com/sasha-s/go-deadlock v0.3.6 h1:TR7sfOnZ7x00tWPfD397Peodt57KzMDo+9Ae9rMiUmw= github.com/sasha-s/go-deadlock v0.3.6/go.mod h1:CUqNyyvMxTyjFqDT7MRg9mb4Dv/btmGTqSR+rky/UXo= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/shirou/gopsutil/v4 v4.25.7 h1:bNb2JuqKuAu3tRlPv5piSmBZyMfecwQ+t/ILq+1JqVM= +github.com/shirou/gopsutil/v4 v4.25.7/go.mod h1:XV/egmwJtd3ZQjBpJVY5kndsiOO4IRqy9TQnmm6VP7U= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= @@ -816,6 +827,10 @@ github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70 github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= github.com/tendermint/go-amino v0.16.0 h1:GyhmgQKvqF82e2oZeuMSp9JTN0N09emoSZlb2lyGa2E= github.com/tendermint/go-amino v0.16.0/go.mod h1:TQU0M1i/ImAo+tYpZi73AU3V/dKeCoMC9Sphe2ZwGME= +github.com/tklauser/go-sysconf v0.3.15 h1:VE89k0criAymJ/Os65CSn1IXaol+1wrsFHEB8Ol49K4= +github.com/tklauser/go-sysconf v0.3.15/go.mod h1:Dmjwr6tYFIseJw7a3dRLJfsHAMXZ3nEnL/aZY+0IuI4= +github.com/tklauser/numcpus v0.10.0 h1:18njr6LDBk1zuna922MgdjQuJFjrdppsZG60sHGfjso= +github.com/tklauser/numcpus v0.10.0/go.mod h1:BiTKazU708GQTYF4mB+cmlpT2Is1gLk7XVuEeem8LsQ= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= @@ -829,6 +844,8 @@ github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= +github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= github.com/zeebo/errs v1.4.0 h1:XNdoD/RRMKP7HD0UhJnIzUy74ISdGGxURlYG8HSWSfM= github.com/zeebo/errs v1.4.0/go.mod h1:sgbWHsvVuTPHcqJJGQ1WhI5KbWlHYz+2+2C/LSEtCw4= github.com/zondax/golem v0.27.0 h1:IbBjGIXF3SoGOZHsILJvIM/F/ylwJzMcHAcggiqniPw= @@ -852,8 +869,12 @@ go.opentelemetry.io/contrib/detectors/gcp v1.36.0 h1:F7q2tNlCaHY9nMKHR6XH9/qkp8F go.opentelemetry.io/contrib/detectors/gcp v1.36.0/go.mod h1:IbBN8uAIIx734PTonTPxAxnjc2pQTxWNkwfstZ+6H2k= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0 h1:q4XOmH/0opmeuJtPsbFNivyl7bCt7yRBbeEm2sC/XtQ= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0/go.mod h1:snMWehoOh2wsEwnvvwtDyFCxVeDAODenXHtn5vzrKjo= +go.opentelemetry.io/contrib/instrumentation/host v0.63.0 h1:zsaUrWypCf0NtYSUby+/BS6QqhXVNxMQD5w4dLczKCQ= +go.opentelemetry.io/contrib/instrumentation/host v0.63.0/go.mod h1:Ru+kuFO+ToZqBKwI59rCStOhW6LWrbGisYrFaX61bJk= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0 h1:Hf9xI/XLML9ElpiHVDNwvqI0hIFlzV8dgIr35kV1kRU= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0/go.mod h1:NfchwuyNoMcZ5MLHwPrODwUF1HWCXWrL31s8gSAdIKY= +go.opentelemetry.io/contrib/instrumentation/runtime v0.63.0 h1:PeBoRj6af6xMI7qCupwFvTbbnd49V7n5YpG6pg8iDYQ= +go.opentelemetry.io/contrib/instrumentation/runtime v0.63.0/go.mod h1:ingqBCtMCe8I4vpz/UVzCW6sxoqgZB37nao91mLQ3Bw= go.opentelemetry.io/contrib/otelconf v0.18.0 h1:ciF2Gf00BWs0DnexKFZXcxg9kJ8r3SUW1LOzW3CsKA8= go.opentelemetry.io/contrib/otelconf v0.18.0/go.mod h1:FcP7k+JLwBLdOxS6qY6VQ/4b5VBntI6L6o80IMwhAeI= go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= @@ -1024,6 +1045,7 @@ golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1041,6 +1063,7 @@ golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1060,6 +1083,7 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= diff --git a/systemtests/go.mod b/systemtests/go.mod index ac8cc478f354..7230935f0337 100644 --- a/systemtests/go.mod +++ b/systemtests/go.mod @@ -60,6 +60,7 @@ require ( github.com/dgraph-io/ristretto/v2 v2.1.0 // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/dvsekhvalnov/jose2go v1.6.0 // indirect + github.com/ebitengine/purego v0.8.4 // indirect github.com/emicklei/dot v1.8.0 // indirect github.com/fatih/color v1.18.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect @@ -70,6 +71,7 @@ require ( github.com/go-logfmt/logfmt v0.6.1 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect + github.com/go-ole/go-ole v1.3.0 // indirect github.com/go-viper/mapstructure/v2 v2.4.0 // indirect github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect github.com/gogo/googleapis v1.4.1 // indirect @@ -108,6 +110,7 @@ require ( github.com/kr/text v0.2.0 // indirect github.com/lib/pq v1.10.9 // indirect github.com/linxGnu/grocksdb v1.10.3 // indirect + github.com/lufia/plan9stats v0.0.0-20250827001030-24949be3fa54 // indirect github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/minio/highwayhash v1.0.3 // indirect @@ -119,6 +122,7 @@ require ( github.com/petermattis/goid v0.0.0-20250813065127-a731cc31b4fe // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect github.com/prometheus/client_golang v1.23.2 // indirect github.com/prometheus/client_model v0.6.2 // indirect github.com/prometheus/common v0.67.1 // indirect @@ -130,6 +134,7 @@ require ( github.com/rs/zerolog v1.34.0 // indirect github.com/sagikazarmark/locafero v0.11.0 // indirect github.com/sasha-s/go-deadlock v0.3.6 // indirect + github.com/shirou/gopsutil/v4 v4.25.7 // indirect github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect github.com/spf13/afero v1.15.0 // indirect github.com/spf13/cast v1.10.0 // indirect @@ -143,13 +148,18 @@ require ( github.com/tidwall/btree v1.8.1 // indirect github.com/tidwall/match v1.1.1 // indirect github.com/tidwall/pretty v1.2.0 // indirect + github.com/tklauser/go-sysconf v0.3.15 // indirect + github.com/tklauser/numcpus v0.10.0 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect + github.com/yusufpapurcu/wmi v1.2.4 // indirect github.com/zondax/golem v0.27.0 // indirect github.com/zondax/hid v0.9.2 // indirect github.com/zondax/ledger-go v1.0.1 // indirect go.etcd.io/bbolt v1.4.0 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect go.opentelemetry.io/contrib/bridges/otelslog v0.13.0 // indirect + go.opentelemetry.io/contrib/instrumentation/host v0.63.0 // indirect + go.opentelemetry.io/contrib/instrumentation/runtime v0.63.0 // indirect go.opentelemetry.io/contrib/otelconf v0.18.0 // indirect go.opentelemetry.io/otel v1.38.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.14.0 // indirect diff --git a/systemtests/go.sum b/systemtests/go.sum index aa4352f4a16e..a4e3d7c18a49 100644 --- a/systemtests/go.sum +++ b/systemtests/go.sum @@ -200,6 +200,8 @@ github.com/dvsekhvalnov/jose2go v1.6.0/go.mod h1:QsHjhyTlD/lAVqn/NSbVZmSCGeDehTB github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= +github.com/ebitengine/purego v0.8.4 h1:CF7LEKg5FFOsASUj0+QwaXf8Ht6TlFxg09+S9wz0omw= +github.com/ebitengine/purego v0.8.4/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= github.com/emicklei/dot v1.8.0 h1:HnD60yAKFAevNeT+TPYr9pb8VB9bqdeSo0nzwIW6IOI= github.com/emicklei/dot v1.8.0/go.mod h1:DeV7GvQtIw4h2u73RKBkkFdvVAz0D9fzeJrgPW6gy/s= @@ -254,6 +256,9 @@ github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= +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/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= @@ -461,6 +466,8 @@ github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-b github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= github.com/linxGnu/grocksdb v1.10.3 h1:0laII9AQ6kFxo5SjhdTfSh9EgF20piD6TMHK6YuDm+4= github.com/linxGnu/grocksdb v1.10.3/go.mod h1:OLQKZwiKwaJiAVCsOzWKvwiLwfZ5Vz8Md5TYR7t7pM8= +github.com/lufia/plan9stats v0.0.0-20250827001030-24949be3fa54 h1:mFWunSatvkQQDhpdyuFAYwyAan3hzCuma+Pz8sqvOfg= +github.com/lufia/plan9stats v0.0.0-20250827001030-24949be3fa54/go.mod h1:autxFIvghDt3jPTLoqZ9OZ7s9qTGNAWmYCjVFWPX/zg= github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= github.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE= github.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= @@ -577,6 +584,8 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU= +github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= @@ -638,6 +647,8 @@ github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0 github.com/sasha-s/go-deadlock v0.3.6 h1:TR7sfOnZ7x00tWPfD397Peodt57KzMDo+9Ae9rMiUmw= github.com/sasha-s/go-deadlock v0.3.6/go.mod h1:CUqNyyvMxTyjFqDT7MRg9mb4Dv/btmGTqSR+rky/UXo= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/shirou/gopsutil/v4 v4.25.7 h1:bNb2JuqKuAu3tRlPv5piSmBZyMfecwQ+t/ILq+1JqVM= +github.com/shirou/gopsutil/v4 v4.25.7/go.mod h1:XV/egmwJtd3ZQjBpJVY5kndsiOO4IRqy9TQnmm6VP7U= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= @@ -704,6 +715,10 @@ github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= +github.com/tklauser/go-sysconf v0.3.15 h1:VE89k0criAymJ/Os65CSn1IXaol+1wrsFHEB8Ol49K4= +github.com/tklauser/go-sysconf v0.3.15/go.mod h1:Dmjwr6tYFIseJw7a3dRLJfsHAMXZ3nEnL/aZY+0IuI4= +github.com/tklauser/numcpus v0.10.0 h1:18njr6LDBk1zuna922MgdjQuJFjrdppsZG60sHGfjso= +github.com/tklauser/numcpus v0.10.0/go.mod h1:BiTKazU708GQTYF4mB+cmlpT2Is1gLk7XVuEeem8LsQ= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= @@ -715,6 +730,8 @@ github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtX github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= +github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= github.com/zondax/golem v0.27.0 h1:IbBjGIXF3SoGOZHsILJvIM/F/ylwJzMcHAcggiqniPw= github.com/zondax/golem v0.27.0/go.mod h1:AmorCgJPt00L8xN1VrMBe13PSifoZksnQ1Ge906bu4A= github.com/zondax/hid v0.9.2 h1:WCJFnEDMiqGF64nlZz28E9qLVZ0KSJ7xpc5DLEyma2U= @@ -732,6 +749,10 @@ go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJyS go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= go.opentelemetry.io/contrib/bridges/otelslog v0.13.0 h1:bwnLpizECbPr1RrQ27waeY2SPIPeccCx/xLuoYADZ9s= go.opentelemetry.io/contrib/bridges/otelslog v0.13.0/go.mod h1:3nWlOiiqA9UtUnrcNk82mYasNxD8ehOspL0gOfEo6Y4= +go.opentelemetry.io/contrib/instrumentation/host v0.63.0 h1:zsaUrWypCf0NtYSUby+/BS6QqhXVNxMQD5w4dLczKCQ= +go.opentelemetry.io/contrib/instrumentation/host v0.63.0/go.mod h1:Ru+kuFO+ToZqBKwI59rCStOhW6LWrbGisYrFaX61bJk= +go.opentelemetry.io/contrib/instrumentation/runtime v0.63.0 h1:PeBoRj6af6xMI7qCupwFvTbbnd49V7n5YpG6pg8iDYQ= +go.opentelemetry.io/contrib/instrumentation/runtime v0.63.0/go.mod h1:ingqBCtMCe8I4vpz/UVzCW6sxoqgZB37nao91mLQ3Bw= go.opentelemetry.io/contrib/otelconf v0.18.0 h1:ciF2Gf00BWs0DnexKFZXcxg9kJ8r3SUW1LOzW3CsKA8= go.opentelemetry.io/contrib/otelconf v0.18.0/go.mod h1:FcP7k+JLwBLdOxS6qY6VQ/4b5VBntI6L6o80IMwhAeI= go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= @@ -887,6 +908,7 @@ golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -903,6 +925,7 @@ golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -921,6 +944,7 @@ golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= diff --git a/telemetry/config.go b/telemetry/config.go index 4689ad2fdfce..0bd329fb9828 100644 --- a/telemetry/config.go +++ b/telemetry/config.go @@ -8,16 +8,33 @@ import ( "os" "go.opentelemetry.io/contrib/bridges/otelslog" + "go.opentelemetry.io/contrib/instrumentation/host" + "go.opentelemetry.io/contrib/instrumentation/runtime" "go.opentelemetry.io/contrib/otelconf/v0.3.0" "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/exporters/stdout/stdoutlog" + "go.opentelemetry.io/otel/exporters/stdout/stdoutmetric" + "go.opentelemetry.io/otel/exporters/stdout/stdouttrace" logglobal "go.opentelemetry.io/otel/log/global" + logsdk "go.opentelemetry.io/otel/sdk/log" + metricsdk "go.opentelemetry.io/otel/sdk/metric" + tracesdk "go.opentelemetry.io/otel/sdk/trace" + "go.yaml.in/yaml/v3" ) var sdk otelconf.SDK +var shutdownFuncs []func(context.Context) error var isTelemetryEnabled = true func init() { + err := doInit() + if err != nil { + panic(err) + } +} + +func doInit() error { var err error var opts []otelconf.ConfigurationOption @@ -26,26 +43,118 @@ func init() { if confFilename != "" { bz, err := os.ReadFile(confFilename) if err != nil { - panic(fmt.Sprintf("failed to read telemetry config file: %v", err)) + return fmt.Errorf("failed to read telemetry config file: %w", err) } cfg, err := otelconf.ParseYAML(bz) if err != nil { - panic(fmt.Sprintf("failed to parse telemetry config file: %v", err)) + return fmt.Errorf("failed to parse telemetry config file: %w", err) } cfgJson, err := json.Marshal(cfg) if err != nil { - panic(fmt.Sprintf("failed to marshal telemetry config file: %v", err)) + return fmt.Errorf("failed to marshal telemetry config file: %w", err) } fmt.Printf("\nInitializing telemetry with config:\n%s\n\n", cfgJson) opts = append(opts, otelconf.WithOpenTelemetryConfiguration(*cfg)) + + // parse cosmos extra config + var extraCfg extraConfig + err = yaml.Unmarshal(bz, &extraCfg) + if err == nil { + if extraCfg.CosmosExtra != nil { + extra := *extraCfg.CosmosExtra + if extra.TraceFile != "" { + fmt.Printf("Initializing trace file: %s\n", extra.TraceFile) + traceFile, err := os.OpenFile(extra.TraceFile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644) + if err != nil { + return fmt.Errorf("failed to open trace file: %w", err) + } + shutdownFuncs = append(shutdownFuncs, func(ctx context.Context) error { + if err := traceFile.Close(); err != nil { + return fmt.Errorf("failed to close trace file: %w", err) + } + return nil + }) + exporter, err := stdouttrace.New( + stdouttrace.WithWriter(traceFile), + stdouttrace.WithPrettyPrint(), + ) + if err != nil { + return fmt.Errorf("failed to create stdout trace exporter: %w", err) + } + opts = append(opts, otelconf.WithTracerProviderOptions( + tracesdk.WithBatcher(exporter), + )) + } + if extra.MetricsFile != "" { + fmt.Printf("Initializing metrics file: %s\n", extra.MetricsFile) + metricsFile, err := os.OpenFile(extra.MetricsFile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644) + if err != nil { + return fmt.Errorf("failed to open metrics file: %w", err) + } + shutdownFuncs = append(shutdownFuncs, func(ctx context.Context) error { + if err := metricsFile.Close(); err != nil { + return fmt.Errorf("failed to close metrics file: %w", err) + } + return nil + }) + exporter, err := stdoutmetric.New( + stdoutmetric.WithWriter(metricsFile), + stdoutmetric.WithPrettyPrint(), + ) + if err != nil { + return fmt.Errorf("failed to create stdout metric exporter: %w", err) + } + opts = append(opts, otelconf.WithMeterProviderOptions( + metricsdk.WithReader(metricsdk.NewPeriodicReader(exporter)), + )) + } + if extra.LogsFile != "" { + fmt.Printf("Initializing logs file: %s\n", extra.LogsFile) + logsFile, err := os.OpenFile(extra.LogsFile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644) + if err != nil { + return fmt.Errorf("failed to open logs file: %w", err) + } + shutdownFuncs = append(shutdownFuncs, func(ctx context.Context) error { + if err := logsFile.Close(); err != nil { + return fmt.Errorf("failed to close logs file: %w", err) + } + return nil + }) + exporter, err := stdoutlog.New( + stdoutlog.WithWriter(logsFile), + stdoutlog.WithPrettyPrint(), + ) + if err != nil { + return fmt.Errorf("failed to create stdout log exporter: %w", err) + } + opts = append(opts, otelconf.WithLoggerProviderOptions( + logsdk.WithProcessor(logsdk.NewBatchProcessor(exporter)), + )) + } + if extra.InstrumentHost { + fmt.Println("Initializing host instrumentation") + if err := host.Start(); err != nil { + return fmt.Errorf("failed to start host instrumentation: %w", err) + } + } + if extra.InstrumentRuntime { + fmt.Println("Initializing runtime instrumentation") + if err := runtime.Start(); err != nil { + return fmt.Errorf("failed to start runtime instrumentation: %w", err) + } + } + } + } else { + fmt.Printf("failed to parse cosmos extra config: %v\n", err) + } } sdk, err = otelconf.NewSDK(opts...) if err != nil { - panic(fmt.Sprintf("failed to initialize telemetry: %v", err)) + return fmt.Errorf("failed to initialize telemetry: %w", err) } // setup otel global providers @@ -56,10 +165,32 @@ func init() { slog.SetDefault(otelslog.NewLogger("", otelslog.WithSource(true))) // emit an initialized message which verifies basic telemetry is working slog.Info("Telemetry initialized") + return nil +} + +type extraConfig struct { + CosmosExtra *cosmosExtra `json:"cosmos_extra" yaml:"cosmos_extra" mapstructure:"cosmos_extra"` +} + +type cosmosExtra struct { + TraceFile string `json:"trace_file" yaml:"trace_file" mapstructure:"trace_file"` + MetricsFile string `json:"metrics_file" yaml:"metrics_file" mapstructure:"metrics_file"` + LogsFile string `json:"logs_file" yaml:"logs_file" mapstructure:"logs_file"` + InstrumentHost bool `json:"instrument_host" yaml:"instrument_host" mapstructure:"instrument_host"` + InstrumentRuntime bool `json:"instrument_runtime" yaml:"instrument_runtime" mapstructure:"instrument_runtime"` } func Shutdown(ctx context.Context) error { - return sdk.Shutdown(ctx) + err := sdk.Shutdown(ctx) + if err != nil { + return fmt.Errorf("failed to shutdown telemetry: %w", err) + } + for _, f := range shutdownFuncs { + if err := f(ctx); err != nil { + return fmt.Errorf("failed to shutdown telemetry: %w", err) + } + } + return nil } func IsTelemetryEnabled() bool { diff --git a/tests/go.mod b/tests/go.mod index 6dc60d9ba6d8..b7cae937a344 100644 --- a/tests/go.mod +++ b/tests/go.mod @@ -100,6 +100,7 @@ require ( github.com/dgraph-io/ristretto/v2 v2.1.0 // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/dvsekhvalnov/jose2go v1.8.0 // indirect + github.com/ebitengine/purego v0.8.4 // indirect github.com/emicklei/dot v1.8.0 // indirect github.com/envoyproxy/go-control-plane/envoy v1.32.4 // indirect github.com/envoyproxy/protoc-gen-validate v1.2.1 // indirect @@ -113,6 +114,7 @@ require ( github.com/go-logfmt/logfmt v0.6.1 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect + github.com/go-ole/go-ole v1.3.0 // indirect github.com/go-viper/mapstructure/v2 v2.4.0 // indirect github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect github.com/gogo/googleapis v1.4.1 // indirect @@ -158,6 +160,7 @@ require ( github.com/kr/text v0.2.0 // indirect github.com/lib/pq v1.10.9 // indirect github.com/linxGnu/grocksdb v1.10.3 // indirect + github.com/lufia/plan9stats v0.0.0-20250827001030-24949be3fa54 // indirect github.com/manifoldco/promptui v0.9.0 // indirect github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect @@ -172,6 +175,7 @@ require ( github.com/pkg/errors v0.9.1 // indirect github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect github.com/prometheus/client_golang v1.23.2 // indirect github.com/prometheus/client_model v0.6.2 // indirect github.com/prometheus/common v0.67.1 // indirect @@ -183,6 +187,7 @@ require ( github.com/rs/zerolog v1.34.0 // indirect github.com/sagikazarmark/locafero v0.11.0 // indirect github.com/sasha-s/go-deadlock v0.3.6 // indirect + github.com/shirou/gopsutil/v4 v4.25.7 // indirect github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect github.com/spf13/afero v1.15.0 // indirect github.com/spf13/cast v1.10.0 // indirect @@ -193,8 +198,11 @@ require ( github.com/supranational/blst v0.3.16 // indirect github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d // indirect github.com/tidwall/btree v1.8.1 // indirect + github.com/tklauser/go-sysconf v0.3.15 // indirect + github.com/tklauser/numcpus v0.10.0 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ulikunitz/xz v0.5.15 // indirect + github.com/yusufpapurcu/wmi v1.2.4 // indirect github.com/zeebo/errs v1.4.0 // indirect github.com/zondax/golem v0.27.0 // indirect github.com/zondax/hid v0.9.2 // indirect @@ -204,7 +212,9 @@ require ( go.opentelemetry.io/contrib/bridges/otelslog v0.13.0 // indirect go.opentelemetry.io/contrib/detectors/gcp v1.36.0 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0 // indirect + go.opentelemetry.io/contrib/instrumentation/host v0.63.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0 // indirect + go.opentelemetry.io/contrib/instrumentation/runtime v0.63.0 // indirect go.opentelemetry.io/contrib/otelconf v0.18.0 // indirect go.opentelemetry.io/otel v1.38.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.14.0 // indirect diff --git a/tests/go.sum b/tests/go.sum index 55cb1ce10c9a..a6914be4baf8 100644 --- a/tests/go.sum +++ b/tests/go.sum @@ -278,6 +278,8 @@ github.com/dvsekhvalnov/jose2go v1.8.0/go.mod h1:QsHjhyTlD/lAVqn/NSbVZmSCGeDehTB github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= +github.com/ebitengine/purego v0.8.4 h1:CF7LEKg5FFOsASUj0+QwaXf8Ht6TlFxg09+S9wz0omw= +github.com/ebitengine/purego v0.8.4/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= github.com/emicklei/dot v1.8.0 h1:HnD60yAKFAevNeT+TPYr9pb8VB9bqdeSo0nzwIW6IOI= github.com/emicklei/dot v1.8.0/go.mod h1:DeV7GvQtIw4h2u73RKBkkFdvVAz0D9fzeJrgPW6gy/s= @@ -343,6 +345,9 @@ github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= +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/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= @@ -570,6 +575,8 @@ github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-b github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= github.com/linxGnu/grocksdb v1.10.3 h1:0laII9AQ6kFxo5SjhdTfSh9EgF20piD6TMHK6YuDm+4= github.com/linxGnu/grocksdb v1.10.3/go.mod h1:OLQKZwiKwaJiAVCsOzWKvwiLwfZ5Vz8Md5TYR7t7pM8= +github.com/lufia/plan9stats v0.0.0-20250827001030-24949be3fa54 h1:mFWunSatvkQQDhpdyuFAYwyAan3hzCuma+Pz8sqvOfg= +github.com/lufia/plan9stats v0.0.0-20250827001030-24949be3fa54/go.mod h1:autxFIvghDt3jPTLoqZ9OZ7s9qTGNAWmYCjVFWPX/zg= github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= github.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE= github.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= @@ -692,6 +699,8 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU= +github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= @@ -753,6 +762,8 @@ github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0 github.com/sasha-s/go-deadlock v0.3.6 h1:TR7sfOnZ7x00tWPfD397Peodt57KzMDo+9Ae9rMiUmw= github.com/sasha-s/go-deadlock v0.3.6/go.mod h1:CUqNyyvMxTyjFqDT7MRg9mb4Dv/btmGTqSR+rky/UXo= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/shirou/gopsutil/v4 v4.25.7 h1:bNb2JuqKuAu3tRlPv5piSmBZyMfecwQ+t/ILq+1JqVM= +github.com/shirou/gopsutil/v4 v4.25.7/go.mod h1:XV/egmwJtd3ZQjBpJVY5kndsiOO4IRqy9TQnmm6VP7U= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= @@ -815,6 +826,10 @@ github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d h1:vfofYNRScrDd github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d/go.mod h1:RRCYJbIwD5jmqPI9XoAFR0OcDxqUctll6zUj/+B4S48= github.com/tendermint/go-amino v0.16.0 h1:GyhmgQKvqF82e2oZeuMSp9JTN0N09emoSZlb2lyGa2E= github.com/tendermint/go-amino v0.16.0/go.mod h1:TQU0M1i/ImAo+tYpZi73AU3V/dKeCoMC9Sphe2ZwGME= +github.com/tklauser/go-sysconf v0.3.15 h1:VE89k0criAymJ/Os65CSn1IXaol+1wrsFHEB8Ol49K4= +github.com/tklauser/go-sysconf v0.3.15/go.mod h1:Dmjwr6tYFIseJw7a3dRLJfsHAMXZ3nEnL/aZY+0IuI4= +github.com/tklauser/numcpus v0.10.0 h1:18njr6LDBk1zuna922MgdjQuJFjrdppsZG60sHGfjso= +github.com/tklauser/numcpus v0.10.0/go.mod h1:BiTKazU708GQTYF4mB+cmlpT2Is1gLk7XVuEeem8LsQ= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= @@ -828,6 +843,8 @@ github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= +github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= github.com/zeebo/errs v1.4.0 h1:XNdoD/RRMKP7HD0UhJnIzUy74ISdGGxURlYG8HSWSfM= github.com/zeebo/errs v1.4.0/go.mod h1:sgbWHsvVuTPHcqJJGQ1WhI5KbWlHYz+2+2C/LSEtCw4= github.com/zondax/golem v0.27.0 h1:IbBjGIXF3SoGOZHsILJvIM/F/ylwJzMcHAcggiqniPw= @@ -851,8 +868,12 @@ go.opentelemetry.io/contrib/detectors/gcp v1.36.0 h1:F7q2tNlCaHY9nMKHR6XH9/qkp8F go.opentelemetry.io/contrib/detectors/gcp v1.36.0/go.mod h1:IbBN8uAIIx734PTonTPxAxnjc2pQTxWNkwfstZ+6H2k= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0 h1:q4XOmH/0opmeuJtPsbFNivyl7bCt7yRBbeEm2sC/XtQ= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0/go.mod h1:snMWehoOh2wsEwnvvwtDyFCxVeDAODenXHtn5vzrKjo= +go.opentelemetry.io/contrib/instrumentation/host v0.63.0 h1:zsaUrWypCf0NtYSUby+/BS6QqhXVNxMQD5w4dLczKCQ= +go.opentelemetry.io/contrib/instrumentation/host v0.63.0/go.mod h1:Ru+kuFO+ToZqBKwI59rCStOhW6LWrbGisYrFaX61bJk= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0 h1:Hf9xI/XLML9ElpiHVDNwvqI0hIFlzV8dgIr35kV1kRU= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0/go.mod h1:NfchwuyNoMcZ5MLHwPrODwUF1HWCXWrL31s8gSAdIKY= +go.opentelemetry.io/contrib/instrumentation/runtime v0.63.0 h1:PeBoRj6af6xMI7qCupwFvTbbnd49V7n5YpG6pg8iDYQ= +go.opentelemetry.io/contrib/instrumentation/runtime v0.63.0/go.mod h1:ingqBCtMCe8I4vpz/UVzCW6sxoqgZB37nao91mLQ3Bw= go.opentelemetry.io/contrib/otelconf v0.18.0 h1:ciF2Gf00BWs0DnexKFZXcxg9kJ8r3SUW1LOzW3CsKA8= go.opentelemetry.io/contrib/otelconf v0.18.0/go.mod h1:FcP7k+JLwBLdOxS6qY6VQ/4b5VBntI6L6o80IMwhAeI= go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= @@ -1024,6 +1045,7 @@ golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1040,6 +1062,7 @@ golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1061,6 +1084,7 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= diff --git a/tests/systemtests/go.mod b/tests/systemtests/go.mod index fcff5d1ed271..73c3a9d35f04 100644 --- a/tests/systemtests/go.mod +++ b/tests/systemtests/go.mod @@ -66,6 +66,7 @@ require ( github.com/dgraph-io/ristretto/v2 v2.1.0 // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/dvsekhvalnov/jose2go v1.8.0 // indirect + github.com/ebitengine/purego v0.8.4 // indirect github.com/emicklei/dot v1.8.0 // indirect github.com/fatih/color v1.18.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect @@ -76,6 +77,7 @@ require ( github.com/go-logfmt/logfmt v0.6.1 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect + github.com/go-ole/go-ole v1.3.0 // indirect github.com/go-viper/mapstructure/v2 v2.4.0 // indirect github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect github.com/gogo/googleapis v1.4.1 // indirect @@ -114,6 +116,7 @@ require ( github.com/kr/text v0.2.0 // indirect github.com/lib/pq v1.10.9 // indirect github.com/linxGnu/grocksdb v1.10.3 // indirect + github.com/lufia/plan9stats v0.0.0-20250827001030-24949be3fa54 // indirect github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/minio/highwayhash v1.0.3 // indirect @@ -125,6 +128,7 @@ require ( github.com/petermattis/goid v0.0.0-20250813065127-a731cc31b4fe // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect github.com/prometheus/client_golang v1.23.2 // indirect github.com/prometheus/client_model v0.6.2 // indirect github.com/prometheus/common v0.67.1 // indirect @@ -136,6 +140,7 @@ require ( github.com/rs/zerolog v1.34.0 // indirect github.com/sagikazarmark/locafero v0.11.0 // indirect github.com/sasha-s/go-deadlock v0.3.6 // indirect + github.com/shirou/gopsutil/v4 v4.25.7 // indirect github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect github.com/spf13/afero v1.15.0 // indirect github.com/spf13/cast v1.10.0 // indirect @@ -149,13 +154,18 @@ require ( github.com/tidwall/btree v1.8.1 // indirect github.com/tidwall/match v1.1.1 // indirect github.com/tidwall/pretty v1.2.0 // indirect + github.com/tklauser/go-sysconf v0.3.15 // indirect + github.com/tklauser/numcpus v0.10.0 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect + github.com/yusufpapurcu/wmi v1.2.4 // indirect github.com/zondax/golem v0.27.0 // indirect github.com/zondax/hid v0.9.2 // indirect github.com/zondax/ledger-go v1.0.1 // indirect go.etcd.io/bbolt v1.4.0 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect go.opentelemetry.io/contrib/bridges/otelslog v0.13.0 // indirect + go.opentelemetry.io/contrib/instrumentation/host v0.63.0 // indirect + go.opentelemetry.io/contrib/instrumentation/runtime v0.63.0 // indirect go.opentelemetry.io/contrib/otelconf v0.18.0 // indirect go.opentelemetry.io/otel v1.38.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.14.0 // indirect diff --git a/tests/systemtests/go.sum b/tests/systemtests/go.sum index e393aa40834a..ae2236127ba5 100644 --- a/tests/systemtests/go.sum +++ b/tests/systemtests/go.sum @@ -198,6 +198,8 @@ github.com/dvsekhvalnov/jose2go v1.8.0/go.mod h1:QsHjhyTlD/lAVqn/NSbVZmSCGeDehTB github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= +github.com/ebitengine/purego v0.8.4 h1:CF7LEKg5FFOsASUj0+QwaXf8Ht6TlFxg09+S9wz0omw= +github.com/ebitengine/purego v0.8.4/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= github.com/emicklei/dot v1.8.0 h1:HnD60yAKFAevNeT+TPYr9pb8VB9bqdeSo0nzwIW6IOI= github.com/emicklei/dot v1.8.0/go.mod h1:DeV7GvQtIw4h2u73RKBkkFdvVAz0D9fzeJrgPW6gy/s= @@ -252,6 +254,9 @@ github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= +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/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= @@ -459,6 +464,8 @@ github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-b github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= github.com/linxGnu/grocksdb v1.10.3 h1:0laII9AQ6kFxo5SjhdTfSh9EgF20piD6TMHK6YuDm+4= github.com/linxGnu/grocksdb v1.10.3/go.mod h1:OLQKZwiKwaJiAVCsOzWKvwiLwfZ5Vz8Md5TYR7t7pM8= +github.com/lufia/plan9stats v0.0.0-20250827001030-24949be3fa54 h1:mFWunSatvkQQDhpdyuFAYwyAan3hzCuma+Pz8sqvOfg= +github.com/lufia/plan9stats v0.0.0-20250827001030-24949be3fa54/go.mod h1:autxFIvghDt3jPTLoqZ9OZ7s9qTGNAWmYCjVFWPX/zg= github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= github.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE= github.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= @@ -575,6 +582,8 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU= +github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= @@ -636,6 +645,8 @@ github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0 github.com/sasha-s/go-deadlock v0.3.6 h1:TR7sfOnZ7x00tWPfD397Peodt57KzMDo+9Ae9rMiUmw= github.com/sasha-s/go-deadlock v0.3.6/go.mod h1:CUqNyyvMxTyjFqDT7MRg9mb4Dv/btmGTqSR+rky/UXo= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/shirou/gopsutil/v4 v4.25.7 h1:bNb2JuqKuAu3tRlPv5piSmBZyMfecwQ+t/ILq+1JqVM= +github.com/shirou/gopsutil/v4 v4.25.7/go.mod h1:XV/egmwJtd3ZQjBpJVY5kndsiOO4IRqy9TQnmm6VP7U= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= @@ -702,6 +713,10 @@ github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= +github.com/tklauser/go-sysconf v0.3.15 h1:VE89k0criAymJ/Os65CSn1IXaol+1wrsFHEB8Ol49K4= +github.com/tklauser/go-sysconf v0.3.15/go.mod h1:Dmjwr6tYFIseJw7a3dRLJfsHAMXZ3nEnL/aZY+0IuI4= +github.com/tklauser/numcpus v0.10.0 h1:18njr6LDBk1zuna922MgdjQuJFjrdppsZG60sHGfjso= +github.com/tklauser/numcpus v0.10.0/go.mod h1:BiTKazU708GQTYF4mB+cmlpT2Is1gLk7XVuEeem8LsQ= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= @@ -713,6 +728,8 @@ github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtX github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= +github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= github.com/zondax/golem v0.27.0 h1:IbBjGIXF3SoGOZHsILJvIM/F/ylwJzMcHAcggiqniPw= github.com/zondax/golem v0.27.0/go.mod h1:AmorCgJPt00L8xN1VrMBe13PSifoZksnQ1Ge906bu4A= github.com/zondax/hid v0.9.2 h1:WCJFnEDMiqGF64nlZz28E9qLVZ0KSJ7xpc5DLEyma2U= @@ -730,6 +747,10 @@ go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJyS go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= go.opentelemetry.io/contrib/bridges/otelslog v0.13.0 h1:bwnLpizECbPr1RrQ27waeY2SPIPeccCx/xLuoYADZ9s= go.opentelemetry.io/contrib/bridges/otelslog v0.13.0/go.mod h1:3nWlOiiqA9UtUnrcNk82mYasNxD8ehOspL0gOfEo6Y4= +go.opentelemetry.io/contrib/instrumentation/host v0.63.0 h1:zsaUrWypCf0NtYSUby+/BS6QqhXVNxMQD5w4dLczKCQ= +go.opentelemetry.io/contrib/instrumentation/host v0.63.0/go.mod h1:Ru+kuFO+ToZqBKwI59rCStOhW6LWrbGisYrFaX61bJk= +go.opentelemetry.io/contrib/instrumentation/runtime v0.63.0 h1:PeBoRj6af6xMI7qCupwFvTbbnd49V7n5YpG6pg8iDYQ= +go.opentelemetry.io/contrib/instrumentation/runtime v0.63.0/go.mod h1:ingqBCtMCe8I4vpz/UVzCW6sxoqgZB37nao91mLQ3Bw= go.opentelemetry.io/contrib/otelconf v0.18.0 h1:ciF2Gf00BWs0DnexKFZXcxg9kJ8r3SUW1LOzW3CsKA8= go.opentelemetry.io/contrib/otelconf v0.18.0/go.mod h1:FcP7k+JLwBLdOxS6qY6VQ/4b5VBntI6L6o80IMwhAeI= go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= @@ -885,6 +906,7 @@ golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -901,6 +923,7 @@ golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -919,6 +942,7 @@ golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= From 0f8085aea5368283e5ca6eec6aa7ea8ff88d302a Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Mon, 3 Nov 2025 18:32:57 -0500 Subject: [PATCH 27/52] add otel custom config options --- client/v2/go.mod | 10 ++++++++ client/v2/go.sum | 24 ++++++++++++++++++ telemetry/wrapper_test.go | 51 --------------------------------------- 3 files changed, 34 insertions(+), 51 deletions(-) delete mode 100644 telemetry/wrapper_test.go diff --git a/client/v2/go.mod b/client/v2/go.mod index 6e8810501d61..57e5cb55cc74 100644 --- a/client/v2/go.mod +++ b/client/v2/go.mod @@ -63,6 +63,7 @@ require ( github.com/dgraph-io/ristretto/v2 v2.1.0 // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/dvsekhvalnov/jose2go v1.6.0 // indirect + github.com/ebitengine/purego v0.8.4 // indirect github.com/emicklei/dot v1.8.0 // indirect github.com/fatih/color v1.18.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect @@ -73,6 +74,7 @@ require ( github.com/go-logfmt/logfmt v0.6.1 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect + github.com/go-ole/go-ole v1.3.0 // indirect github.com/go-viper/mapstructure/v2 v2.4.0 // indirect github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect github.com/gogo/googleapis v1.4.1 // indirect @@ -111,6 +113,7 @@ require ( github.com/kr/text v0.2.0 // indirect github.com/lib/pq v1.10.9 // indirect github.com/linxGnu/grocksdb v1.10.3 // indirect + github.com/lufia/plan9stats v0.0.0-20250827001030-24949be3fa54 // indirect github.com/manifoldco/promptui v0.9.0 // indirect github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect @@ -123,6 +126,7 @@ require ( github.com/petermattis/goid v0.0.0-20250813065127-a731cc31b4fe // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect github.com/prometheus/client_golang v1.23.2 // indirect github.com/prometheus/client_model v0.6.2 // indirect github.com/prometheus/common v0.67.1 // indirect @@ -134,6 +138,7 @@ require ( github.com/rs/zerolog v1.34.0 // indirect github.com/sagikazarmark/locafero v0.11.0 // indirect github.com/sasha-s/go-deadlock v0.3.6 // indirect + github.com/shirou/gopsutil/v4 v4.25.7 // indirect github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect github.com/spf13/afero v1.15.0 // indirect github.com/spf13/cast v1.10.0 // indirect @@ -143,13 +148,18 @@ require ( github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d // indirect github.com/tendermint/go-amino v0.16.0 // indirect github.com/tidwall/btree v1.8.1 // indirect + github.com/tklauser/go-sysconf v0.3.15 // indirect + github.com/tklauser/numcpus v0.10.0 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect + github.com/yusufpapurcu/wmi v1.2.4 // indirect github.com/zondax/golem v0.27.0 // indirect github.com/zondax/hid v0.9.2 // indirect github.com/zondax/ledger-go v1.0.1 // indirect go.etcd.io/bbolt v1.4.0 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect go.opentelemetry.io/contrib/bridges/otelslog v0.13.0 // indirect + go.opentelemetry.io/contrib/instrumentation/host v0.63.0 // indirect + go.opentelemetry.io/contrib/instrumentation/runtime v0.63.0 // indirect go.opentelemetry.io/contrib/otelconf v0.18.0 // indirect go.opentelemetry.io/otel v1.38.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.14.0 // indirect diff --git a/client/v2/go.sum b/client/v2/go.sum index 670ac1e03247..c4d65fca960a 100644 --- a/client/v2/go.sum +++ b/client/v2/go.sum @@ -200,6 +200,8 @@ github.com/dvsekhvalnov/jose2go v1.6.0/go.mod h1:QsHjhyTlD/lAVqn/NSbVZmSCGeDehTB github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= +github.com/ebitengine/purego v0.8.4 h1:CF7LEKg5FFOsASUj0+QwaXf8Ht6TlFxg09+S9wz0omw= +github.com/ebitengine/purego v0.8.4/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= github.com/emicklei/dot v1.8.0 h1:HnD60yAKFAevNeT+TPYr9pb8VB9bqdeSo0nzwIW6IOI= github.com/emicklei/dot v1.8.0/go.mod h1:DeV7GvQtIw4h2u73RKBkkFdvVAz0D9fzeJrgPW6gy/s= @@ -254,6 +256,9 @@ github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= +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/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= @@ -461,6 +466,8 @@ github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-b github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= github.com/linxGnu/grocksdb v1.10.3 h1:0laII9AQ6kFxo5SjhdTfSh9EgF20piD6TMHK6YuDm+4= github.com/linxGnu/grocksdb v1.10.3/go.mod h1:OLQKZwiKwaJiAVCsOzWKvwiLwfZ5Vz8Md5TYR7t7pM8= +github.com/lufia/plan9stats v0.0.0-20250827001030-24949be3fa54 h1:mFWunSatvkQQDhpdyuFAYwyAan3hzCuma+Pz8sqvOfg= +github.com/lufia/plan9stats v0.0.0-20250827001030-24949be3fa54/go.mod h1:autxFIvghDt3jPTLoqZ9OZ7s9qTGNAWmYCjVFWPX/zg= github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= github.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE= github.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= @@ -577,6 +584,8 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU= +github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= @@ -638,6 +647,8 @@ github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0 github.com/sasha-s/go-deadlock v0.3.6 h1:TR7sfOnZ7x00tWPfD397Peodt57KzMDo+9Ae9rMiUmw= github.com/sasha-s/go-deadlock v0.3.6/go.mod h1:CUqNyyvMxTyjFqDT7MRg9mb4Dv/btmGTqSR+rky/UXo= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/shirou/gopsutil/v4 v4.25.7 h1:bNb2JuqKuAu3tRlPv5piSmBZyMfecwQ+t/ILq+1JqVM= +github.com/shirou/gopsutil/v4 v4.25.7/go.mod h1:XV/egmwJtd3ZQjBpJVY5kndsiOO4IRqy9TQnmm6VP7U= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= @@ -695,6 +706,10 @@ github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d h1:vfofYNRScrDd github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d/go.mod h1:RRCYJbIwD5jmqPI9XoAFR0OcDxqUctll6zUj/+B4S48= github.com/tendermint/go-amino v0.16.0 h1:GyhmgQKvqF82e2oZeuMSp9JTN0N09emoSZlb2lyGa2E= github.com/tendermint/go-amino v0.16.0/go.mod h1:TQU0M1i/ImAo+tYpZi73AU3V/dKeCoMC9Sphe2ZwGME= +github.com/tklauser/go-sysconf v0.3.15 h1:VE89k0criAymJ/Os65CSn1IXaol+1wrsFHEB8Ol49K4= +github.com/tklauser/go-sysconf v0.3.15/go.mod h1:Dmjwr6tYFIseJw7a3dRLJfsHAMXZ3nEnL/aZY+0IuI4= +github.com/tklauser/numcpus v0.10.0 h1:18njr6LDBk1zuna922MgdjQuJFjrdppsZG60sHGfjso= +github.com/tklauser/numcpus v0.10.0/go.mod h1:BiTKazU708GQTYF4mB+cmlpT2Is1gLk7XVuEeem8LsQ= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= @@ -706,6 +721,8 @@ github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtX github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= +github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= github.com/zondax/golem v0.27.0 h1:IbBjGIXF3SoGOZHsILJvIM/F/ylwJzMcHAcggiqniPw= github.com/zondax/golem v0.27.0/go.mod h1:AmorCgJPt00L8xN1VrMBe13PSifoZksnQ1Ge906bu4A= github.com/zondax/hid v0.9.2 h1:WCJFnEDMiqGF64nlZz28E9qLVZ0KSJ7xpc5DLEyma2U= @@ -723,6 +740,10 @@ go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJyS go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= go.opentelemetry.io/contrib/bridges/otelslog v0.13.0 h1:bwnLpizECbPr1RrQ27waeY2SPIPeccCx/xLuoYADZ9s= go.opentelemetry.io/contrib/bridges/otelslog v0.13.0/go.mod h1:3nWlOiiqA9UtUnrcNk82mYasNxD8ehOspL0gOfEo6Y4= +go.opentelemetry.io/contrib/instrumentation/host v0.63.0 h1:zsaUrWypCf0NtYSUby+/BS6QqhXVNxMQD5w4dLczKCQ= +go.opentelemetry.io/contrib/instrumentation/host v0.63.0/go.mod h1:Ru+kuFO+ToZqBKwI59rCStOhW6LWrbGisYrFaX61bJk= +go.opentelemetry.io/contrib/instrumentation/runtime v0.63.0 h1:PeBoRj6af6xMI7qCupwFvTbbnd49V7n5YpG6pg8iDYQ= +go.opentelemetry.io/contrib/instrumentation/runtime v0.63.0/go.mod h1:ingqBCtMCe8I4vpz/UVzCW6sxoqgZB37nao91mLQ3Bw= go.opentelemetry.io/contrib/otelconf v0.18.0 h1:ciF2Gf00BWs0DnexKFZXcxg9kJ8r3SUW1LOzW3CsKA8= go.opentelemetry.io/contrib/otelconf v0.18.0/go.mod h1:FcP7k+JLwBLdOxS6qY6VQ/4b5VBntI6L6o80IMwhAeI= go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= @@ -878,6 +899,7 @@ golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -894,6 +916,7 @@ golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -913,6 +936,7 @@ golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= diff --git a/telemetry/wrapper_test.go b/telemetry/wrapper_test.go deleted file mode 100644 index 5388839874bc..000000000000 --- a/telemetry/wrapper_test.go +++ /dev/null @@ -1,51 +0,0 @@ -package telemetry - -import ( - "sync" - "testing" - "time" - - "github.com/stretchr/testify/assert" -) - -var mu sync.Mutex - -func initTelemetry(v bool) { - globalTelemetryEnabled = v -} - -// Reset the global state to a known disabled state before each test. -func setupTest(t *testing.T) { - t.Helper() - mu.Lock() // Ensure no other test can modify global state at the same time. - defer mu.Unlock() - initTelemetry(false) -} - -// TestNow tests the Now function when telemetry is enabled and disabled. -func TestNow(t *testing.T) { - setupTest(t) // Locks the mutex to avoid race condition. - - initTelemetry(true) - telemetryTime := Now() - assert.NotEqual(t, time.Time{}, telemetryTime, "Now() should not return zero time when telemetry is enabled") - - setupTest(t) // Reset the global state and lock the mutex again. - - initTelemetry(false) - telemetryTime = Now() - assert.Equal(t, time.Time{}, telemetryTime, "Now() should return zero time when telemetry is disabled") -} - -// TestIsTelemetryEnabled tests the IsTelemetryEnabled function. -func TestIsTelemetryEnabled(t *testing.T) { - setupTest(t) // Locks the mutex to avoid race condition. - - initTelemetry(true) - assert.True(t, IsTelemetryEnabled(), "IsTelemetryEnabled() should return true when globalTelemetryEnabled is set to true") - - setupTest(t) // Reset the global state and lock the mutex again. - - initTelemetry(false) - assert.False(t, IsTelemetryEnabled(), "IsTelemetryEnabled() should return false when globalTelemetryEnabled is set to false") -} From 03b60693e4648296fe5f8f9daa112fa07da86181 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Mon, 3 Nov 2025 18:34:42 -0500 Subject: [PATCH 28/52] add more instrumentation --- baseapp/baseapp.go | 4 ++-- types/module/module.go | 27 +++++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/baseapp/baseapp.go b/baseapp/baseapp.go index 1b1df303cdef..89a74b748fc6 100644 --- a/baseapp/baseapp.go +++ b/baseapp/baseapp.go @@ -66,8 +66,8 @@ const ( var _ servertypes.ABCI = (*BaseApp)(nil) var ( - tracer = otel.Tracer("baseapp") - meter = otel.Meter("baseapp") + tracer = otel.Tracer("cosmos-sdk/baseapp") + meter = otel.Meter("cosmos-sdk/baseapp") blockCnt metric.Int64Counter txCnt metric.Int64Counter blockTime metric.Float64Histogram diff --git a/types/module/module.go b/types/module/module.go index 7d49b533748e..0f99847177e5 100644 --- a/types/module/module.go +++ b/types/module/module.go @@ -39,6 +39,8 @@ import ( abci "github.com/cometbft/cometbft/abci/types" "github.com/grpc-ecosystem/grpc-gateway/runtime" "github.com/spf13/cobra" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/trace" "cosmossdk.io/core/appmodule" "cosmossdk.io/core/genesis" @@ -52,6 +54,10 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) +var ( + tracer = otel.Tracer("cosmos-sdk/types/module") +) + // AppModuleBasic is the standard form for basic non-dependent elements of an application module. type AppModuleBasic interface { HasName @@ -752,8 +758,14 @@ func (m Manager) RunMigrations(ctx context.Context, cfg Configurator, fromVM Ver // It takes the current context as a parameter and returns a boolean value // indicating whether the migration was successfully executed or not. func (m *Manager) PreBlock(ctx sdk.Context) (*sdk.ResponsePreBlock, error) { + var span trace.Span + ctx, span = ctx.StartSpan(tracer, "Manager.PreBlock") + defer span.End() + paramsChanged := false for _, moduleName := range m.OrderPreBlockers { + var modSpan trace.Span + ctx, modSpan = ctx.StartSpan(tracer, fmt.Sprintf("PreBlock.%s", moduleName)) if module, ok := m.Modules[moduleName].(appmodule.HasPreBlocker); ok { rsp, err := module.PreBlock(ctx) if err != nil { @@ -763,6 +775,7 @@ func (m *Manager) PreBlock(ctx sdk.Context) (*sdk.ResponsePreBlock, error) { paramsChanged = true } } + modSpan.End() } return &sdk.ResponsePreBlock{ ConsensusParamsChanged: paramsChanged, @@ -773,13 +786,20 @@ func (m *Manager) PreBlock(ctx sdk.Context) (*sdk.ResponsePreBlock, error) { // child context with an event manager to aggregate events emitted from all // modules. func (m *Manager) BeginBlock(ctx sdk.Context) (sdk.BeginBlock, error) { + var span trace.Span + ctx, span = ctx.StartSpan(tracer, "Manager.BeginBlock") + defer span.End() + ctx = ctx.WithEventManager(sdk.NewEventManager()) for _, moduleName := range m.OrderBeginBlockers { + var modSpan trace.Span + ctx, modSpan = ctx.StartSpan(tracer, fmt.Sprintf("BeginBlock.%s", moduleName)) if module, ok := m.Modules[moduleName].(appmodule.HasBeginBlocker); ok { if err := module.BeginBlock(ctx); err != nil { return sdk.BeginBlock{}, err } } + modSpan.End() } return sdk.BeginBlock{ @@ -791,10 +811,16 @@ func (m *Manager) BeginBlock(ctx sdk.Context) (sdk.BeginBlock, error) { // child context with an event manager to aggregate events emitted from all // modules. func (m *Manager) EndBlock(ctx sdk.Context) (sdk.EndBlock, error) { + var span trace.Span + ctx, span = ctx.StartSpan(tracer, "Manager.EndBlock") + defer span.End() + ctx = ctx.WithEventManager(sdk.NewEventManager()) validatorUpdates := []abci.ValidatorUpdate{} for _, moduleName := range m.OrderEndBlockers { + var modSpan trace.Span + ctx, modSpan = ctx.StartSpan(tracer, fmt.Sprintf("EndBlock.%s", moduleName)) if module, ok := m.Modules[moduleName].(appmodule.HasEndBlocker); ok { err := module.EndBlock(ctx) if err != nil { @@ -819,6 +845,7 @@ func (m *Manager) EndBlock(ctx sdk.Context) (sdk.EndBlock, error) { } else { continue } + modSpan.End() } return sdk.EndBlock{ From c4dbd070ab384e1c28733a019a3460809222c339 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Mon, 3 Nov 2025 19:21:13 -0500 Subject: [PATCH 29/52] remove pretty print --- telemetry/config.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/telemetry/config.go b/telemetry/config.go index 0bd329fb9828..dd34478cdd49 100644 --- a/telemetry/config.go +++ b/telemetry/config.go @@ -79,7 +79,7 @@ func doInit() error { }) exporter, err := stdouttrace.New( stdouttrace.WithWriter(traceFile), - stdouttrace.WithPrettyPrint(), + //stdouttrace.WithPrettyPrint(), ) if err != nil { return fmt.Errorf("failed to create stdout trace exporter: %w", err) @@ -102,7 +102,7 @@ func doInit() error { }) exporter, err := stdoutmetric.New( stdoutmetric.WithWriter(metricsFile), - stdoutmetric.WithPrettyPrint(), + //stdoutmetric.WithPrettyPrint(), ) if err != nil { return fmt.Errorf("failed to create stdout metric exporter: %w", err) @@ -125,7 +125,7 @@ func doInit() error { }) exporter, err := stdoutlog.New( stdoutlog.WithWriter(logsFile), - stdoutlog.WithPrettyPrint(), + //stdoutlog.WithPrettyPrint(), ) if err != nil { return fmt.Errorf("failed to create stdout log exporter: %w", err) From 7b3ee34284aa88e0e0b7f878bc4fe9d65e1ee138 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Thu, 6 Nov 2025 17:34:29 -0500 Subject: [PATCH 30/52] add hashicorp/go-metrics otel/compatibility layer --- telemetry/compat.go | 127 +++++++++++++++++++ telemetry/config.go | 202 ------------------------------ telemetry/doc.go | 6 +- telemetry/metrics.go | 250 ++++++++++++++++++++++++++++++++++++++ telemetry/metrics_test.go | 77 ++++++++++++ telemetry/otel.go | 205 +++++++++++++++++++++++++++++++ telemetry/wrapper.go | 30 ++--- telemetry/wrapper_test.go | 51 ++++++++ 8 files changed, 722 insertions(+), 226 deletions(-) create mode 100644 telemetry/compat.go delete mode 100644 telemetry/config.go create mode 100644 telemetry/metrics.go create mode 100644 telemetry/metrics_test.go create mode 100644 telemetry/otel.go create mode 100644 telemetry/wrapper_test.go diff --git a/telemetry/compat.go b/telemetry/compat.go new file mode 100644 index 000000000000..61f92c342955 --- /dev/null +++ b/telemetry/compat.go @@ -0,0 +1,127 @@ +package telemetry + +import ( + "bytes" + "context" + "fmt" + "strings" + "sync" + + gometrics "github.com/hashicorp/go-metrics" + "go.opentelemetry.io/otel/attribute" + otelmetric "go.opentelemetry.io/otel/metric" +) + +type otelGoMetricsSink struct { + meter otelmetric.Meter + ctx context.Context + counters sync.Map + gauges sync.Map + histograms sync.Map +} + +func newOtelGoMetricsSink(ctx context.Context, meter otelmetric.Meter) gometrics.MetricSink { + return &otelGoMetricsSink{ + meter: meter, + ctx: ctx, + } +} + +func (o *otelGoMetricsSink) getGauge(key string) otelmetric.Float64Gauge { + entry, ok := o.gauges.Load(key) + if ok { + return entry.(otelmetric.Float64Gauge) + } + gauge, err := o.meter.Float64Gauge(key) + if err != nil { + panic(fmt.Sprintf("failed to create gauge metric %s: %v", key, err)) + } + o.gauges.Store(key, gauge) + return gauge +} + +func (o *otelGoMetricsSink) SetGauge(key []string, val float32) { + o.getGauge(flattenKey(key)).Record(o.ctx, float64(val)) +} + +func (o *otelGoMetricsSink) SetGaugeWithLabels(key []string, val float32, labels []gometrics.Label) { + o.getGauge(flattenKey(key)).Record(o.ctx, float64(val), toOtelAttrs(labels)) +} + +func (o *otelGoMetricsSink) getCounter(key string) otelmetric.Float64Counter { + entry, ok := o.counters.Load(key) + if ok { + return entry.(otelmetric.Float64Counter) + } + counter, err := o.meter.Float64Counter(key) + if err != nil { + panic(fmt.Sprintf("failed to create counter metric %s: %v", key, err)) + } + o.counters.Store(key, counter) + return counter +} + +func (o *otelGoMetricsSink) IncrCounter(key []string, val float32) { + o.getCounter(flattenKey(key)).Add(o.ctx, float64(val)) +} + +func (o *otelGoMetricsSink) IncrCounterWithLabels(key []string, val float32, labels []gometrics.Label) { + o.getCounter(flattenKey(key)).Add(o.ctx, float64(val), toOtelAttrs(labels)) +} + +func (o *otelGoMetricsSink) getHistogram(key string) otelmetric.Float64Histogram { + entry, ok := o.histograms.Load(key) + if ok { + return entry.(otelmetric.Float64Histogram) + } + hist, err := o.meter.Float64Histogram(key) + if err != nil { + panic(fmt.Sprintf("failed to create histogram metric %s: %v", key, err)) + } + o.histograms.Store(key, hist) + return hist +} + +func (o *otelGoMetricsSink) EmitKey(key []string, val float32) { + o.getHistogram(flattenKey(key)).Record(o.ctx, float64(val)) +} + +func (o *otelGoMetricsSink) AddSample(key []string, val float32) { + o.getHistogram(flattenKey(key)).Record(o.ctx, float64(val)) +} + +func (o *otelGoMetricsSink) AddSampleWithLabels(key []string, val float32, labels []gometrics.Label) { + o.getHistogram(flattenKey(key)).Record(o.ctx, float64(val), toOtelAttrs(labels)) +} + +func (o *otelGoMetricsSink) SetPrecisionGauge(key []string, val float64) { + o.getGauge(flattenKey(key)).Record(o.ctx, val) +} + +func (o *otelGoMetricsSink) SetPrecisionGaugeWithLabels(key []string, val float64, labels []gometrics.Label) { + o.getGauge(flattenKey(key)).Record(o.ctx, val, toOtelAttrs(labels)) +} + +var _ gometrics.MetricSink = &otelGoMetricsSink{} +var _ gometrics.PrecisionGaugeMetricSink = &otelGoMetricsSink{} + +var spaceReplacer = strings.NewReplacer(" ", "_") + +// NOTE: this code was copied from https://github.com/hashicorp/go-metrics/blob/v0.5.4/inmem.go +func flattenKey(parts []string) string { + buf := &bytes.Buffer{} + + joined := strings.Join(parts, ".") + + spaceReplacer.WriteString(buf, joined) + + return buf.String() +} + +func toOtelAttrs(labels []gometrics.Label) otelmetric.MeasurementOption { + attrs := make([]attribute.KeyValue, len(labels)) + for i, l := range labels { + attrs[i] = attribute.String(l.Name, l.Value) + } + return otelmetric.WithAttributes(attrs...) +} diff --git a/telemetry/config.go b/telemetry/config.go deleted file mode 100644 index dd34478cdd49..000000000000 --- a/telemetry/config.go +++ /dev/null @@ -1,202 +0,0 @@ -package telemetry - -import ( - "context" - "encoding/json" - "fmt" - "log/slog" - "os" - - "go.opentelemetry.io/contrib/bridges/otelslog" - "go.opentelemetry.io/contrib/instrumentation/host" - "go.opentelemetry.io/contrib/instrumentation/runtime" - "go.opentelemetry.io/contrib/otelconf/v0.3.0" - "go.opentelemetry.io/otel" - "go.opentelemetry.io/otel/exporters/stdout/stdoutlog" - "go.opentelemetry.io/otel/exporters/stdout/stdoutmetric" - "go.opentelemetry.io/otel/exporters/stdout/stdouttrace" - logglobal "go.opentelemetry.io/otel/log/global" - logsdk "go.opentelemetry.io/otel/sdk/log" - metricsdk "go.opentelemetry.io/otel/sdk/metric" - tracesdk "go.opentelemetry.io/otel/sdk/trace" - "go.yaml.in/yaml/v3" -) - -var sdk otelconf.SDK -var shutdownFuncs []func(context.Context) error - -var isTelemetryEnabled = true - -func init() { - err := doInit() - if err != nil { - panic(err) - } -} - -func doInit() error { - var err error - - var opts []otelconf.ConfigurationOption - - confFilename := os.Getenv("OTEL_EXPERIMENTAL_CONFIG_FILE") - if confFilename != "" { - bz, err := os.ReadFile(confFilename) - if err != nil { - return fmt.Errorf("failed to read telemetry config file: %w", err) - } - - cfg, err := otelconf.ParseYAML(bz) - if err != nil { - return fmt.Errorf("failed to parse telemetry config file: %w", err) - } - - cfgJson, err := json.Marshal(cfg) - if err != nil { - return fmt.Errorf("failed to marshal telemetry config file: %w", err) - } - fmt.Printf("\nInitializing telemetry with config:\n%s\n\n", cfgJson) - - opts = append(opts, otelconf.WithOpenTelemetryConfiguration(*cfg)) - - // parse cosmos extra config - var extraCfg extraConfig - err = yaml.Unmarshal(bz, &extraCfg) - if err == nil { - if extraCfg.CosmosExtra != nil { - extra := *extraCfg.CosmosExtra - if extra.TraceFile != "" { - fmt.Printf("Initializing trace file: %s\n", extra.TraceFile) - traceFile, err := os.OpenFile(extra.TraceFile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644) - if err != nil { - return fmt.Errorf("failed to open trace file: %w", err) - } - shutdownFuncs = append(shutdownFuncs, func(ctx context.Context) error { - if err := traceFile.Close(); err != nil { - return fmt.Errorf("failed to close trace file: %w", err) - } - return nil - }) - exporter, err := stdouttrace.New( - stdouttrace.WithWriter(traceFile), - //stdouttrace.WithPrettyPrint(), - ) - if err != nil { - return fmt.Errorf("failed to create stdout trace exporter: %w", err) - } - opts = append(opts, otelconf.WithTracerProviderOptions( - tracesdk.WithBatcher(exporter), - )) - } - if extra.MetricsFile != "" { - fmt.Printf("Initializing metrics file: %s\n", extra.MetricsFile) - metricsFile, err := os.OpenFile(extra.MetricsFile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644) - if err != nil { - return fmt.Errorf("failed to open metrics file: %w", err) - } - shutdownFuncs = append(shutdownFuncs, func(ctx context.Context) error { - if err := metricsFile.Close(); err != nil { - return fmt.Errorf("failed to close metrics file: %w", err) - } - return nil - }) - exporter, err := stdoutmetric.New( - stdoutmetric.WithWriter(metricsFile), - //stdoutmetric.WithPrettyPrint(), - ) - if err != nil { - return fmt.Errorf("failed to create stdout metric exporter: %w", err) - } - opts = append(opts, otelconf.WithMeterProviderOptions( - metricsdk.WithReader(metricsdk.NewPeriodicReader(exporter)), - )) - } - if extra.LogsFile != "" { - fmt.Printf("Initializing logs file: %s\n", extra.LogsFile) - logsFile, err := os.OpenFile(extra.LogsFile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644) - if err != nil { - return fmt.Errorf("failed to open logs file: %w", err) - } - shutdownFuncs = append(shutdownFuncs, func(ctx context.Context) error { - if err := logsFile.Close(); err != nil { - return fmt.Errorf("failed to close logs file: %w", err) - } - return nil - }) - exporter, err := stdoutlog.New( - stdoutlog.WithWriter(logsFile), - //stdoutlog.WithPrettyPrint(), - ) - if err != nil { - return fmt.Errorf("failed to create stdout log exporter: %w", err) - } - opts = append(opts, otelconf.WithLoggerProviderOptions( - logsdk.WithProcessor(logsdk.NewBatchProcessor(exporter)), - )) - } - if extra.InstrumentHost { - fmt.Println("Initializing host instrumentation") - if err := host.Start(); err != nil { - return fmt.Errorf("failed to start host instrumentation: %w", err) - } - } - if extra.InstrumentRuntime { - fmt.Println("Initializing runtime instrumentation") - if err := runtime.Start(); err != nil { - return fmt.Errorf("failed to start runtime instrumentation: %w", err) - } - } - } - } else { - fmt.Printf("failed to parse cosmos extra config: %v\n", err) - } - } - - sdk, err = otelconf.NewSDK(opts...) - if err != nil { - return fmt.Errorf("failed to initialize telemetry: %w", err) - } - - // setup otel global providers - otel.SetTracerProvider(sdk.TracerProvider()) - otel.SetMeterProvider(sdk.MeterProvider()) - logglobal.SetLoggerProvider(sdk.LoggerProvider()) - // setup slog default provider so that any logs emitted the default slog will be traced - slog.SetDefault(otelslog.NewLogger("", otelslog.WithSource(true))) - // emit an initialized message which verifies basic telemetry is working - slog.Info("Telemetry initialized") - return nil -} - -type extraConfig struct { - CosmosExtra *cosmosExtra `json:"cosmos_extra" yaml:"cosmos_extra" mapstructure:"cosmos_extra"` -} - -type cosmosExtra struct { - TraceFile string `json:"trace_file" yaml:"trace_file" mapstructure:"trace_file"` - MetricsFile string `json:"metrics_file" yaml:"metrics_file" mapstructure:"metrics_file"` - LogsFile string `json:"logs_file" yaml:"logs_file" mapstructure:"logs_file"` - InstrumentHost bool `json:"instrument_host" yaml:"instrument_host" mapstructure:"instrument_host"` - InstrumentRuntime bool `json:"instrument_runtime" yaml:"instrument_runtime" mapstructure:"instrument_runtime"` -} - -func Shutdown(ctx context.Context) error { - err := sdk.Shutdown(ctx) - if err != nil { - return fmt.Errorf("failed to shutdown telemetry: %w", err) - } - for _, f := range shutdownFuncs { - if err := f(ctx); err != nil { - return fmt.Errorf("failed to shutdown telemetry: %w", err) - } - } - return nil -} - -func IsTelemetryEnabled() bool { - return isTelemetryEnabled -} - -func SetTelemetryEnabled(v bool) { - isTelemetryEnabled = v -} diff --git a/telemetry/doc.go b/telemetry/doc.go index 606ace81fdd8..2dc4a014c8a1 100644 --- a/telemetry/doc.go +++ b/telemetry/doc.go @@ -1,2 +1,6 @@ -// Package telemetry initializes OpenTelemetry and provides legacy metrics wrapper functions. +// Package telemetry initializes OpenTelemetry global using the OpenTelemetry declarative configuration API. +// It also provides some deprecated legacy metrics wrapper functions and metrics configuration using +// github.com/hashicorp/go-metrics. +// By default, this package configures the github.com/hashicorp/go-metrics default instance to +// send all metrics to OpenTelemetry. package telemetry diff --git a/telemetry/metrics.go b/telemetry/metrics.go new file mode 100644 index 000000000000..240cbdda5f69 --- /dev/null +++ b/telemetry/metrics.go @@ -0,0 +1,250 @@ +package telemetry + +import ( + "bytes" + "encoding/json" + "errors" + "fmt" + "net/http" + "time" + + "github.com/hashicorp/go-metrics" + "github.com/hashicorp/go-metrics/datadog" + metricsprom "github.com/hashicorp/go-metrics/prometheus" + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/common/expfmt" +) + +// globalTelemetryEnabled is a private variable that stores the telemetry enabled state. +// It is set on initialization and does not change for the lifetime of the program. +var globalTelemetryEnabled bool + +// Deprecated: IsTelemetryEnabled provides controlled access to check if telemetry is enabled. +func IsTelemetryEnabled() bool { + return globalTelemetryEnabled +} + +// Deprecated: EnableTelemetry allows for the global telemetry enabled state to be set. +func EnableTelemetry() { + globalTelemetryEnabled = true +} + +// globalLabels defines the set of global labels that will be applied to all +// metrics emitted using the telemetry package function wrappers. +var globalLabels = []metrics.Label{} + +// Metrics supported format types. +const ( + // Deprecated: FormatDefault is the default format for metrics gathering. + FormatDefault = "" + // Deprecated: FormatPrometheus indicates Prometheus format for metrics gathering. + FormatPrometheus = "prometheus" + // Deprecated: FormatText indicates text format for metrics gathering. + FormatText = "text" + // Deprecated: ContentTypeText is the content type for text formatted metrics. + ContentTypeText = `text/plain; version=` + expfmt.TextVersion + `; charset=utf-8` + + // Deprecated: MetricSinkInMem indicates in-memory metrics sink. + MetricSinkInMem = "mem" + // Deprecated: MetricSinkPrometheus indicates Prometheus metrics sink. + MetricSinkStatsd = "statsd" + // Deprecated: MetricSinkDogsStatsd indicates DogStatsD metrics sink. + MetricSinkDogsStatsd = "dogstatsd" + // Deprecated: MetricSinkOtel indicates OpenTelemetry metrics sink. + MetricSinkOtel = "otel" +) + +// Deprecated: DisplayableSink is an interface that defines a method for displaying metrics. +type DisplayableSink interface { + DisplayMetrics(resp http.ResponseWriter, req *http.Request) (any, error) +} + +// Deprecated: Config defines the configuration options for application telemetry. +type Config struct { + // Prefixed with keys to separate services + ServiceName string `mapstructure:"service-name"` + + // Enabled enables the application telemetry functionality. When enabled, + // an in-memory sink is also enabled by default. Operators may also enabled + // other sinks such as Prometheus. + Enabled bool `mapstructure:"enabled"` + + // Enable prefixing gauge values with hostname + EnableHostname bool `mapstructure:"enable-hostname"` + + // Enable adding hostname to labels + EnableHostnameLabel bool `mapstructure:"enable-hostname-label"` + + // Enable adding service to labels + EnableServiceLabel bool `mapstructure:"enable-service-label"` + + // PrometheusRetentionTime, when positive, enables a Prometheus metrics sink. + // It defines the retention duration in seconds. + PrometheusRetentionTime int64 `mapstructure:"prometheus-retention-time"` + + // GlobalLabels defines a global set of name/value label tuples applied to all + // metrics emitted using the wrapper functions defined in telemetry package. + // + // Example: + // [["chain_id", "cosmoshub-1"]] + GlobalLabels [][]string `mapstructure:"global-labels"` + + // MetricsSink defines the type of metrics backend to use. + MetricsSink string `mapstructure:"metrics-sink" default:"mem"` + + // StatsdAddr defines the address of a statsd server to send metrics to. + // Only utilized if MetricsSink is set to "statsd" or "dogstatsd". + StatsdAddr string `mapstructure:"statsd-addr"` + + // DatadogHostname defines the hostname to use when emitting metrics to + // Datadog. Only utilized if MetricsSink is set to "dogstatsd". + DatadogHostname string `mapstructure:"datadog-hostname"` +} + +// Deprecated: Metrics defines a wrapper around application telemetry functionality. It allows +// metrics to be gathered at any point in time. When creating a Metrics object, +// internally, a global metrics is registered with a set of sinks as configured +// by the operator. In addition to the sinks, when a process gets a SIGUSR1, a +// dump of formatted recent metrics will be sent to STDERR. +type Metrics struct { + sink metrics.MetricSink + prometheusEnabled bool +} + +// Deprecated: GatherResponse is the response type of registered metrics +type GatherResponse struct { + Metrics []byte + ContentType string +} + +// Deprecated: New creates a new instance of Metrics +func New(cfg Config) (_ *Metrics, rerr error) { + globalTelemetryEnabled = cfg.Enabled + if !cfg.Enabled { + return nil, nil + } + + if numGlobalLabels := len(cfg.GlobalLabels); numGlobalLabels > 0 { + parsedGlobalLabels := make([]metrics.Label, numGlobalLabels) + for i, gl := range cfg.GlobalLabels { + parsedGlobalLabels[i] = NewLabel(gl[0], gl[1]) + } + globalLabels = parsedGlobalLabels + } + + metricsConf := metrics.DefaultConfig(cfg.ServiceName) + metricsConf.EnableHostname = cfg.EnableHostname + metricsConf.EnableHostnameLabel = cfg.EnableHostnameLabel + + var ( + sink metrics.MetricSink + err error + ) + switch cfg.MetricsSink { + case MetricSinkStatsd: + sink, err = metrics.NewStatsdSink(cfg.StatsdAddr) + case MetricSinkDogsStatsd: + sink, err = datadog.NewDogStatsdSink(cfg.StatsdAddr, cfg.DatadogHostname) + default: + memSink := metrics.NewInmemSink(10*time.Second, time.Minute) + sink = memSink + inMemSig := metrics.DefaultInmemSignal(memSink) + defer func() { + if rerr != nil { + inMemSig.Stop() + } + }() + } + + if err != nil { + return nil, err + } + + m := &Metrics{sink: sink} + fanout := metrics.FanoutSink{sink} + + if cfg.PrometheusRetentionTime > 0 { + m.prometheusEnabled = true + prometheusOpts := metricsprom.PrometheusOpts{ + Expiration: time.Duration(cfg.PrometheusRetentionTime) * time.Second, + } + + promSink, err := metricsprom.NewPrometheusSinkFrom(prometheusOpts) + if err != nil { + return nil, err + } + + fanout = append(fanout, promSink) + } + + if _, err := metrics.NewGlobal(metricsConf, fanout); err != nil { + return nil, err + } + + return m, nil +} + +// Gather collects all registered metrics and returns a GatherResponse where the +// metrics are encoded depending on the type. Metrics are either encoded via +// Prometheus or JSON if in-memory. +func (m *Metrics) Gather(format string) (GatherResponse, error) { + switch format { + case FormatPrometheus: + return m.gatherPrometheus() + + case FormatText: + return m.gatherGeneric() + + case FormatDefault: + return m.gatherGeneric() + + default: + return GatherResponse{}, fmt.Errorf("unsupported metrics format: %s", format) + } +} + +// gatherPrometheus collects Prometheus metrics and returns a GatherResponse. +// If Prometheus metrics are not enabled, it returns an error. +func (m *Metrics) gatherPrometheus() (GatherResponse, error) { + if !m.prometheusEnabled { + return GatherResponse{}, errors.New("prometheus metrics are not enabled") + } + + metricsFamilies, err := prometheus.DefaultGatherer.Gather() + if err != nil { + return GatherResponse{}, fmt.Errorf("failed to gather prometheus metrics: %w", err) + } + + buf := &bytes.Buffer{} + defer buf.Reset() + + e := expfmt.NewEncoder(buf, expfmt.NewFormat(expfmt.TypeTextPlain)) + + for _, mf := range metricsFamilies { + if err := e.Encode(mf); err != nil { + return GatherResponse{}, fmt.Errorf("failed to encode prometheus metrics: %w", err) + } + } + + return GatherResponse{ContentType: ContentTypeText, Metrics: buf.Bytes()}, nil +} + +// gatherGeneric collects generic metrics and returns a GatherResponse. +func (m *Metrics) gatherGeneric() (GatherResponse, error) { + gm, ok := m.sink.(DisplayableSink) + if !ok { + return GatherResponse{}, errors.New("non in-memory metrics sink does not support generic format") + } + + summary, err := gm.DisplayMetrics(nil, nil) + if err != nil { + return GatherResponse{}, fmt.Errorf("failed to gather in-memory metrics: %w", err) + } + + content, err := json.Marshal(summary) + if err != nil { + return GatherResponse{}, fmt.Errorf("failed to encode in-memory metrics: %w", err) + } + + return GatherResponse{ContentType: "application/json", Metrics: content}, nil +} diff --git a/telemetry/metrics_test.go b/telemetry/metrics_test.go new file mode 100644 index 000000000000..b741f007db22 --- /dev/null +++ b/telemetry/metrics_test.go @@ -0,0 +1,77 @@ +package telemetry + +import ( + "encoding/json" + "strings" + "testing" + "time" + + "github.com/hashicorp/go-metrics" + "github.com/stretchr/testify/require" +) + +func TestMetrics_Disabled(t *testing.T) { + m, err := New(Config{Enabled: false}) + require.Nil(t, m) + require.Nil(t, err) +} + +func TestMetrics_InMem(t *testing.T) { + m, err := New(Config{ + MetricsSink: MetricSinkInMem, + Enabled: true, + EnableHostname: false, + ServiceName: "test", + }) + require.NoError(t, err) + require.NotNil(t, m) + + emitMetrics() + + gr, err := m.Gather(FormatText) + require.NoError(t, err) + require.Equal(t, gr.ContentType, "application/json") + + jsonMetrics := make(map[string]any) + require.NoError(t, json.Unmarshal(gr.Metrics, &jsonMetrics)) + + counters := jsonMetrics["Counters"].([]any) + require.Equal(t, counters[0].(map[string]any)["Count"].(float64), 10.0) + require.Equal(t, counters[0].(map[string]any)["Name"].(string), "test.dummy_counter") +} + +func TestMetrics_Prom(t *testing.T) { + m, err := New(Config{ + MetricsSink: MetricSinkInMem, + Enabled: true, + EnableHostname: false, + ServiceName: "test", + PrometheusRetentionTime: 60, + EnableHostnameLabel: false, + }) + require.NoError(t, err) + require.NotNil(t, m) + require.True(t, m.prometheusEnabled) + + emitMetrics() + + gr, err := m.Gather(FormatPrometheus) + require.NoError(t, err) + require.Equal(t, gr.ContentType, string(ContentTypeText)) + + require.True(t, strings.Contains(string(gr.Metrics), "test_dummy_counter 30")) +} + +func emitMetrics() { + ticker := time.NewTicker(time.Second) + timeout := time.After(30 * time.Second) + + for { + select { + case <-ticker.C: + metrics.IncrCounter([]string{"dummy_counter"}, 1.0) + case <-timeout: + return + } + } +} diff --git a/telemetry/otel.go b/telemetry/otel.go new file mode 100644 index 000000000000..e80b1cebd28a --- /dev/null +++ b/telemetry/otel.go @@ -0,0 +1,205 @@ +package telemetry + +import ( + "context" + "encoding/json" + "fmt" + "log/slog" + "os" + + "github.com/hashicorp/go-metrics" + "go.opentelemetry.io/contrib/bridges/otelslog" + "go.opentelemetry.io/contrib/instrumentation/host" + "go.opentelemetry.io/contrib/instrumentation/runtime" + "go.opentelemetry.io/contrib/otelconf/v0.3.0" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/exporters/stdout/stdoutlog" + "go.opentelemetry.io/otel/exporters/stdout/stdoutmetric" + "go.opentelemetry.io/otel/exporters/stdout/stdouttrace" + logglobal "go.opentelemetry.io/otel/log/global" + logsdk "go.opentelemetry.io/otel/sdk/log" + metricsdk "go.opentelemetry.io/otel/sdk/metric" + tracesdk "go.opentelemetry.io/otel/sdk/trace" + "go.yaml.in/yaml/v3" +) + +var sdk otelconf.SDK +var shutdownFuncs []func(context.Context) error + +func init() { + err := doInit() + if err != nil { + panic(err) + } +} + +func doInit() error { + var err error + + var opts []otelconf.ConfigurationOption + + confFilename := os.Getenv("OTEL_EXPERIMENTAL_CONFIG_FILE") + if confFilename == "" { + return nil + } + + bz, err := os.ReadFile(confFilename) + if err != nil { + return fmt.Errorf("failed to read telemetry config file: %w", err) + } + + cfg, err := otelconf.ParseYAML(bz) + if err != nil { + return fmt.Errorf("failed to parse telemetry config file: %w", err) + } + + cfgJson, err := json.Marshal(cfg) + if err != nil { + return fmt.Errorf("failed to marshal telemetry config file: %w", err) + } + fmt.Printf("\nInitializing telemetry with config:\n%s\n\n", cfgJson) + + opts = append(opts, otelconf.WithOpenTelemetryConfiguration(*cfg)) + + // parse cosmos extra config + var extraCfg extraConfig + err = yaml.Unmarshal(bz, &extraCfg) + if err == nil { + if extraCfg.CosmosExtra != nil { + extra := *extraCfg.CosmosExtra + if extra.TraceFile != "" { + fmt.Printf("Initializing trace file: %s\n", extra.TraceFile) + traceFile, err := os.OpenFile(extra.TraceFile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644) + if err != nil { + return fmt.Errorf("failed to open trace file: %w", err) + } + shutdownFuncs = append(shutdownFuncs, func(ctx context.Context) error { + if err := traceFile.Close(); err != nil { + return fmt.Errorf("failed to close trace file: %w", err) + } + return nil + }) + exporter, err := stdouttrace.New( + stdouttrace.WithWriter(traceFile), + //stdouttrace.WithPrettyPrint(), + ) + if err != nil { + return fmt.Errorf("failed to create stdout trace exporter: %w", err) + } + opts = append(opts, otelconf.WithTracerProviderOptions( + tracesdk.WithBatcher(exporter), + )) + } + if extra.MetricsFile != "" { + fmt.Printf("Initializing metrics file: %s\n", extra.MetricsFile) + metricsFile, err := os.OpenFile(extra.MetricsFile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644) + if err != nil { + return fmt.Errorf("failed to open metrics file: %w", err) + } + shutdownFuncs = append(shutdownFuncs, func(ctx context.Context) error { + if err := metricsFile.Close(); err != nil { + return fmt.Errorf("failed to close metrics file: %w", err) + } + return nil + }) + exporter, err := stdoutmetric.New( + stdoutmetric.WithWriter(metricsFile), + //stdoutmetric.WithPrettyPrint(), + ) + if err != nil { + return fmt.Errorf("failed to create stdout metric exporter: %w", err) + } + opts = append(opts, otelconf.WithMeterProviderOptions( + metricsdk.WithReader(metricsdk.NewPeriodicReader(exporter)), + )) + } + if extra.LogsFile != "" { + fmt.Printf("Initializing logs file: %s\n", extra.LogsFile) + logsFile, err := os.OpenFile(extra.LogsFile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644) + if err != nil { + return fmt.Errorf("failed to open logs file: %w", err) + } + shutdownFuncs = append(shutdownFuncs, func(ctx context.Context) error { + if err := logsFile.Close(); err != nil { + return fmt.Errorf("failed to close logs file: %w", err) + } + return nil + }) + exporter, err := stdoutlog.New( + stdoutlog.WithWriter(logsFile), + //stdoutlog.WithPrettyPrint(), + ) + if err != nil { + return fmt.Errorf("failed to create stdout log exporter: %w", err) + } + opts = append(opts, otelconf.WithLoggerProviderOptions( + logsdk.WithProcessor(logsdk.NewBatchProcessor(exporter)), + )) + } + if extra.InstrumentHost { + fmt.Println("Initializing host instrumentation") + if err := host.Start(); err != nil { + return fmt.Errorf("failed to start host instrumentation: %w", err) + } + } + if extra.InstrumentRuntime { + fmt.Println("Initializing runtime instrumentation") + if err := runtime.Start(); err != nil { + return fmt.Errorf("failed to start runtime instrumentation: %w", err) + } + } + } + } else { + fmt.Printf("failed to parse cosmos extra config: %v\n", err) + } + + sdk, err = otelconf.NewSDK(opts...) + if err != nil { + return fmt.Errorf("failed to initialize telemetry: %w", err) + } + + // setup otel global providers + otel.SetTracerProvider(sdk.TracerProvider()) + otel.SetMeterProvider(sdk.MeterProvider()) + logglobal.SetLoggerProvider(sdk.LoggerProvider()) + // setup slog default provider so that any logs emitted the default slog will be traced + slog.SetDefault(otelslog.NewLogger("", otelslog.WithSource(true))) + // emit an initialized message which verifies basic telemetry is working + slog.Info("Telemetry initialized") + + // setup go-metrics compatibility layer + _, err = metrics.NewGlobal(metrics.DefaultConfig("cosmos-sdk"), newOtelGoMetricsSink( + context.Background(), + sdk.MeterProvider().Meter("gometrics"), + )) + if err != nil { + return fmt.Errorf("failed to initialize go-metrics compatibility layer: %w", err) + } + + return nil +} + +type extraConfig struct { + CosmosExtra *cosmosExtra `json:"cosmos_extra" yaml:"cosmos_extra" mapstructure:"cosmos_extra"` +} + +type cosmosExtra struct { + TraceFile string `json:"trace_file" yaml:"trace_file" mapstructure:"trace_file"` + MetricsFile string `json:"metrics_file" yaml:"metrics_file" mapstructure:"metrics_file"` + LogsFile string `json:"logs_file" yaml:"logs_file" mapstructure:"logs_file"` + InstrumentHost bool `json:"instrument_host" yaml:"instrument_host" mapstructure:"instrument_host"` + InstrumentRuntime bool `json:"instrument_runtime" yaml:"instrument_runtime" mapstructure:"instrument_runtime"` +} + +func Shutdown(ctx context.Context) error { + err := sdk.Shutdown(ctx) + if err != nil { + return fmt.Errorf("failed to shutdown telemetry: %w", err) + } + for _, f := range shutdownFuncs { + if err := f(ctx); err != nil { + return fmt.Errorf("failed to shutdown telemetry: %w", err) + } + } + return nil +} diff --git a/telemetry/wrapper.go b/telemetry/wrapper.go index 1d28e8af4d73..50ca00c3d64a 100644 --- a/telemetry/wrapper.go +++ b/telemetry/wrapper.go @@ -1,16 +1,11 @@ package telemetry import ( - "sync" "time" "github.com/hashicorp/go-metrics" - "go.opentelemetry.io/otel" - "go.opentelemetry.io/otel/metric" ) -var globalLabels []metrics.Label - // Common metric key constants const ( MetricKeyPreBlocker = "pre_blocker" @@ -19,17 +14,6 @@ const ( MetricLabelNameModule = "module" ) -var meter = otel.Meter("cosmos-sdk") -var mtx sync.RWMutex -var counters map[string]metric.Float64Counter -var gauges map[string]metric.Float64Gauge -var histograms map[string]metric.Float64Histogram - -type Label struct { - Name string - Value string -} - // NewLabel creates a new instance of Label with name and value func NewLabel(name, value string) metrics.Label { return metrics.Label{Name: name, Value: value} @@ -50,7 +34,7 @@ func ModuleMeasureSince(module string, start time.Time, keys ...string) { ) } -// ModuleSetGauge provides a short hand method for emitting a gauge metric for a +// Deprecated: ModuleSetGauge provides a short hand method for emitting a gauge metric for a // module with a given set of keys. If any global labels are defined, they will // be added to the module label. func ModuleSetGauge(module string, val float32, keys ...string) { @@ -65,7 +49,7 @@ func ModuleSetGauge(module string, val float32, keys ...string) { ) } -// IncrCounter provides a wrapper functionality for emitting a counter metric with +// Deprecated: IncrCounter provides a wrapper functionality for emitting a counter metric with // global labels (if any). func IncrCounter(val float32, keys ...string) { if !IsTelemetryEnabled() { @@ -75,7 +59,7 @@ func IncrCounter(val float32, keys ...string) { metrics.IncrCounterWithLabels(keys, val, globalLabels) } -// IncrCounterWithLabels provides a wrapper functionality for emitting a counter +// Deprecated: IncrCounterWithLabels provides a wrapper functionality for emitting a counter // metric with global labels (if any) along with the provided labels. func IncrCounterWithLabels(keys []string, val float32, labels []metrics.Label) { if !IsTelemetryEnabled() { @@ -85,7 +69,7 @@ func IncrCounterWithLabels(keys []string, val float32, labels []metrics.Label) { metrics.IncrCounterWithLabels(keys, val, append(labels, globalLabels...)) } -// SetGauge provides a wrapper functionality for emitting a gauge metric with +// Deprecated: SetGauge provides a wrapper functionality for emitting a gauge metric with // global labels (if any). func SetGauge(val float32, keys ...string) { if !IsTelemetryEnabled() { @@ -95,7 +79,7 @@ func SetGauge(val float32, keys ...string) { metrics.SetGaugeWithLabels(keys, val, globalLabels) } -// SetGaugeWithLabels provides a wrapper functionality for emitting a gauge +// Deprecated: SetGaugeWithLabels provides a wrapper functionality for emitting a gauge // metric with global labels (if any) along with the provided labels. func SetGaugeWithLabels(keys []string, val float32, labels []metrics.Label) { if !IsTelemetryEnabled() { @@ -105,7 +89,7 @@ func SetGaugeWithLabels(keys []string, val float32, labels []metrics.Label) { metrics.SetGaugeWithLabels(keys, val, append(labels, globalLabels...)) } -// MeasureSince provides a wrapper functionality for emitting a time measure +// Deprecated: MeasureSince provides a wrapper functionality for emitting a time measure // metric with global labels (if any). func MeasureSince(start time.Time, keys ...string) { if !IsTelemetryEnabled() { @@ -115,7 +99,7 @@ func MeasureSince(start time.Time, keys ...string) { metrics.MeasureSinceWithLabels(keys, start.UTC(), globalLabels) } -// Now return the current time if telemetry is enabled or a zero time if it's not +// Deprecated: Now return the current time if telemetry is enabled or a zero time if it's not func Now() time.Time { if !IsTelemetryEnabled() { return time.Time{} diff --git a/telemetry/wrapper_test.go b/telemetry/wrapper_test.go new file mode 100644 index 000000000000..5388839874bc --- /dev/null +++ b/telemetry/wrapper_test.go @@ -0,0 +1,51 @@ +package telemetry + +import ( + "sync" + "testing" + "time" + + "github.com/stretchr/testify/assert" +) + +var mu sync.Mutex + +func initTelemetry(v bool) { + globalTelemetryEnabled = v +} + +// Reset the global state to a known disabled state before each test. +func setupTest(t *testing.T) { + t.Helper() + mu.Lock() // Ensure no other test can modify global state at the same time. + defer mu.Unlock() + initTelemetry(false) +} + +// TestNow tests the Now function when telemetry is enabled and disabled. +func TestNow(t *testing.T) { + setupTest(t) // Locks the mutex to avoid race condition. + + initTelemetry(true) + telemetryTime := Now() + assert.NotEqual(t, time.Time{}, telemetryTime, "Now() should not return zero time when telemetry is enabled") + + setupTest(t) // Reset the global state and lock the mutex again. + + initTelemetry(false) + telemetryTime = Now() + assert.Equal(t, time.Time{}, telemetryTime, "Now() should return zero time when telemetry is disabled") +} + +// TestIsTelemetryEnabled tests the IsTelemetryEnabled function. +func TestIsTelemetryEnabled(t *testing.T) { + setupTest(t) // Locks the mutex to avoid race condition. + + initTelemetry(true) + assert.True(t, IsTelemetryEnabled(), "IsTelemetryEnabled() should return true when globalTelemetryEnabled is set to true") + + setupTest(t) // Reset the global state and lock the mutex again. + + initTelemetry(false) + assert.False(t, IsTelemetryEnabled(), "IsTelemetryEnabled() should return false when globalTelemetryEnabled is set to false") +} From 06e124581fcb8e88d6c0fd5cc71ef38efb0997d3 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Thu, 6 Nov 2025 18:34:04 -0500 Subject: [PATCH 31/52] bring back server telemetry config, revert unrelated changes --- server/api/server.go | 29 +++++++++++++++++++++++++++++ server/config/config.go | 21 +++++++++++++-------- server/start.go | 29 +++++++++++++++++++++++------ testutil/network/network.go | 4 ++-- types/simulation/config.go | 1 - x/simulation/client/cli/flags.go | 3 --- 6 files changed, 67 insertions(+), 20 deletions(-) diff --git a/server/api/server.go b/server/api/server.go index 5a107edd4a9f..180775c34099 100644 --- a/server/api/server.go +++ b/server/api/server.go @@ -2,6 +2,7 @@ package api import ( "context" + "fmt" "net" "net/http" "strings" @@ -23,6 +24,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec/legacy" "github.com/cosmos/cosmos-sdk/server/config" cmtlogwrapper "github.com/cosmos/cosmos-sdk/server/log" + "github.com/cosmos/cosmos-sdk/telemetry" grpctypes "github.com/cosmos/cosmos-sdk/types/grpc" ) @@ -33,6 +35,7 @@ type Server struct { ClientCtx client.Context GRPCSrv *grpc.Server logger log.Logger + metrics *telemetry.Metrics // Start() is blocking and generally called from a separate goroutine. // Close() can be called asynchronously and access shared memory @@ -188,6 +191,32 @@ func (s *Server) Close() error { return s.listener.Close() } +// Deprecated +func (s *Server) SetTelemetry(m *telemetry.Metrics) { + s.mtx.Lock() + s.registerMetrics(m) + s.mtx.Unlock() +} + +func (s *Server) registerMetrics(m *telemetry.Metrics) { + s.metrics = m + + metricsHandler := func(w http.ResponseWriter, r *http.Request) { + format := strings.TrimSpace(r.FormValue("format")) + + gr, err := s.metrics.Gather(format) + if err != nil { + writeErrorResponse(w, http.StatusBadRequest, fmt.Sprintf("failed to gather metrics: %s", err)) + return + } + + w.Header().Set("Content-Type", gr.ContentType) + _, _ = w.Write(gr.Metrics) + } + + s.Router.HandleFunc("/metrics", metricsHandler).Methods("GET") +} + // errorResponse defines the attributes of a JSON error response. type errorResponse struct { Code int `json:"code,omitempty"` diff --git a/server/config/config.go b/server/config/config.go index c9fa4351a087..15c9343599fc 100644 --- a/server/config/config.go +++ b/server/config/config.go @@ -8,7 +8,7 @@ import ( pruningtypes "cosmossdk.io/store/pruning/types" - _ "github.com/cosmos/cosmos-sdk/telemetry" + "github.com/cosmos/cosmos-sdk/telemetry" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) @@ -189,13 +189,14 @@ type ( type Config struct { BaseConfig `mapstructure:",squash"` - // Telemetry defines the application telemetry configuration - API APIConfig `mapstructure:"api"` - GRPC GRPCConfig `mapstructure:"grpc"` - GRPCWeb GRPCWebConfig `mapstructure:"grpc-web"` - StateSync StateSyncConfig `mapstructure:"state-sync"` - Streaming StreamingConfig `mapstructure:"streaming"` - Mempool MempoolConfig `mapstructure:"mempool"` + // Deprecated: Telemetry defines the application telemetry configuration + Telemetry telemetry.Config `mapstructure:"telemetry"` + API APIConfig `mapstructure:"api"` + GRPC GRPCConfig `mapstructure:"grpc"` + GRPCWeb GRPCWebConfig `mapstructure:"grpc-web"` + StateSync StateSyncConfig `mapstructure:"state-sync"` + Streaming StreamingConfig `mapstructure:"streaming"` + Mempool MempoolConfig `mapstructure:"mempool"` } // SetMinGasPrices sets the validator's minimum gas prices. @@ -233,6 +234,10 @@ func DefaultConfig() *Config { IAVLDisableFastNode: false, AppDBBackend: "", }, + Telemetry: telemetry.Config{ + Enabled: false, + GlobalLabels: [][]string{}, + }, API: APIConfig{ Enable: false, Swagger: false, diff --git a/server/start.go b/server/start.go index 36e874ea2ab4..f942cd2a3b0c 100644 --- a/server/start.go +++ b/server/start.go @@ -230,15 +230,20 @@ func start(svrCtx *Context, clientCtx client.Context, appCreator types.AppCreato } defer appCleanupFn() + metrics, err := startTelemetry(svrCfg) + if err != nil { + return fmt.Errorf("failed to start telemetry: %w", err) + } + emitServerInfoMetrics() if !withCmt { - return startStandAlone(svrCtx, svrCfg, clientCtx, app, opts) + return startStandAlone(svrCtx, svrCfg, clientCtx, app, metrics, opts) } - return startInProcess(svrCtx, svrCfg, clientCtx, app, opts) + return startInProcess(svrCtx, svrCfg, clientCtx, app, metrics, opts) } -func startStandAlone(svrCtx *Context, svrCfg serverconfig.Config, clientCtx client.Context, app types.Application, opts StartCmdOptions) error { +func startStandAlone(svrCtx *Context, svrCfg serverconfig.Config, clientCtx client.Context, app types.Application, metrics *telemetry.Metrics, opts StartCmdOptions) error { addr := svrCtx.Viper.GetString(flagAddress) transport := svrCtx.Viper.GetString(flagTransport) @@ -277,7 +282,7 @@ func startStandAlone(svrCtx *Context, svrCfg serverconfig.Config, clientCtx clie return err } - err = startAPIServer(ctx, g, svrCfg, clientCtx, svrCtx, app, svrCtx.Config.RootDir, grpcSrv) + err = startAPIServer(ctx, g, svrCfg, clientCtx, svrCtx, app, svrCtx.Config.RootDir, grpcSrv, metrics) if err != nil { return err } @@ -304,7 +309,9 @@ func startStandAlone(svrCtx *Context, svrCfg serverconfig.Config, clientCtx clie return g.Wait() } -func startInProcess(svrCtx *Context, svrCfg serverconfig.Config, clientCtx client.Context, app types.Application, opts StartCmdOptions) error { +func startInProcess(svrCtx *Context, svrCfg serverconfig.Config, clientCtx client.Context, app types.Application, + metrics *telemetry.Metrics, opts StartCmdOptions, +) error { cmtCfg := svrCtx.Config gRPCOnly := svrCtx.Viper.GetBool(flagGRPCOnly) @@ -341,7 +348,7 @@ func startInProcess(svrCtx *Context, svrCfg serverconfig.Config, clientCtx clien return fmt.Errorf("failed to start grpc server: %w", err) } - err = startAPIServer(ctx, g, svrCfg, clientCtx, svrCtx, app, cmtCfg.RootDir, grpcSrv) + err = startAPIServer(ctx, g, svrCfg, clientCtx, svrCtx, app, cmtCfg.RootDir, grpcSrv, metrics) if err != nil { return fmt.Errorf("failed to start api server: %w", err) } @@ -510,6 +517,7 @@ func startAPIServer( app types.Application, home string, grpcSrv *grpc.Server, + metrics *telemetry.Metrics, ) error { if !svrCfg.API.Enable { return nil @@ -520,12 +528,20 @@ func startAPIServer( apiSrv := api.New(clientCtx, svrCtx.Logger.With("module", "api-server"), grpcSrv) app.RegisterAPIRoutes(apiSrv, svrCfg.API) + if svrCfg.Telemetry.Enabled { + apiSrv.SetTelemetry(metrics) + } + g.Go(func() error { return apiSrv.Start(ctx, svrCfg) }) return nil } +func startTelemetry(cfg serverconfig.Config) (*telemetry.Metrics, error) { + return telemetry.New(cfg.Telemetry) +} + // wrapCPUProfile starts CPU profiling, if enabled, and executes the provided // callbackFn in a separate goroutine, then will wait for that callback to // return. @@ -608,6 +624,7 @@ func startApp(svrCtx *Context, appCreator types.AppCreator, opts StartCmdOptions cleanupFn = func() { traceCleanupFn() + // shutdown telemetry with a 5 second timeout shutdownCtx, _ := context.WithTimeout(context.Background(), 5*time.Second) if err := telemetry.Shutdown(shutdownCtx); err != nil { svrCtx.Logger.Error("failed to shutdown telemetry", "error", err) diff --git a/testutil/network/network.go b/testutil/network/network.go index d4a0dfc9efee..138b94bf77de 100644 --- a/testutil/network/network.go +++ b/testutil/network/network.go @@ -25,12 +25,11 @@ import ( "google.golang.org/grpc" "cosmossdk.io/depinject" + "cosmossdk.io/log" sdkmath "cosmossdk.io/math" "cosmossdk.io/math/unsafe" pruningtypes "cosmossdk.io/store/pruning/types" - "cosmossdk.io/log" - "github.com/cosmos/cosmos-sdk/baseapp" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/flags" @@ -378,6 +377,7 @@ func New(l Logger, baseDir string, cfg Config) (*Network, error) { appCfg.MinGasPrices = cfg.MinGasPrices appCfg.API.Enable = true appCfg.API.Swagger = false + appCfg.Telemetry.Enabled = false ctx := server.NewDefaultContext() cmtCfg := ctx.Config diff --git a/types/simulation/config.go b/types/simulation/config.go index b903ed3bc1f7..1e385fdfa1d6 100644 --- a/types/simulation/config.go +++ b/types/simulation/config.go @@ -16,7 +16,6 @@ type Config struct { InitialBlockHeight int // initial block to start the simulation GenesisTime int64 // genesis time to start the simulation NumBlocks int // number of new blocks to simulate from the initial block height - NumRuns int // number of times to run the simulation for simulations that have multiple runs BlockSize int // operations per block ChainID string // chain-id used on the simulation diff --git a/x/simulation/client/cli/flags.go b/x/simulation/client/cli/flags.go index c8552fec91bc..8479b83f5e1c 100644 --- a/x/simulation/client/cli/flags.go +++ b/x/simulation/client/cli/flags.go @@ -20,7 +20,6 @@ var ( FlagSeedValue int64 FlagInitialBlockHeightValue int FlagNumBlocksValue int - FlagNumRunsValue int FlagBlockSizeValue int FlagLeanValue bool FlagCommitValue bool @@ -52,7 +51,6 @@ func GetSimulatorFlags() { flag.StringVar(&FlagExportStatsPathValue, "ExportStatsPath", "", "custom file path to save the exported simulation statistics JSON") flag.Int64Var(&FlagSeedValue, "Seed", DefaultSeedValue, "simulation random seed") flag.IntVar(&FlagInitialBlockHeightValue, "InitialBlockHeight", 1, "initial block to start the simulation") - flag.IntVar(&FlagNumRunsValue, "NumRuns", 3, "number of runs to run for simulations that do multiple runs at once") flag.IntVar(&FlagNumBlocksValue, "NumBlocks", 500, "number of new blocks to simulate from the initial block height") flag.IntVar(&FlagBlockSizeValue, "BlockSize", 200, "operations per block") flag.BoolVar(&FlagLeanValue, "Lean", false, "lean simulation log output") @@ -83,7 +81,6 @@ func NewConfigFromFlags() simulation.Config { Seed: FlagSeedValue, InitialBlockHeight: FlagInitialBlockHeightValue, GenesisTime: FlagGenesisTimeValue, - NumRuns: FlagNumRunsValue, NumBlocks: FlagNumBlocksValue, BlockSize: FlagBlockSizeValue, Lean: FlagLeanValue, From cf720f95643d756085e539599743ef1ef35d81ef Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Thu, 6 Nov 2025 18:39:37 -0500 Subject: [PATCH 32/52] address review comments, remove timing histograms --- baseapp/abci.go | 5 ++--- baseapp/baseapp.go | 30 ++++-------------------------- 2 files changed, 6 insertions(+), 29 deletions(-) diff --git a/baseapp/abci.go b/baseapp/abci.go index ae5f6f888818..1f30a8443907 100644 --- a/baseapp/abci.go +++ b/baseapp/abci.go @@ -156,7 +156,8 @@ func (app *BaseApp) Info(_ *abci.RequestInfo) (*abci.ResponseInfo, error) { // Query implements the ABCI interface. It delegates to CommitMultiStore if it // implements Queryable. func (app *BaseApp) Query(ctx context.Context, req *abci.RequestQuery) (resp *abci.ResponseQuery, err error) { - ctx, span := tracer.Start(ctx, "Query") + // TODO: propagate context with span into the sdk.Context used for queries + _, span := tracer.Start(ctx, "Query") defer span.End() // add panic recovery for all queries @@ -1034,8 +1035,6 @@ func (app *BaseApp) Commit() (*abci.ResponseCommit, error) { app.snapshotManager.SnapshotIfApplicable(header.Height) blockCnt.Add(ctx, 1) - blockTime.Record(ctx, time.Since(app.blockStartTime).Seconds()) - app.blockStartTime = time.Now() return resp, nil } diff --git a/baseapp/baseapp.go b/baseapp/baseapp.go index 89a74b748fc6..4fcfd9e8f52e 100644 --- a/baseapp/baseapp.go +++ b/baseapp/baseapp.go @@ -7,7 +7,6 @@ import ( "slices" "strconv" "sync" - "time" "github.com/cockroachdb/errors" abci "github.com/cometbft/cometbft/abci/types" @@ -66,12 +65,10 @@ const ( var _ servertypes.ABCI = (*BaseApp)(nil) var ( - tracer = otel.Tracer("cosmos-sdk/baseapp") - meter = otel.Meter("cosmos-sdk/baseapp") - blockCnt metric.Int64Counter - txCnt metric.Int64Counter - blockTime metric.Float64Histogram - txTime metric.Int64Histogram + tracer = otel.Tracer("cosmos-sdk/baseapp") + meter = otel.Meter("cosmos-sdk/baseapp") + blockCnt metric.Int64Counter + txCnt metric.Int64Counter ) func init() { @@ -84,20 +81,6 @@ func init() { if err != nil { panic(err) } - blockTime, err = meter.Float64Histogram("block.time", - metric.WithUnit("s"), - metric.WithDescription("Block time in seconds"), - ) - if err != nil { - panic(err) - } - txTime, err = meter.Int64Histogram("tx.time", - metric.WithUnit("us"), - metric.WithDescription("Transaction time in microseconds"), - ) - if err != nil { - panic(err) - } } // BaseApp reflects the ABCI application implementation. @@ -205,8 +188,6 @@ type BaseApp struct { // Optional alternative tx runner, used for block-stm parallel transaction execution. If nil, default txRunner is used. txRunner sdk.TxRunner - - blockStartTime time.Time } // NewBaseApp returns a reference to an initialized BaseApp. It accepts a @@ -227,7 +208,6 @@ func NewBaseApp( fauxMerkleMode: false, sigverifyTx: true, gasConfig: config.GasConfig{QueryGasLimit: math.MaxUint64}, - blockStartTime: time.Now(), } // initialize tracer @@ -827,7 +807,6 @@ func (app *BaseApp) endBlock() (sdk.EndBlock, error) { // both txbytes and the decoded tx are passed to runTx to avoid the state machine encoding the tx and decoding the transaction twice // passing the decoded tx to runTX is optional, it will be decoded if the tx is nil func (app *BaseApp) RunTx(mode sdk.ExecMode, txBytes []byte, tx sdk.Tx, txIndex int, txMultiStore storetypes.MultiStore, incarnationCache map[string]any) (gInfo sdk.GasInfo, result *sdk.Result, anteEvents []abci.Event, err error) { - startTime := time.Now() ctx := app.getContextForTx(mode, txBytes, txIndex) ctx, span := ctx.StartSpan(tracer, "runTx") defer span.End() @@ -1013,7 +992,6 @@ func (app *BaseApp) RunTx(mode sdk.ExecMode, txBytes []byte, tx sdk.Tx, txIndex msCache.Write() txCnt.Add(ctx, 1) - txTime.Record(ctx, time.Since(startTime).Microseconds()) } if len(anteEvents) > 0 && (mode == execModeFinalize || mode == execModeSimulate) { From 743fdc926db7468d1f2e8b250ef8d962618d8bcf Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Thu, 6 Nov 2025 18:40:59 -0500 Subject: [PATCH 33/52] support otel routing through legacy metrics config --- telemetry/metrics.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/telemetry/metrics.go b/telemetry/metrics.go index 240cbdda5f69..0168cf9bb0ff 100644 --- a/telemetry/metrics.go +++ b/telemetry/metrics.go @@ -2,6 +2,7 @@ package telemetry import ( "bytes" + "context" "encoding/json" "errors" "fmt" @@ -13,6 +14,7 @@ import ( metricsprom "github.com/hashicorp/go-metrics/prometheus" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/common/expfmt" + "go.opentelemetry.io/otel" ) // globalTelemetryEnabled is a private variable that stores the telemetry enabled state. @@ -90,6 +92,7 @@ type Config struct { GlobalLabels [][]string `mapstructure:"global-labels"` // MetricsSink defines the type of metrics backend to use. + // Can be one of "mem", "statsd", "dogstatsd", or "otel". MetricsSink string `mapstructure:"metrics-sink" default:"mem"` // StatsdAddr defines the address of a statsd server to send metrics to. @@ -145,6 +148,8 @@ func New(cfg Config) (_ *Metrics, rerr error) { sink, err = metrics.NewStatsdSink(cfg.StatsdAddr) case MetricSinkDogsStatsd: sink, err = datadog.NewDogStatsdSink(cfg.StatsdAddr, cfg.DatadogHostname) + case MetricSinkOtel: + sink = newOtelGoMetricsSink(context.Background(), otel.Meter("gometrics")) default: memSink := metrics.NewInmemSink(10*time.Second, time.Minute) sink = memSink From 5bfe1920485358b256f5a20ea0b7f4183822d727 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Thu, 6 Nov 2025 18:46:29 -0500 Subject: [PATCH 34/52] go mod tidy, bring in additional config from iavlx branch --- client/v2/go.mod | 1 + client/v2/go.sum | 1 + go.mod | 5 +++-- go.sum | 1 + simapp/go.mod | 1 + simapp/go.sum | 1 + systemtests/go.mod | 1 + systemtests/go.sum | 1 + telemetry/{otel.go => config.go} | 26 ++++++++++++++++++++------ tests/go.mod | 1 + tests/go.sum | 1 + tests/systemtests/go.mod | 1 + tests/systemtests/go.sum | 1 + 13 files changed, 34 insertions(+), 8 deletions(-) rename telemetry/{otel.go => config.go} (83%) diff --git a/client/v2/go.mod b/client/v2/go.mod index fade216223a1..321682f3c590 100644 --- a/client/v2/go.mod +++ b/client/v2/go.mod @@ -30,6 +30,7 @@ require ( filippo.io/edwards25519 v1.1.0 // indirect github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect github.com/99designs/keyring v1.2.1 // indirect + github.com/DataDog/datadog-go v3.2.0+incompatible // indirect github.com/DataDog/zstd v1.5.7 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bgentry/speakeasy v0.2.0 // indirect diff --git a/client/v2/go.sum b/client/v2/go.sum index 828f67f134f2..6d1c5151e1cd 100644 --- a/client/v2/go.sum +++ b/client/v2/go.sum @@ -29,6 +29,7 @@ github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25 github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/DataDog/datadog-go v3.2.0+incompatible h1:qSG2N4FghB1He/r2mFrWKCaL7dXCilEuNEeAn20fdD4= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/DataDog/zstd v1.5.7 h1:ybO8RBeh29qrxIhCA9E8gKY6xfONU9T6G6aP9DTKfLE= github.com/DataDog/zstd v1.5.7/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= diff --git a/go.mod b/go.mod index 3aa6d7e33b9a..3b98b05d457a 100644 --- a/go.mod +++ b/go.mod @@ -46,6 +46,8 @@ require ( github.com/manifoldco/promptui v0.9.0 github.com/mattn/go-isatty v0.0.20 github.com/mdp/qrterminal/v3 v3.2.1 + github.com/prometheus/client_golang v1.23.2 + github.com/prometheus/common v0.67.1 github.com/rs/zerolog v1.34.0 github.com/spf13/cast v1.10.0 github.com/spf13/cobra v1.10.1 @@ -93,6 +95,7 @@ require ( cosmossdk.io/schema v1.1.0 // indirect filippo.io/edwards25519 v1.1.0 // indirect github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect + github.com/DataDog/datadog-go v3.2.0+incompatible // indirect github.com/DataDog/zstd v1.5.7 // indirect github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.29.0 // indirect github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.53.0 // indirect @@ -203,9 +206,7 @@ require ( github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect - github.com/prometheus/client_golang v1.23.2 // indirect github.com/prometheus/client_model v0.6.2 // indirect - github.com/prometheus/common v0.67.1 // indirect github.com/prometheus/otlptranslator v0.0.2 // indirect github.com/prometheus/procfs v0.17.0 // indirect github.com/rcrowley/go-metrics v0.0.0-20250401214520-65e299d6c5c9 // indirect diff --git a/go.sum b/go.sum index 6c09a18f602f..eadab82ec068 100644 --- a/go.sum +++ b/go.sum @@ -51,6 +51,7 @@ github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25 github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/DataDog/datadog-go v3.2.0+incompatible h1:qSG2N4FghB1He/r2mFrWKCaL7dXCilEuNEeAn20fdD4= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/DataDog/zstd v1.5.7 h1:ybO8RBeh29qrxIhCA9E8gKY6xfONU9T6G6aP9DTKfLE= github.com/DataDog/zstd v1.5.7/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= diff --git a/simapp/go.mod b/simapp/go.mod index 8617152ebf7d..b7663deab28e 100644 --- a/simapp/go.mod +++ b/simapp/go.mod @@ -41,6 +41,7 @@ require ( filippo.io/edwards25519 v1.1.0 // indirect github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect github.com/99designs/keyring v1.2.2 // indirect + github.com/DataDog/datadog-go v3.2.0+incompatible // indirect github.com/DataDog/zstd v1.5.7 // indirect github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.29.0 // indirect github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.53.0 // indirect diff --git a/simapp/go.sum b/simapp/go.sum index 8eb6ccc6a86e..885449bc1cb4 100644 --- a/simapp/go.sum +++ b/simapp/go.sum @@ -55,6 +55,7 @@ github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25 github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/DataDog/datadog-go v3.2.0+incompatible h1:qSG2N4FghB1He/r2mFrWKCaL7dXCilEuNEeAn20fdD4= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/DataDog/zstd v1.5.7 h1:ybO8RBeh29qrxIhCA9E8gKY6xfONU9T6G6aP9DTKfLE= github.com/DataDog/zstd v1.5.7/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= diff --git a/systemtests/go.mod b/systemtests/go.mod index f14bfd6ae28f..f22b533ca023 100644 --- a/systemtests/go.mod +++ b/systemtests/go.mod @@ -26,6 +26,7 @@ require ( filippo.io/edwards25519 v1.1.0 // indirect github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect github.com/99designs/keyring v1.2.1 // indirect + github.com/DataDog/datadog-go v3.2.0+incompatible // indirect github.com/DataDog/zstd v1.5.7 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bgentry/speakeasy v0.2.0 // indirect diff --git a/systemtests/go.sum b/systemtests/go.sum index c7669a93f985..c9c8e43578fc 100644 --- a/systemtests/go.sum +++ b/systemtests/go.sum @@ -31,6 +31,7 @@ github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25 github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/DataDog/datadog-go v3.2.0+incompatible h1:qSG2N4FghB1He/r2mFrWKCaL7dXCilEuNEeAn20fdD4= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/DataDog/zstd v1.5.7 h1:ybO8RBeh29qrxIhCA9E8gKY6xfONU9T6G6aP9DTKfLE= github.com/DataDog/zstd v1.5.7/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= diff --git a/telemetry/otel.go b/telemetry/config.go similarity index 83% rename from telemetry/otel.go rename to telemetry/config.go index e80b1cebd28a..e7c96d05c78f 100644 --- a/telemetry/otel.go +++ b/telemetry/config.go @@ -6,6 +6,7 @@ import ( "fmt" "log/slog" "os" + "time" "github.com/hashicorp/go-metrics" "go.opentelemetry.io/contrib/bridges/otelslog" @@ -109,8 +110,20 @@ func doInit() error { if err != nil { return fmt.Errorf("failed to create stdout metric exporter: %w", err) } + + // Configure periodic reader with custom interval if specified + readerOpts := []metricsdk.PeriodicReaderOption{} + if extra.MetricsFileInterval != "" { + interval, err := time.ParseDuration(extra.MetricsFileInterval) + if err != nil { + return fmt.Errorf("failed to parse metrics_file_interval: %w", err) + } + fmt.Printf("Configuring metrics export interval: %v\n", interval) + readerOpts = append(readerOpts, metricsdk.WithInterval(interval)) + } + opts = append(opts, otelconf.WithMeterProviderOptions( - metricsdk.WithReader(metricsdk.NewPeriodicReader(exporter)), + metricsdk.WithReader(metricsdk.NewPeriodicReader(exporter, readerOpts...)), )) } if extra.LogsFile != "" { @@ -184,11 +197,12 @@ type extraConfig struct { } type cosmosExtra struct { - TraceFile string `json:"trace_file" yaml:"trace_file" mapstructure:"trace_file"` - MetricsFile string `json:"metrics_file" yaml:"metrics_file" mapstructure:"metrics_file"` - LogsFile string `json:"logs_file" yaml:"logs_file" mapstructure:"logs_file"` - InstrumentHost bool `json:"instrument_host" yaml:"instrument_host" mapstructure:"instrument_host"` - InstrumentRuntime bool `json:"instrument_runtime" yaml:"instrument_runtime" mapstructure:"instrument_runtime"` + TraceFile string `json:"trace_file" yaml:"trace_file" mapstructure:"trace_file"` + MetricsFile string `json:"metrics_file" yaml:"metrics_file" mapstructure:"metrics_file"` + MetricsFileInterval string `json:"metrics_file_interval" yaml:"metrics_file_interval" mapstructure:"metrics_file_interval"` + LogsFile string `json:"logs_file" yaml:"logs_file" mapstructure:"logs_file"` + InstrumentHost bool `json:"instrument_host" yaml:"instrument_host" mapstructure:"instrument_host"` + InstrumentRuntime bool `json:"instrument_runtime" yaml:"instrument_runtime" mapstructure:"instrument_runtime"` } func Shutdown(ctx context.Context) error { diff --git a/tests/go.mod b/tests/go.mod index 6b84edfe74fc..3d121e7da389 100644 --- a/tests/go.mod +++ b/tests/go.mod @@ -44,6 +44,7 @@ require ( filippo.io/edwards25519 v1.1.0 // indirect github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect github.com/99designs/keyring v1.2.2 // indirect + github.com/DataDog/datadog-go v3.2.0+incompatible // indirect github.com/DataDog/zstd v1.5.7 // indirect github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.29.0 // indirect github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.53.0 // indirect diff --git a/tests/go.sum b/tests/go.sum index d603bf72895e..16316b14ae95 100644 --- a/tests/go.sum +++ b/tests/go.sum @@ -53,6 +53,7 @@ github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25 github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/DataDog/datadog-go v3.2.0+incompatible h1:qSG2N4FghB1He/r2mFrWKCaL7dXCilEuNEeAn20fdD4= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/DataDog/zstd v1.5.7 h1:ybO8RBeh29qrxIhCA9E8gKY6xfONU9T6G6aP9DTKfLE= github.com/DataDog/zstd v1.5.7/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= diff --git a/tests/systemtests/go.mod b/tests/systemtests/go.mod index 1be332b45516..b7d7566e3a77 100644 --- a/tests/systemtests/go.mod +++ b/tests/systemtests/go.mod @@ -30,6 +30,7 @@ require ( filippo.io/edwards25519 v1.1.0 // indirect github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect github.com/99designs/keyring v1.2.2 // indirect + github.com/DataDog/datadog-go v3.2.0+incompatible // indirect github.com/DataDog/zstd v1.5.7 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bgentry/speakeasy v0.2.0 // indirect diff --git a/tests/systemtests/go.sum b/tests/systemtests/go.sum index 10cd941213c7..21c2b6c2431e 100644 --- a/tests/systemtests/go.sum +++ b/tests/systemtests/go.sum @@ -29,6 +29,7 @@ github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25 github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/DataDog/datadog-go v3.2.0+incompatible h1:qSG2N4FghB1He/r2mFrWKCaL7dXCilEuNEeAn20fdD4= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/DataDog/zstd v1.5.7 h1:ybO8RBeh29qrxIhCA9E8gKY6xfONU9T6G6aP9DTKfLE= github.com/DataDog/zstd v1.5.7/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= From 4f507097eb5986294f099f5a0df3a2c3a6f74416 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Thu, 6 Nov 2025 19:36:29 -0500 Subject: [PATCH 35/52] revert unrelated changes --- simapp/app_di.go | 2 +- simapp/sim_test.go | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/simapp/app_di.go b/simapp/app_di.go index fdb393e1b6a0..972edc75fa1a 100644 --- a/simapp/app_di.go +++ b/simapp/app_di.go @@ -9,9 +9,9 @@ import ( clienthelpers "cosmossdk.io/client/v2/helpers" "cosmossdk.io/depinject" + "cosmossdk.io/log" storetypes "cosmossdk.io/store/types" - "cosmossdk.io/log" "github.com/cosmos/cosmos-sdk/baseapp" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/codec" diff --git a/simapp/sim_test.go b/simapp/sim_test.go index 4f2bf6ad95f0..012c016146a3 100644 --- a/simapp/sim_test.go +++ b/simapp/sim_test.go @@ -19,7 +19,6 @@ import ( "github.com/stretchr/testify/require" "cosmossdk.io/log" - "cosmossdk.io/store" storetypes "cosmossdk.io/store/types" @@ -163,10 +162,9 @@ func IsEmptyValidatorSetErr(err error) bool { } func TestAppStateDeterminism(t *testing.T) { - cfg := simcli.NewConfigFromFlags() - numTimesToRunPerSeed := cfg.NumRuns + const numTimesToRunPerSeed = 3 var seeds []int64 - if s := cfg.Seed; s != simcli.DefaultSeedValue { + if s := simcli.NewConfigFromFlags().Seed; s != simcli.DefaultSeedValue { // We will be overriding the random seed and just run a single simulation on the provided seed value for j := 0; j < numTimesToRunPerSeed; j++ { // multiple rounds seeds = append(seeds, s) From c3e781dad4e78d233d665c6dbe9021c81631ec2c Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Fri, 7 Nov 2025 14:06:22 -0500 Subject: [PATCH 36/52] bug fix & better go-metric -> otel naming --- telemetry/config.go | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/telemetry/config.go b/telemetry/config.go index e7c96d05c78f..3fdbd5c6754f 100644 --- a/telemetry/config.go +++ b/telemetry/config.go @@ -180,14 +180,28 @@ func doInit() error { // emit an initialized message which verifies basic telemetry is working slog.Info("Telemetry initialized") + // extract service name from config for go-metrics compatibility layer + serviceName := "cosmos-sdk" // default fallback + if cfg.Resource != nil && cfg.Resource.Attributes != nil { + for _, attr := range cfg.Resource.Attributes { + if attr.Name == "service.name" { + if svcNameStr, ok := attr.Value.(string); ok { + serviceName = svcNameStr + } + break + } + } + } + // setup go-metrics compatibility layer - _, err = metrics.NewGlobal(metrics.DefaultConfig("cosmos-sdk"), newOtelGoMetricsSink( + _, err = metrics.NewGlobal(metrics.DefaultConfig(serviceName), newOtelGoMetricsSink( context.Background(), sdk.MeterProvider().Meter("gometrics"), )) if err != nil { return fmt.Errorf("failed to initialize go-metrics compatibility layer: %w", err) } + globalTelemetryEnabled = true return nil } From 6ddac1d00276f2ccf5076a4742010b6415a9c277 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Mon, 10 Nov 2025 19:20:03 -0500 Subject: [PATCH 37/52] propagate context better and add some basic tracing for grpc queries --- baseapp/abci.go | 15 +++++++++++---- baseapp/state/manager.go | 18 ++++++++++++++++++ baseapp/state/state.go | 3 +++ 3 files changed, 32 insertions(+), 4 deletions(-) diff --git a/baseapp/abci.go b/baseapp/abci.go index 1f30a8443907..df3efaf83929 100644 --- a/baseapp/abci.go +++ b/baseapp/abci.go @@ -11,6 +11,8 @@ import ( abci "github.com/cometbft/cometbft/abci/types" cmtproto "github.com/cometbft/cometbft/proto/tendermint/types" "github.com/cosmos/gogoproto/proto" + otelattr "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/trace" "google.golang.org/grpc/codes" grpcstatus "google.golang.org/grpc/status" @@ -156,8 +158,9 @@ func (app *BaseApp) Info(_ *abci.RequestInfo) (*abci.ResponseInfo, error) { // Query implements the ABCI interface. It delegates to CommitMultiStore if it // implements Queryable. func (app *BaseApp) Query(ctx context.Context, req *abci.RequestQuery) (resp *abci.ResponseQuery, err error) { - // TODO: propagate context with span into the sdk.Context used for queries - _, span := tracer.Start(ctx, "Query") + ctx, span := tracer.Start(ctx, "Query", + trace.WithAttributes(otelattr.String("path", req.Path)), + ) defer span.End() // add panic recovery for all queries @@ -185,7 +188,7 @@ func (app *BaseApp) Query(ctx context.Context, req *abci.RequestQuery) (resp *ab // handle gRPC routes first rather than calling splitPath because '/' characters // are used as part of gRPC paths if grpcHandler := app.grpcQueryRouter.Route(req.Path); grpcHandler != nil { - return app.handleQueryGRPC(grpcHandler, req), nil + return app.handleQueryGRPC(grpcHandler, req, ctx), nil } path := SplitABCIQueryPath(req.Path) @@ -193,6 +196,7 @@ func (app *BaseApp) Query(ctx context.Context, req *abci.RequestQuery) (resp *ab return sdkerrors.QueryResult(errorsmod.Wrap(sdkerrors.ErrUnknownRequest, "no query path provided"), app.trace), nil } + // TODO: propagate context with span into the sdk.Context used for queries so that we can trace queries properly switch path[0] { case QueryPathApp: // "/app" prefix for special application queries @@ -1205,12 +1209,15 @@ func (app *BaseApp) getContextForProposal(ctx sdk.Context, height int64) sdk.Con return ctx } -func (app *BaseApp) handleQueryGRPC(handler GRPCQueryHandler, req *abci.RequestQuery) *abci.ResponseQuery { +func (app *BaseApp) handleQueryGRPC(handler GRPCQueryHandler, req *abci.RequestQuery, baseCtx context.Context) *abci.ResponseQuery { ctx, err := app.CreateQueryContext(req.Height, req.Prove) if err != nil { return sdkerrors.QueryResult(err, app.trace) } + // add base context for tracing + ctx = ctx.WithContext(baseCtx) + resp, err := handler(ctx, req) if err != nil { resp = sdkerrors.QueryResult(gRPCErrorToSDKError(err), app.trace) diff --git a/baseapp/state/manager.go b/baseapp/state/manager.go index fb8cb55e730f..6e8a1f901f32 100644 --- a/baseapp/state/manager.go +++ b/baseapp/state/manager.go @@ -5,6 +5,9 @@ import ( "sync" cmtproto "github.com/cometbft/cometbft/proto/tendermint/types" + "go.opentelemetry.io/otel" + otelattr "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/trace" "cosmossdk.io/core/header" "cosmossdk.io/log" @@ -14,6 +17,10 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ) +var ( + tracer = otel.Tracer("cosmos-sdk/baseapp") +) + type Manager struct { // volatile states: // @@ -107,6 +114,13 @@ func (mgr *Manager) SetState( mgr.processProposalState = baseState case sdk.ExecModeFinalize: + // add tracing span instrumentation here when the context is initialized for the block + baseState.ctx, baseState.span = baseState.ctx.StartSpan(tracer, "Block", + trace.WithAttributes( + otelattr.Int64("height", h.Height), + otelattr.Int64("time_unix_nano", h.Time.UnixNano()), + ), + ) mgr.finalizeBlockState = baseState default: @@ -129,6 +143,10 @@ func (mgr *Manager) ClearState(mode sdk.ExecMode) { mgr.processProposalState = nil case sdk.ExecModeFinalize: + // complete tracing span instrumentation here when the context is cleared for the block + if mgr.finalizeBlockState != nil { + mgr.finalizeBlockState.span.End() + } mgr.finalizeBlockState = nil default: diff --git a/baseapp/state/state.go b/baseapp/state/state.go index fedfe5b1fd62..7655e8f83c12 100644 --- a/baseapp/state/state.go +++ b/baseapp/state/state.go @@ -4,6 +4,7 @@ import ( "sync" storetypes "cosmossdk.io/store/types" + "go.opentelemetry.io/otel/trace" sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -13,6 +14,8 @@ type State struct { mtx sync.RWMutex ctx sdk.Context + + span trace.Span } func NewState(ctx sdk.Context, ms storetypes.CacheMultiStore) *State { From 70e8fa821f31c9ecc792be92d6c0a123b1d53fdd Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Tue, 11 Nov 2025 12:43:25 -0500 Subject: [PATCH 38/52] basic log unification --- baseapp/baseapp.go | 2 -- go.mod | 1 + log/go.mod | 11 +++++++++++ log/go.sum | 28 +++++++++++++++++++++++++++- log/logger.go | 12 +++++++++++- log/options.go | 10 ++++++++++ log/otel.go | 21 +++++++++++++++++++++ log/slog.go | 44 ++++++++++++++++++++++++++++++++++++++++++++ log/slog/logger.go | 35 +++-------------------------------- log/testing.go | 18 +++++++++++++++++- server/util.go | 17 +++++++++++++++-- telemetry/README.md | 31 ++++++++++++++++++++++++------- telemetry/config.go | 9 +++++++++ 13 files changed, 193 insertions(+), 46 deletions(-) create mode 100644 log/otel.go create mode 100644 log/slog.go diff --git a/baseapp/baseapp.go b/baseapp/baseapp.go index 4fcfd9e8f52e..b7ac2e3b07c7 100644 --- a/baseapp/baseapp.go +++ b/baseapp/baseapp.go @@ -210,8 +210,6 @@ func NewBaseApp( gasConfig: config.GasConfig{QueryGasLimit: math.MaxUint64}, } - // initialize tracer - for _, option := range options { option(app) } diff --git a/go.mod b/go.mod index 3b98b05d457a..70cb38954dd7 100644 --- a/go.mod +++ b/go.mod @@ -265,6 +265,7 @@ require ( // Here are the short-lived replace from the Cosmos SDK // Replace here are pending PRs, or version to be tagged +replace cosmossdk.io/log => ./log // Below are the long-lived replace of the Cosmos SDK replace ( diff --git a/log/go.mod b/log/go.mod index f8d2244b213a..ce56f2b02158 100644 --- a/log/go.mod +++ b/log/go.mod @@ -6,16 +6,27 @@ require ( github.com/bytedance/sonic v1.14.2 github.com/pkg/errors v0.9.1 github.com/rs/zerolog v1.34.0 + github.com/samber/slog-zerolog/v2 v2.9.0 + go.opentelemetry.io/otel/log v0.14.0 ) require ( github.com/bytedance/gopkg v0.1.3 // indirect github.com/bytedance/sonic/loader v0.4.0 // indirect github.com/cloudwego/base64x v0.1.6 // indirect + github.com/go-logr/logr v1.4.3 // indirect + github.com/go-logr/stdr v1.2.2 // indirect github.com/klauspost/cpuid/v2 v2.2.10 // indirect github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect + github.com/samber/lo v1.51.0 // indirect + github.com/samber/slog-common v0.19.0 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect + go.opentelemetry.io/auto/sdk v1.1.0 // indirect + go.opentelemetry.io/otel v1.38.0 // indirect + go.opentelemetry.io/otel/metric v1.38.0 // indirect + go.opentelemetry.io/otel/trace v1.38.0 // indirect golang.org/x/arch v0.22.0 // indirect golang.org/x/sys v0.37.0 // indirect + golang.org/x/text v0.22.0 // indirect ) diff --git a/log/go.sum b/log/go.sum index fa004f25b81c..235b945aa584 100644 --- a/log/go.sum +++ b/log/go.sum @@ -10,7 +10,14 @@ github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSV github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= +github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE= github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= @@ -27,6 +34,12 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0= github.com/rs/zerolog v1.34.0 h1:k43nTLIwcTVQAncfCw4KZ2VY6ukYoZaBPNOE8txlOeY= github.com/rs/zerolog v1.34.0/go.mod h1:bJsvje4Z08ROH4Nhs5iH600c3IkWhwp44iRc54W6wYQ= +github.com/samber/lo v1.51.0 h1:kysRYLbHy/MB7kQZf5DSN50JHmMsNEdeY24VzJFu7wI= +github.com/samber/lo v1.51.0/go.mod h1:4+MXEGsJzbKGaUEQFKBq2xtfuznW9oz/WrgyzMzRoM0= +github.com/samber/slog-common v0.19.0 h1:fNcZb8B2uOLooeYwFpAlKjkQTUafdjfqKcwcC89G9YI= +github.com/samber/slog-common v0.19.0/go.mod h1:dTz+YOU76aH007YUU0DffsXNsGFQRQllPQh9XyNoA3M= +github.com/samber/slog-zerolog/v2 v2.9.0 h1:6LkOabJmZdNLaUWkTC3IVVA+dq7b/V0FM6lz6/7+THI= +github.com/samber/slog-zerolog/v2 v2.9.0/go.mod h1:gnQW9VnCfM34v2pRMUIGMsZOVbYLqY/v0Wxu6atSVGc= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= @@ -34,10 +47,21 @@ github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= +go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= +go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= +go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= +go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= +go.opentelemetry.io/otel/log v0.14.0 h1:2rzJ+pOAZ8qmZ3DDHg73NEKzSZkhkGIua9gXtxNGgrM= +go.opentelemetry.io/otel/log v0.14.0/go.mod h1:5jRG92fEAgx0SU/vFPxmJvhIuDU9E1SUnEQrMlJpOno= +go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= +go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= +go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= +go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= golang.org/x/arch v0.22.0 h1:c/Zle32i5ttqRXjdLyyHZESLD/bB90DCU1g9l/0YBDI= golang.org/x/arch v0.22.0/go.mod h1:dNHoOeKiyja7GTvF9NJS1l3Z2yntpQNzgrjh1cU103A= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -45,6 +69,8 @@ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ= golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM= +golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/log/logger.go b/log/logger.go index b284968039df..8deac73d6f24 100644 --- a/log/logger.go +++ b/log/logger.go @@ -5,11 +5,13 @@ import ( "encoding/json" "fmt" "io" + "log/slog" "github.com/bytedance/sonic" "github.com/pkg/errors" "github.com/rs/zerolog" "github.com/rs/zerolog/pkgerrors" + slogzerolog "github.com/samber/slog-zerolog/v2" ) func init() { @@ -145,12 +147,20 @@ func NewLogger(dst io.Writer, options ...Option) Logger { logger = logger.Level(logCfg.Level) logger = logger.Hook(logCfg.Hooks...) - return zeroLogWrapper{ + wrapper := zeroLogWrapper{ Logger: &logger, regularLevel: logCfg.Level, verboseLevel: logCfg.VerboseLevel, filterWriter: fltWtr, } + + if logCfg.SetDefaultSlog { + slog.SetDefault(slog.New(slogzerolog.Option{ + // NOTE: this slog default logger won't respect any verbose level changes + Logger: wrapper.Logger, + }.NewZerologHandler())) + } + return wrapper } // NewCustomLogger returns a new logger with the given zerolog logger. diff --git a/log/options.go b/log/options.go index 6da1254f75cc..683f9320518a 100644 --- a/log/options.go +++ b/log/options.go @@ -35,6 +35,9 @@ type Config struct { StackTrace bool TimeFormat string Hooks []zerolog.Hook + // SetDefaultSlog indicates whether to set this logger instance as the default slog logger globally + // to capture logs from libraries using slog.Default(). + SetDefaultSlog bool } type Option func(*Config) @@ -78,6 +81,13 @@ func ColorOption(val bool) Option { } } +// SetDefaultSlogOption adds an option to set logger this logger to be the default slog logger +func SetDefaultSlogOption() Option { + return func(cfg *Config) { + cfg.SetDefaultSlog = true + } +} + // TimeFormatOption configures timestamp format of the logger // Timestamps are disabled if empty. // It is the responsibility of the caller to provide correct values diff --git a/log/otel.go b/log/otel.go new file mode 100644 index 000000000000..6c2e889cccfd --- /dev/null +++ b/log/otel.go @@ -0,0 +1,21 @@ +package log + +import ( + "sync/atomic" +) + +var otelConfigured atomic.Bool + +// IsOpenTelemetryConfigured returns true if OpenTelemetry has been configured. +// This is used to determine whether to route log messages to OpenTelemetry. +func IsOpenTelemetryConfigured() bool { + return otelConfigured.Load() +} + +// SetOpenTelemetryConfigured sets whether OpenTelemetry has been configured. +// Setting this true, that indicates that global loggers should route log messages to OpenTelemetry. +// It also will indicate to automatic OpenTelemetry configuration code that OpenTelemetry has already been set up, +// so that it does not attempt to set it up again. +func SetOpenTelemetryConfigured(configured bool) { + otelConfigured.Store(configured) +} diff --git a/log/slog.go b/log/slog.go new file mode 100644 index 000000000000..8dd7b84a07e5 --- /dev/null +++ b/log/slog.go @@ -0,0 +1,44 @@ +package log + +import "log/slog" + +var _ Logger = SlogLogger{} + +// SlogLogger satisfies [log.Logger] with logging backed by +// an instance of [*slog.Logger]. +type SlogLogger struct { + log *slog.Logger +} + +// NewSlogLogger returns a Logger backed by an existing slog.Logger instance. +// All logging methods are called directly on the *slog.Logger; +// therefore it is the caller's responsibility to configure message filtering, +// level filtering, output format, and so on. +func NewSlogLogger(log *slog.Logger) SlogLogger { + return SlogLogger{log: log} +} + +func (l SlogLogger) Info(msg string, keyVals ...any) { + l.log.Info(msg, keyVals...) +} + +func (l SlogLogger) Warn(msg string, keyVals ...any) { + l.log.Warn(msg, keyVals...) +} + +func (l SlogLogger) Error(msg string, keyVals ...any) { + l.log.Error(msg, keyVals...) +} + +func (l SlogLogger) Debug(msg string, keyVals ...any) { + l.log.Debug(msg, keyVals...) +} + +func (l SlogLogger) With(keyVals ...any) Logger { + return SlogLogger{log: l.log.With(keyVals...)} +} + +// Impl returns l's underlying [*slog.Logger]. +func (l SlogLogger) Impl() any { + return l.log +} diff --git a/log/slog/logger.go b/log/slog/logger.go index 4b6c30ec4b97..3af4d1a3ba9b 100644 --- a/log/slog/logger.go +++ b/log/slog/logger.go @@ -8,43 +8,14 @@ import ( "cosmossdk.io/log" ) -var _ log.Logger = Logger{} - // Logger satisfies [log.Logger] with logging backed by // an instance of [*slog.Logger]. -type Logger struct { - log *slog.Logger -} +type Logger = log.SlogLogger // NewCustomLogger returns a Logger backed by an existing slog.Logger instance. // All logging methods are called directly on the *slog.Logger; // therefore it is the caller's responsibility to configure message filtering, // level filtering, output format, and so on. -func NewCustomLogger(log *slog.Logger) Logger { - return Logger{log: log} -} - -func (l Logger) Info(msg string, keyVals ...any) { - l.log.Info(msg, keyVals...) -} - -func (l Logger) Warn(msg string, keyVals ...any) { - l.log.Warn(msg, keyVals...) -} - -func (l Logger) Error(msg string, keyVals ...any) { - l.log.Error(msg, keyVals...) -} - -func (l Logger) Debug(msg string, keyVals ...any) { - l.log.Debug(msg, keyVals...) -} - -func (l Logger) With(keyVals ...any) log.Logger { - return Logger{log: l.log.With(keyVals...)} -} - -// Impl returns l's underlying [*slog.Logger]. -func (l Logger) Impl() any { - return l.log +func NewCustomLogger(logger *slog.Logger) Logger { + return log.NewSlogLogger(logger) } diff --git a/log/testing.go b/log/testing.go index 0e82eced62ba..c8927b91525b 100644 --- a/log/testing.go +++ b/log/testing.go @@ -1,9 +1,11 @@ package log import ( + "log/slog" "time" "github.com/rs/zerolog" + slogzerolog "github.com/samber/slog-zerolog/v2" ) // TestingT is the interface required for logging in tests. @@ -38,11 +40,19 @@ func NewTestLoggerInfo(t TestingT) Logger { // // This is primarily helpful during active debugging of a test // with verbose logs. +// +// If OpenTelemetry is configured, all log messages will be +// routed to the OpenTelemetry instead. +// If OpenTelemetry is not configured, the default global log/slog logger +// will be routed to the test output we have configured at the Error level. func NewTestLoggerError(t TestingT) Logger { return newTestLogger(t, zerolog.ErrorLevel) } func newTestLogger(t TestingT, lvl zerolog.Level) Logger { + if IsOpenTelemetryConfigured() { + return NewSlogLogger(slog.Default()) + } cw := zerolog.ConsoleWriter{ NoColor: true, TimeFormat: time.Kitchen, @@ -56,5 +66,11 @@ func newTestLogger(t TestingT, lvl zerolog.Level) Logger { Frame: 7, }, } - return NewCustomLogger(zerolog.New(cw).Level(lvl)) + logger := NewCustomLogger(zerolog.New(cw).Level(lvl)).(zeroLogWrapper) + + // set this as the default slog logger to capture logs from libraries using slog.Default() + slog.SetDefault(slog.New(slogzerolog.Option{Logger: logger.Logger}.NewZerologHandler())) + + return logger + } diff --git a/server/util.go b/server/util.go index 42d01bd65d09..01bd4cb8f393 100644 --- a/server/util.go +++ b/server/util.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "io" + "log/slog" "net" "os" "os/signal" @@ -24,12 +25,13 @@ import ( "github.com/spf13/viper" "golang.org/x/sync/errgroup" - "cosmossdk.io/log" "cosmossdk.io/store" "cosmossdk.io/store/snapshots" snapshottypes "cosmossdk.io/store/snapshots/types" storetypes "cosmossdk.io/store/types" + "cosmossdk.io/log" + "github.com/cosmos/cosmos-sdk/baseapp" "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/server/config" @@ -167,7 +169,16 @@ func InterceptConfigsAndCreateContext(cmd *cobra.Command, customAppConfigTemplat // CreateSDKLogger creates the default SDK logger. // It reads the log level and format from the server context. +// If OpenTelemetry is configured, then that will take precedence over any server +// settings and all logs will be routed to OpenTelemetry. +// If OpenTelemetry is not configured, the SDK logger will also capture any +// logs sent to the default log/slog logger. func CreateSDKLogger(ctx *Context, out io.Writer) (log.Logger, error) { + if log.IsOpenTelemetryConfigured() { + // NOTE: we assume that the default slog logger is already configured to route to OpenTelemetry + return log.NewSlogLogger(slog.Default()), nil + } + var opts []log.Option if ctx.Viper.GetString(flags.FlagLogFormat) == flags.OutputFormatJSON { opts = append(opts, log.OutputJSONOption()) @@ -175,7 +186,9 @@ func CreateSDKLogger(ctx *Context, out io.Writer) (log.Logger, error) { opts = append(opts, log.ColorOption(!ctx.Viper.GetBool(flags.FlagLogNoColor)), // We use CometBFT flag (cmtcli.TraceFlag) for trace logging. - log.TraceOption(ctx.Viper.GetBool(FlagTrace))) + log.TraceOption(ctx.Viper.GetBool(FlagTrace)), + log.SetDefaultSlogOption(), + ) verboseLogLevelStr := ctx.Viper.GetString(flags.FlagVerboseLogLevel) if verboseLogLevelStr != "" { diff --git a/telemetry/README.md b/telemetry/README.md index bbaabbe34c01..b92332157f0a 100644 --- a/telemetry/README.md +++ b/telemetry/README.md @@ -1,11 +1,15 @@ ## Quick Start For Local Telemetry To quickly setup a local telemetry environment where OpenTelemetry data is sent to a local instance of Grafana LGTM: + 1. start the [Grafana LGTM docker image](https://hub.docker.com/r/grafana/otel-lgtm): + ```shell docker run -p 3000:3000 -p 4317:4317 -p 4318:4318 --rm -ti grafana/otel-lgtm ``` + 2. create a basic OpenTelemetry configuration file which will send data to the local instance of Grafana LGTM: + ```yaml resource: attributes: @@ -34,8 +38,9 @@ logger_provider: protocol: grpc endpoint: http://localhost:4317 ``` + 3. set the `OTEL_EXPERIMENTAL_CONFIG_FILE` environment variable to the path of the configuration file: -`export OTEL_EXPERIMENTAL_CONFIG_FILE=path/to/config.yaml` + `export OTEL_EXPERIMENTAL_CONFIG_FILE=path/to/config.yaml` 4. start your application or tests 5. view the data in Grafana LGTM at http://localhost:3000/. The Drilldown views are suggested for getting started. @@ -43,7 +48,8 @@ logger_provider: While manual OpenTelemetry initialization is still supported, this package provides a single point of initialization such that end users can just use the official -OpenTelemetry declarative configuration spec: https://opentelemetry.io/docs/languages/sdk-configuration/declarative-configuration/ +OpenTelemetry declarative configuration +spec: https://opentelemetry.io/docs/languages/sdk-configuration/declarative-configuration/ End users only need to set the `OTEL_EXPERIMENTAL_CONFIG_FILE` environment variable to the path of an OpenTelemetry configuration file and that's it. All the documentation necessary is provided in the OpenTelemetry documentation. @@ -51,9 +57,10 @@ All the documentation necessary is provided in the OpenTelemetry documentation. ## Developer Usage Developers need to do two things to use this package properly: - 1. Import this package before declaring any otel Tracer, Meter or Logger instances. - 2. Make sure Shutdown() is called when the application is shutting down. - Tests can use the TestingInit function at startup to accomplish this. + +1. Import this package before declaring any otel Tracer, Meter or Logger instances. +2. Make sure Shutdown() is called when the application is shutting down. + Tests can use the TestingInit function at startup to accomplish this. If these steps are followed, developers can follow the official golang otel conventions of declaring package-level tracer and meter instances using otel.Tracer() and otel.Meter(). @@ -61,5 +68,15 @@ NOTE: it is important to thread context.Context properly for spans, metrics and correlated correctly. When using the SDK's context type, spans must be started with Context.StartSpan to get an SDK context which has the span set correctly. -For logging, go.opentelemetry.io/contrib/bridges/otelslog provides a way to do this with the standard -library slog package. +If developers would like to emit log messages which are correlated with the current span, +for now they should use the global `log/slog` default context logging methods directly, i.e., `slog.InfoContext`, +`slog.ErrorContext`, etc. +Other approaches to logging with `context.Context` may be supported in the future. + +## Overriding Automatic OpenTelemetry Configuration + +If a user would like to provide their own configuration for OpenTelemetry instead of using the +declarative configuration file approach, their code must call `cosmossdk.io/log.SetOpenTelemetryConfigured` +before importing this package. +This package will not perform OpenTelemetry initialization if `cosmossdk.io/log.IsOpenTelemetryConfigured()` +returns true. diff --git a/telemetry/config.go b/telemetry/config.go index 3fdbd5c6754f..428e4d9a1851 100644 --- a/telemetry/config.go +++ b/telemetry/config.go @@ -22,6 +22,8 @@ import ( metricsdk "go.opentelemetry.io/otel/sdk/metric" tracesdk "go.opentelemetry.io/otel/sdk/trace" "go.yaml.in/yaml/v3" + + "cosmossdk.io/log" ) var sdk otelconf.SDK @@ -35,6 +37,11 @@ func init() { } func doInit() error { + // if otel is already marked as configured, skip + if log.IsOpenTelemetryConfigured() { + return nil + } + var err error var opts []otelconf.ConfigurationOption @@ -177,6 +184,8 @@ func doInit() error { logglobal.SetLoggerProvider(sdk.LoggerProvider()) // setup slog default provider so that any logs emitted the default slog will be traced slog.SetDefault(otelslog.NewLogger("", otelslog.WithSource(true))) + // mark otel as configured in the log package + log.SetOpenTelemetryConfigured(true) // emit an initialized message which verifies basic telemetry is working slog.Info("Telemetry initialized") From 0968a22902735042036e2b3a550b56be86ac10dd Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Thu, 13 Nov 2025 17:45:19 -0500 Subject: [PATCH 39/52] go mod tidy --- client/v2/go.mod | 45 ++++++++++++++++++++++++++++++++----- client/v2/go.sum | 4 ++-- go.mod | 48 ++++++++++++++++++++++++++++++++-------- go.sum | 4 ++-- log/go.mod | 8 +------ log/go.sum | 17 -------------- simapp/go.mod | 46 +++++++++++++++++++++++++++++++------- simapp/go.sum | 4 ++-- systemtests/go.mod | 45 ++++++++++++++++++++++++++++++++----- systemtests/go.sum | 4 ++-- tests/go.mod | 46 +++++++++++++++++++++++++++++++------- tests/go.sum | 4 ++-- tests/systemtests/go.mod | 45 ++++++++++++++++++++++++++++++++----- tests/systemtests/go.sum | 4 ++-- 14 files changed, 245 insertions(+), 79 deletions(-) diff --git a/client/v2/go.mod b/client/v2/go.mod index 1dfc6fa0d838..53ce7aa1ad09 100644 --- a/client/v2/go.mod +++ b/client/v2/go.mod @@ -38,6 +38,7 @@ require ( github.com/bytedance/sonic v1.14.2 // indirect github.com/bytedance/sonic/loader v0.4.0 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect + github.com/cenkalti/backoff/v5 v5.0.3 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/chzyer/readline v1.5.1 // indirect github.com/cloudwego/base64x v0.1.6 // indirect @@ -63,6 +64,7 @@ require ( github.com/dgraph-io/ristretto/v2 v2.1.0 // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/dvsekhvalnov/jose2go v1.6.0 // indirect + github.com/ebitengine/purego v0.8.4 // indirect github.com/emicklei/dot v1.8.0 // indirect github.com/fatih/color v1.18.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect @@ -73,6 +75,7 @@ require ( github.com/go-logfmt/logfmt v0.6.1 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect + github.com/go-ole/go-ole v1.3.0 // indirect github.com/go-viper/mapstructure/v2 v2.4.0 // indirect github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect github.com/gogo/googleapis v1.4.1 // indirect @@ -83,11 +86,14 @@ require ( github.com/google/flatbuffers v25.2.10+incompatible // indirect github.com/google/go-cmp v0.7.0 // indirect github.com/google/orderedcode v0.0.1 // indirect + github.com/google/uuid v1.6.0 // indirect github.com/gorilla/handlers v1.5.2 // indirect github.com/gorilla/mux v1.8.1 // indirect github.com/gorilla/websocket v1.5.3 // indirect + github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc // indirect github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 // indirect github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect github.com/hashicorp/go-hclog v1.6.3 // indirect github.com/hashicorp/go-immutable-radix v1.3.1 // indirect @@ -108,6 +114,7 @@ require ( github.com/kr/text v0.2.0 // indirect github.com/lib/pq v1.10.9 // indirect github.com/linxGnu/grocksdb v1.10.3 // indirect + github.com/lufia/plan9stats v0.0.0-20250827001030-24949be3fa54 // indirect github.com/manifoldco/promptui v0.9.0 // indirect github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect @@ -120,16 +127,19 @@ require ( github.com/petermattis/goid v0.0.0-20250813065127-a731cc31b4fe // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect github.com/prometheus/client_golang v1.23.2 // indirect github.com/prometheus/client_model v0.6.2 // indirect github.com/prometheus/common v0.67.1 // indirect - github.com/prometheus/procfs v0.16.1 // indirect + github.com/prometheus/otlptranslator v0.0.2 // indirect + github.com/prometheus/procfs v0.17.0 // indirect github.com/rcrowley/go-metrics v0.0.0-20250401214520-65e299d6c5c9 // indirect github.com/rogpeppe/go-internal v1.14.1 // indirect github.com/rs/cors v1.11.1 // indirect github.com/rs/zerolog v1.34.0 // indirect github.com/sagikazarmark/locafero v0.11.0 // indirect github.com/sasha-s/go-deadlock v0.3.6 // indirect + github.com/shirou/gopsutil/v4 v4.25.7 // indirect github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect github.com/spf13/afero v1.15.0 // indirect github.com/spf13/cast v1.10.0 // indirect @@ -139,15 +149,38 @@ require ( github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d // indirect github.com/tendermint/go-amino v0.16.0 // indirect github.com/tidwall/btree v1.8.1 // indirect + github.com/tklauser/go-sysconf v0.3.15 // indirect + github.com/tklauser/numcpus v0.10.0 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect + github.com/yusufpapurcu/wmi v1.2.4 // indirect github.com/zondax/golem v0.27.0 // indirect github.com/zondax/hid v0.9.2 // indirect github.com/zondax/ledger-go v1.0.1 // indirect go.etcd.io/bbolt v1.4.0 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect - go.opentelemetry.io/otel v1.37.0 // indirect - go.opentelemetry.io/otel/metric v1.37.0 // indirect - go.opentelemetry.io/otel/trace v1.37.0 // indirect + go.opentelemetry.io/contrib/bridges/otelslog v0.13.0 // indirect + go.opentelemetry.io/contrib/instrumentation/host v0.63.0 // indirect + go.opentelemetry.io/contrib/instrumentation/runtime v0.63.0 // indirect + go.opentelemetry.io/contrib/otelconf v0.18.0 // indirect + go.opentelemetry.io/otel v1.38.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.14.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.14.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.38.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.38.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0 // indirect + go.opentelemetry.io/otel/exporters/prometheus v0.60.0 // indirect + go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.14.0 // indirect + go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.38.0 // indirect + go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.38.0 // indirect + go.opentelemetry.io/otel/log v0.14.0 // indirect + go.opentelemetry.io/otel/metric v1.38.0 // indirect + go.opentelemetry.io/otel/sdk v1.38.0 // indirect + go.opentelemetry.io/otel/sdk/log v0.14.0 // indirect + go.opentelemetry.io/otel/sdk/metric v1.38.0 // indirect + go.opentelemetry.io/otel/trace v1.38.0 // indirect + go.opentelemetry.io/proto/otlp v1.7.1 // indirect go.uber.org/mock v0.6.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect @@ -162,8 +195,8 @@ require ( golang.org/x/term v0.37.0 // indirect golang.org/x/text v0.31.0 // indirect google.golang.org/genproto v0.0.0-20250603155806-513f23925822 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20250818200422-3122310a409c // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20250818200422-3122310a409c // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect nhooyr.io/websocket v1.8.17 // indirect pgregory.net/rapid v1.2.0 // indirect diff --git a/client/v2/go.sum b/client/v2/go.sum index 5969819affc8..88a38b20d6fe 100644 --- a/client/v2/go.sum +++ b/client/v2/go.sum @@ -812,8 +812,8 @@ go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0= go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= -golang.org/x/arch v0.22.0 h1:c/Zle32i5ttqRXjdLyyHZESLD/bB90DCU1g9l/0YBDI= -golang.org/x/arch v0.22.0/go.mod h1:dNHoOeKiyja7GTvF9NJS1l3Z2yntpQNzgrjh1cU103A= +golang.org/x/arch v0.21.0 h1:iTC9o7+wP6cPWpDWkivCvQFGAHDQ59SrSxsLPcnkArw= +golang.org/x/arch v0.21.0/go.mod h1:dNHoOeKiyja7GTvF9NJS1l3Z2yntpQNzgrjh1cU103A= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= diff --git a/go.mod b/go.mod index a5346b9632f5..f772b1908c46 100644 --- a/go.mod +++ b/go.mod @@ -57,10 +57,25 @@ require ( github.com/tendermint/go-amino v0.16.0 github.com/test-go/testify v1.1.4 github.com/tidwall/btree v1.8.1 + go.opentelemetry.io/contrib/bridges/otelslog v0.13.0 + go.opentelemetry.io/contrib/instrumentation/host v0.63.0 + go.opentelemetry.io/contrib/instrumentation/runtime v0.63.0 + go.opentelemetry.io/contrib/otelconf v0.18.0 + go.opentelemetry.io/otel v1.38.0 + go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.14.0 + go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.38.0 + go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.38.0 + go.opentelemetry.io/otel/log v0.14.0 + go.opentelemetry.io/otel/metric v1.38.0 + go.opentelemetry.io/otel/sdk v1.38.0 + go.opentelemetry.io/otel/sdk/log v0.14.0 + go.opentelemetry.io/otel/sdk/metric v1.38.0 + go.opentelemetry.io/otel/trace v1.38.0 go.uber.org/mock v0.6.0 + go.yaml.in/yaml/v3 v3.0.4 golang.org/x/crypto v0.44.0 golang.org/x/sync v0.18.0 - google.golang.org/genproto/googleapis/api v0.0.0-20250818200422-3122310a409c + google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5 google.golang.org/grpc v1.76.0 google.golang.org/protobuf v1.36.10 gotest.tools/v3 v3.5.2 @@ -110,6 +125,7 @@ require ( github.com/bytedance/sonic v1.14.2 // indirect github.com/bytedance/sonic/loader v0.4.0 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect + github.com/cenkalti/backoff/v5 v5.0.3 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/cloudwego/base64x v0.1.6 // indirect github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443 // indirect @@ -128,6 +144,7 @@ require ( github.com/dgraph-io/ristretto/v2 v2.1.0 // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/dvsekhvalnov/jose2go v1.6.0 // indirect + github.com/ebitengine/purego v0.8.4 // indirect github.com/emicklei/dot v1.8.0 // indirect github.com/envoyproxy/go-control-plane/envoy v1.32.4 // indirect github.com/envoyproxy/protoc-gen-validate v1.2.1 // indirect @@ -141,6 +158,7 @@ require ( github.com/go-logfmt/logfmt v0.6.1 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect + github.com/go-ole/go-ole v1.3.0 // indirect github.com/go-viper/mapstructure/v2 v2.4.0 // indirect github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect github.com/gogo/googleapis v1.4.1 // indirect @@ -154,6 +172,8 @@ require ( github.com/googleapis/enterprise-certificate-proxy v0.3.6 // indirect github.com/googleapis/gax-go/v2 v2.15.0 // indirect github.com/gorilla/websocket v1.5.3 // indirect + github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 // indirect github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect github.com/hashicorp/aws-sdk-go-base/v2 v2.0.0-beta.65 // indirect github.com/hashicorp/go-hclog v1.6.3 // indirect @@ -171,6 +191,7 @@ require ( github.com/kr/text v0.2.0 // indirect github.com/lib/pq v1.10.9 // indirect github.com/linxGnu/grocksdb v1.10.3 // indirect + github.com/lufia/plan9stats v0.0.0-20250827001030-24949be3fa54 // indirect github.com/mattn/go-colorable v0.1.14 // indirect github.com/minio/highwayhash v1.0.3 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect @@ -184,21 +205,27 @@ require ( github.com/pkg/errors v0.9.1 // indirect github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect github.com/prometheus/client_model v0.6.2 // indirect - github.com/prometheus/procfs v0.16.1 // indirect + github.com/prometheus/otlptranslator v0.0.2 // indirect + github.com/prometheus/procfs v0.17.0 // indirect github.com/rcrowley/go-metrics v0.0.0-20250401214520-65e299d6c5c9 // indirect github.com/rogpeppe/go-internal v1.14.1 // indirect github.com/rs/cors v1.11.1 // indirect github.com/sagikazarmark/locafero v0.11.0 // indirect github.com/sasha-s/go-deadlock v0.3.6 // indirect + github.com/shirou/gopsutil/v4 v4.25.7 // indirect github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect github.com/spf13/afero v1.15.0 // indirect github.com/spiffe/go-spiffe/v2 v2.5.0 // indirect github.com/subosito/gotenv v1.6.0 // indirect github.com/supranational/blst v0.3.16 // indirect github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d // indirect + github.com/tklauser/go-sysconf v0.3.15 // indirect + github.com/tklauser/numcpus v0.10.0 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ulikunitz/xz v0.5.15 // indirect + github.com/yusufpapurcu/wmi v1.2.4 // indirect github.com/zeebo/errs v1.4.0 // indirect github.com/zondax/golem v0.27.0 // indirect github.com/zondax/hid v0.9.2 // indirect @@ -208,15 +235,18 @@ require ( go.opentelemetry.io/contrib/detectors/gcp v1.36.0 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0 // indirect - go.opentelemetry.io/otel v1.37.0 // indirect - go.opentelemetry.io/otel/metric v1.37.0 // indirect - go.opentelemetry.io/otel/sdk v1.37.0 // indirect - go.opentelemetry.io/otel/sdk/metric v1.37.0 // indirect - go.opentelemetry.io/otel/trace v1.37.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.14.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.14.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.38.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.38.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0 // indirect + go.opentelemetry.io/otel/exporters/prometheus v0.60.0 // indirect + go.opentelemetry.io/proto/otlp v1.7.1 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect go.yaml.in/yaml/v2 v2.4.3 // indirect - go.yaml.in/yaml/v3 v3.0.4 // indirect golang.org/x/arch v0.21.0 // indirect golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6 // indirect golang.org/x/net v0.46.0 // indirect @@ -227,7 +257,7 @@ require ( golang.org/x/time v0.13.0 // indirect google.golang.org/api v0.247.0 // indirect google.golang.org/genproto v0.0.0-20250603155806-513f23925822 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20250818200422-3122310a409c // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect nhooyr.io/websocket v1.8.17 // indirect rsc.io/qr v0.2.0 // indirect diff --git a/go.sum b/go.sum index a0c545a725aa..42de334b4d97 100644 --- a/go.sum +++ b/go.sum @@ -937,8 +937,8 @@ go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= -golang.org/x/arch v0.22.0 h1:c/Zle32i5ttqRXjdLyyHZESLD/bB90DCU1g9l/0YBDI= -golang.org/x/arch v0.22.0/go.mod h1:dNHoOeKiyja7GTvF9NJS1l3Z2yntpQNzgrjh1cU103A= +golang.org/x/arch v0.21.0 h1:iTC9o7+wP6cPWpDWkivCvQFGAHDQ59SrSxsLPcnkArw= +golang.org/x/arch v0.21.0/go.mod h1:dNHoOeKiyja7GTvF9NJS1l3Z2yntpQNzgrjh1cU103A= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= diff --git a/log/go.mod b/log/go.mod index ce56f2b02158..267117d91fec 100644 --- a/log/go.mod +++ b/log/go.mod @@ -7,25 +7,19 @@ require ( github.com/pkg/errors v0.9.1 github.com/rs/zerolog v1.34.0 github.com/samber/slog-zerolog/v2 v2.9.0 - go.opentelemetry.io/otel/log v0.14.0 ) require ( github.com/bytedance/gopkg v0.1.3 // indirect github.com/bytedance/sonic/loader v0.4.0 // indirect github.com/cloudwego/base64x v0.1.6 // indirect - github.com/go-logr/logr v1.4.3 // indirect - github.com/go-logr/stdr v1.2.2 // indirect github.com/klauspost/cpuid/v2 v2.2.10 // indirect github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/samber/lo v1.51.0 // indirect github.com/samber/slog-common v0.19.0 // indirect + github.com/stretchr/testify v1.11.1 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect - go.opentelemetry.io/auto/sdk v1.1.0 // indirect - go.opentelemetry.io/otel v1.38.0 // indirect - go.opentelemetry.io/otel/metric v1.38.0 // indirect - go.opentelemetry.io/otel/trace v1.38.0 // indirect golang.org/x/arch v0.22.0 // indirect golang.org/x/sys v0.37.0 // indirect golang.org/x/text v0.22.0 // indirect diff --git a/log/go.sum b/log/go.sum index 235b945aa584..30b8ba522609 100644 --- a/log/go.sum +++ b/log/go.sum @@ -10,14 +10,7 @@ github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSV github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= -github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= -github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= -github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= -github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE= github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= @@ -52,16 +45,6 @@ github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= -go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= -go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= -go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= -go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= -go.opentelemetry.io/otel/log v0.14.0 h1:2rzJ+pOAZ8qmZ3DDHg73NEKzSZkhkGIua9gXtxNGgrM= -go.opentelemetry.io/otel/log v0.14.0/go.mod h1:5jRG92fEAgx0SU/vFPxmJvhIuDU9E1SUnEQrMlJpOno= -go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= -go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= -go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= -go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= golang.org/x/arch v0.22.0 h1:c/Zle32i5ttqRXjdLyyHZESLD/bB90DCU1g9l/0YBDI= golang.org/x/arch v0.22.0/go.mod h1:dNHoOeKiyja7GTvF9NJS1l3Z2yntpQNzgrjh1cU103A= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= diff --git a/simapp/go.mod b/simapp/go.mod index 7eef90a5dcc3..82b491b49d58 100644 --- a/simapp/go.mod +++ b/simapp/go.mod @@ -72,6 +72,7 @@ require ( github.com/bytedance/sonic v1.14.2 // indirect github.com/bytedance/sonic/loader v0.4.0 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect + github.com/cenkalti/backoff/v5 v5.0.3 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/chzyer/readline v1.5.1 // indirect github.com/cloudwego/base64x v0.1.6 // indirect @@ -101,6 +102,7 @@ require ( github.com/dgraph-io/ristretto/v2 v2.1.0 // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/dvsekhvalnov/jose2go v1.8.0 // indirect + github.com/ebitengine/purego v0.8.4 // indirect github.com/emicklei/dot v1.8.0 // indirect github.com/envoyproxy/go-control-plane/envoy v1.32.4 // indirect github.com/envoyproxy/protoc-gen-validate v1.2.1 // indirect @@ -114,6 +116,7 @@ require ( github.com/go-logfmt/logfmt v0.6.1 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect + github.com/go-ole/go-ole v1.3.0 // indirect github.com/go-viper/mapstructure/v2 v2.4.0 // indirect github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect github.com/gogo/googleapis v1.4.1 // indirect @@ -131,8 +134,10 @@ require ( github.com/gorilla/handlers v1.5.2 // indirect github.com/gorilla/mux v1.8.1 // indirect github.com/gorilla/websocket v1.5.3 // indirect + github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc // indirect github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 // indirect github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect github.com/hashicorp/aws-sdk-go-base/v2 v2.0.0-beta.65 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect @@ -157,6 +162,7 @@ require ( github.com/kr/text v0.2.0 // indirect github.com/lib/pq v1.10.9 // indirect github.com/linxGnu/grocksdb v1.10.3 // indirect + github.com/lufia/plan9stats v0.0.0-20250827001030-24949be3fa54 // indirect github.com/manifoldco/promptui v0.9.0 // indirect github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect @@ -172,16 +178,19 @@ require ( github.com/pkg/errors v0.9.1 // indirect github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect github.com/prometheus/client_golang v1.23.2 // indirect github.com/prometheus/client_model v0.6.2 // indirect github.com/prometheus/common v0.67.1 // indirect - github.com/prometheus/procfs v0.16.1 // indirect + github.com/prometheus/otlptranslator v0.0.2 // indirect + github.com/prometheus/procfs v0.17.0 // indirect github.com/rcrowley/go-metrics v0.0.0-20250401214520-65e299d6c5c9 // indirect github.com/rogpeppe/go-internal v1.14.1 // indirect github.com/rs/cors v1.11.1 // indirect github.com/rs/zerolog v1.34.0 // indirect github.com/sagikazarmark/locafero v0.11.0 // indirect github.com/sasha-s/go-deadlock v0.3.6 // indirect + github.com/shirou/gopsutil/v4 v4.25.7 // indirect github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect github.com/spf13/afero v1.15.0 // indirect github.com/spiffe/go-spiffe/v2 v2.5.0 // indirect @@ -190,22 +199,43 @@ require ( github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d // indirect github.com/tendermint/go-amino v0.16.0 // indirect github.com/tidwall/btree v1.8.1 // indirect + github.com/tklauser/go-sysconf v0.3.15 // indirect + github.com/tklauser/numcpus v0.10.0 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ulikunitz/xz v0.5.15 // indirect + github.com/yusufpapurcu/wmi v1.2.4 // indirect github.com/zeebo/errs v1.4.0 // indirect github.com/zondax/golem v0.27.0 // indirect github.com/zondax/hid v0.9.2 // indirect github.com/zondax/ledger-go v1.0.1 // indirect go.etcd.io/bbolt v1.4.0 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect + go.opentelemetry.io/contrib/bridges/otelslog v0.13.0 // indirect go.opentelemetry.io/contrib/detectors/gcp v1.36.0 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0 // indirect + go.opentelemetry.io/contrib/instrumentation/host v0.63.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0 // indirect - go.opentelemetry.io/otel v1.37.0 // indirect - go.opentelemetry.io/otel/metric v1.37.0 // indirect - go.opentelemetry.io/otel/sdk v1.37.0 // indirect - go.opentelemetry.io/otel/sdk/metric v1.37.0 // indirect - go.opentelemetry.io/otel/trace v1.37.0 // indirect + go.opentelemetry.io/contrib/instrumentation/runtime v0.63.0 // indirect + go.opentelemetry.io/contrib/otelconf v0.18.0 // indirect + go.opentelemetry.io/otel v1.38.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.14.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.14.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.38.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.38.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0 // indirect + go.opentelemetry.io/otel/exporters/prometheus v0.60.0 // indirect + go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.14.0 // indirect + go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.38.0 // indirect + go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.38.0 // indirect + go.opentelemetry.io/otel/log v0.14.0 // indirect + go.opentelemetry.io/otel/metric v1.38.0 // indirect + go.opentelemetry.io/otel/sdk v1.38.0 // indirect + go.opentelemetry.io/otel/sdk/log v0.14.0 // indirect + go.opentelemetry.io/otel/sdk/metric v1.38.0 // indirect + go.opentelemetry.io/otel/trace v1.38.0 // indirect + go.opentelemetry.io/proto/otlp v1.7.1 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect go.yaml.in/yaml/v2 v2.4.3 // indirect @@ -222,8 +252,8 @@ require ( golang.org/x/time v0.13.0 // indirect google.golang.org/api v0.247.0 // indirect google.golang.org/genproto v0.0.0-20250603155806-513f23925822 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20250818200422-3122310a409c // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20250818200422-3122310a409c // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5 // indirect google.golang.org/grpc v1.76.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect gotest.tools/v3 v3.5.2 // indirect diff --git a/simapp/go.sum b/simapp/go.sum index c2229000b1ea..1fe86461c8c0 100644 --- a/simapp/go.sum +++ b/simapp/go.sum @@ -945,8 +945,8 @@ go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= -golang.org/x/arch v0.22.0 h1:c/Zle32i5ttqRXjdLyyHZESLD/bB90DCU1g9l/0YBDI= -golang.org/x/arch v0.22.0/go.mod h1:dNHoOeKiyja7GTvF9NJS1l3Z2yntpQNzgrjh1cU103A= +golang.org/x/arch v0.21.0 h1:iTC9o7+wP6cPWpDWkivCvQFGAHDQ59SrSxsLPcnkArw= +golang.org/x/arch v0.21.0/go.mod h1:dNHoOeKiyja7GTvF9NJS1l3Z2yntpQNzgrjh1cU103A= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= diff --git a/systemtests/go.mod b/systemtests/go.mod index 8b5a04f8becd..c544b74f6d30 100644 --- a/systemtests/go.mod +++ b/systemtests/go.mod @@ -34,6 +34,7 @@ require ( github.com/bytedance/sonic v1.14.2 // indirect github.com/bytedance/sonic/loader v0.4.0 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect + github.com/cenkalti/backoff/v5 v5.0.3 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/cloudwego/base64x v0.1.6 // indirect github.com/cockroachdb/errors v1.12.0 // indirect @@ -60,6 +61,7 @@ require ( github.com/dgraph-io/ristretto/v2 v2.1.0 // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/dvsekhvalnov/jose2go v1.6.0 // indirect + github.com/ebitengine/purego v0.8.4 // indirect github.com/emicklei/dot v1.8.0 // indirect github.com/fatih/color v1.18.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect @@ -70,6 +72,7 @@ require ( github.com/go-logfmt/logfmt v0.6.1 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect + github.com/go-ole/go-ole v1.3.0 // indirect github.com/go-viper/mapstructure/v2 v2.4.0 // indirect github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect github.com/gogo/googleapis v1.4.1 // indirect @@ -80,11 +83,14 @@ require ( github.com/google/flatbuffers v25.2.10+incompatible // indirect github.com/google/go-cmp v0.7.0 // indirect github.com/google/orderedcode v0.0.1 // indirect + github.com/google/uuid v1.6.0 // indirect github.com/gorilla/handlers v1.5.2 // indirect github.com/gorilla/mux v1.8.1 // indirect github.com/gorilla/websocket v1.5.3 // indirect + github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc // indirect github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 // indirect github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect github.com/hashicorp/go-hclog v1.6.3 // indirect github.com/hashicorp/go-immutable-radix v1.3.1 // indirect @@ -105,6 +111,7 @@ require ( github.com/kr/text v0.2.0 // indirect github.com/lib/pq v1.10.9 // indirect github.com/linxGnu/grocksdb v1.10.3 // indirect + github.com/lufia/plan9stats v0.0.0-20250827001030-24949be3fa54 // indirect github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/minio/highwayhash v1.0.3 // indirect @@ -116,16 +123,19 @@ require ( github.com/petermattis/goid v0.0.0-20250813065127-a731cc31b4fe // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect github.com/prometheus/client_golang v1.23.2 // indirect github.com/prometheus/client_model v0.6.2 // indirect github.com/prometheus/common v0.67.1 // indirect - github.com/prometheus/procfs v0.16.1 // indirect + github.com/prometheus/otlptranslator v0.0.2 // indirect + github.com/prometheus/procfs v0.17.0 // indirect github.com/rcrowley/go-metrics v0.0.0-20250401214520-65e299d6c5c9 // indirect github.com/rogpeppe/go-internal v1.14.1 // indirect github.com/rs/cors v1.11.1 // indirect github.com/rs/zerolog v1.34.0 // indirect github.com/sagikazarmark/locafero v0.11.0 // indirect github.com/sasha-s/go-deadlock v0.3.6 // indirect + github.com/shirou/gopsutil/v4 v4.25.7 // indirect github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect github.com/spf13/afero v1.15.0 // indirect github.com/spf13/cast v1.10.0 // indirect @@ -139,15 +149,38 @@ require ( github.com/tidwall/btree v1.8.1 // indirect github.com/tidwall/match v1.1.1 // indirect github.com/tidwall/pretty v1.2.0 // indirect + github.com/tklauser/go-sysconf v0.3.15 // indirect + github.com/tklauser/numcpus v0.10.0 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect + github.com/yusufpapurcu/wmi v1.2.4 // indirect github.com/zondax/golem v0.27.0 // indirect github.com/zondax/hid v0.9.2 // indirect github.com/zondax/ledger-go v1.0.1 // indirect go.etcd.io/bbolt v1.4.0 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect - go.opentelemetry.io/otel v1.37.0 // indirect - go.opentelemetry.io/otel/metric v1.37.0 // indirect - go.opentelemetry.io/otel/trace v1.37.0 // indirect + go.opentelemetry.io/contrib/bridges/otelslog v0.13.0 // indirect + go.opentelemetry.io/contrib/instrumentation/host v0.63.0 // indirect + go.opentelemetry.io/contrib/instrumentation/runtime v0.63.0 // indirect + go.opentelemetry.io/contrib/otelconf v0.18.0 // indirect + go.opentelemetry.io/otel v1.38.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.14.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.14.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.38.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.38.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0 // indirect + go.opentelemetry.io/otel/exporters/prometheus v0.60.0 // indirect + go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.14.0 // indirect + go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.38.0 // indirect + go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.38.0 // indirect + go.opentelemetry.io/otel/log v0.14.0 // indirect + go.opentelemetry.io/otel/metric v1.38.0 // indirect + go.opentelemetry.io/otel/sdk v1.38.0 // indirect + go.opentelemetry.io/otel/sdk/log v0.14.0 // indirect + go.opentelemetry.io/otel/sdk/metric v1.38.0 // indirect + go.opentelemetry.io/otel/trace v1.38.0 // indirect + go.opentelemetry.io/proto/otlp v1.7.1 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect go.yaml.in/yaml/v2 v2.4.3 // indirect @@ -161,8 +194,8 @@ require ( golang.org/x/term v0.37.0 // indirect golang.org/x/text v0.31.0 // indirect google.golang.org/genproto v0.0.0-20250603155806-513f23925822 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20250818200422-3122310a409c // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20250818200422-3122310a409c // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5 // indirect google.golang.org/protobuf v1.36.10 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect gotest.tools/v3 v3.5.2 // indirect diff --git a/systemtests/go.sum b/systemtests/go.sum index c46b23dd7fda..dbd778f2961b 100644 --- a/systemtests/go.sum +++ b/systemtests/go.sum @@ -821,8 +821,8 @@ go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0= go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= -golang.org/x/arch v0.22.0 h1:c/Zle32i5ttqRXjdLyyHZESLD/bB90DCU1g9l/0YBDI= -golang.org/x/arch v0.22.0/go.mod h1:dNHoOeKiyja7GTvF9NJS1l3Z2yntpQNzgrjh1cU103A= +golang.org/x/arch v0.21.0 h1:iTC9o7+wP6cPWpDWkivCvQFGAHDQ59SrSxsLPcnkArw= +golang.org/x/arch v0.21.0/go.mod h1:dNHoOeKiyja7GTvF9NJS1l3Z2yntpQNzgrjh1cU103A= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= diff --git a/tests/go.mod b/tests/go.mod index 2f609c5d6fcd..f75074790091 100644 --- a/tests/go.mod +++ b/tests/go.mod @@ -75,6 +75,7 @@ require ( github.com/bytedance/sonic v1.14.2 // indirect github.com/bytedance/sonic/loader v0.4.0 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect + github.com/cenkalti/backoff/v5 v5.0.3 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/chzyer/readline v1.5.1 // indirect github.com/cloudwego/base64x v0.1.6 // indirect @@ -100,6 +101,7 @@ require ( github.com/dgraph-io/ristretto/v2 v2.1.0 // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/dvsekhvalnov/jose2go v1.8.0 // indirect + github.com/ebitengine/purego v0.8.4 // indirect github.com/emicklei/dot v1.8.0 // indirect github.com/envoyproxy/go-control-plane/envoy v1.32.4 // indirect github.com/envoyproxy/protoc-gen-validate v1.2.1 // indirect @@ -113,6 +115,7 @@ require ( github.com/go-logfmt/logfmt v0.6.1 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect + github.com/go-ole/go-ole v1.3.0 // indirect github.com/go-viper/mapstructure/v2 v2.4.0 // indirect github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect github.com/gogo/googleapis v1.4.1 // indirect @@ -130,8 +133,10 @@ require ( github.com/gorilla/handlers v1.5.2 // indirect github.com/gorilla/mux v1.8.1 // indirect github.com/gorilla/websocket v1.5.3 // indirect + github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc // indirect github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 // indirect github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect github.com/hashicorp/aws-sdk-go-base/v2 v2.0.0-beta.65 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect @@ -156,6 +161,7 @@ require ( github.com/kr/text v0.2.0 // indirect github.com/lib/pq v1.10.9 // indirect github.com/linxGnu/grocksdb v1.10.3 // indirect + github.com/lufia/plan9stats v0.0.0-20250827001030-24949be3fa54 // indirect github.com/manifoldco/promptui v0.9.0 // indirect github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect @@ -170,16 +176,19 @@ require ( github.com/pkg/errors v0.9.1 // indirect github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect github.com/prometheus/client_golang v1.23.2 // indirect github.com/prometheus/client_model v0.6.2 // indirect github.com/prometheus/common v0.67.1 // indirect - github.com/prometheus/procfs v0.16.1 // indirect + github.com/prometheus/otlptranslator v0.0.2 // indirect + github.com/prometheus/procfs v0.17.0 // indirect github.com/rcrowley/go-metrics v0.0.0-20250401214520-65e299d6c5c9 // indirect github.com/rogpeppe/go-internal v1.14.1 // indirect github.com/rs/cors v1.11.1 // indirect github.com/rs/zerolog v1.34.0 // indirect github.com/sagikazarmark/locafero v0.11.0 // indirect github.com/sasha-s/go-deadlock v0.3.6 // indirect + github.com/shirou/gopsutil/v4 v4.25.7 // indirect github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect github.com/spf13/afero v1.15.0 // indirect github.com/spf13/cast v1.10.0 // indirect @@ -190,22 +199,43 @@ require ( github.com/supranational/blst v0.3.16 // indirect github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d // indirect github.com/tidwall/btree v1.8.1 // indirect + github.com/tklauser/go-sysconf v0.3.15 // indirect + github.com/tklauser/numcpus v0.10.0 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ulikunitz/xz v0.5.15 // indirect + github.com/yusufpapurcu/wmi v1.2.4 // indirect github.com/zeebo/errs v1.4.0 // indirect github.com/zondax/golem v0.27.0 // indirect github.com/zondax/hid v0.9.2 // indirect github.com/zondax/ledger-go v1.0.1 // indirect go.etcd.io/bbolt v1.4.0 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect + go.opentelemetry.io/contrib/bridges/otelslog v0.13.0 // indirect go.opentelemetry.io/contrib/detectors/gcp v1.36.0 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0 // indirect + go.opentelemetry.io/contrib/instrumentation/host v0.63.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0 // indirect - go.opentelemetry.io/otel v1.37.0 // indirect - go.opentelemetry.io/otel/metric v1.37.0 // indirect - go.opentelemetry.io/otel/sdk v1.37.0 // indirect - go.opentelemetry.io/otel/sdk/metric v1.37.0 // indirect - go.opentelemetry.io/otel/trace v1.37.0 // indirect + go.opentelemetry.io/contrib/instrumentation/runtime v0.63.0 // indirect + go.opentelemetry.io/contrib/otelconf v0.18.0 // indirect + go.opentelemetry.io/otel v1.38.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.14.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.14.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.38.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.38.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0 // indirect + go.opentelemetry.io/otel/exporters/prometheus v0.60.0 // indirect + go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.14.0 // indirect + go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.38.0 // indirect + go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.38.0 // indirect + go.opentelemetry.io/otel/log v0.14.0 // indirect + go.opentelemetry.io/otel/metric v1.38.0 // indirect + go.opentelemetry.io/otel/sdk v1.38.0 // indirect + go.opentelemetry.io/otel/sdk/log v0.14.0 // indirect + go.opentelemetry.io/otel/sdk/metric v1.38.0 // indirect + go.opentelemetry.io/otel/trace v1.38.0 // indirect + go.opentelemetry.io/proto/otlp v1.7.1 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect go.yaml.in/yaml/v2 v2.4.3 // indirect @@ -222,8 +252,8 @@ require ( golang.org/x/time v0.13.0 // indirect google.golang.org/api v0.247.0 // indirect google.golang.org/genproto v0.0.0-20250603155806-513f23925822 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20250818200422-3122310a409c // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20250818200422-3122310a409c // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect nhooyr.io/websocket v1.8.17 // indirect sigs.k8s.io/yaml v1.6.0 // indirect diff --git a/tests/go.sum b/tests/go.sum index b26854bb825f..f03db442b100 100644 --- a/tests/go.sum +++ b/tests/go.sum @@ -944,8 +944,8 @@ go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= -golang.org/x/arch v0.22.0 h1:c/Zle32i5ttqRXjdLyyHZESLD/bB90DCU1g9l/0YBDI= -golang.org/x/arch v0.22.0/go.mod h1:dNHoOeKiyja7GTvF9NJS1l3Z2yntpQNzgrjh1cU103A= +golang.org/x/arch v0.21.0 h1:iTC9o7+wP6cPWpDWkivCvQFGAHDQ59SrSxsLPcnkArw= +golang.org/x/arch v0.21.0/go.mod h1:dNHoOeKiyja7GTvF9NJS1l3Z2yntpQNzgrjh1cU103A= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= diff --git a/tests/systemtests/go.mod b/tests/systemtests/go.mod index eef05baca22c..af975e8ac999 100644 --- a/tests/systemtests/go.mod +++ b/tests/systemtests/go.mod @@ -38,6 +38,7 @@ require ( github.com/bytedance/sonic v1.14.2 // indirect github.com/bytedance/sonic/loader v0.4.0 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect + github.com/cenkalti/backoff/v5 v5.0.3 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/cloudwego/base64x v0.1.6 // indirect github.com/cockroachdb/errors v1.12.0 // indirect @@ -66,6 +67,7 @@ require ( github.com/dgraph-io/ristretto/v2 v2.1.0 // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/dvsekhvalnov/jose2go v1.8.0 // indirect + github.com/ebitengine/purego v0.8.4 // indirect github.com/emicklei/dot v1.8.0 // indirect github.com/fatih/color v1.18.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect @@ -76,6 +78,7 @@ require ( github.com/go-logfmt/logfmt v0.6.1 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect + github.com/go-ole/go-ole v1.3.0 // indirect github.com/go-viper/mapstructure/v2 v2.4.0 // indirect github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect github.com/gogo/googleapis v1.4.1 // indirect @@ -86,11 +89,14 @@ require ( github.com/google/flatbuffers v25.2.10+incompatible // indirect github.com/google/go-cmp v0.7.0 // indirect github.com/google/orderedcode v0.0.1 // indirect + github.com/google/uuid v1.6.0 // indirect github.com/gorilla/handlers v1.5.2 // indirect github.com/gorilla/mux v1.8.1 // indirect github.com/gorilla/websocket v1.5.3 // indirect + github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc // indirect github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 // indirect github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect github.com/hashicorp/go-hclog v1.6.3 // indirect github.com/hashicorp/go-immutable-radix v1.3.1 // indirect @@ -111,6 +117,7 @@ require ( github.com/kr/text v0.2.0 // indirect github.com/lib/pq v1.10.9 // indirect github.com/linxGnu/grocksdb v1.10.3 // indirect + github.com/lufia/plan9stats v0.0.0-20250827001030-24949be3fa54 // indirect github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/minio/highwayhash v1.0.3 // indirect @@ -122,16 +129,19 @@ require ( github.com/petermattis/goid v0.0.0-20250813065127-a731cc31b4fe // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect github.com/prometheus/client_golang v1.23.2 // indirect github.com/prometheus/client_model v0.6.2 // indirect github.com/prometheus/common v0.67.1 // indirect - github.com/prometheus/procfs v0.16.1 // indirect + github.com/prometheus/otlptranslator v0.0.2 // indirect + github.com/prometheus/procfs v0.17.0 // indirect github.com/rcrowley/go-metrics v0.0.0-20250401214520-65e299d6c5c9 // indirect github.com/rogpeppe/go-internal v1.14.1 // indirect github.com/rs/cors v1.11.1 // indirect github.com/rs/zerolog v1.34.0 // indirect github.com/sagikazarmark/locafero v0.11.0 // indirect github.com/sasha-s/go-deadlock v0.3.6 // indirect + github.com/shirou/gopsutil/v4 v4.25.7 // indirect github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect github.com/spf13/afero v1.15.0 // indirect github.com/spf13/cast v1.10.0 // indirect @@ -145,15 +155,38 @@ require ( github.com/tidwall/btree v1.8.1 // indirect github.com/tidwall/match v1.1.1 // indirect github.com/tidwall/pretty v1.2.0 // indirect + github.com/tklauser/go-sysconf v0.3.15 // indirect + github.com/tklauser/numcpus v0.10.0 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect + github.com/yusufpapurcu/wmi v1.2.4 // indirect github.com/zondax/golem v0.27.0 // indirect github.com/zondax/hid v0.9.2 // indirect github.com/zondax/ledger-go v1.0.1 // indirect go.etcd.io/bbolt v1.4.0 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect - go.opentelemetry.io/otel v1.37.0 // indirect - go.opentelemetry.io/otel/metric v1.37.0 // indirect - go.opentelemetry.io/otel/trace v1.37.0 // indirect + go.opentelemetry.io/contrib/bridges/otelslog v0.13.0 // indirect + go.opentelemetry.io/contrib/instrumentation/host v0.63.0 // indirect + go.opentelemetry.io/contrib/instrumentation/runtime v0.63.0 // indirect + go.opentelemetry.io/contrib/otelconf v0.18.0 // indirect + go.opentelemetry.io/otel v1.38.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.14.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.14.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.38.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.38.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0 // indirect + go.opentelemetry.io/otel/exporters/prometheus v0.60.0 // indirect + go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.14.0 // indirect + go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.38.0 // indirect + go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.38.0 // indirect + go.opentelemetry.io/otel/log v0.14.0 // indirect + go.opentelemetry.io/otel/metric v1.38.0 // indirect + go.opentelemetry.io/otel/sdk v1.38.0 // indirect + go.opentelemetry.io/otel/sdk/log v0.14.0 // indirect + go.opentelemetry.io/otel/sdk/metric v1.38.0 // indirect + go.opentelemetry.io/otel/trace v1.38.0 // indirect + go.opentelemetry.io/proto/otlp v1.7.1 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect go.yaml.in/yaml/v2 v2.4.3 // indirect @@ -167,8 +200,8 @@ require ( golang.org/x/term v0.37.0 // indirect golang.org/x/text v0.31.0 // indirect google.golang.org/genproto v0.0.0-20250603155806-513f23925822 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20250818200422-3122310a409c // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20250818200422-3122310a409c // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5 // indirect google.golang.org/grpc v1.76.0 // indirect google.golang.org/protobuf v1.36.10 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/tests/systemtests/go.sum b/tests/systemtests/go.sum index 2054b6810ae3..c1f90ea0433b 100644 --- a/tests/systemtests/go.sum +++ b/tests/systemtests/go.sum @@ -819,8 +819,8 @@ go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0= go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= -golang.org/x/arch v0.22.0 h1:c/Zle32i5ttqRXjdLyyHZESLD/bB90DCU1g9l/0YBDI= -golang.org/x/arch v0.22.0/go.mod h1:dNHoOeKiyja7GTvF9NJS1l3Z2yntpQNzgrjh1cU103A= +golang.org/x/arch v0.21.0 h1:iTC9o7+wP6cPWpDWkivCvQFGAHDQ59SrSxsLPcnkArw= +golang.org/x/arch v0.21.0/go.mod h1:dNHoOeKiyja7GTvF9NJS1l3Z2yntpQNzgrjh1cU103A= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= From 6fb271d6f6e5755180b704e6092efeca09ec49f2 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Thu, 13 Nov 2025 18:20:13 -0500 Subject: [PATCH 40/52] update CHANGELOG.md, UPGRADING.md and remove example telemetry configuration --- CHANGELOG.md | 10 ++++++++++ UPGRADING.md | 12 +++++++++++ server/config/toml.go | 46 ------------------------------------------- 3 files changed, 22 insertions(+), 46 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 787216cbd698..f80bdd215d2e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -36,6 +36,16 @@ Ref: https://keepachangelog.com/en/1.0.0/ # Changelog +## Unreleased + +### Features + +*[#25516](https://github.com/cosmos/cosmos-sdk/pull/25516) Support automatic configuration of OpenTelemetry exporters via [OpenTelemetry declarative configuration](https://pkg.go.dev/go.opentelemetry.io/contrib/otelconf). + +### Deprecated + +*[#25516](https://github.com/cosmos/cosmos-sdk/pull/25516) Deprecate all existing methods and types in the `telemetry` package, usage of `github.com/hashicorp/go-metrics` and the `telemetry` configuration section. New instrumentation should use the official [OpenTelemetry go API](https://pkg.go.dev/go.opentelemetry.io/otel) and Cosmos SDK appllications can automatically expose OpenTelemetry metrics, traces and logs via [OpenTelemetry declarative configuration](https://pkg.go.dev/go.opentelemetry.io/contrib/otelconf). + ## [v0.53.4](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.53.3) - 2025-07-25 This patch update also includes minor dependency bumps. diff --git a/UPGRADING.md b/UPGRADING.md index aaefe25ffd0c..8ae936aa9c46 100644 --- a/UPGRADING.md +++ b/UPGRADING.md @@ -24,3 +24,15 @@ the existing `timout_commit` values that validators have been using will be main For setting the field in your application, there is a new `baseapp` option, `SetNextBlockDelay` which can be passed to your application upon initialization in `app.go`. Setting this value to any non-zero value will override anything that is set in validators' `config.toml`. + +#### Adoption of OpenTelemetry and Deprecation of `github.com/hashicorp/go-metrics` + +Existing Cosmos SDK telemetry support is provide by `github.com/hashicorp/go-metrics` which is undermaintained and only supported metrics instrumentation. +OpenTelemetry provides an integrated solution for metrics, traces and logging which is widely adopted and actively maintained. +Also the existing wrapper functions in the `telemetry` package required acquiring mutex locks and map lookups for every metric operation which is sub-optimal. OpenTelemetry's API uses atomic concurrency wherever possible and should introduce less performance overhead during metric collection. + +The [README.md](telemetry/README.md) in the `telemetry` package provides more details on usage, but below is a quick summary: +1. application developers should follow the official [go OpenTelemetry](https://pkg.go.dev/go.opentelemetry.io/otel) guidelines when instrumenting their applications. +2. node operators who want to configure OpenTelemetry exporters should set the `OTEL_EXPERIMENTAL_CONFIG_FILE` environment variable to the path of a yaml file which follows the OpenTelemetry declarative configuration format specified here: https://pkg.go.dev/go.opentelemetry.io/contrib/otelconf. As long as the `telemetry` package has been imported somwhere (it should already be imported if you are using the SDK), OpenTelemetry will be initialized automatically based on the configuration file. + +NOTE: the go implementation of [otelconf](https://pkg.go.dev/go.opentelemetry.io/contrib/otelconf) is still under development and we will update our usage of it as it matures. \ No newline at end of file diff --git a/server/config/toml.go b/server/config/toml.go index caf01eb43237..649aff916cf5 100644 --- a/server/config/toml.go +++ b/server/config/toml.go @@ -86,52 +86,6 @@ iavl-disable-fastnode = {{ .BaseConfig.IAVLDisableFastNode }} # The fallback is the db_backend value set in CometBFT's config.toml. app-db-backend = "{{ .BaseConfig.AppDBBackend }}" -############################################################################### -### Telemetry Configuration ### -############################################################################### - -[telemetry] - -# Prefixed with keys to separate services. -service-name = "{{ .Telemetry.ServiceName }}" - -# Enabled enables the application telemetry functionality. When enabled, -# an in-memory sink is also enabled by default. Operators may also enable -# other sinks such as Prometheus. -enabled = {{ .Telemetry.Enabled }} - -# Enable prefixing gauge values with hostname. -enable-hostname = {{ .Telemetry.EnableHostname }} - -# Enable adding hostname to labels. -enable-hostname-label = {{ .Telemetry.EnableHostnameLabel }} - -# Enable adding service to labels. -enable-service-label = {{ .Telemetry.EnableServiceLabel }} - -# PrometheusRetentionTime, when positive, enables a Prometheus metrics sink. -prometheus-retention-time = {{ .Telemetry.PrometheusRetentionTime }} - -# GlobalLabels defines a global set of name/value label tuples applied to all -# metrics emitted using the wrapper functions defined in telemetry package. -# -# Example: -# [["chain_id", "cosmoshub-1"]] -global-labels = [{{ range $k, $v := .Telemetry.GlobalLabels }} - ["{{index $v 0 }}", "{{ index $v 1}}"],{{ end }} -] - -# MetricsSink defines the type of metrics sink to use. -metrics-sink = "{{ .Telemetry.MetricsSink }}" - -# StatsdAddr defines the address of a statsd server to send metrics to. -# Only utilized if MetricsSink is set to "statsd" or "dogstatsd". -statsd-addr = "{{ .Telemetry.StatsdAddr }}" - -# DatadogHostname defines the hostname to use when emitting metrics to -# Datadog. Only utilized if MetricsSink is set to "dogstatsd". -datadog-hostname = "{{ .Telemetry.DatadogHostname }}" - ############################################################################### ### API Configuration ### ############################################################################### From 90885bb37a3b4a63607e43de2b786e037fd6888e Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Thu, 13 Nov 2025 18:22:09 -0500 Subject: [PATCH 41/52] update CHANGELOG.md, UPGRADING.md --- CHANGELOG.md | 2 +- UPGRADING.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f80bdd215d2e..17fba1ba0910 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -40,7 +40,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### Features -*[#25516](https://github.com/cosmos/cosmos-sdk/pull/25516) Support automatic configuration of OpenTelemetry exporters via [OpenTelemetry declarative configuration](https://pkg.go.dev/go.opentelemetry.io/contrib/otelconf). +*[#25516](https://github.com/cosmos/cosmos-sdk/pull/25516) Support automatic configuration of OpenTelemetry via [OpenTelemetry declarative configuration](https://pkg.go.dev/go.opentelemetry.io/contrib/otelconf) and add OpenTelemetry instrumentation of `BaseApp`. ### Deprecated diff --git a/UPGRADING.md b/UPGRADING.md index 8ae936aa9c46..bcb0c4a3e824 100644 --- a/UPGRADING.md +++ b/UPGRADING.md @@ -33,6 +33,6 @@ Also the existing wrapper functions in the `telemetry` package required acquirin The [README.md](telemetry/README.md) in the `telemetry` package provides more details on usage, but below is a quick summary: 1. application developers should follow the official [go OpenTelemetry](https://pkg.go.dev/go.opentelemetry.io/otel) guidelines when instrumenting their applications. -2. node operators who want to configure OpenTelemetry exporters should set the `OTEL_EXPERIMENTAL_CONFIG_FILE` environment variable to the path of a yaml file which follows the OpenTelemetry declarative configuration format specified here: https://pkg.go.dev/go.opentelemetry.io/contrib/otelconf. As long as the `telemetry` package has been imported somwhere (it should already be imported if you are using the SDK), OpenTelemetry will be initialized automatically based on the configuration file. +2. node operators who want to configure OpenTelemetry exporters should set the `OTEL_EXPERIMENTAL_CONFIG_FILE` environment variable to the path of a yaml file which follows the OpenTelemetry declarative configuration format specified here: https://pkg.go.dev/go.opentelemetry.io/contrib/otelconf. As long as the `telemetry` package has been imported somewhere (it should already be imported if you are using the SDK), OpenTelemetry will be initialized automatically based on the configuration file. NOTE: the go implementation of [otelconf](https://pkg.go.dev/go.opentelemetry.io/contrib/otelconf) is still under development and we will update our usage of it as it matures. \ No newline at end of file From 5e9c6ba426dd49946bbdecfa5562f748fd39c5eb Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Thu, 13 Nov 2025 18:29:14 -0500 Subject: [PATCH 42/52] update docs --- server/api/server.go | 2 +- server/config/config.go | 2 +- telemetry/config.go | 8 ++------ telemetry/doc.go | 2 ++ telemetry/metrics.go | 2 +- telemetry/wrapper.go | 4 ++-- 6 files changed, 9 insertions(+), 11 deletions(-) diff --git a/server/api/server.go b/server/api/server.go index 180775c34099..2b3919779713 100644 --- a/server/api/server.go +++ b/server/api/server.go @@ -191,7 +191,7 @@ func (s *Server) Close() error { return s.listener.Close() } -// Deprecated +// Deprecated: Use OpenTelemetry instead, see the `telemetry` package for more details. func (s *Server) SetTelemetry(m *telemetry.Metrics) { s.mtx.Lock() s.registerMetrics(m) diff --git a/server/config/config.go b/server/config/config.go index 15c9343599fc..e803d18011b3 100644 --- a/server/config/config.go +++ b/server/config/config.go @@ -189,7 +189,7 @@ type ( type Config struct { BaseConfig `mapstructure:",squash"` - // Deprecated: Telemetry defines the application telemetry configuration + // Deprecated: Use OpenTelemetry instead, see the `telemetry` package for more details. Telemetry telemetry.Config `mapstructure:"telemetry"` API APIConfig `mapstructure:"api"` GRPC GRPCConfig `mapstructure:"grpc"` diff --git a/telemetry/config.go b/telemetry/config.go index 428e4d9a1851..6615eef1c199 100644 --- a/telemetry/config.go +++ b/telemetry/config.go @@ -61,11 +61,7 @@ func doInit() error { return fmt.Errorf("failed to parse telemetry config file: %w", err) } - cfgJson, err := json.Marshal(cfg) - if err != nil { - return fmt.Errorf("failed to marshal telemetry config file: %w", err) - } - fmt.Printf("\nInitializing telemetry with config:\n%s\n\n", cfgJson) + fmt.Printf("\nInitializing OpenTelemetry\n") opts = append(opts, otelconf.WithOpenTelemetryConfiguration(*cfg)) @@ -187,7 +183,7 @@ func doInit() error { // mark otel as configured in the log package log.SetOpenTelemetryConfigured(true) // emit an initialized message which verifies basic telemetry is working - slog.Info("Telemetry initialized") + slog.Info("OpenTelemetry initialized", "config", cfg) // extract service name from config for go-metrics compatibility layer serviceName := "cosmos-sdk" // default fallback diff --git a/telemetry/doc.go b/telemetry/doc.go index 2dc4a014c8a1..aadefd1d4b9f 100644 --- a/telemetry/doc.go +++ b/telemetry/doc.go @@ -3,4 +3,6 @@ // github.com/hashicorp/go-metrics. // By default, this package configures the github.com/hashicorp/go-metrics default instance to // send all metrics to OpenTelemetry. +// Existing users of the legacy wrapper functions in this package should begin to migrate their +// code to use OpenTelemetry APIs directly. package telemetry diff --git a/telemetry/metrics.go b/telemetry/metrics.go index 0168cf9bb0ff..ec817b1f6c62 100644 --- a/telemetry/metrics.go +++ b/telemetry/metrics.go @@ -61,7 +61,7 @@ type DisplayableSink interface { DisplayMetrics(resp http.ResponseWriter, req *http.Request) (any, error) } -// Deprecated: Config defines the configuration options for application telemetry. +// Deprecated: Use OpenTelemetry instead. type Config struct { // Prefixed with keys to separate services ServiceName string `mapstructure:"service-name"` diff --git a/telemetry/wrapper.go b/telemetry/wrapper.go index 50ca00c3d64a..23ec9543f674 100644 --- a/telemetry/wrapper.go +++ b/telemetry/wrapper.go @@ -14,12 +14,12 @@ const ( MetricLabelNameModule = "module" ) -// NewLabel creates a new instance of Label with name and value +// Deprecated: NewLabel creates a new instance of Label with name and value func NewLabel(name, value string) metrics.Label { return metrics.Label{Name: name, Value: value} } -// ModuleMeasureSince provides a short hand method for emitting a time measure +// Deprecated: ModuleMeasureSince provides a short hand method for emitting a time measure // metric for a module with a given set of keys. If any global labels are defined, // they will be added to the module label. func ModuleMeasureSince(module string, start time.Time, keys ...string) { From a1f27c8373db26345b9dcb865c379baf7d15d062 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Fri, 14 Nov 2025 13:17:33 -0500 Subject: [PATCH 43/52] revert any logging configuration, other than setting up the otel logger provider --- log/go.mod | 5 ----- log/go.sum | 11 +---------- log/logger.go | 12 +----------- log/options.go | 10 ---------- log/otel.go | 21 --------------------- log/slog.go | 44 -------------------------------------------- log/slog/logger.go | 35 ++++++++++++++++++++++++++++++++--- log/testing.go | 18 +----------------- server/util.go | 17 ++--------------- telemetry/config.go | 17 +---------------- 10 files changed, 38 insertions(+), 152 deletions(-) delete mode 100644 log/otel.go delete mode 100644 log/slog.go diff --git a/log/go.mod b/log/go.mod index 267117d91fec..f8d2244b213a 100644 --- a/log/go.mod +++ b/log/go.mod @@ -6,7 +6,6 @@ require ( github.com/bytedance/sonic v1.14.2 github.com/pkg/errors v0.9.1 github.com/rs/zerolog v1.34.0 - github.com/samber/slog-zerolog/v2 v2.9.0 ) require ( @@ -16,11 +15,7 @@ require ( github.com/klauspost/cpuid/v2 v2.2.10 // indirect github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect - github.com/samber/lo v1.51.0 // indirect - github.com/samber/slog-common v0.19.0 // indirect - github.com/stretchr/testify v1.11.1 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect golang.org/x/arch v0.22.0 // indirect golang.org/x/sys v0.37.0 // indirect - golang.org/x/text v0.22.0 // indirect ) diff --git a/log/go.sum b/log/go.sum index 30b8ba522609..fa004f25b81c 100644 --- a/log/go.sum +++ b/log/go.sum @@ -27,12 +27,6 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0= github.com/rs/zerolog v1.34.0 h1:k43nTLIwcTVQAncfCw4KZ2VY6ukYoZaBPNOE8txlOeY= github.com/rs/zerolog v1.34.0/go.mod h1:bJsvje4Z08ROH4Nhs5iH600c3IkWhwp44iRc54W6wYQ= -github.com/samber/lo v1.51.0 h1:kysRYLbHy/MB7kQZf5DSN50JHmMsNEdeY24VzJFu7wI= -github.com/samber/lo v1.51.0/go.mod h1:4+MXEGsJzbKGaUEQFKBq2xtfuznW9oz/WrgyzMzRoM0= -github.com/samber/slog-common v0.19.0 h1:fNcZb8B2uOLooeYwFpAlKjkQTUafdjfqKcwcC89G9YI= -github.com/samber/slog-common v0.19.0/go.mod h1:dTz+YOU76aH007YUU0DffsXNsGFQRQllPQh9XyNoA3M= -github.com/samber/slog-zerolog/v2 v2.9.0 h1:6LkOabJmZdNLaUWkTC3IVVA+dq7b/V0FM6lz6/7+THI= -github.com/samber/slog-zerolog/v2 v2.9.0/go.mod h1:gnQW9VnCfM34v2pRMUIGMsZOVbYLqY/v0Wxu6atSVGc= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= @@ -40,9 +34,8 @@ github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= -github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= golang.org/x/arch v0.22.0 h1:c/Zle32i5ttqRXjdLyyHZESLD/bB90DCU1g9l/0YBDI= @@ -52,8 +45,6 @@ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ= golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM= -golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/log/logger.go b/log/logger.go index 8deac73d6f24..b284968039df 100644 --- a/log/logger.go +++ b/log/logger.go @@ -5,13 +5,11 @@ import ( "encoding/json" "fmt" "io" - "log/slog" "github.com/bytedance/sonic" "github.com/pkg/errors" "github.com/rs/zerolog" "github.com/rs/zerolog/pkgerrors" - slogzerolog "github.com/samber/slog-zerolog/v2" ) func init() { @@ -147,20 +145,12 @@ func NewLogger(dst io.Writer, options ...Option) Logger { logger = logger.Level(logCfg.Level) logger = logger.Hook(logCfg.Hooks...) - wrapper := zeroLogWrapper{ + return zeroLogWrapper{ Logger: &logger, regularLevel: logCfg.Level, verboseLevel: logCfg.VerboseLevel, filterWriter: fltWtr, } - - if logCfg.SetDefaultSlog { - slog.SetDefault(slog.New(slogzerolog.Option{ - // NOTE: this slog default logger won't respect any verbose level changes - Logger: wrapper.Logger, - }.NewZerologHandler())) - } - return wrapper } // NewCustomLogger returns a new logger with the given zerolog logger. diff --git a/log/options.go b/log/options.go index 683f9320518a..6da1254f75cc 100644 --- a/log/options.go +++ b/log/options.go @@ -35,9 +35,6 @@ type Config struct { StackTrace bool TimeFormat string Hooks []zerolog.Hook - // SetDefaultSlog indicates whether to set this logger instance as the default slog logger globally - // to capture logs from libraries using slog.Default(). - SetDefaultSlog bool } type Option func(*Config) @@ -81,13 +78,6 @@ func ColorOption(val bool) Option { } } -// SetDefaultSlogOption adds an option to set logger this logger to be the default slog logger -func SetDefaultSlogOption() Option { - return func(cfg *Config) { - cfg.SetDefaultSlog = true - } -} - // TimeFormatOption configures timestamp format of the logger // Timestamps are disabled if empty. // It is the responsibility of the caller to provide correct values diff --git a/log/otel.go b/log/otel.go deleted file mode 100644 index 6c2e889cccfd..000000000000 --- a/log/otel.go +++ /dev/null @@ -1,21 +0,0 @@ -package log - -import ( - "sync/atomic" -) - -var otelConfigured atomic.Bool - -// IsOpenTelemetryConfigured returns true if OpenTelemetry has been configured. -// This is used to determine whether to route log messages to OpenTelemetry. -func IsOpenTelemetryConfigured() bool { - return otelConfigured.Load() -} - -// SetOpenTelemetryConfigured sets whether OpenTelemetry has been configured. -// Setting this true, that indicates that global loggers should route log messages to OpenTelemetry. -// It also will indicate to automatic OpenTelemetry configuration code that OpenTelemetry has already been set up, -// so that it does not attempt to set it up again. -func SetOpenTelemetryConfigured(configured bool) { - otelConfigured.Store(configured) -} diff --git a/log/slog.go b/log/slog.go deleted file mode 100644 index 8dd7b84a07e5..000000000000 --- a/log/slog.go +++ /dev/null @@ -1,44 +0,0 @@ -package log - -import "log/slog" - -var _ Logger = SlogLogger{} - -// SlogLogger satisfies [log.Logger] with logging backed by -// an instance of [*slog.Logger]. -type SlogLogger struct { - log *slog.Logger -} - -// NewSlogLogger returns a Logger backed by an existing slog.Logger instance. -// All logging methods are called directly on the *slog.Logger; -// therefore it is the caller's responsibility to configure message filtering, -// level filtering, output format, and so on. -func NewSlogLogger(log *slog.Logger) SlogLogger { - return SlogLogger{log: log} -} - -func (l SlogLogger) Info(msg string, keyVals ...any) { - l.log.Info(msg, keyVals...) -} - -func (l SlogLogger) Warn(msg string, keyVals ...any) { - l.log.Warn(msg, keyVals...) -} - -func (l SlogLogger) Error(msg string, keyVals ...any) { - l.log.Error(msg, keyVals...) -} - -func (l SlogLogger) Debug(msg string, keyVals ...any) { - l.log.Debug(msg, keyVals...) -} - -func (l SlogLogger) With(keyVals ...any) Logger { - return SlogLogger{log: l.log.With(keyVals...)} -} - -// Impl returns l's underlying [*slog.Logger]. -func (l SlogLogger) Impl() any { - return l.log -} diff --git a/log/slog/logger.go b/log/slog/logger.go index 3af4d1a3ba9b..4b6c30ec4b97 100644 --- a/log/slog/logger.go +++ b/log/slog/logger.go @@ -8,14 +8,43 @@ import ( "cosmossdk.io/log" ) +var _ log.Logger = Logger{} + // Logger satisfies [log.Logger] with logging backed by // an instance of [*slog.Logger]. -type Logger = log.SlogLogger +type Logger struct { + log *slog.Logger +} // NewCustomLogger returns a Logger backed by an existing slog.Logger instance. // All logging methods are called directly on the *slog.Logger; // therefore it is the caller's responsibility to configure message filtering, // level filtering, output format, and so on. -func NewCustomLogger(logger *slog.Logger) Logger { - return log.NewSlogLogger(logger) +func NewCustomLogger(log *slog.Logger) Logger { + return Logger{log: log} +} + +func (l Logger) Info(msg string, keyVals ...any) { + l.log.Info(msg, keyVals...) +} + +func (l Logger) Warn(msg string, keyVals ...any) { + l.log.Warn(msg, keyVals...) +} + +func (l Logger) Error(msg string, keyVals ...any) { + l.log.Error(msg, keyVals...) +} + +func (l Logger) Debug(msg string, keyVals ...any) { + l.log.Debug(msg, keyVals...) +} + +func (l Logger) With(keyVals ...any) log.Logger { + return Logger{log: l.log.With(keyVals...)} +} + +// Impl returns l's underlying [*slog.Logger]. +func (l Logger) Impl() any { + return l.log } diff --git a/log/testing.go b/log/testing.go index c8927b91525b..0e82eced62ba 100644 --- a/log/testing.go +++ b/log/testing.go @@ -1,11 +1,9 @@ package log import ( - "log/slog" "time" "github.com/rs/zerolog" - slogzerolog "github.com/samber/slog-zerolog/v2" ) // TestingT is the interface required for logging in tests. @@ -40,19 +38,11 @@ func NewTestLoggerInfo(t TestingT) Logger { // // This is primarily helpful during active debugging of a test // with verbose logs. -// -// If OpenTelemetry is configured, all log messages will be -// routed to the OpenTelemetry instead. -// If OpenTelemetry is not configured, the default global log/slog logger -// will be routed to the test output we have configured at the Error level. func NewTestLoggerError(t TestingT) Logger { return newTestLogger(t, zerolog.ErrorLevel) } func newTestLogger(t TestingT, lvl zerolog.Level) Logger { - if IsOpenTelemetryConfigured() { - return NewSlogLogger(slog.Default()) - } cw := zerolog.ConsoleWriter{ NoColor: true, TimeFormat: time.Kitchen, @@ -66,11 +56,5 @@ func newTestLogger(t TestingT, lvl zerolog.Level) Logger { Frame: 7, }, } - logger := NewCustomLogger(zerolog.New(cw).Level(lvl)).(zeroLogWrapper) - - // set this as the default slog logger to capture logs from libraries using slog.Default() - slog.SetDefault(slog.New(slogzerolog.Option{Logger: logger.Logger}.NewZerologHandler())) - - return logger - + return NewCustomLogger(zerolog.New(cw).Level(lvl)) } diff --git a/server/util.go b/server/util.go index 01bd4cb8f393..42d01bd65d09 100644 --- a/server/util.go +++ b/server/util.go @@ -5,7 +5,6 @@ import ( "errors" "fmt" "io" - "log/slog" "net" "os" "os/signal" @@ -25,13 +24,12 @@ import ( "github.com/spf13/viper" "golang.org/x/sync/errgroup" + "cosmossdk.io/log" "cosmossdk.io/store" "cosmossdk.io/store/snapshots" snapshottypes "cosmossdk.io/store/snapshots/types" storetypes "cosmossdk.io/store/types" - "cosmossdk.io/log" - "github.com/cosmos/cosmos-sdk/baseapp" "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/server/config" @@ -169,16 +167,7 @@ func InterceptConfigsAndCreateContext(cmd *cobra.Command, customAppConfigTemplat // CreateSDKLogger creates the default SDK logger. // It reads the log level and format from the server context. -// If OpenTelemetry is configured, then that will take precedence over any server -// settings and all logs will be routed to OpenTelemetry. -// If OpenTelemetry is not configured, the SDK logger will also capture any -// logs sent to the default log/slog logger. func CreateSDKLogger(ctx *Context, out io.Writer) (log.Logger, error) { - if log.IsOpenTelemetryConfigured() { - // NOTE: we assume that the default slog logger is already configured to route to OpenTelemetry - return log.NewSlogLogger(slog.Default()), nil - } - var opts []log.Option if ctx.Viper.GetString(flags.FlagLogFormat) == flags.OutputFormatJSON { opts = append(opts, log.OutputJSONOption()) @@ -186,9 +175,7 @@ func CreateSDKLogger(ctx *Context, out io.Writer) (log.Logger, error) { opts = append(opts, log.ColorOption(!ctx.Viper.GetBool(flags.FlagLogNoColor)), // We use CometBFT flag (cmtcli.TraceFlag) for trace logging. - log.TraceOption(ctx.Viper.GetBool(FlagTrace)), - log.SetDefaultSlogOption(), - ) + log.TraceOption(ctx.Viper.GetBool(FlagTrace))) verboseLogLevelStr := ctx.Viper.GetString(flags.FlagVerboseLogLevel) if verboseLogLevelStr != "" { diff --git a/telemetry/config.go b/telemetry/config.go index 6615eef1c199..bb928ba98217 100644 --- a/telemetry/config.go +++ b/telemetry/config.go @@ -2,14 +2,11 @@ package telemetry import ( "context" - "encoding/json" "fmt" - "log/slog" "os" "time" "github.com/hashicorp/go-metrics" - "go.opentelemetry.io/contrib/bridges/otelslog" "go.opentelemetry.io/contrib/instrumentation/host" "go.opentelemetry.io/contrib/instrumentation/runtime" "go.opentelemetry.io/contrib/otelconf/v0.3.0" @@ -22,8 +19,6 @@ import ( metricsdk "go.opentelemetry.io/otel/sdk/metric" tracesdk "go.opentelemetry.io/otel/sdk/trace" "go.yaml.in/yaml/v3" - - "cosmossdk.io/log" ) var sdk otelconf.SDK @@ -37,11 +32,6 @@ func init() { } func doInit() error { - // if otel is already marked as configured, skip - if log.IsOpenTelemetryConfigured() { - return nil - } - var err error var opts []otelconf.ConfigurationOption @@ -178,12 +168,7 @@ func doInit() error { otel.SetTracerProvider(sdk.TracerProvider()) otel.SetMeterProvider(sdk.MeterProvider()) logglobal.SetLoggerProvider(sdk.LoggerProvider()) - // setup slog default provider so that any logs emitted the default slog will be traced - slog.SetDefault(otelslog.NewLogger("", otelslog.WithSource(true))) - // mark otel as configured in the log package - log.SetOpenTelemetryConfigured(true) - // emit an initialized message which verifies basic telemetry is working - slog.Info("OpenTelemetry initialized", "config", cfg) + fmt.Printf("\nOpenTelemetry initialized successfully\n") // extract service name from config for go-metrics compatibility layer serviceName := "cosmos-sdk" // default fallback From 75279facb130cf355a6ca765f49dae6cc3b75a51 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Fri, 14 Nov 2025 13:41:49 -0500 Subject: [PATCH 44/52] lint fix --- baseapp/baseapp.go | 3 +-- baseapp/state/manager.go | 4 +--- baseapp/state/state.go | 3 ++- telemetry/compat.go | 6 ++++-- telemetry/config.go | 18 ++++++++++-------- types/context.go | 3 +-- types/module/module.go | 4 +--- 7 files changed, 20 insertions(+), 21 deletions(-) diff --git a/baseapp/baseapp.go b/baseapp/baseapp.go index b7ac2e3b07c7..025a4bfde74a 100644 --- a/baseapp/baseapp.go +++ b/baseapp/baseapp.go @@ -21,13 +21,12 @@ import ( protov2 "google.golang.org/protobuf/proto" errorsmod "cosmossdk.io/errors" + "cosmossdk.io/log" "cosmossdk.io/store" storemetrics "cosmossdk.io/store/metrics" "cosmossdk.io/store/snapshots" storetypes "cosmossdk.io/store/types" - "cosmossdk.io/log" - "github.com/cosmos/cosmos-sdk/baseapp/config" "github.com/cosmos/cosmos-sdk/baseapp/oe" "github.com/cosmos/cosmos-sdk/baseapp/state" diff --git a/baseapp/state/manager.go b/baseapp/state/manager.go index 6e8a1f901f32..28956263d62b 100644 --- a/baseapp/state/manager.go +++ b/baseapp/state/manager.go @@ -17,9 +17,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ) -var ( - tracer = otel.Tracer("cosmos-sdk/baseapp") -) +var tracer = otel.Tracer("cosmos-sdk/baseapp") type Manager struct { // volatile states: diff --git a/baseapp/state/state.go b/baseapp/state/state.go index 7655e8f83c12..fe6681d35787 100644 --- a/baseapp/state/state.go +++ b/baseapp/state/state.go @@ -3,9 +3,10 @@ package state import ( "sync" - storetypes "cosmossdk.io/store/types" "go.opentelemetry.io/otel/trace" + storetypes "cosmossdk.io/store/types" + sdk "github.com/cosmos/cosmos-sdk/types" ) diff --git a/telemetry/compat.go b/telemetry/compat.go index 61f92c342955..2b0199f24dd8 100644 --- a/telemetry/compat.go +++ b/telemetry/compat.go @@ -102,8 +102,10 @@ func (o *otelGoMetricsSink) SetPrecisionGaugeWithLabels(key []string, val float6 o.getGauge(flattenKey(key)).Record(o.ctx, val, toOtelAttrs(labels)) } -var _ gometrics.MetricSink = &otelGoMetricsSink{} -var _ gometrics.PrecisionGaugeMetricSink = &otelGoMetricsSink{} +var ( + _ gometrics.MetricSink = &otelGoMetricsSink{} + _ gometrics.PrecisionGaugeMetricSink = &otelGoMetricsSink{} +) var spaceReplacer = strings.NewReplacer(" ", "_") diff --git a/telemetry/config.go b/telemetry/config.go index bb928ba98217..119ca1a23504 100644 --- a/telemetry/config.go +++ b/telemetry/config.go @@ -21,8 +21,10 @@ import ( "go.yaml.in/yaml/v3" ) -var sdk otelconf.SDK -var shutdownFuncs []func(context.Context) error +var ( + sdk otelconf.SDK + shutdownFuncs []func(context.Context) error +) func init() { err := doInit() @@ -63,7 +65,7 @@ func doInit() error { extra := *extraCfg.CosmosExtra if extra.TraceFile != "" { fmt.Printf("Initializing trace file: %s\n", extra.TraceFile) - traceFile, err := os.OpenFile(extra.TraceFile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644) + traceFile, err := os.OpenFile(extra.TraceFile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0o644) if err != nil { return fmt.Errorf("failed to open trace file: %w", err) } @@ -75,7 +77,7 @@ func doInit() error { }) exporter, err := stdouttrace.New( stdouttrace.WithWriter(traceFile), - //stdouttrace.WithPrettyPrint(), + // stdouttrace.WithPrettyPrint(), ) if err != nil { return fmt.Errorf("failed to create stdout trace exporter: %w", err) @@ -86,7 +88,7 @@ func doInit() error { } if extra.MetricsFile != "" { fmt.Printf("Initializing metrics file: %s\n", extra.MetricsFile) - metricsFile, err := os.OpenFile(extra.MetricsFile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644) + metricsFile, err := os.OpenFile(extra.MetricsFile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0o644) if err != nil { return fmt.Errorf("failed to open metrics file: %w", err) } @@ -98,7 +100,7 @@ func doInit() error { }) exporter, err := stdoutmetric.New( stdoutmetric.WithWriter(metricsFile), - //stdoutmetric.WithPrettyPrint(), + // stdoutmetric.WithPrettyPrint(), ) if err != nil { return fmt.Errorf("failed to create stdout metric exporter: %w", err) @@ -121,7 +123,7 @@ func doInit() error { } if extra.LogsFile != "" { fmt.Printf("Initializing logs file: %s\n", extra.LogsFile) - logsFile, err := os.OpenFile(extra.LogsFile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644) + logsFile, err := os.OpenFile(extra.LogsFile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0o644) if err != nil { return fmt.Errorf("failed to open logs file: %w", err) } @@ -133,7 +135,7 @@ func doInit() error { }) exporter, err := stdoutlog.New( stdoutlog.WithWriter(logsFile), - //stdoutlog.WithPrettyPrint(), + // stdoutlog.WithPrettyPrint(), ) if err != nil { return fmt.Errorf("failed to create stdout log exporter: %w", err) diff --git a/types/context.go b/types/context.go index 34f4a85cfd2f..724707f0abfa 100644 --- a/types/context.go +++ b/types/context.go @@ -10,10 +10,9 @@ import ( "cosmossdk.io/core/comet" "cosmossdk.io/core/header" + "cosmossdk.io/log" "cosmossdk.io/store/gaskv" storetypes "cosmossdk.io/store/types" - - "cosmossdk.io/log" ) // ExecMode defines the execution mode which can be set on a Context. diff --git a/types/module/module.go b/types/module/module.go index 0c09b7a89cf4..1caf5569be30 100644 --- a/types/module/module.go +++ b/types/module/module.go @@ -54,9 +54,7 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) -var ( - tracer = otel.Tracer("cosmos-sdk/types/module") -) +var tracer = otel.Tracer("cosmos-sdk/types/module") // AppModuleBasic is the standard form for basic non-dependent elements of an application module. type AppModuleBasic interface { From 10436c99b1364eaeed42c5c679457bd34ce914ee Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Fri, 14 Nov 2025 14:02:23 -0500 Subject: [PATCH 45/52] Update UPGRADING.md Co-authored-by: Tyler <48813565+technicallyty@users.noreply.github.com> --- UPGRADING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/UPGRADING.md b/UPGRADING.md index bcb0c4a3e824..20269ce3811b 100644 --- a/UPGRADING.md +++ b/UPGRADING.md @@ -27,7 +27,7 @@ initialization in `app.go`. Setting this value to any non-zero value will overr #### Adoption of OpenTelemetry and Deprecation of `github.com/hashicorp/go-metrics` -Existing Cosmos SDK telemetry support is provide by `github.com/hashicorp/go-metrics` which is undermaintained and only supported metrics instrumentation. +Existing Cosmos SDK telemetry support is provided by `github.com/hashicorp/go-metrics` which is undermaintained and only supported metrics instrumentation. OpenTelemetry provides an integrated solution for metrics, traces and logging which is widely adopted and actively maintained. Also the existing wrapper functions in the `telemetry` package required acquiring mutex locks and map lookups for every metric operation which is sub-optimal. OpenTelemetry's API uses atomic concurrency wherever possible and should introduce less performance overhead during metric collection. From b870b7c9770616e9719efcb3e00a0cdfe835c473 Mon Sep 17 00:00:00 2001 From: Tyler <48813565+technicallyty@users.noreply.github.com> Date: Mon, 17 Nov 2025 17:58:18 -0500 Subject: [PATCH 46/52] re-add telemetry toml --- go.mod | 1 - go.sum | 2 -- server/config/toml.go | 46 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 46 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index f772b1908c46..9a00da029290 100644 --- a/go.mod +++ b/go.mod @@ -57,7 +57,6 @@ require ( github.com/tendermint/go-amino v0.16.0 github.com/test-go/testify v1.1.4 github.com/tidwall/btree v1.8.1 - go.opentelemetry.io/contrib/bridges/otelslog v0.13.0 go.opentelemetry.io/contrib/instrumentation/host v0.63.0 go.opentelemetry.io/contrib/instrumentation/runtime v0.63.0 go.opentelemetry.io/contrib/otelconf v0.18.0 diff --git a/go.sum b/go.sum index 42de334b4d97..774a47c2078c 100644 --- a/go.sum +++ b/go.sum @@ -856,8 +856,6 @@ go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= -go.opentelemetry.io/contrib/bridges/otelslog v0.13.0 h1:bwnLpizECbPr1RrQ27waeY2SPIPeccCx/xLuoYADZ9s= -go.opentelemetry.io/contrib/bridges/otelslog v0.13.0/go.mod h1:3nWlOiiqA9UtUnrcNk82mYasNxD8ehOspL0gOfEo6Y4= go.opentelemetry.io/contrib/detectors/gcp v1.36.0 h1:F7q2tNlCaHY9nMKHR6XH9/qkp8FktLnIcy6jJNyOCQw= go.opentelemetry.io/contrib/detectors/gcp v1.36.0/go.mod h1:IbBN8uAIIx734PTonTPxAxnjc2pQTxWNkwfstZ+6H2k= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0 h1:q4XOmH/0opmeuJtPsbFNivyl7bCt7yRBbeEm2sC/XtQ= diff --git a/server/config/toml.go b/server/config/toml.go index 649aff916cf5..caf01eb43237 100644 --- a/server/config/toml.go +++ b/server/config/toml.go @@ -86,6 +86,52 @@ iavl-disable-fastnode = {{ .BaseConfig.IAVLDisableFastNode }} # The fallback is the db_backend value set in CometBFT's config.toml. app-db-backend = "{{ .BaseConfig.AppDBBackend }}" +############################################################################### +### Telemetry Configuration ### +############################################################################### + +[telemetry] + +# Prefixed with keys to separate services. +service-name = "{{ .Telemetry.ServiceName }}" + +# Enabled enables the application telemetry functionality. When enabled, +# an in-memory sink is also enabled by default. Operators may also enable +# other sinks such as Prometheus. +enabled = {{ .Telemetry.Enabled }} + +# Enable prefixing gauge values with hostname. +enable-hostname = {{ .Telemetry.EnableHostname }} + +# Enable adding hostname to labels. +enable-hostname-label = {{ .Telemetry.EnableHostnameLabel }} + +# Enable adding service to labels. +enable-service-label = {{ .Telemetry.EnableServiceLabel }} + +# PrometheusRetentionTime, when positive, enables a Prometheus metrics sink. +prometheus-retention-time = {{ .Telemetry.PrometheusRetentionTime }} + +# GlobalLabels defines a global set of name/value label tuples applied to all +# metrics emitted using the wrapper functions defined in telemetry package. +# +# Example: +# [["chain_id", "cosmoshub-1"]] +global-labels = [{{ range $k, $v := .Telemetry.GlobalLabels }} + ["{{index $v 0 }}", "{{ index $v 1}}"],{{ end }} +] + +# MetricsSink defines the type of metrics sink to use. +metrics-sink = "{{ .Telemetry.MetricsSink }}" + +# StatsdAddr defines the address of a statsd server to send metrics to. +# Only utilized if MetricsSink is set to "statsd" or "dogstatsd". +statsd-addr = "{{ .Telemetry.StatsdAddr }}" + +# DatadogHostname defines the hostname to use when emitting metrics to +# Datadog. Only utilized if MetricsSink is set to "dogstatsd". +datadog-hostname = "{{ .Telemetry.DatadogHostname }}" + ############################################################################### ### API Configuration ### ############################################################################### From 3b2440cc64160ad2ae4044f4d2af02af30e4ac7c Mon Sep 17 00:00:00 2001 From: Tyler <48813565+technicallyty@users.noreply.github.com> Date: Tue, 18 Nov 2025 09:20:52 -0500 Subject: [PATCH 47/52] add deprecation notice to telemetry toml config --- server/config/toml.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/server/config/toml.go b/server/config/toml.go index caf01eb43237..535b0fbcfde2 100644 --- a/server/config/toml.go +++ b/server/config/toml.go @@ -90,6 +90,10 @@ app-db-backend = "{{ .BaseConfig.AppDBBackend }}" ### Telemetry Configuration ### ############################################################################### +# DEPRECATED: telemetry will be removed in a future release as we migrate to OpenTelemetry. +# To route the existing metrics to OpenTelemetry, set metrics-sink to 'otel'. +# It is highly encouraged to begin migrating telemetry data to use native OpenTelemetry. +# See https://opentelemetry.io/docs/languages/go/getting-started/ to get started. [telemetry] # Prefixed with keys to separate services. From 2c20c902a91ce4275ff85a78390988f73cfa74cc Mon Sep 17 00:00:00 2001 From: Tyler <48813565+technicallyty@users.noreply.github.com> Date: Tue, 18 Nov 2025 09:47:28 -0500 Subject: [PATCH 48/52] remove legacy metrics init in opentelemetry init --- telemetry/config.go | 30 +++--------------------------- 1 file changed, 3 insertions(+), 27 deletions(-) diff --git a/telemetry/config.go b/telemetry/config.go index 119ca1a23504..484c4a3a5a7d 100644 --- a/telemetry/config.go +++ b/telemetry/config.go @@ -6,10 +6,9 @@ import ( "os" "time" - "github.com/hashicorp/go-metrics" "go.opentelemetry.io/contrib/instrumentation/host" "go.opentelemetry.io/contrib/instrumentation/runtime" - "go.opentelemetry.io/contrib/otelconf/v0.3.0" + otelconf "go.opentelemetry.io/contrib/otelconf/v0.3.0" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/exporters/stdout/stdoutlog" "go.opentelemetry.io/otel/exporters/stdout/stdoutmetric" @@ -27,13 +26,13 @@ var ( ) func init() { - err := doInit() + err := initOpenTelemetry() if err != nil { panic(err) } } -func doInit() error { +func initOpenTelemetry() error { var err error var opts []otelconf.ConfigurationOption @@ -172,29 +171,6 @@ func doInit() error { logglobal.SetLoggerProvider(sdk.LoggerProvider()) fmt.Printf("\nOpenTelemetry initialized successfully\n") - // extract service name from config for go-metrics compatibility layer - serviceName := "cosmos-sdk" // default fallback - if cfg.Resource != nil && cfg.Resource.Attributes != nil { - for _, attr := range cfg.Resource.Attributes { - if attr.Name == "service.name" { - if svcNameStr, ok := attr.Value.(string); ok { - serviceName = svcNameStr - } - break - } - } - } - - // setup go-metrics compatibility layer - _, err = metrics.NewGlobal(metrics.DefaultConfig(serviceName), newOtelGoMetricsSink( - context.Background(), - sdk.MeterProvider().Meter("gometrics"), - )) - if err != nil { - return fmt.Errorf("failed to initialize go-metrics compatibility layer: %w", err) - } - globalTelemetryEnabled = true - return nil } From ebe7fd9b36c75f2409624af558b25693f24398f9 Mon Sep 17 00:00:00 2001 From: Tyler <48813565+technicallyty@users.noreply.github.com> Date: Tue, 18 Nov 2025 12:22:43 -0500 Subject: [PATCH 49/52] re-add changelog entries --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 274b1d72f0f3..cb9ccd4518e5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -56,6 +56,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ * (crypto) [#24861](https://github.com/cosmos/cosmos-sdk/pull/24861) add `PubKeyFromCometTypeAndBytes` helper function to convert from `comet/v2` PubKeys to the `cryptotypes.Pubkey` interface. * (abci_utils) [#25008](https://github.com/cosmos/cosmos-sdk/pull/25008) add the ability to assign a custom signer extraction adapter in `DefaultProposalHandler`. * (crypto/ledger) [#25435](https://github.com/cosmos/cosmos-sdk/pull/25435) Add SetDERConversion to reset skipDERConversion and App name for ledger. +* [#25516](https://github.com/cosmos/cosmos-sdk/pull/25516) Support automatic configuration of OpenTelemetry via [OpenTelemetry declarative configuration](https://pkg.go.dev/go.opentelemetry.io/contrib/otelconf) and add OpenTelemetry instrumentation of `BaseApp`. ### Improvements @@ -84,6 +85,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ * (x/nft) [#24575](https://github.com/cosmos/cosmos-sdk/pull/24575) Deprecate the `x/nft` module in the Cosmos SDK repository. This module will not be maintained to the extent that our core modules will and will be kept in a [legacy repo](https://github.com/cosmos/cosmos-legacy). * (x/group) [#24571](https://github.com/cosmos/cosmos-sdk/pull/24571) Deprecate the `x/group` module in the Cosmos SDK repository. This module will not be maintained to the extent that our core modules will and will be kept in a [legacy repo](https://github.com/cosmos/cosmos-legacy). * (types) [#24664](https://github.com/cosmos/cosmos-sdk/pull/24664) Deprecate the `Invariant` type in the Cosmos SDK. +* [#25516](https://github.com/cosmos/cosmos-sdk/pull/25516) Deprecate all existing methods and types in the `telemetry` package, usage of `github.com/hashicorp/go-metrics` and the `telemetry` configuration section. New instrumentation should use the official [OpenTelemetry go API](https://pkg.go.dev/go.opentelemetry.io/otel) and Cosmos SDK appllications can automatically expose OpenTelemetry metrics, traces and logs via [OpenTelemetry declarative configuration](https://pkg.go.dev/go.opentelemetry.io/contrib/otelconf). ## [v0.53.4](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.53.3) - 2025-07-25 From 9e09f538461a26a4bcfaad93037f1ea5ebbfd533 Mon Sep 17 00:00:00 2001 From: Tyler <48813565+technicallyty@users.noreply.github.com> Date: Wed, 19 Nov 2025 12:25:13 -0500 Subject: [PATCH 50/52] changelog.md --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2b2af6210e90..05f721ab40c6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -57,6 +57,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ * (abci_utils) [#25008](https://github.com/cosmos/cosmos-sdk/pull/25008) add the ability to assign a custom signer extraction adapter in `DefaultProposalHandler`. * (crypto/ledger) [#25435](https://github.com/cosmos/cosmos-sdk/pull/25435) Add SetDERConversion to reset skipDERConversion and App name for ledger. * (gRPC) [#25565](https://github.com/cosmos/cosmos-sdk/pull/25565) Support for multi gRPC query clients serve with historical binaries to serve proper historical state. +* [#25516](https://github.com/cosmos/cosmos-sdk/pull/25516) Support automatic configuration of OpenTelemetry via [OpenTelemetry declarative configuration](https://pkg.go.dev/go.opentelemetry.io/contrib/otelconf) and add OpenTelemetry instrumentation of `BaseApp`. ### Improvements @@ -85,6 +86,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ * (x/nft) [#24575](https://github.com/cosmos/cosmos-sdk/pull/24575) Deprecate the `x/nft` module in the Cosmos SDK repository. This module will not be maintained to the extent that our core modules will and will be kept in a [legacy repo](https://github.com/cosmos/cosmos-legacy). * (x/group) [#24571](https://github.com/cosmos/cosmos-sdk/pull/24571) Deprecate the `x/group` module in the Cosmos SDK repository. This module will not be maintained to the extent that our core modules will and will be kept in a [legacy repo](https://github.com/cosmos/cosmos-legacy). * (types) [#24664](https://github.com/cosmos/cosmos-sdk/pull/24664) Deprecate the `Invariant` type in the Cosmos SDK. +* [#25516](https://github.com/cosmos/cosmos-sdk/pull/25516) Deprecate all existing methods and types in the `telemetry` package, usage of `github.com/hashicorp/go-metrics` and the `telemetry` configuration section. New instrumentation should use the official [OpenTelemetry go API](https://pkg.go.dev/go.opentelemetry.io/otel) and Cosmos SDK appllications can automatically expose OpenTelemetry metrics, traces and logs via [OpenTelemetry declarative configuration](https://pkg.go.dev/go.opentelemetry.io/contrib/otelconf). ## [v0.53.4](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.53.3) - 2025-07-25 From 8b4e5f2972bb21c53976a8e1a78d5722db83bcad Mon Sep 17 00:00:00 2001 From: Tyler <48813565+technicallyty@users.noreply.github.com> Date: Fri, 21 Nov 2025 14:27:26 -0500 Subject: [PATCH 51/52] shutdown only if sdk set, and error if sink is set to otel but no config set --- telemetry/config.go | 25 ++++++++++++++++--------- telemetry/metrics.go | 5 +++++ 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/telemetry/config.go b/telemetry/config.go index 484c4a3a5a7d..44f16b9588ea 100644 --- a/telemetry/config.go +++ b/telemetry/config.go @@ -20,8 +20,12 @@ import ( "go.yaml.in/yaml/v3" ) +const ( + OtelConfigEnvVar = "OTEL_EXPERIMENTAL_CONFIG_FILE" +) + var ( - sdk otelconf.SDK + sdk *otelconf.SDK shutdownFuncs []func(context.Context) error ) @@ -37,7 +41,7 @@ func initOpenTelemetry() error { var opts []otelconf.ConfigurationOption - confFilename := os.Getenv("OTEL_EXPERIMENTAL_CONFIG_FILE") + confFilename := os.Getenv(OtelConfigEnvVar) if confFilename == "" { return nil } @@ -160,10 +164,11 @@ func initOpenTelemetry() error { fmt.Printf("failed to parse cosmos extra config: %v\n", err) } - sdk, err = otelconf.NewSDK(opts...) + otelSDK, err := otelconf.NewSDK(opts...) if err != nil { return fmt.Errorf("failed to initialize telemetry: %w", err) } + sdk = &otelSDK // setup otel global providers otel.SetTracerProvider(sdk.TracerProvider()) @@ -188,14 +193,16 @@ type cosmosExtra struct { } func Shutdown(ctx context.Context) error { - err := sdk.Shutdown(ctx) - if err != nil { - return fmt.Errorf("failed to shutdown telemetry: %w", err) - } - for _, f := range shutdownFuncs { - if err := f(ctx); err != nil { + if sdk != nil { + err := sdk.Shutdown(ctx) + if err != nil { return fmt.Errorf("failed to shutdown telemetry: %w", err) } + for _, f := range shutdownFuncs { + if err := f(ctx); err != nil { + return fmt.Errorf("failed to shutdown telemetry: %w", err) + } + } } return nil } diff --git a/telemetry/metrics.go b/telemetry/metrics.go index ec817b1f6c62..89ef5cdd381f 100644 --- a/telemetry/metrics.go +++ b/telemetry/metrics.go @@ -7,6 +7,7 @@ import ( "errors" "fmt" "net/http" + "os" "time" "github.com/hashicorp/go-metrics" @@ -149,6 +150,10 @@ func New(cfg Config) (_ *Metrics, rerr error) { case MetricSinkDogsStatsd: sink, err = datadog.NewDogStatsdSink(cfg.StatsdAddr, cfg.DatadogHostname) case MetricSinkOtel: + otelCfg := os.Getenv(OtelConfigEnvVar) + if otelCfg == "" { + return nil, fmt.Errorf("using the %s sink requires %s environment variable to be set. see: https://opentelemetry.io/docs/languages/sdk-configuration/declarative-configuration/ for details", MetricSinkOtel, OtelConfigEnvVar) + } sink = newOtelGoMetricsSink(context.Background(), otel.Meter("gometrics")) default: memSink := metrics.NewInmemSink(10*time.Second, time.Minute) From 6c961ea5aea144ce086bb9f5cb71b15fd7fe0124 Mon Sep 17 00:00:00 2001 From: Tyler <48813565+technicallyty@users.noreply.github.com> Date: Fri, 21 Nov 2025 14:50:50 -0500 Subject: [PATCH 52/52] add a note to histograms --- telemetry/compat.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/telemetry/compat.go b/telemetry/compat.go index 2b0199f24dd8..94c960343d5c 100644 --- a/telemetry/compat.go +++ b/telemetry/compat.go @@ -74,7 +74,11 @@ func (o *otelGoMetricsSink) getHistogram(key string) otelmetric.Float64Histogram if ok { return entry.(otelmetric.Float64Histogram) } - hist, err := o.meter.Float64Histogram(key) + // Otel doesn't have a histogram summary like go-metrics does, and the default bucket boundaries are not suitable for + // the main processes that use it, so we will set some reasonable default here. + // If these defaults are not suitable the user can override them by supplying their own values in the otel yaml config. + // See example here: https://github.com/open-telemetry/opentelemetry-configuration/blob/65274d8cde98640e91932903e35287b330e482f4/examples/kitchen-sink.yaml#L177 + hist, err := o.meter.Float64Histogram(key, otelmetric.WithExplicitBucketBoundaries(0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10)) if err != nil { panic(fmt.Sprintf("failed to create histogram metric %s: %v", key, err)) }