Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,4 @@ nul
/artifacts/tmp
scripts/agent.json
scripts/me.json
.github/instructions/python-venv-path.instructions.md
3 changes: 2 additions & 1 deletion application/single_app/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -952,8 +952,9 @@ def list_semantic_kernel_plugins():
# ------------------- API Thoughts Routes ----------------
register_route_backend_thoughts(app)

# ------------------- Extenral Health Routes ----------
# ------------------- External Health Routes ----------
register_route_external_health(app)
register_no_auth_health(app)

if __name__ == '__main__':
debug_mode = os.environ.get("FLASK_DEBUG", "0") == "1"
Expand Down
1 change: 1 addition & 0 deletions application/single_app/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@
#"font-src 'self' https://cdn.jsdelivr.net https://stackpath.bootstrapcdn.com; "
"connect-src 'self' https: wss: ws:; "
"media-src 'self' blob:; "
"frame-src 'self' blob:; "
"object-src 'none'; "
"frame-ancestors 'self'; "
"base-uri 'self';"
Expand Down
25 changes: 22 additions & 3 deletions application/single_app/functions_activity_logging.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,24 @@
from config import cosmos_activity_logs_container


def coerce_activity_log_user_id(user_id: Any) -> str:
"""Extract a stable string user id from a scalar or session-style identity payload."""
if user_id is None:
return ''

if isinstance(user_id, str):
return user_id.strip()

if isinstance(user_id, dict):
for key in ('oid', 'sub', 'id', 'user_id'):
candidate = user_id.get(key)
if isinstance(candidate, str) and candidate.strip():
return candidate.strip()
return ''

return str(user_id).strip()


USER_LOGIN_ACTIVITY_SESSION_KEY = 'last_user_login_activity_epoch'
USER_LOGIN_ACTIVITY_MIN_INTERVAL_SECONDS = 15 * 60

Expand Down Expand Up @@ -1725,14 +1743,15 @@ def log_general_admin_action(
"""

try:
normalized_admin_user_id = coerce_activity_log_user_id(admin_user_id)
activity_record = {
'id': str(uuid.uuid4()),
'user_id': admin_user_id,
'user_id': normalized_admin_user_id,
'activity_type': 'admin_action',
'timestamp': datetime.utcnow().isoformat(),
'created_at': datetime.utcnow().isoformat(),
'admin': {
'user_id': admin_user_id,
'user_id': normalized_admin_user_id,
'email': admin_email
},
'action': action,
Expand All @@ -1759,7 +1778,7 @@ def log_general_admin_action(
log_event(
message=f"Error logging admin action: {str(e)}",
extra={
'admin_user_id': admin_user_id,
'admin_user_id': normalized_admin_user_id,
'admin_email': admin_email,
'action': action,
'error': str(e)
Expand Down
60 changes: 51 additions & 9 deletions application/single_app/functions_appinsights.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,18 +75,60 @@ def is_debug_enabled() -> bool:
return bool(settings.get('enable_debug_logging', False))


def _get_appinsights_debug_logger() -> Optional[logging.Logger]:
"""Return a logger that can emit DEBUG traces without widening parent logger levels."""
base_logger = get_appinsights_logger()
if not base_logger:
return None

base_name = base_logger.name or 'root'
debug_logger_name = 'appinsights.debug' if base_name == 'root' else f"{base_name}.debug"
debug_logger = logging.getLogger(debug_logger_name)
debug_logger.setLevel(logging.DEBUG)
return debug_logger


def _emit_appinsights_debug_trace(
message: str,
category: str,
details: Optional[Dict[str, Any]] = None,
) -> None:
"""Send a tagged debug trace to App Insights when Azure Monitor logging is configured."""
if not _azure_monitor_configured:
return

debug_logger = _get_appinsights_debug_logger()
if not debug_logger:
return

trace_properties = dict(details or {})
trace_properties.setdefault('debug_tag', '[debug]')
trace_properties.setdefault('debug_category', category)
trace_message = f"[debug] [{category}] {message}"

try:
# Use a child logger so DEBUG traces can flow to App Insights even when the
# parent logger stays at INFO to avoid broad third-party debug noise.
if trace_properties:
debug_logger.debug(trace_message, extra=trace_properties, stacklevel=3)
else:
debug_logger.debug(trace_message, stacklevel=3)
except Exception:
pass


def debug_print(message: Any, *args: Any, category: str = "INFO", **kwargs: Any) -> None:
"""Emit a debug-only console message using the unified logging implementation."""
"""Emit debug-only console output and forward a tagged App Insights trace when available."""
flush = kwargs.pop('flush', False)
details = kwargs or None
log_event(
message,
extra=details,
debug_only=True,
category=category,
flush=flush,
message_args=args,
)
formatted_message = _format_message(message, args)
settings = _load_logging_settings()

_emit_debug_message(settings, formatted_message, category, flush, details)
if not settings.get('enable_debug_logging', False):
return

_emit_appinsights_debug_trace(formatted_message, category, details)


def get_appinsights_logger():
Expand Down
5 changes: 2 additions & 3 deletions application/single_app/functions_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,8 @@ def get_settings(use_cosmos=False, include_source=False):
import secrets
default_settings = {
# External health check
'enable_external_healthcheck': True,
'enable_external_healthcheck': False,
'enable_no_auth_external_healthcheck': False,
# Security settings
'enable_appinsights_global_logging': False,
'enable_debug_logging': False,
Expand Down Expand Up @@ -390,8 +391,6 @@ def get_settings(use_cosmos=False, include_source=False):
'file_timer_value': 1,
'file_timer_unit': 'hours',
'file_processing_logs_turnoff_time': None,
'enable_external_healthcheck': False,

# Streaming settings
'streamingEnabled': True,

Expand Down
2 changes: 1 addition & 1 deletion application/single_app/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,4 @@ pyyaml==6.0.2
aiohttp==3.13.4
html2text==2025.4.15
matplotlib==3.10.7
azure-cognitiveservices-speech==1.47.0
azure-cognitiveservices-speech==1.48.2
Loading
Loading