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

  1. In src/appinsight/logger.py, we will create decorator that help inject trace to App Insight

    def 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.

Map

Reading traces:

Traces