У меня есть следующая функция:
#[tracing::instrument(skip_all)]
pub(crate) async fn blocks_with_triggers(
adapter: Arc<EthereumAdapter>,
logger: Logger,
chain_store: Arc<dyn ChainStore>,
subgraph_metrics: Arc<SubgraphEthRpcMetrics>,
from: BlockNumber,
to: BlockNumber,
filter: &TriggerFilter,
unified_api_version: UnifiedMappingApiVersion,
) -> Result<Vec<BlockWithTriggers<crate::Chain>>, Error> {
// lots of stuff
let to_hash_fut = eth.block_hash_by_block_number(&logger, to)
.and_then(|hash| match hash {
Some(hash) => Ok(hash),
None => {
warn!(logger,
"Ethereum endpoint is behind";
"url" => eth.provider()
);
bail!("Block {} not found in the chain", to)
}
})
.compat();
// lots more stuff, eventually I wait on the above future
}
block_hash_by_block_number
объявляется следующим образом:
#[tracing::instrument(skip_all)]
fn block_hash_by_block_number(
&self,
logger: &Logger,
block_number: BlockNumber,
) -> Box<dyn Future<Item = Option<H256>, Error = Error> + Send> {
// code that uses https://crates.io/crates/reqwest-tracing
}
Когда я запускаю эту программу, создаваемые трассировки не имеют имени промежутка block_hash_by_block_number
под промежутком blocks_with_triggers
. Вместо этого я рассматриваю интервалы POST
как прямые дочерние элементы blocks_with_triggers
, что нежелательно. Однако, если я изменю вызов на
let to_hash_span = info_span!("to_hash_future");
let to_hash_fut = {
eth.block_hash_by_block_number(&logger, to)
.and_then(|hash| match hash {
Some(hash) => Ok(hash),
None => {
warn!(logger,
"Ethereum endpoint is behind";
"url" => eth.provider()
);
bail!("Block {} not found in the chain", to)
}
})
.compat()
.instrument(to_hash_span)
};
Тогда я вижу to_hash_future
как прямого дочернего элемента blocks_with_triggers
, а старые POST
промежутки теперь являются дочерними элементами to_hash_future
(но я все еще не рассматриваю block_hash_by_block_number
как дочерний элемент to_hash_future
).
Похоже, что в этом конкретном пути кода атрибут #instrument
неправильно реализует функцию block_hash_by_block_number
.
Вот как datadog собирает промежутки. Я ожидал бы, что отношения родитель-потомок будут to_hash_future
-> block_hash_by_block_number
-> POST
-> yellow stuff
, но вместо этого мы видим, что to_hash_future
и block_hash_by_block_number
являются братьями и сестрами.
Вот как я объявляю фильтр для своего приложения:
let filter_layer =
EnvFilter::try_new("graph_chain_ethereum,reqwest_tracing::reqwest_otel_span_builder")
.unwrap();
Добавлен фрагмент фильтра в OP, а также снимок экрана с интервалами, полученными datadog.
Пожалуйста, предоставьте Минимально воспроизводимый пример.
При использовании макроса instrument
для функции созданный диапазон вводится только внутри этой функции.
block_hash_by_block_number
не является функцией async
, а представляет собой обычную функцию, возвращающую будущее, которое вы затем выполняете после выхода из диапазона.
Хотя эти два случая в большинстве случаев семантически одинаковы, макрос instrument
действует по-разному в зависимости от того, является ли функция обычной функцией синхронизации или асинхронной функцией.
Макрос instrument
для обычной функции работает следующим образом:
#[instrument]
fn foo() { /* fn body */ }
// gets turned into
// |
// V
fn foo() {
let foo_span = info_span!("foo");
let _guard = foo_span.enter();
/* fn body */
// span exits here
}
А на асинхронных функциях это работает так (не уверен, что именно это и получается, но скорее всего это хорошее приближение):
#[instrument]
async fn foo() { /* fn body */ }
// gets turned into
// |
// V
fn foo() -> impl Future<...> {
let foo_span = info_span!("foo");
let future = async { /* fn body */ };
// span gets attached to the future, and is exited when that future completes
return future.instrument(foo_span);
}
Если вы хотите, чтобы все события в этом будущем находились внутри диапазона, но при этом возвращали Box<dyn Future<...>>
, вам следует либо создать новый диапазон, либо получить текущий диапазон с помощью tracing::Span::current()
и вызвать .instrument(span)
, прежде чем возвращать это будущее из block_hash_by_block_number
.
Я думаю, важно отметить, что block_hash_by_block_number
возвращает будущее из ящика Futures 0.1.
Это означает, что если добавление интервала в месте вызова неприемлемо, либо block_hash_by_block_number
придется изменить подпись, чтобы вернуть будущее, совместимое со стандартом, либо необходимо будет добавить новую функцию (например, block_hash_by_block_number_compat
) для вызова compat, а затем добавьте пролет.
Какой у вас фильтр уровня?