Search code examples
pythonazureloggingazure-application-insightsazure-webapps

Azure WebApp LogStream shows the same log multiple times and displays all logs as [ERROR], even though they are [INFO] level


Azure WebApp LogStream shows the same log multiple times and displays all logs as [ERROR], even though they are [INFO] level. Following image shows the actual screenshot of the logstream. Logs

Following python code shows the logger.py implementation. `

import logging
import os
import uuid
from opencensus.ext.azure.log_exporter import AzureLogHandler

class CustomFormatter(logging.Formatter):
    def __init__(self, fmt=None, datefmt=None, style='%', custom_value=''):
        super().__init__(fmt, datefmt, style)
        self.custom_value = custom_value

    def format(self, record):
        # Add the custom value to the log record
        record.custom_value = self.custom_value
        # Call the original format method
        return super().format(record)

def set_logger():
    logger_id = str(uuid.uuid4())
    logging.basicConfig(level=logging.INFO)
    format_str = 'log_id: %(custom_value)s - %(asctime)s - %(name)s - %(levelname)s - %(message)s'
    handler = logging.StreamHandler()
    custom_formatter = CustomFormatter(fmt=format_str, custom_value=logger_id)
    handler.setFormatter(custom_formatter)
    logger = logging.getLogger(__name__)
    logger.setLevel(logging.INFO)
    logger.addHandler(AzureLogHandler(connection_string=os.environ["LOG_CONNECTION_STRING"]))
    logger.addHandler(handler)
    return logger

`

I need to display unique logs without repetitions and ensure that INFO logs are shown as INFO, ERROR logs as ERROR, and so on.


Solution

  • I created a sample Fast API project with Azure logging, successfully deployed it to Azure App service and displayed logs without any issues.

    I installed the below packages in my project

    pip install fastapi uvicorn
    pip install opencensus-ext-azure
    

    This is my project structure:

    Fastapilogging/
    ├── venv/
    ├── logger.py
    ├── main.py
    ├── .env
    └── requirements.txt
    

    set up virtual environment

    python -m venv venv
    venv\Scripts\activate
    

    Logger .py:

    import  logging
    import  os
    import  uuid
    from  opencensus.ext.azure.log_exporter  import  AzureLogHandler
    class  CustomFormatter(logging.Formatter):
    def  __init__(self, fmt=None, datefmt=None, style='%', custom_value=''):
    super().__init__(fmt, datefmt, style)
    self.custom_value  =  custom_value
    def  format(self, record):
    record.custom_value =  self.custom_value
    return  super().format(record)
    def  set_logger():
    logger_id  =  str(uuid.uuid4())
    logging.basicConfig(level=logging.INFO)
    format_str  =  'log_id: %(custom_value)s - %(asctime)s - %(name)s - %(levelname)s - %(message)s'
    handler  =  logging.StreamHandler()
    custom_formatter  =  CustomFormatter(fmt=format_str, custom_value=logger_id)
    handler.setFormatter(custom_formatter)
    logger  =  logging.getLogger(__name__)
    logger.setLevel(logging.INFO)
    connection_string  =  os.getenv("LOG_CONNECTION_STRING")
    if  connection_string:
    logger.addHandler(AzureLogHandler(connection_string=connection_string))
    logger.addHandler(handler)
    return  logger
    

    Add connection string in your .env file .env:

    LOG_CONNECTION_STRING=your_azure_connection_string_here
    

    And run this command

    pip install python-dotenv
    

    I've added load_dotenv() to main .py so that it will load environment variable from .env

    main .py:

    from  fastapi  import  FastAPI
    from  logger  import  set_logger
    from  dotenv  import  load_dotenv
    import  os
    load_dotenv()
    app  =  FastAPI()
    logger  =  set_logger()
    @app.get("/")
    def  read_root():
    logger.info("Info level log: Hello, world!")
    logger.error("Error level log: Something went wrong!")
    return {"message": "Hello, World"}
    @app.get("/items/{item_id}")
    def  read_item(item_id: int, q: str  =  None):
    logger.info(f"Fetching item {item_id} with query {q}")
    return {"item_id": item_id, "q": q}
    

    Local output:

    enter image description here

    Before deploying the app to Azure App Service, run the following command in the project's root directory

    pip freeze > requirements.txt
    

    This will generate a requirements.txt file with all the dependencies needed for your project.

    set the environment variable WEBSITE_RUN_FROM_PACKAGE to 1 in your azure app service.

    enter image description here

    Add the below startup command in the Configuration section of the web app.

    uvicorn main:app --host 0.0.0.0 --port 8000
    

    enter image description here

    Output after deployment:

    enter image description here

    enter image description here

    Log stream:

    enter image description here