Search code examples
pythonazurefastapiazure-application-insightsazure-managed-identity

Writing to application insights from FastAPI with managed identity


I am trying to log from a FastAPI application to Azure application insights. It is working with a connection string, but I would like it to be working with managed identity. The code below does not fail - no errors or anything. But it does not log anything. Any suggestions to sove the problem, or how to troubleshoot as I get no errors:

from fastapi import FastAPI,Request
from fastapi.middleware.cors import CORSMiddleware
from fastapi_azure_auth import SingleTenantAzureAuthorizationCodeBearer
import uvicorn
from fastapi import FastAPI, Security
import os
from typing import Dict
from azure.identity import DefaultAzureCredential
import logging
from azure.monitor.opentelemetry import configure_azure_monitor
from opentelemetry import trace,metrics

from settings import Settings

from pydantic import AnyHttpUrl,BaseModel

from contextlib import asynccontextmanager
from typing import AsyncGenerator

from fastapi_azure_auth.user import User

settings = Settings()

@asynccontextmanager
async def lifespan(app: FastAPI) -> AsyncGenerator[None, None]:
    """
    Load OpenID config on startup.
    """
    await azure_scheme.openid_config.load_config()
    yield


app = FastAPI(
    swagger_ui_oauth2_redirect_url='/oauth2-redirect',
    swagger_ui_init_oauth={
        'usePkceWithAuthorizationCodeGrant': True,
        'clientId': settings.OPENAPI_CLIENT_ID,
        'scopes': settings.SCOPE_NAME,
    },
)

if settings.BACKEND_CORS_ORIGINS:
    app.add_middleware(
        CORSMiddleware,
        allow_origins=[str(origin) for origin in settings.BACKEND_CORS_ORIGINS],
        allow_credentials=True,
        allow_methods=['*'],
        allow_headers=['*'],
    )

azure_scheme = SingleTenantAzureAuthorizationCodeBearer(
    app_client_id=settings.APP_CLIENT_ID,
    tenant_id=settings.TENANT_ID,
    scopes=settings.SCOPES,
)

class User(BaseModel):
    name: str
    roles: list[str] = []


logger = logging.getLogger(__name__) 
logger.setLevel(logging.INFO)
   
credential = DefaultAzureCredential()

configure_azure_monitor(
    credential=credential,
    connection_string="InstrumentationKey=xx-xx-xx-xx-xx"
)
   
@app.get("/log", dependencies=[Security(azure_scheme)])
async def root():
    print("Yo test")
    logger.info("Segato5", extra={"custom_dimension": "Kam_value","test1": "val1"})

    meter = metrics.get_meter_provider().get_meter(__name__)
    counter = meter.create_counter("segato2")
    counter.add(8)

    return {"whoIsTheBest": "!!"}

if __name__ == '__main__':
    uvicorn.run('main:app', reload=True)   

 

Solution

    • Yes, you can use managed identity but you can need to use connection string along with it too as its a mandatory parameter.

    • Also, to use managed identity, you need to deploy your code to any Azure resource such as Function app or Web App.

    • I have deployed below code to web app and then enabled system managed identity in it. I have granted Monitoring Metrics Publisher RBAC role to my Web App in Application Insight.

    enter image description here

    from fastapi import FastAPI
    import logging
    import uvicorn
    from azure.identity import ManagedIdentityCredential
    from azure.monitor.opentelemetry import configure_azure_monitor
    from opentelemetry import metrics
    from opentelemetry.instrumentation.fastapi import FastAPIInstrumentor
    
    app = FastAPI()
    
    logger = logging.getLogger(__name__)
    logger.setLevel(logging.INFO)
    
    credential = ManagedIdentityCredential()
    
    configure_azure_monitor(
        connection_string="InstrumentationKey=06a13******8b029b9",
        credential=credential
    )
    
    FastAPIInstrumentor().instrument_app(app)
    
    @app.get("/log")
    async def root():
        print("Yo test")
        logger.info("Segato5", extra={"custom_dimension": "Kam_value","test1": "val1"})
    
        meter = metrics.get_meter_provider().get_meter(__name__)
        counter = meter.create_counter("segato2")
        counter.add(8)
    
        return {"whoIsTheBest": "!!"}
    
    if __name__ == '__main__':
        uvicorn.run('main:app', reload=True)
    
    • Add gunicorn -w 2 -k uvicorn.workers.UvicornWorker -b 0.0.0.0:8000 main:app in Configuration.

    enter image description here

    • I am able to get the logs in Application insight.

    enter image description here

    enter image description here

    enter image description here

    Thanks AnuragSingh-MSFT for clarifying the use of managed identity and connection string in this question.