07: Logging with App Insight
Before we start, we need to verify if Azure Function App is connected to an instance of App Insight or not.
To check this, go to Application Insights
in Azure Function and verify if it is connected to an App Insight Resource. If not, we either need to create a new App Insight resource and attach it to Function App or use an existing App Insight app.
Get App Insight Connection String
- Click on App Insight attached to Azure Function
- Copy
Instrumentation Key
andConnection String
from overview tab
Code Changes
Notes:
- An AI need a unique
role_name
instance to separate events from different app. This can be done using a callback function. (function name:callback_add_role_name
) - Azure has custom logger that can emits logs to AI. This is available in
opencensus.ext.azure.log_exporter
module. - We need to enable traces for
logging
and if there is need to trace HTTP calls, then we also need to enable it forrequests
. Please check here for all available integration.
-
Create a folder
appinsight
in src. -
Create a python file
logger.py
insrc/appinsight
-
In
src/appinsight/logger.py
, we will create custom logger forAzureLogHandler
import inspect import logging from functools import wraps from logging import Logger from opencensus.ext.azure.log_exporter import AzureLogHandler from opencensus.trace import config_integration from opencensus.trace import execution_context from opencensus.trace.tracer import Tracer config_integration.trace_integrations(['logging', 'requests']) AI_KEY = "xxxxxx-ae15-44c2-xxxx-xxxxxxxxx" AI_CONNECTION_STRING = "InstrumentationKey=xxxxxx-ae15-44c2-xxxx-xxxxxxxxx;IngestionEndpoint=https://westus-0.in.applicationinsights.azure.com/;LiveEndpoint=https://westus.livediagnostics.monitor.azure.com/" WEBSITE_NAME = "function-demo" class CustomDimensionsFilter(logging.Filter): """Add custom-dimensions in each log by using filters.""" def __init__(self, custom_dimensions=None): """Initialize CustomDimensionsFilter.""" super().__init__() self.custom_dimensions = custom_dimensions or {} def filter(self, record): """Add the default custom_dimensions into the current log record.""" dim = {**self.custom_dimensions, **getattr(record, "custom_dimensions", {})} record.custom_dimensions = dim return True def callback_add_role_name(envelope): """Add role name for logger.""" envelope.tags['ai.cloud.role'] = WEBSITE_NAME envelope.tags["ai.cloud.roleInstance"] = WEBSITE_NAME def get_logger(name: str, propagate: bool = True, custom_dimensions=None) -> Logger: if custom_dimensions is None: custom_dimensions = {} # Azure Log Handler azure_log_handler = AzureLogHandler(connection_string=AI_CONNECTION_STRING) azure_log_handler.add_telemetry_processor(callback_add_role_name) azure_log_handler.setLevel(logging.DEBUG) # Formatter formatter = logging.Formatter('%(asctime)s traceId=%(traceId)s api=%(name)s.%(funcName)s ' '[%(levelname)-7s]: %(message)s') azure_log_handler.setFormatter(formatter) azure_log_handler.addFilter(CustomDimensionsFilter(custom_dimensions)) # Logger logger = logging.getLogger(name) logger.setLevel(logging.DEBUG) logger.addHandler(azure_log_handler) logger.propagate = propagate if not logger.handlers: logger.addHandler(azure_log_handler) return logger
-
Now let’s replace logger with an AzureLogHandler in all place i.e.
replace
import logging
logger = logging.getLogger(__name__)
with
from src.appinsight.logger import get_logger
logger = get_logger(__name__)
- Once updated as above, restart azure function locally from VSCode to test.
- To Test, let us invoke API: http://localhost:7071/vault?secret=name with/without Authorization Header.
Event Types = Request
may not be logged for localhost. We can push code and test on Azure Function deployed on Cloud for this to test again. - Push the code.
Transaction Search
!!! info “It takes upto 3-5 minutes for Transaction and Traces to propagate in App Insights”
- Open App Insight attached to Azure Function.
- Under
Investigate
>Transaction Search
- We are returning
x-function-invocationId
as response header from our code. We can use this to search Transaction related to a specific request.