Reputation: 19
We are wanting to log custom properties using the Opencensus library in our Azure function. We are able to log custom properties (in our logs) into Azure Monitor via a standalone python code (locally run). We are also able to log custom properties into Azure Monitor when the Azure function is run locally. However, when we deploy the function in Azure, the Azure Function SDK behaves very differently every time.
import logging
import azure.functions as func
from opencensus.ext.azure.trace_exporter import AzureExporter
from opencensus.ext.azure.log_exporter import AzureLogHandler
from opencensus.trace import config_integration
from opencensus.trace.samplers import ProbabilitySampler, AlwaysOnSampler
from opencensus.trace.tracer import Tracer
from opencensus.trace import execution_context
from opencensus.trace.propagation.trace_context_http_header_format import TraceContextPropagator
config_integration.trace_integrations(['logging'])
def main(req: func.HttpRequest, context: func.Context) -> func.HttpResponse:
try:
exporter = AzureExporter(connection_string=<ConnString>)
logger = logging.getLogger(__name__)
handler = AzureLogHandler(connection_string=<ConnString>)
if(logger.hasHandlers()):
logger.handlers.clear()
logger.addHandler(handler)
logger.info('Python HTTP trigger function processed a request.')
properties = {'custom_dimensions': {'memberId': '220', 'transactionId': '98480dcc-3abc-45a3-9145-f4b97b991f95'}}
span_context = TraceContextPropagator().from_headers({
"traceparent": context.trace_context.Traceparent,
"tracestate": context.trace_context.Tracestate
})
tracer = Tracer(
span_context=span_context,
exporter=exporter,
sampler=AlwaysOnSampler()
)
execution_context.set_opencensus_tracer(tracer)
logger.warning('Before the span', extra=properties)
with tracer.span("custom_dimensions_span"):
# properties = {'custom_dimensions': {'ABCD': 'EFG'}}
logger.info("This HTTP triggered function executed successfully. Pass a name in the query string or in the request body for a personalized response.", extra=properties)
logger.warning('After the span', extra=properties)
name = req.params.get('name')
if not name:
try:
req_body = req.get_json()
except ValueError:
pass
else:
name = req_body.get('name')
#result = 1 / 0 # generate a ZeroDivisionError
if name:
return func.HttpResponse(f"Hello, {name}. This HTTP triggered function executed successfully.")
else:
return func.HttpResponse(
"This HTTP triggered function executed successfully. Pass a name in the query string or in the request body for a personalized response.",
status_code=200
)
except Exception as e:
logger.error('Captured an exception. ' + str(e), extra=properties)
Upvotes: 0
Views: 3552
Reputation: 4776
Whenever the main is called it adds the handler to the logger. Each time the handler writes the log. For that, it was repeating. Whenever the getLogger can be called it will return the same object. addHandler doesn't check whether the handler is already added or not.
logger.propagate = False
logger = logging.getLoggger('Your_logger')
if not logger.handlers:
#Create the handlers
#call the .addHandler('Your_handler')
logger = logging.getLogger(__name__)
if logger.hasHandlers():
# Logger is already configured, remove all handlers by passing empty value
logger.handlers = []
Upvotes: 0