opencensus-python icon indicating copy to clipboard operation
opencensus-python copied to clipboard

Request name is empty when export grpc service to Azure Moniter.

Open fanshaohua-fan opened this issue 5 years ago • 3 comments

I'm trying to integrate our python application with Azure Application Insights. The python application is used for providing grpc service. So I followed the hello_word_server example from opencensus-ext-grpc but replace the stackdriver exporter with AzureExporter.

but the Request name is displayed as undefined in Application Insights. Any clue what's the reason?

Describe your environment. Python 3.8 Ubuntu 20.04

Steps to reproduce.

import time
from concurrent import futures

import grpc

import hello_world_pb2
import hello_world_pb2_grpc
from opencensus.ext.grpc import server_interceptor
# from opencensus.ext.stackdriver import trace_exporter as stackdriver_exporter
from opencensus.trace import samplers
from opencensus.ext.azure.trace_exporter import AzureExporter

_ONE_DAY_IN_SECONDS = 60 * 60 * 24

# Callback function to add os_type: linux to span properties
def callback_function(envelope):
    envelope.data.baseData.properties['os_type'] = 'linux'
    return True

class HelloWorld(hello_world_pb2_grpc.GreeterServicer):

    def SayHello(self, request, context):
        return hello_world_pb2.HelloReply(message='Hello, %s!' % request.name)


def serve():
    sampler = samplers.AlwaysOnSampler()
    # exporter = stackdriver_exporter.StackdriverExporter()
    exporter = AzureExporter()
    exporter.add_telemetry_processor(callback_function)

    tracer_interceptor = server_interceptor.OpenCensusServerInterceptor(
        sampler, exporter)
    server = grpc.server(
        futures.ThreadPoolExecutor(max_workers=10),
        interceptors=(tracer_interceptor,))
    hello_world_pb2_grpc.add_GreeterServicer_to_server(HelloWorld(), server)
    server.add_insecure_port('[::]:50051')
    server.start()
    try:
        while True:
            time.sleep(_ONE_DAY_IN_SECONDS)
    except KeyboardInterrupt:
        server.stop(0)


if __name__ == '__main__':
    serve()

What is the expected behavior? Expect to see the function path as the name. So in this case: helloworld.Greeter.SayHello

What is the actual behavior? name is undefined/empty in the application insights GUI.

image

here is the envelope that I captured with callback:

{
   "iKey":"619cfb06-af79-4759-9dac-9047b7b69cee",
   "tags":{
      "ai.cloud.role":"hello_world_server.py",
      "ai.cloud.roleInstance":"fan-NUC10i7FNK",
      "ai.device.id":"fan-NUC10i7FNK",
      "ai.device.locale":"en_US",
      "ai.device.osVersion":"#57-Ubuntu SMP Thu Oct 15 10:57:00 UTC 2020",
      "ai.device.type":"Other",
      "ai.internal.sdkVersion":"py3.8.5:oc0.7.11:ext1.0.5",
      "ai.operation.id":"a6dd3500130b9f9ff5b824e042372886",
      "ai.operation.parentId":"0000000000000000"
   },
   "time":"2020-10-28T09:05:37.270290Z",
   "name":"Microsoft.ApplicationInsights.Request",
   "data":{
      "baseData":{
         "id":"9d62b242ef1c012b",
         "duration":"0.00:00:00.000",
         "responseCode":"0",
         "success":True,
         "properties":{
            "component":"grpc"
         },
         "ver":2,
         "name":"",
         "source":"None",
         "url":"None",
         "measurements":"None"
      },
      "baseType":"RequestData"
   },
   "ver":1,
   "sampleRate":"None",
   "seq":"None",
   "flags":"None"
}

fanshaohua-fan avatar Oct 28 '20 09:10 fanshaohua-fan

@fanshaohua-fan AzureExporter depends on the existence of http.method, http.route or http.path in the span attributes to populate the name field. It seems like opencensus-ext-grpc does not add these fields in the span logic.

As a workaround, you can modify the name of the telemetry item yourself by using telemetry processor.

So your function would look like:

def callback_function(envelope):
    envelope.data.baseData.name = "GET" + <route>
    return True

lzchen avatar Oct 28 '20 14:10 lzchen

@lzchen , thanks a lot for the info. There are many functions within our gRPC service, it's not possible to set dynamic route for each function.

So I added these http. fields under OpenCensusServerInterceptor._start_server_span. Apparently it works perfectly for me, the output is almost the same as the ones generated from my another grpc service with asp.net core.

Do you think if it's a solid solution? Shall I pull a request with my fix?

diff --git a/contrib/opencensus-ext-grpc/opencensus/ext/grpc/server_interceptor.py b/contrib/opencensus-ext-grpc/opencensus/ext/grpc/server_interceptor.py
index 7b82773..de02abe 100644
--- a/contrib/opencensus-ext-grpc/opencensus/ext/grpc/server_interceptor.py
+++ b/contrib/opencensus-ext-grpc/opencensus/ext/grpc/server_interceptor.py
@@ -106,11 +106,35 @@ class OpenCensusServerInterceptor(grpc.ServerInterceptor):
             name=_get_span_name(servicer_context)
         )
 
+        grpc_host = servicer_context._rpc_event.call_details.host.decode('utf-8')
+        grpc_methed = servicer_context._rpc_event.call_details.method.decode('utf-8')
+
         span.span_kind = span_module.SpanKind.SERVER
         tracer.add_attribute_to_current_span(
             attribute_key=attributes_helper.COMMON_ATTRIBUTES.get(
                 ATTRIBUTE_COMPONENT),
             attribute_value='grpc')
+        tracer.add_attribute_to_current_span(
+            attribute_key=attributes_helper.GRPC_ATTRIBUTES.get(
+                'GRPC_METHOD'),
+            attribute_value=grpc_methed)
+
+        tracer.add_attribute_to_current_span(
+            attribute_key=attributes_helper.COMMON_ATTRIBUTES.get(
+                'HTTP_HOST'),
+            attribute_value=grpc_host)
+        tracer.add_attribute_to_current_span(
+            attribute_key=attributes_helper.COMMON_ATTRIBUTES.get(
+                'HTTP_METHOD'),
+            attribute_value='POST')
+        tracer.add_attribute_to_current_span(
+            attribute_key=attributes_helper.COMMON_ATTRIBUTES.get(
+                'HTTP_ROUTE'),
+            attribute_value=grpc_methed)
+        tracer.add_attribute_to_current_span(
+            attribute_key=attributes_helper.COMMON_ATTRIBUTES.get(
+                'HTTP_URL'),
+            attribute_value= grpc_host + grpc_methed)
 
         execution_context.set_opencensus_tracer(tracer)
         execution_context.set_current_span(span)

fanshaohua-fan avatar Oct 28 '20 16:10 fanshaohua-fan

@fanshaohua-fan That looks great! Feel free to submit a PR.

lzchen avatar Oct 28 '20 16:10 lzchen