Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Usage examples for async would be really valuable #174

Closed
time4tea opened this issue Jun 9, 2024 · 3 comments
Closed

Usage examples for async would be really valuable #174

time4tea opened this issue Jun 9, 2024 · 3 comments

Comments

@time4tea
Copy link

time4tea commented Jun 9, 2024

Hiya - Thanks for this library!

I'm trying to instrument an async process, and its not clear to me how to track the call through the system.

For example, plugging into 'dio' using interceptors, i can create a new span like this:

  dynamic startHttpRequest(RequestOptions options, handler) {
    var span =
        tracer.startSpan("http", context: ZoneContext.current, attributes: [
      Attribute.fromString(SemanticAttributes.httpMethod, options.method),
      Attribute.fromString(SemanticAttributes.httpHost, options.uri.host),
      Attribute.fromString(SemanticAttributes.httpScheme, options.uri.scheme),
    ]);

    print(span.spanContext.spanId);

    ZoneContext.current.withSpan(span).execute(() {
      handler.next(options);
    });
  }

and then I'm hoping to be able to close the span at the end of the request like this:

  dynamic endHttpRequest(Response<dynamic> response, handler) {
    var span = ZoneContext.current.span;

    print(span.spanContext.spanId);

    span.setAttributes([
      Attribute.fromInt(SemanticAttributes.httpStatusCode, response.statusCode!)
    ]);

    span.end();
    handler.next(response);
  }

however, the spanid at the end is the invalid span, so i guess I'm not doing the right thing with the context. Are there any examples for how to instrument something like dio?

Of course - if i get this working, it could be contributed, if that were useful.

Thank you!

@ukasz123
Copy link

@time4tea Following interceptor implementation worked for me.

import 'package:dio/dio.dart';
import 'package:opentelemetry/api.dart' as otel_api;

class TracingInterceptor implements Interceptor {
  static const _spanExtra = 'telemetry_span';

  static const _tracerName = 'HTTP-client';

  List<otel_api.Attribute> _getRequestAttributes(RequestOptions options) {
    // NO-OP
    return [];
  }

  String _getSpanName(RequestOptions options) {
    // NO-OP
    return 'http';
  }

  @override
  void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
    final requestSpan =
        otel_api.globalTracerProvider.getTracer(_tracerName).startSpan(
              _getSpanName(options),
              kind: otel_api.SpanKind.client,
              attributes: _getRequestAttributes(options),
            );
    // store the span object for later
    options.extra[_spanExtra] = requestSpan;

    handler.next(options);
  }

  @override
  void onResponse(Response response, ResponseInterceptorHandler handler) {
    final requestSpan =
        response.requestOptions.extra[_spanExtra] as otel_api.Span;
    requestSpan.end();
    handler.next(response);
  }

  @override
  void onError(DioException err, ErrorInterceptorHandler handler) {
    final requestSpan = err.requestOptions.extra[_spanExtra] as otel_api.Span;
    requestSpan.recordException(err);
    requestSpan.end();
    handler.next(err);
  }
}

@time4tea
Copy link
Author

Thank you! I will try this!

@time4tea
Copy link
Author

I did try this and it worked very nicely.

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

No branches or pull requests

3 participants