opencensus-python
opencensus-python copied to clipboard
Request name is empty when export grpc service to Azure Moniter.
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.

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
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 , 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 That looks great! Feel free to submit a PR.