Span attributes: putting the tx hash on the span

2 min read

Short answer

Span attributes are key-value pairs that describe the operation a span tracks. Keys are strings; values are strings, booleans, integers, floating point numbers or arrays of one of these. They're what you search and group by in your tracing backend, so the transaction hash belongs there.

On this page

The demo agent’s withdrawal reverted. To find it in Jaeger, you don’t read through spans. You search for blockchain.tx.status=reverted and get the span. That works because the status is an attribute.

The attributes on a reverted confirm span with their types, and a log scale showing why wei amounts go into OpenTelemetry attributes as decimal strings rather than numbers or int64.

What is an attribute?

A key-value pair on a span that describes the operation it tracks (OpenTelemetry traces). The rules are short:

Rule
Key A non-empty string. Case matters.
Value String, boolean, integer, floating point, or an array of one of these
Same key twice The new value overwrites the old one
How many 128 per span by default; the SDK drops new keys after that

The full definitions are in the common spec. Attributes that are set when the span starts are also visible to the sampler, which decides whether to keep the span.

Why are fees strings?

Because wei doesn’t fit. A JavaScript number is a double, exact only up to 2^53, which is about 0.009 ETH in wei. A signed 64-bit integer stops at about 9.22 ETH. A fee or a transfer can be larger than either.

The JavaScript API’s type checker rejects a bigint, and at runtime the SDK drops it with “Invalid attribute value set”. Converting with Number() silently rounds:

const fee = 1234567890123456789n; // wei, about 1.23 ETH
const span = tracer.startSpan('confirm 8453');
span.setAttributes({
'blockchain.chain.id': 8453,
'blockchain.tx.hash': '0x41837fea9c6d02d542c8fd48e32b26bd4ffd0e4762568884f34afbf66ae2b3ce',
'blockchain.tx.gas.used': 21000,
'fee.as_number': Number(fee), // precision lost
'blockchain.tx.fee': fee.toString(), // exact
});
span.end();
'blockchain.tx.gas.used': 21000,
'fee.as_number': 1234567890123456800,
'blockchain.tx.fee': '1234567890123456789'

The last three digits changed. The string keeps every one.

Which key names?

Use a standard name when one exists, such as error.type. Otherwise pick a namespace so your keys can’t collide with anyone else’s. OpenTelemetry has no conventions for blockchains yet, so hashspan uses blockchain.*, modelled on db.* and rpc.*.

FAQ

How do I add custom span attributes in OpenTelemetry?

Call span.setAttribute(key, value) or span.setAttributes({...}), or pass attributes when you start the span. Give custom keys a namespace of your own, such as blockchain.tx.hash, so they can't collide with standard names.

What types can a span attribute have?

In the JavaScript API: string, number, boolean, or an array of one of these. A bigint is rejected by the type checker and dropped at runtime, so large integers go in as strings.

What happens if I set the same attribute twice?

The new value replaces the old one. A span keeps one value per key.

Go further

Type to search the docs, Learn topics and the blog.