opentelemetry-cpp icon indicating copy to clipboard operation
opentelemetry-cpp copied to clipboard

[Trace] reopen - Missing example instrumenting asynchronous operation #1463

Open keminming opened this issue 3 years ago • 9 comments

Open this issue since I don’t think #1463 Is well resolved, as we don’t find a good example how to instrument function call with async callback, in most condition, I/O operation will be made in an asynchrous fashion, but it doesn’t seem to be well supported by the cpp lib.

keminming avatar Jun 22 '22 05:06 keminming

Ok fair enough. Please let us know which HTTP async library you are going to use - the example would depend on that.

lalitb avatar Jun 22 '22 06:06 lalitb

It’s an in-house http client, the usage is described in #1463, where the “get” method takes a callback to handle the http response.

Think you can make an example based on the async http client you shared here: https://github.com/open-telemetry/opentelemetry-cpp/blob/main/ext/include/opentelemetry/ext/http/client/http_client.h

keminming avatar Jun 22 '22 06:06 keminming

The rough code (not tested) should be something like this, do you see any issue in this -

auto span = ... ;
// not creating any scope, as it won't work for async mode.
http_client->Get(url, carrier.headers_,[&span](http_client::Result result){
if (result)
{
  span->SetAttribute(..);
  span->SetStatus(...);
  span->End(); // span exported here
});

scope object won't work in the async case. scope object is helpful for creating nested spans (i.e, the inner span is a child of the outer span). So the nested span scenario would now look like this -

auto outer_span =  tracer->StartSpan(name1, attributes);
// not creating any scope, as it won't work for async mode.
http_client->Get(url, carrier.headers_,[&outer_span, &tracer](http_client::Result result){
if (result)
{
  outer_span->SetAttribute(..);
  outer_span->SetStatus(...);
  StartSpanOptions option;
  option.parent = outer_span.GetSpanContext();
  auto innner_span =  tracer->StartSpan(name2, attributes, option);
  inner_span->SetAttribute(...);
  inner_span->SetStatus(...);
  inner_span->End(); //inner span exported here
  outer_span->End(); // outer span exporter here...
});

lalitb avatar Jun 22 '22 07:06 lalitb

@keminming - Let me know if the above example brings clarity. You can try this, and update here if it doesn't work. And if it works, feel free to contribute async example.

lalitb avatar Jun 22 '22 22:06 lalitb

@lalitb Thanks for sharing the example. I've run debugging on it and the result looks to be as expected. It ended up with 2 spans, outer and inner, and the parent span of inner is outer.

So "scope" seems only helps for nested sync calls, that don't require passing parent span explicitly to the callee to set up the parent/child relationship. Also noticed "span link" is designed to express a certain relationship between spans, is there guidance on when to use parent and when to use span link? Does it have any impact on how the backend visualizes spans like in Jaeger or Zipkin?

keminming avatar Jun 23 '22 22:06 keminming

. Also noticed "span link" is designed to express a certain relationship between spans, is there guidance on when to use parent and when to use span link?

You can find few of the examples of links here - https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/overview.md#links-between-spans

Does it have any impact on how the backend visualizes spans like in Jaeger or Zipkin?

  • Links are not exported to Zipkin ( Refer - https://github.com/open-telemetry/opentelemetry-specification/blob/9abbdd39d0b35f635f833f072013431da419894e/specification/trace/sdk_exporters/zipkin.md#summary )
  • Links are exported as Span reference in Jaeger ( https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/sdk_exporters/jaeger.md#summary). You have to check Jaeger docs on how references are visualized.

lalitb avatar Jun 25 '22 02:06 lalitb

@keminming - Let me know if it is good to close this issue unless you have plans to add the async example?

lalitb avatar Jun 27 '22 18:06 lalitb

@lalitb This is the sample code I wrote for testing, based on the default http_client. For some reason, the onResponse handler won't trigger, so I add the code in the onEvent handler. Feel it's definitely helpful to include an async example (not have to be this one), which has 2-3 layers of the nested HTTP call.

` auto httpClient = http_client::HttpClientFactory::Create();

class CustomEventHandler : public http_client::EventHandler { public: void setSpan(nostd::shared_ptr<Span> span, std::shared_ptr<http_client::Session> session){ _span = span; _session = session; }

virtual void OnEvent(http_client::SessionState state, nostd::string_view reason) noexcept override
{
  _span->End();
  StartSpanOptions option;
  option.parent = _span->GetContext();
  auto inner_span =  get_tracer("http-client")->StartSpan("name2", option);
  /*
  /auto request = _session->CreateRequest();
  CustomEventHandler res_handler;
  res_handler.setSpan(inner_span, _session);
  _session->SendRequest(res_handler);
   */
  inner_span->End();
}
virtual void OnConnecting(const http_client::SSLCertificate &) noexcept {}
virtual ~CustomEventHandler() = default;
nostd::shared_ptr<Span> _span;
std::shared_ptr<http_client::Session> _session;

};

auto session = httpClient->CreateSession("localhost" + 8000); auto request = session->CreateRequest(); //request->AddHeader(..); CustomEventHandler res_handler;

auto outer_span = get_tracer("http-client")->StartSpan("name1"); res_handler.setSpan(outer_span, session); session->SendRequest(res_handler);`

keminming avatar Jun 27 '22 18:06 keminming

This issue was marked as stale due to lack of activity.

github-actions[bot] avatar Aug 27 '22 02:08 github-actions[bot]