Dynatrace / OneAgent-SDK-for-dotnet

Enables custom tracing of .NET applications in Dynatrace
https://www.dynatrace.com/support/help/extend-dynatrace/oneagent-sdk/what-is-oneagent-sdk/
Apache License 2.0
18 stars 3 forks source link

How to trace IAsyncEnumerable calls #24

Open andre-ss6 opened 2 years ago

andre-ss6 commented 2 years ago

The current ITrace API has Trace(Func<T> func) and TraceAsync(Func<Task<T>> func), but none of these two can trace an IAsyncEnumerable call. It would be possible to do it with the now-obsolete StartAsync method, eg.:


_tracer.StartAsync();
try 
{
  await foreach (var item in items)
  {
    yield return item;
  }
}
catch (Exception ex)
{
  _tracer.Error(ex);
}
finally
{
  _tracer.End();
}

Though I'm not even sure if this would be the best implementation, since it would also take into consideration the time the caller took to do whatever computation with the streamed items.

The current alternative is to just _tracer.Trace(MethodThatReturnsIAsyncEnumerable), but this also has its drawbacks, namely that it will only trace the call that starts the streaming, but will not track the streaming itself. For example, if an error occurs while streaming from the database, the tracer will not catch that.

andre-ss6 commented 2 years ago

Actually I think there's a [better?] alternative:

public async IAsyncEnumerable<T> TraceAsync<T>(Func<IAsyncEnumerable<T>> func)
{
    var enumerable = _tracer.Trace(func);
    await using var enumerator = enumerable.GetAsyncEnumerator();

    while (await _tracer.TraceAsync(() => enumerator.MoveNextAsync().AsTask()))
    {
        yield return enumerator.Current;
    }
}

This will, though, generate multiple requests to whatever this tracer has been configured for. I don't know if there is a better way though, unless Dynatrace had support specifically for something like streaming.

This alternative also has an advantage over the one I presented on the OP in that this one will include the time the caller takes to process each of the items.

There is one possible disadvantage, though, in that - I'm not really sure, but I think I've seen somewhere that it's not recommended to use the IAsyncEnumerator API directly, and instead only rely on await foreach. But I'm not sure.