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()

```

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)

{"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"}]}