Skip to content

Add Stellar WriteReport Beholder telemetry#672

Open
Krish-vemula wants to merge 2 commits into
mainfrom
feat/stellar-write-beholder-metrics
Open

Add Stellar WriteReport Beholder telemetry#672
Krish-vemula wants to merge 2 commits into
mainfrom
feat/stellar-write-beholder-metrics

Conversation

@Krish-vemula

@Krish-vemula Krish-vemula commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Add Stellar WriteReport Beholder proto events, metrics, processor wiring, and message builders
  • Emit lifecycle telemetry from WriteReport, tx hash retrieval phases, and InvalidTransmissionState events
  • Align error handling with EVM

Depends on

  • feat/stellar-write-capability - PR (stacked PR merge that first)

@Krish-vemula Krish-vemula marked this pull request as ready for review July 2, 2026 22:51
@Krish-vemula Krish-vemula requested review from a team as code owners July 2, 2026 22:51
Base automatically changed from feat/stellar-write-capability to main July 3, 2026 10:31
Emit WriteReport lifecycle, tx hash retrieval, duplicate tx, invalid transmission state, and InvokeOnReport duration events with metrics, processor wiring, and coverage tests aligned with Aptos/EVM patterns.
@Krish-vemula Krish-vemula force-pushed the feat/stellar-write-beholder-metrics branch from 6be63c3 to 8a2f162 Compare July 3, 2026 12:42
Resolve GetLatestLedger conflict by keeping hash-based consensus from main (#673).
@cl-sonarqube-production

Copy link
Copy Markdown

Comment on lines +70 to +76
case *WriteReportTxHashRetrievalPhase:
if err := p.Metrics.OnWriteReportTxHashRetrievalPhase(ctx, msg); err != nil {
return fmt.Errorf("failed to publish WriteReportTxHashRetrievalPhase metrics: %w", err)
}
case *WriteReportInvokeOnReportDuration:
if err := p.Metrics.OnWriteReportInvokeOnReportDuration(ctx, msg); err != nil {
return fmt.Errorf("failed to publish WriteReportInvokeOnReportDuration metrics: %w", err)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Logging is missing

return details, nil
}

func (r *TxHashRetriever) emitTxHashRetrievalPhase(ctx context.Context, lookupType, result string, phaseStart time.Time, txHash string) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lookupType, result, these should be string enums

}
}
r.lggr.Errorw("No successful transmission found", "txCount", len(details), "transactions", details.String())
r.emitTxHashRetrievalPhase(ctx, txHashLookupTypeSuccessful, "NotFound", time.Now(), "")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • Right before this emitTxHashRetrievalPhase is emitted with Found and then here its emitted as NotFound. Just think from the perspective of wanting to debug something and what metric would be useful, this would be really confusing both with naming and chaotic attribute values that are inconsistently populated
  • What does time.Now() tell us here?

basic capmonitoring.MetricsCapBasic
}
WriteReportTxHashRetrievalPhase struct {
count metric.Int64Counter

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the value of count here, this is a metric that gets emitted every time, I can see querying it to see how long the retrieval phase lasts on avg, but no need to count something that always happens

}
WriteReportTxHashRetrievalPhase struct {
count metric.Int64Counter
phaseDuration metric.Int64Histogram

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just duration is fine


func (r *WriteReportTxHashRetrievalPhase) MetricAttributes() []attribute.KeyValue {
return append([]attribute.KeyValue{
attribute.String("phase", r.GetPhase()),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Phase is always hardocoded to EventPoll, what is the value of this attribute?

func (r *WriteReportTxHashRetrievalPhase) MetricAttributes() []attribute.KeyValue {
return append([]attribute.KeyValue{
attribute.String("phase", r.GetPhase()),
attribute.String("result", r.GetResult()),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This attribute is too broad in my opinion wdyt? We can log it, but I don't think that its a useful metric, look at our dashboard to get a feel for what we usually look for in metrics, this is too specific.

@ilija42

ilija42 commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Submitting first part of review, the tx retrieval metric looks like its copied from Aptos, the diffrence is that Aptos tx lookup is complicated and it makes way more sense to keep track of whats happening, here most of the attributes for this metric would be dead weight with high cardinality while not providing much useful insight into the WriteReport lifecycle

return details, nil
}

func (r *TxHashRetriever) emitTxHashRetrievalPhase(ctx context.Context, lookupType, result string, phaseStart time.Time, txHash string) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no need for this wrapper

func appendUserErrorLogAttributes(reqAttrs []attribute.KeyValue, summary string, isUserError bool, ec *capmonitoring.ExecutionContext) []attribute.KeyValue {
return append(append(reqAttrs,
attribute.String("summary", summary),
attribute.Bool("isUserError", isUserError),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the label is wrong

func (r *WriteReportInvalidTransmissionState) LogAttributes() []attribute.KeyValue {
return append(append(writeReportRequestLogAttributes(r.Req),
attribute.String("summary", r.GetSummary()),
attribute.String("transmission_state", strconv.FormatUint(uint64(r.GetTransmissionState()), 10)),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

attribute.String is not right for numerical transmission state

return ec.MetricsAttributes()
}

func appendExecutionLogAttributes(reqAttrs []attribute.KeyValue, ec *capmonitoring.ExecutionContext) []attribute.KeyValue {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unnecessary wrapper

}
}

func executionMetricAttributes(ec *capmonitoring.ExecutionContext) []attribute.KeyValue {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unnecessary wrapper


const (
reportProcessedTopicPrefix = "forwarder_ReportProcessed"
defaultForwarderLookbackLedgers = int64(100)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This constant is duplicate and is in two differnt places

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants