08: Telemetry with App Insight
Let us now create work on injestig code for App Insight telemetry. This help observe how a request was served from the different part of the code.
Code Changes
-
In
src/appinsight/logger.py
, we will create decorator that help inject trace to App Insightdef trace_as_dependency(tracer: Tracer = None, name: str = None, prefix: str = None): """trace_as_dependency [method decorator to trace a method invocation as a dependency (in AppInsights)] Args: tracer (Tracer): [Opencensus tracer object used to create the trace record.] name (str): [Name of the created trace record] prefix (str): [Prefix to be attached to Name] Returns: The inner function """ def inner_function(method): @wraps(method) def wrapper(*args, **kwargs): file_name = inspect.getfile(method).split("/")[-1].split(".py")[0] f = inspect.currentframe() i = inspect.getframeinfo(f.f_back) line_number = i.lineno trace_name = name if (name is not None) else method.__name__ trace_name = f"{file_name}.{trace_name}" if prefix: trace_name = f"{prefix}.{trace_name}" oc_tracer = ( tracer if (tracer is not None) else execution_context.get_opencensus_tracer() ) if oc_tracer is not None: with oc_tracer.span(trace_name): result = method(*args, **kwargs) else: result = method(*args, **kwargs) return result return wrapper return inner_function def get_opencensus_tracer() -> Tracer: return execution_context.get_opencensus_tracer()
Starting Tracer
In the entrypoint of Azure Function i.e. functiondemo/__init__.py
we will initialize telemetry processor.
from opencensus.extension.azure.functions import OpenCensusExtension
from src.appinsight.logger import AI_CONNECTION_STRING, callback_add_role_name
from src.appinsight.logger import trace_as_dependency
# configure opencensus ext for azure function.
# this ensures that an opencensus tracer is created and associated with the func context
OpenCensusExtension.configure(connection_string=AI_CONNECTION_STRING)
# ensure that dependency records have the correct role name
OpenCensusExtension._exporter.add_telemetry_processor(callback_add_role_name)
Using Tracer
As decorator
We now just need to anotate function with trace_as_dependency
. For example:
from src.appinsight.logger import trace_as_dependency
@trace_as_dependency(name="entrypoint")
def main(req: func.HttpRequest, context: func.Context) -> func.HttpResponse:
As Context Manager
from src.appinsight.logger import trace_as_dependency, get_opencensus_trace
@app.route("/health", methods=['GET', 'HEAD'])
@trace_as_dependency(name="health")
def health():
tracer = get_opencensus_tracer()
logger.info("Checking health of the function.")
with tracer.span('get_linkedin.com'):
try:
res = requests.get("https://www.linkedin.com", timeout=10)
if res.status_code == 200:
response = "Health Check Ok"
status_code = res.status_code
else:
response = "Health Check Failed"
status_code = res.status_code
return jsonify(message=response), status_code
except Exception as error:
return jsonify(message=str(error)), 500
Reading Traces
We can check the application map generated in App Insight.
Reading traces: