Azure  

Observability in Azure Functions: Enabling Application Insights and Custom Logging for Real-Time Fraud Detection

Table of Contents

  • Introduction

  • Why Observability Matters in Financial Systems

  • Enabling Application Insights for Azure Functions

  • Implementing Custom Structured Logging

  • Real-World Scenario: Real-Time Payment Fraud Detection

  • Best Practices for Enterprise-Grade Logging

  • Conclusion

Introduction

In modern cloud-native architectures, observability isn’t optional—it’s essential. Azure Functions, as a serverless compute service, abstracts infrastructure but not the need for deep visibility into execution behavior, performance, and errors. For enterprise systems—especially in regulated domains like finance—robust logging and telemetry are non-negotiable. This article shows how to enable Application Insights and implement custom structured logging in Azure Functions using a real-world scenario: real-time payment fraud detection in a global fintech platform.

Why Observability Matters in Financial Systems

Imagine a payment processing system handling 10,000 transactions per minute across 50 countries. A subtle anomaly—like a sudden spike in declined transactions from a specific region—could signal either a fraud wave or a failing downstream service. Without granular, contextual logs and telemetry, your incident response time balloons from seconds to hours.

In such environments, Application Insights becomes your central nervous system for monitoring, while custom logging injects business context into every trace.

Enabling Application Insights for Azure Functions

Azure Functions integrates natively with Application Insights. Here’s how to enable it correctly in an enterprise deployment:

Step 1. Infrastructure-as-Code (Bicep)

// main.bicep
param appName string = 'fraud-detection-func'
param location string = 'eastus'

resource appInsights 'Microsoft.Insights/components@2020-02-02' = {
  name: '${appName}-ai'
  location: location
  kind: 'web'
  properties: {
    Application_Type: 'web'
    Request_Source: 'IbizaWebAppExtensionCreate'
  }
}

resource functionApp 'Microsoft.Web/sites@2022-03-01' = {
  name: appName
  location: location
  kind: 'functionapp'
  properties: {
    serverFarmId: appServicePlan.id
    siteConfig: {
      appSettings: [
        {
          name: 'APPLICATIONINSIGHTS_CONNECTION_STRING'
          value: appInsights.properties.ConnectionString
        }
        {
          name: 'AzureWebJobsStorage'
          value: '...'
        }
        {
          name: 'FUNCTIONS_EXTENSION_VERSION'
          value: '~4'
        }
        {
          name: 'FUNCTIONS_WORKER_RUNTIME'
          value: 'python' // or 'dotnet', 'node', etc.
        }
      ]
    }
  }
}

Always inject the APPLICATIONINSIGHTS_CONNECTION_STRING via infrastructure—not hardcoded in code.

Step 2. Confirm Auto-Instrumentation

Once deployed, Azure Functions automatically sends:

  • Function invocations

  • Duration

  • Failures

  • Dependency calls (e.g., to Cosmos DB, Service Bus)

No extra code needed. But this is just the baseline.

Implementing Custom Structured Logging

Auto-telemetry lacks business context. To detect fraud, you need logs like:

“Transaction ID txn_8a3b from user usr_9921 (country: NG) scored 0.92—flagged as high risk.”

Python Example (Azure Functions v4)

# __init__.py
import azure.functions as func
import logging
import json
from opencensus.ext.azure.log_exporter import AzureLogHandler

# Add Application Insights handler to root logger
logger = logging.getLogger()
logger.addHandler(AzureLogHandler())

def main(req: func.HttpRequest) -> func.HttpResponse:
    transaction = req.get_json()
    txn_id = transaction.get("id")
    user_id = transaction.get("user_id")
    amount = transaction.get("amount")
    country = transaction.get("country")

    # Business logic: fraud scoring (simplified)
    risk_score = calculate_fraud_score(amount, country)
    is_fraud = risk_score > 0.85

    # Custom structured log
    logger.info(
        "Fraud analysis completed",
        extra={
            "custom_dimensions": {
                "transaction_id": txn_id,
                "user_id": user_id,
                "amount": amount,
                "country": country,
                "risk_score": risk_score,
                "is_fraud": is_fraud,
                "service": "fraud-detection-engine"
            }
        }
    )

    if is_fraud:
        return func.HttpResponse(json.dumps({"blocked": True}), status_code=403)

    return func.HttpResponse(json.dumps({"approved": True}), status_code=200)


def calculate_fraud_score(amount: float, country: str) -> float:
    # Placeholder for ML model or rules engine
    high_risk_countries = {"NG", "VE", "SY"}
    base_score = 0.2
    if country in high_risk_countries:
        base_score += 0.5
    if amount > 10000:
        base_score += 0.3
    return min(base_score, 0.99)

Critical Notes:

  • Use extra={"custom_dimensions": {...}} to ensure properties appear in Application Insights customDimensions.

  • Never log PII (e.g., full card numbers). Mask or omit sensitive fields.

  • Use consistent property names across services for cross-component correlation.

1

2

3

4

5

Real-World Scenario: Real-Time Payment Fraud Detection

At FinGlobal Inc., every payment triggers an Azure Function that:

  1. Validates transaction metadata

  2. Calls a fraud scoring model (hosted in Azure ML)

  3. Logs decision context to Application Insights

  4. Blocks high-risk transactions instantly

Using customDimensions, their SOC team built an Application Insights Workbook that shows:

  • Real-time fraud rate by country

  • Top 10 riskiest user IDs (anonymized)

  • Latency vs. risk score correlation

This reduced false positives by 22% and cut fraud losses by $4.3M in Q1 2025.

PlantUML Diagram

Best Practices for Enterprise-Grade Logging

  1. Never disable sampling in production—use adaptive sampling to balance cost and fidelity.

  2. Correlate logs with operation_Id—Azure Functions auto-injects this. Preserve it in async workflows.

  3. Use semantic logging—log what happened, not just that something happened.

  4. Enforce log schema governance—define a shared logging contract across microservices.

  5. Alert on log anomalies—e.g., “sudden drop in is_fraud: true logs” may indicate model drift.

Conclusion

Enabling Application Insights in Azure Functions takes minutes. But engineering observability into your business logic—with structured, contextual, and secure logging—is what separates reactive systems from resilient ones.

In high-stakes domains like fintech, your logs aren’t just diagnostics—they’re audit trails, forensic evidence, and business intelligence. Treat them accordingly.

Pair this with Azure Policy to enforce APPLICATIONINSIGHTS_CONNECTION_STRING on all Function Apps—no exceptions. Observability is a compliance requirement, not a nice-to-have.