prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Streamlit logger working on root
  ### Summary
  
  Upon import, Streamlit adds a new **global** log handler that dumps logs in text format. Packages should not be doing that, because it might break the logging convention of the host systems. 
  In our case for example, we dump logs in JSON format and push it all to our logging aggregation system. Streamlit's log message break the format and so it happens that the only service we can't debug properly is Streamlit.
  
  ### Steps to reproduce
  Nothing special, logging comes out of the box.
  
  **Expected behavior:**
  Streamlit should attach its handler to a specific logger namespace (e.g. `streamlit`) instead of attaching it to the root logger.
  
  **Actual behavior:**
  
  Streamlit attaches a stream handler to the root logger
  
  ### Is this a regression?
  
  That is, did this use to work the way you expected in the past?
  no
  
  ### Debug info
  
  - Streamlit version: 1.1.0
  - Python version: 3.8
  - Using Conda? PipEnv? PyEnv? Pex?
  - OS version: Any
  - Browser version: Irrelevant
  
  ---
  
  Community voting on feature requests enables the Streamlit team to understand which features are most important to our users.
  
  **If you'd like the Streamlit team to prioritize this feature request, please use the 👍 (thumbs up emoji) reaction in response to the initial post.**
  
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `lib/streamlit/logger.py`
  Content:
  ```
  1 # Copyright (c) Streamlit Inc. (2018-2022) Snowflake Inc. (2022)
  2 #
  3 # Licensed under the Apache License, Version 2.0 (the "License");
  4 # you may not use this file except in compliance with the License.
  5 # You may obtain a copy of the License at
  6 #
  7 #     http://www.apache.org/licenses/LICENSE-2.0
  8 #
  9 # Unless required by applicable law or agreed to in writing, software
  10 # distributed under the License is distributed on an "AS IS" BASIS,
  11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12 # See the License for the specific language governing permissions and
  13 # limitations under the License.
  14 
  15 """Logging module."""
  16 
  17 import logging
  18 import sys
  19 from typing import Dict, Union
  20 
  21 from typing_extensions import Final
  22 
  23 DEFAULT_LOG_MESSAGE: Final = "%(asctime)s %(levelname) -7s " "%(name)s: %(message)s"
  24 
  25 # Loggers for each name are saved here.
  26 _loggers: Dict[str, logging.Logger] = {}
  27 
  28 # The global log level is set here across all names.
  29 _global_log_level = logging.INFO
  30 
  31 
  32 def set_log_level(level: Union[str, int]) -> None:
  33     """Set log level."""
  34     logger = get_logger(__name__)
  35 
  36     if isinstance(level, str):
  37         level = level.upper()
  38     if level == "CRITICAL" or level == logging.CRITICAL:
  39         log_level = logging.CRITICAL
  40     elif level == "ERROR" or level == logging.ERROR:
  41         log_level = logging.ERROR
  42     elif level == "WARNING" or level == logging.WARNING:
  43         log_level = logging.WARNING
  44     elif level == "INFO" or level == logging.INFO:
  45         log_level = logging.INFO
  46     elif level == "DEBUG" or level == logging.DEBUG:
  47         log_level = logging.DEBUG
  48     else:
  49         msg = 'undefined log level "%s"' % level
  50         logger.critical(msg)
  51         sys.exit(1)
  52 
  53     for log in _loggers.values():
  54         log.setLevel(log_level)
  55 
  56     global _global_log_level
  57     _global_log_level = log_level
  58 
  59 
  60 def setup_formatter(logger: logging.Logger) -> None:
  61     """Set up the console formatter for a given logger."""
  62     # Deregister any previous console loggers.
  63     if hasattr(logger, "streamlit_console_handler"):
  64         logger.removeHandler(logger.streamlit_console_handler)
  65 
  66     logger.streamlit_console_handler = logging.StreamHandler()  # type: ignore[attr-defined]
  67 
  68     # Import here to avoid circular imports
  69     from streamlit import config
  70 
  71     if config._config_options:
  72         # logger is required in ConfigOption.set_value
  73         # Getting the config option before the config file has been parsed
  74         # can create an infinite loop
  75         message_format = config.get_option("logger.messageFormat")
  76     else:
  77         message_format = DEFAULT_LOG_MESSAGE
  78     formatter = logging.Formatter(fmt=message_format)
  79     formatter.default_msec_format = "%s.%03d"
  80     logger.streamlit_console_handler.setFormatter(formatter)  # type: ignore[attr-defined]
  81 
  82     # Register the new console logger.
  83     logger.addHandler(logger.streamlit_console_handler)  # type: ignore[attr-defined]
  84 
  85 
  86 def update_formatter() -> None:
  87     for log in _loggers.values():
  88         setup_formatter(log)
  89 
  90 
  91 def init_tornado_logs() -> None:
  92     """Set Tornado log levels.
  93 
  94     This function does not import any Tornado code, so it's safe to call even
  95     when Server is not running.
  96     """
  97     # http://www.tornadoweb.org/en/stable/log.html
  98     for log in ("access", "application", "general"):
  99         # get_logger will set the log level for the logger with the given name.
  100         get_logger(f"tornado.{log}")
  101 
  102 
  103 def get_logger(name: str) -> logging.Logger:
  104     """Return a logger.
  105 
  106     Parameters
  107     ----------
  108     name : str
  109         The name of the logger to use. You should just pass in __name__.
  110 
  111     Returns
  112     -------
  113     Logger
  114 
  115     """
  116     if name in _loggers.keys():
  117         return _loggers[name]
  118 
  119     if name == "root":
  120         logger = logging.getLogger()
  121     else:
  122         logger = logging.getLogger(name)
  123 
  124     logger.setLevel(_global_log_level)
  125     logger.propagate = False
  126     setup_formatter(logger)
  127 
  128     _loggers[name] = logger
  129 
  130     return logger
  131
  ```
  --- END FILES ---
  
  Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.
  
  Here is an example:
  
  ```diff
  diff --git a/examples/server_async.py b/examples/server_async.py
  --- a/examples/server_async.py
  +++ b/examples/server_async.py
  @@ -313,4 +313,4 @@
   
   
   if __name__ == "__main__":
  -    asyncio.run(run_async_server("."), debug=True)
  +    asyncio.run(run_async_server(), debug=True)
  diff --git a/examples/server_sync.py b/examples/server_sync.py
  --- a/examples/server_sync.py
  +++ b/examples/server_sync.py
  @@ -313,5 +313,5 @@
   
   
   if __name__ == "__main__":
  -    server = run_sync_server(".")
  +    server = run_sync_server()
       server.shutdown()
  
  ```
  
golden_diff: diff --git a/lib/streamlit/logger.py b/lib/streamlit/logger.py
  --- a/lib/streamlit/logger.py
  +++ b/lib/streamlit/logger.py
  @@ -117,7 +117,7 @@
           return _loggers[name]
   
       if name == "root":
  -        logger = logging.getLogger()
  +        logger = logging.getLogger("streamlit")
       else:
           logger = logging.getLogger(name)
  
verification_info: {"golden_diff": "diff --git a/lib/streamlit/logger.py b/lib/streamlit/logger.py\n--- a/lib/streamlit/logger.py\n+++ b/lib/streamlit/logger.py\n@@ -117,7 +117,7 @@\n         return _loggers[name]\n \n     if name == \"root\":\n-        logger = logging.getLogger()\n+        logger = logging.getLogger(\"streamlit\")\n     else:\n         logger = logging.getLogger(name)\n", "issue": "Streamlit logger working on root\n### Summary\r\n\r\nUpon import, Streamlit adds a new **global** log handler that dumps logs in text format. Packages should not be doing that, because it might break the logging convention of the host systems. \r\nIn our case for example, we dump logs in JSON format and push it all to our logging aggregation system. Streamlit's log message break the format and so it happens that the only service we can't debug properly is Streamlit.\r\n\r\n### Steps to reproduce\r\nNothing special, logging comes out of the box.\r\n\r\n**Expected behavior:**\r\nStreamlit should attach its handler to a specific logger namespace (e.g. `streamlit`) instead of attaching it to the root logger.\r\n\r\n**Actual behavior:**\r\n\r\nStreamlit attaches a stream handler to the root logger\r\n\r\n### Is this a regression?\r\n\r\nThat is, did this use to work the way you expected in the past?\r\nno\r\n\r\n### Debug info\r\n\r\n- Streamlit version: 1.1.0\r\n- Python version: 3.8\r\n- Using Conda? PipEnv? PyEnv? Pex?\r\n- OS version: Any\r\n- Browser version: Irrelevant\r\n\r\n---\r\n\r\nCommunity voting on feature requests enables the Streamlit team to understand which features are most important to our users.\r\n\r\n**If you'd like the Streamlit team to prioritize this feature request, please use the \ud83d\udc4d (thumbs up emoji) reaction in response to the initial post.**\r\n\n", "before_files": [{"content": "# Copyright (c) Streamlit Inc. (2018-2022) Snowflake Inc. (2022)\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n\"\"\"Logging module.\"\"\"\n\nimport logging\nimport sys\nfrom typing import Dict, Union\n\nfrom typing_extensions import Final\n\nDEFAULT_LOG_MESSAGE: Final = \"%(asctime)s %(levelname) -7s \" \"%(name)s: %(message)s\"\n\n# Loggers for each name are saved here.\n_loggers: Dict[str, logging.Logger] = {}\n\n# The global log level is set here across all names.\n_global_log_level = logging.INFO\n\n\ndef set_log_level(level: Union[str, int]) -> None:\n    \"\"\"Set log level.\"\"\"\n    logger = get_logger(__name__)\n\n    if isinstance(level, str):\n        level = level.upper()\n    if level == \"CRITICAL\" or level == logging.CRITICAL:\n        log_level = logging.CRITICAL\n    elif level == \"ERROR\" or level == logging.ERROR:\n        log_level = logging.ERROR\n    elif level == \"WARNING\" or level == logging.WARNING:\n        log_level = logging.WARNING\n    elif level == \"INFO\" or level == logging.INFO:\n        log_level = logging.INFO\n    elif level == \"DEBUG\" or level == logging.DEBUG:\n        log_level = logging.DEBUG\n    else:\n        msg = 'undefined log level \"%s\"' % level\n        logger.critical(msg)\n        sys.exit(1)\n\n    for log in _loggers.values():\n        log.setLevel(log_level)\n\n    global _global_log_level\n    _global_log_level = log_level\n\n\ndef setup_formatter(logger: logging.Logger) -> None:\n    \"\"\"Set up the console formatter for a given logger.\"\"\"\n    # Deregister any previous console loggers.\n    if hasattr(logger, \"streamlit_console_handler\"):\n        logger.removeHandler(logger.streamlit_console_handler)\n\n    logger.streamlit_console_handler = logging.StreamHandler()  # type: ignore[attr-defined]\n\n    # Import here to avoid circular imports\n    from streamlit import config\n\n    if config._config_options:\n        # logger is required in ConfigOption.set_value\n        # Getting the config option before the config file has been parsed\n        # can create an infinite loop\n        message_format = config.get_option(\"logger.messageFormat\")\n    else:\n        message_format = DEFAULT_LOG_MESSAGE\n    formatter = logging.Formatter(fmt=message_format)\n    formatter.default_msec_format = \"%s.%03d\"\n    logger.streamlit_console_handler.setFormatter(formatter)  # type: ignore[attr-defined]\n\n    # Register the new console logger.\n    logger.addHandler(logger.streamlit_console_handler)  # type: ignore[attr-defined]\n\n\ndef update_formatter() -> None:\n    for log in _loggers.values():\n        setup_formatter(log)\n\n\ndef init_tornado_logs() -> None:\n    \"\"\"Set Tornado log levels.\n\n    This function does not import any Tornado code, so it's safe to call even\n    when Server is not running.\n    \"\"\"\n    # http://www.tornadoweb.org/en/stable/log.html\n    for log in (\"access\", \"application\", \"general\"):\n        # get_logger will set the log level for the logger with the given name.\n        get_logger(f\"tornado.{log}\")\n\n\ndef get_logger(name: str) -> logging.Logger:\n    \"\"\"Return a logger.\n\n    Parameters\n    ----------\n    name : str\n        The name of the logger to use. You should just pass in __name__.\n\n    Returns\n    -------\n    Logger\n\n    \"\"\"\n    if name in _loggers.keys():\n        return _loggers[name]\n\n    if name == \"root\":\n        logger = logging.getLogger()\n    else:\n        logger = logging.getLogger(name)\n\n    logger.setLevel(_global_log_level)\n    logger.propagate = False\n    setup_formatter(logger)\n\n    _loggers[name] = logger\n\n    return logger\n", "path": "lib/streamlit/logger.py"}], "after_files": [{"content": "# Copyright (c) Streamlit Inc. (2018-2022) Snowflake Inc. (2022)\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n\"\"\"Logging module.\"\"\"\n\nimport logging\nimport sys\nfrom typing import Dict, Union\n\nfrom typing_extensions import Final\n\nDEFAULT_LOG_MESSAGE: Final = \"%(asctime)s %(levelname) -7s \" \"%(name)s: %(message)s\"\n\n# Loggers for each name are saved here.\n_loggers: Dict[str, logging.Logger] = {}\n\n# The global log level is set here across all names.\n_global_log_level = logging.INFO\n\n\ndef set_log_level(level: Union[str, int]) -> None:\n    \"\"\"Set log level.\"\"\"\n    logger = get_logger(__name__)\n\n    if isinstance(level, str):\n        level = level.upper()\n    if level == \"CRITICAL\" or level == logging.CRITICAL:\n        log_level = logging.CRITICAL\n    elif level == \"ERROR\" or level == logging.ERROR:\n        log_level = logging.ERROR\n    elif level == \"WARNING\" or level == logging.WARNING:\n        log_level = logging.WARNING\n    elif level == \"INFO\" or level == logging.INFO:\n        log_level = logging.INFO\n    elif level == \"DEBUG\" or level == logging.DEBUG:\n        log_level = logging.DEBUG\n    else:\n        msg = 'undefined log level \"%s\"' % level\n        logger.critical(msg)\n        sys.exit(1)\n\n    for log in _loggers.values():\n        log.setLevel(log_level)\n\n    global _global_log_level\n    _global_log_level = log_level\n\n\ndef setup_formatter(logger: logging.Logger) -> None:\n    \"\"\"Set up the console formatter for a given logger.\"\"\"\n    # Deregister any previous console loggers.\n    if hasattr(logger, \"streamlit_console_handler\"):\n        logger.removeHandler(logger.streamlit_console_handler)\n\n    logger.streamlit_console_handler = logging.StreamHandler()  # type: ignore[attr-defined]\n\n    # Import here to avoid circular imports\n    from streamlit import config\n\n    if config._config_options:\n        # logger is required in ConfigOption.set_value\n        # Getting the config option before the config file has been parsed\n        # can create an infinite loop\n        message_format = config.get_option(\"logger.messageFormat\")\n    else:\n        message_format = DEFAULT_LOG_MESSAGE\n    formatter = logging.Formatter(fmt=message_format)\n    formatter.default_msec_format = \"%s.%03d\"\n    logger.streamlit_console_handler.setFormatter(formatter)  # type: ignore[attr-defined]\n\n    # Register the new console logger.\n    logger.addHandler(logger.streamlit_console_handler)  # type: ignore[attr-defined]\n\n\ndef update_formatter() -> None:\n    for log in _loggers.values():\n        setup_formatter(log)\n\n\ndef init_tornado_logs() -> None:\n    \"\"\"Set Tornado log levels.\n\n    This function does not import any Tornado code, so it's safe to call even\n    when Server is not running.\n    \"\"\"\n    # http://www.tornadoweb.org/en/stable/log.html\n    for log in (\"access\", \"application\", \"general\"):\n        # get_logger will set the log level for the logger with the given name.\n        get_logger(f\"tornado.{log}\")\n\n\ndef get_logger(name: str) -> logging.Logger:\n    \"\"\"Return a logger.\n\n    Parameters\n    ----------\n    name : str\n        The name of the logger to use. You should just pass in __name__.\n\n    Returns\n    -------\n    Logger\n\n    \"\"\"\n    if name in _loggers.keys():\n        return _loggers[name]\n\n    if name == \"root\":\n        logger = logging.getLogger(\"streamlit\")\n    else:\n        logger = logging.getLogger(name)\n\n    logger.setLevel(_global_log_level)\n    logger.propagate = False\n    setup_formatter(logger)\n\n    _loggers[name] = logger\n\n    return logger\n", "path": "lib/streamlit/logger.py"}]}