Skip to content

Commit 28ffa99

Browse files
authored
Fix logging (#1874)
* Fix logging * Fix
1 parent a5b3334 commit 28ffa99

File tree

3 files changed

+70
-11
lines changed

3 files changed

+70
-11
lines changed

app/backend/app.py

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -128,13 +128,13 @@ async def content_file(path: str, auth_claims: Dict[str, Any]):
128128
if path.find("#page=") > 0:
129129
path_parts = path.rsplit("#page=", 1)
130130
path = path_parts[0]
131-
logging.info("Opening file %s", path)
131+
current_app.logger.info("Opening file %s", path)
132132
blob_container_client: ContainerClient = current_app.config[CONFIG_BLOB_CONTAINER_CLIENT]
133133
blob: Union[BlobDownloader, DatalakeDownloader]
134134
try:
135135
blob = await blob_container_client.get_blob_client(path).download_blob()
136136
except ResourceNotFoundError:
137-
logging.info("Path not found in general Blob container: %s", path)
137+
current_app.logger.info("Path not found in general Blob container: %s", path)
138138
if current_app.config[CONFIG_USER_UPLOAD_ENABLED]:
139139
try:
140140
user_oid = auth_claims["oid"]
@@ -143,7 +143,7 @@ async def content_file(path: str, auth_claims: Dict[str, Any]):
143143
file_client = user_directory_client.get_file_client(path)
144144
blob = await file_client.download_file()
145145
except ResourceNotFoundError:
146-
logging.exception("Path not found in DataLake: %s", path)
146+
current_app.logger.exception("Path not found in DataLake: %s", path)
147147
abort(404)
148148
else:
149149
abort(404)
@@ -314,7 +314,7 @@ async def speech():
314314
current_app.logger.error("Unexpected result reason: %s", result.reason)
315315
raise Exception("Speech synthesis failed. Check logs for details.")
316316
except Exception as e:
317-
logging.exception("Exception in /speech")
317+
current_app.logger.exception("Exception in /speech")
318318
return jsonify({"error": str(e)}), 500
319319

320320

@@ -453,6 +453,7 @@ async def setup_clients():
453453
# Set up authentication helper
454454
search_index = None
455455
if AZURE_USE_AUTHENTICATION:
456+
current_app.logger.info("AZURE_USE_AUTHENTICATION is true, setting up search index client")
456457
search_index_client = SearchIndexClient(
457458
endpoint=f"https://{AZURE_SEARCH_SERVICE}.search.windows.net",
458459
credential=azure_credential,
@@ -516,6 +517,7 @@ async def setup_clients():
516517
openai_client: AsyncOpenAI
517518

518519
if USE_SPEECH_OUTPUT_AZURE:
520+
current_app.logger.info("USE_SPEECH_OUTPUT_AZURE is true, setting up Azure speech service")
519521
if not AZURE_SPEECH_SERVICE_ID or AZURE_SPEECH_SERVICE_ID == "":
520522
raise ValueError("Azure speech resource not configured correctly, missing AZURE_SPEECH_SERVICE_ID")
521523
if not AZURE_SPEECH_SERVICE_LOCATION or AZURE_SPEECH_SERVICE_LOCATION == "":
@@ -530,28 +532,36 @@ async def setup_clients():
530532
if OPENAI_HOST.startswith("azure"):
531533
api_version = os.getenv("AZURE_OPENAI_API_VERSION") or "2024-03-01-preview"
532534
if OPENAI_HOST == "azure_custom":
535+
current_app.logger.info("OPENAI_HOST is azure_custom, setting up Azure OpenAI custom client")
533536
if not AZURE_OPENAI_CUSTOM_URL:
534537
raise ValueError("AZURE_OPENAI_CUSTOM_URL must be set when OPENAI_HOST is azure_custom")
535538
endpoint = AZURE_OPENAI_CUSTOM_URL
536539
else:
540+
current_app.logger.info("OPENAI_HOST is azure, setting up Azure OpenAI client")
537541
if not AZURE_OPENAI_SERVICE:
538542
raise ValueError("AZURE_OPENAI_SERVICE must be set when OPENAI_HOST is azure")
539543
endpoint = f"https://{AZURE_OPENAI_SERVICE}.openai.azure.com"
540544
if api_key := os.getenv("AZURE_OPENAI_API_KEY"):
545+
current_app.logger.info("AZURE_OPENAI_API_KEY found, using as value for api_key for Azure OpenAI client")
541546
openai_client = AsyncAzureOpenAI(api_version=api_version, azure_endpoint=endpoint, api_key=api_key)
542547
else:
548+
current_app.logger.info("Using Azure credential (passwordless authentication) for Azure OpenAI client")
543549
token_provider = get_bearer_token_provider(azure_credential, "https://cognitiveservices.azure.com/.default")
544550
openai_client = AsyncAzureOpenAI(
545551
api_version=api_version,
546552
azure_endpoint=endpoint,
547553
azure_ad_token_provider=token_provider,
548554
)
549555
elif OPENAI_HOST == "local":
556+
current_app.logger.info("OPENAI_HOST is local, setting up local OpenAI client for OPENAI_BASE_URL with no key")
550557
openai_client = AsyncOpenAI(
551558
base_url=os.environ["OPENAI_BASE_URL"],
552559
api_key="no-key-required",
553560
)
554561
else:
562+
current_app.logger.info(
563+
"OPENAI_HOST is not azure, setting up OpenAI client using OPENAI_API_KEY and OPENAI_ORGANIZATION environment variables"
564+
)
555565
openai_client = AsyncOpenAI(
556566
api_key=OPENAI_API_KEY,
557567
organization=OPENAI_ORGANIZATION,
@@ -660,6 +670,7 @@ def create_app():
660670
app.register_blueprint(bp)
661671

662672
if os.getenv("APPLICATIONINSIGHTS_CONNECTION_STRING"):
673+
app.logger.info("APPLICATIONINSIGHTS_CONNECTION_STRING is set, enabling Azure Monitor")
663674
configure_azure_monitor()
664675
# This tracks HTTP requests made by aiohttp:
665676
AioHttpClientInstrumentor().instrument()
@@ -670,13 +681,14 @@ def create_app():
670681
# This middleware tracks app route requests:
671682
app.asgi_app = OpenTelemetryMiddleware(app.asgi_app) # type: ignore[assignment]
672683

673-
# Level should be one of https://docs.python.org/3/library/logging.html#logging-levels
674-
default_level = "INFO" # In development, log more verbosely
675-
if os.getenv("WEBSITE_HOSTNAME"): # In production, don't log as heavily
676-
default_level = "WARNING"
677-
logging.basicConfig(level=os.getenv("APP_LOG_LEVEL", default_level))
684+
# Log levels should be one of https://docs.python.org/3/library/logging.html#logging-levels
685+
# Set root level to WARNING to avoid seeing overly verbose logs from SDKS
686+
logging.basicConfig(level=logging.WARNING)
687+
# Set the app logger level to INFO by default
688+
default_level = "INFO"
689+
app.logger.setLevel(os.getenv("APP_LOG_LEVEL", default_level))
678690

679691
if allowed_origin := os.getenv("ALLOWED_ORIGIN"):
680-
app.logger.info("CORS enabled for %s", allowed_origin)
692+
app.logger.info("ALLOWED_ORIGIN is set, enabling CORS for %s", allowed_origin)
681693
cors(app, allow_origin=allowed_origin, allow_methods=["GET", "POST"])
682694
return app
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
from uvicorn.workers import UvicornWorker
2+
3+
logconfig_dict = {
4+
"version": 1,
5+
"disable_existing_loggers": False,
6+
"formatters": {
7+
"default": {
8+
"()": "uvicorn.logging.DefaultFormatter",
9+
"format": "%(asctime)s - %(levelname)s - %(message)s",
10+
},
11+
"access": {
12+
"()": "uvicorn.logging.AccessFormatter",
13+
"format": "%(asctime)s - %(message)s",
14+
},
15+
},
16+
"handlers": {
17+
"default": {
18+
"formatter": "default",
19+
"class": "logging.StreamHandler",
20+
"stream": "ext://sys.stderr",
21+
},
22+
"access": {
23+
"formatter": "access",
24+
"class": "logging.StreamHandler",
25+
"stream": "ext://sys.stdout",
26+
},
27+
},
28+
"loggers": {
29+
"root": {"handlers": ["default"]},
30+
"uvicorn.error": {
31+
"level": "INFO",
32+
"handlers": ["default"],
33+
"propagate": False,
34+
},
35+
"uvicorn.access": {
36+
"level": "INFO",
37+
"handlers": ["access"],
38+
"propagate": False,
39+
},
40+
},
41+
}
42+
43+
44+
class CustomUvicornWorker(UvicornWorker):
45+
CONFIG_KWARGS = {
46+
"log_config": logconfig_dict,
47+
}

app/backend/gunicorn.conf.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,4 @@
1515
workers = 1
1616
else:
1717
workers = (num_cpus * 2) + 1
18-
worker_class = "uvicorn.workers.UvicornWorker"
18+
worker_class = "custom_uvicorn_worker.CustomUvicornWorker"

0 commit comments

Comments
 (0)