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.
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:
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.
Add the below startup command in the Configuration section of the web app.
uvicorn main:app --host 0.0.0.0 --port 8000
Output after deployment:
Log stream: