How to avoid `opentelemetry.trace` overriding issues

Hi there,

We have a Streamlit frontend in production that logs stuff using the standard library logging module, which is exported to Azure Application Insights using opencensus. Since the opencensus Python SDK is to be retired by Microsoft on September 30, 2024, we are migrating the codebase to use the opentelemetry Python SDK. Due to streamlit reloading pages many times on runtime, we are running into Overriding of current TracerProvider is not allowed messages, meaning that log records are not correctly stored in Azure Application Insights, but rather just the message Attempting to instrument while already instrumented is saved. I thought caching the logger and tracer via streamlit.cache_resource might solve the issue, but in doing so log records simply will not upload to Application Insights. Please find below a minimal example reproducing the issue: commenting out the st.cache_resource decorator results in Attempting to instrument while already instrumented errors and otherwise nothing happens.

Would somebody be so nice of helping us with this issue? We have considered using opentelemetry.sdk._logs, but the Python SDK API is not yet stable so we’d rather refactor to use it when that API is stable.

Cheers and thank you in advance,
Gorka.

import logging
import os
from pathlib import Path

import opentelemetry
import streamlit as st
import streamlit_authenticator as stauth
import yaml
from azure.monitor.opentelemetry import configure_azure_monitor
from dotenv import load_dotenv
from opentelemetry import trace
from opentelemetry.instrumentation.logging import LoggingInstrumentor
from streamlit_calendar import calendar
from yaml.loader import SafeLoader


def user_config() -> tuple[str, bool, str, stauth.Authenticate]:
    here = Path(__file__).parent
    users_yaml_path = here / "src" / "frontend" / "users.yaml"

    with open(users_yaml_path) as file:
        config = yaml.load(file, Loader=SafeLoader)

    authenticator = stauth.Authenticate(
        config["credentials"],
        config["cookie"]["name"],
        config["cookie"]["key"],
        config["cookie"]["expiry_days"],
        config["preauthorized"],
    )

    name, authentication_status, username = authenticator.login("Login", "main")

    return name, authentication_status, username, authenticator


def logged_in(authenticator: stauth.Authenticate, username: str) -> None:
    with st.sidebar:
        st.write(f'Welcome *{st.session_state["name"]}*')
        vaults_markdown_list = "\n".join(
            f"- {vault_name}"
            for vault_name in authenticator.credentials["usernames"][username][
                "vaults"
            ].split(";")
        )
        st.write(f"You have access to these vaults:\n{vaults_markdown_list}")
        authenticator.logout("Logout", "main")


def not_logged_in() -> None:
    if not st.session_state["authentication_status"]:
        st.error("Username/password is incorrect")
        st.markdown(
            """
        <style>
            section[data-testid="stSidebar"][aria-expanded="true"]{
                display: none;
            }
        </style>
        """,
            unsafe_allow_html=True,
        )

    elif st.session_state["authentication_status"] is None:
        st.warning("Please enter your username and password")
        st.markdown(
            """
        <style>
            section[data-testid="stSidebar"][aria-expanded="true"]{
                display: none;
            }
        </style>
        """,
            unsafe_allow_html=True,
        )


# @st.cache_resource
def set_logger_and_tracer() -> tuple[logging.Logger, opentelemetry.trace.Tracer]:
    configure_azure_monitor(
        connection_string=os.environ["web_app_insights_connection_string"]
    )
    tracer = trace.get_tracer(__name__)
    LoggingInstrumentor(set_logging_format=True, log_level=logging.INFO).instrument()
    logger = logging.getLogger(__name__)
    return logger, tracer


load_dotenv()
name, authentication_status, username, authenticator = user_config()
if st.session_state["authentication_status"]:
    logger, tracer = set_logger_and_tracer()
    with tracer.start_as_current_span("span_name"):
        logger.info("Some logging")
        logged_in(authenticator, username)
        calendar_options = {
            "headerToolbar": {
                "left": "today prev,next",
                "center": "title",
                "right": "timeGridDay,timeGridWeek",
            },
            "slotMinTime": "00:00:00",
            "slotMaxTime": "24:00:00",
            "initialView": "timeGridWeek",
            "selectable": True,
            "selectMirror": True,
            "editable": True,
        }
        custom_css = """
            .fc-event-past {
                opacity: 0.8;
            }
            .fc-event-time {
                font-style: italic;
            }
            .fc-event-title {
                font-weight: 700;
            }
            .fc-toolbar-title {
                font-size: 2rem;
            }
        """

        new_event = calendar(
            events=[],
            options=calendar_options,
            custom_css=custom_css,
            callbacks=["dateClick", "eventChange", "eventClick", "eventsSet"],
        )
else:
    not_logged_in()

See answer here: `opentelemetry` + `streamlit` = `Overriding of current TracerProvider is not allowed messages` and `Attempting to instrument while already instrumented` Β· Issue #3743 Β· open-telemetry/opentelemetry-python Β· GitHub