Open Bibob7 opened 4 years ago
For our use case, this would allow us to have spans for calls to GCP services as it makes use of GRPC.
Same here, most of our internal calls happen over gRPC, and currently we're blind on PHP apps.
We do not have enough bandwidth to work on this integration during this quarter. Things might change if anyone of the other big challenges we are currently working on (support for PHP-8, adding profiling, stability/performance) will leave us some extra time.
I just added the label up-for-grabs
, in case anyone from the community is interested.
Leaving this here for folks who might find this issue. I have a limited use case for tracing gRPC at the moment and only care about simple requests / unary calls. Was able to get things nicely into DD with the following snippet:
\dd_trace_method(BaseStub::class, '_simpleRequest', function ($spanData, $args, $returnValue, $exception = null) {
$method = $args[0];
$name = array_values(array_filter(explode('/', $method)))[0];
// Not great to have to do this, but without that, there's just no info available during the `wait` call
// so that's what it is for now
$returnValue->__dd_trace_info = [
'name' => $name,
'resource' => $args[0],
];
$spanData->name = $returnValue->__dd_trace_info['name'];
$spanData->resource = 'init:'.$returnValue->__dd_trace_info['resource'];
$spanData->service = 'grpc';
});
\dd_trace_method(UnaryCall::class, 'wait', function ($spanData, $args, $returnValue, $exception = null) {
$spanData->name = $this->__dd_trace_info['name'] ?? '__grpc_name';
$spanData->resource = 'wait:'.$this->__dd_trace_info['resource'] ?? '__grpc_resource';
$spanData->service = 'grpc';
});
@khepin: Thanks for your snipped, but also in this case, you will have no distributed tracing. For that we need to be able to exchange span and trace id via grpc metadata.
@labbati: Are there any plans to work on that in the current or next quarter? For us this is still a relevant topic.
Hello @Bibob7, at the moment this has not been scheduled for Q2 and I have not an ETA I can commit to.
We have achieved distributed tracing with the following:
use DDTrace\GlobalTracer;
use DDTrace\Tag;
use Grpc\Interceptor;
class DatadogGrpcInterceptor extends Interceptor
{
const DEFAULT_BAGGAGE_HEADER_PREFIX = 'ot-baggage-';
const DEFAULT_TRACE_ID_HEADER = 'x-datadog-trace-id';
const DEFAULT_PARENT_ID_HEADER = 'x-datadog-parent-id';
const DEFAULT_SAMPLING_PRIORITY_HEADER = 'x-datadog-sampling-priority';
const DEFAULT_ORIGIN_HEADER = 'x-datadog-origin';
public function interceptUnaryUnary($method, $argument, $deserialize, array $metadata = [], array $options = [], $continuation) // phpcs:ignore
{
$scope = GlobalTracer::get()->startActiveSpan("interceptUnaryUnary");
$scope->getSpan()->setTag(Tag::SERVICE_NAME, "grpc-outbound");
$scope->getSpan()->setTag(Tag::RESOURCE_NAME, $method);
$spanContext = $scope->getSpan()->getContext();
if ($spanContext->getTraceId() !== null) {
$metadata[self::DEFAULT_TRACE_ID_HEADER] = array($spanContext->getTraceId());
}
if ($spanContext->getSpanId() !== null) {
$metadata[self::DEFAULT_PARENT_ID_HEADER] = array($spanContext->getSpanId());
}
foreach ($spanContext as $key => $value) {
if ($value !== null) {
$metadata[self::DEFAULT_BAGGAGE_HEADER_PREFIX . $key] = array($value);
}
}
$prioritySampling = GlobalTracer::get()->getPrioritySampling();
if ($prioritySampling !== null) {
$metadata[self::DEFAULT_SAMPLING_PRIORITY_HEADER] = array(strval($prioritySampling));
}
if (!empty($spanContext->origin)) {
$metadata[self::DEFAULT_ORIGIN_HEADER] = array($spanContext->origin);
}
try {
return $continuation($method, $argument, $deserialize, $metadata, $options);
} finally {
$scope->close();
}
}
}
And in the Channel/Client factory do something like this:
private function createChannel(string $host, array $args = []): \Grpc\Channel
{
$channel = new \Grpc\Channel($host, $args);
return \Grpc\Interceptor::intercept($channel, $this->interceptors);
}
@diutsu your method worked fantastically, thank you!
One minor change was where we set the service tag: $scope->getSpan()->setTag(Tag::SERVICE_NAME, getenv('DD_SERVICE'));
- this way we can use the interceptor in multiple services.
For anyone else unsure about how to use the diutsu's method, you pass the channel that you create to the constructor of your php grpc service class e.g. new FooServiceClient('foo-service:5000', ['credentials' => null], $channel);
.
Is your feature request related to a problem? Please describe. We would like to have full support for this extension: https://github.com/grpc/grpc-php with distributed tracing.
Describe the solution you'd like When sending an receiving grpc requests with https://github.com/grpc/grpc-php, I would like to be able to see distributed traces.
Describe alternatives you've considered We already implemented a tracing integration on php site, which works fine apart from distributed tracing. (see: #915) However, for the future it would be fine, if there is full support for this extension.