We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
log repeat twice
The log print in screen like
**`2021-04-28 17:55:36,274 - mmseg - INFO - Distributed training: True `
`INFO:mmseg:Distributed training: True`**
All log messages ware printed twice in screen, but in log files, the message was only writed once. 
I tried to locate the bug, and found that after run `c = c.parent`(anaconda3/envs/open-mmlab/lib/python3.7/logging/__init__.py, line 1590),  c was changed to `[StreamHandler <stderr> (NOTSET)]`. And then, the message was print again.


------------------------------------------------------------
sys.platform: linux
Python: 3.7.10 (default, Feb 26 2021, 18:47:35) [GCC 7.3.0]
CUDA available: True
GPU 0,1,2,3,4,5,6,7: GeForce RTX 3090
CUDA_HOME: /data/lfxuan/softwares/cuda-11.1
NVCC: Build cuda_11.1.TC455_06.29069683_0
GCC: gcc (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0
PyTorch: 1.8.1+cu111
PyTorch compiling details: PyTorch built with:
  - GCC 7.3
  - C++ Version: 201402
  - Intel(R) Math Kernel Library Version 2020.0.0 Product Build 20191122 for Intel(R) 64 architecture applications
  - Intel(R) MKL-DNN v1.7.0 (Git Hash 7aed236906b1f7a05c0917e5257a1af05e9ff683)
  - OpenMP 201511 (a.k.a. OpenMP 4.5)
  - NNPACK is enabled
  - CPU capability usage: AVX2
  - CUDA Runtime 11.1
  - NVCC architecture flags: -gencode;arch=compute_37,code=sm_37;-gencode;arch=compute_50,code=sm_50;-gencode;arch=compute_60,code=sm_60;-gencode;arch=compute_70,code=sm_70;-gencode;arch=compute_75,code=sm_75;-gencode;arch=compute_80,code=sm_80;-gencode;arch=compute_86,code=sm_86
  - CuDNN 8.0.5
  - Magma 2.5.2
  - Build settings: BLAS_INFO=mkl, BUILD_TYPE=Release, CUDA_VERSION=11.1, CUDNN_VERSION=8.0.5, CXX_COMPILER=/opt/rh/devtoolset-7/root/usr/bin/c++, CXX_FLAGS= -Wno-deprecated -fvisibility-inlines-hidden -DUSE_PTHREADPOOL -fopenmp -DNDEBUG -DUSE_KINETO -DUSE_FBGEMM -DUSE_QNNPACK -DUSE_PYTORCH_QNNPACK -DUSE_XNNPACK -O2 -fPIC -Wno-narrowing -Wall -Wextra -Werror=return-type -Wno-missing-field-initializers -Wno-type-limits -Wno-array-bounds -Wno-unknown-pragmas -Wno-sign-compare -Wno-unused-parameter -Wno-unused-variable -Wno-unused-function -Wno-unused-result -Wno-unused-local-typedefs -Wno-strict-overflow -Wno-strict-aliasing -Wno-error=deprecated-declarations -Wno-stringop-overflow -Wno-psabi -Wno-error=pedantic -Wno-error=redundant-decls -Wno-error=old-style-cast -fdiagnostics-color=always -faligned-new -Wno-unused-but-set-variable -Wno-maybe-uninitialized -fno-math-errno -fno-trapping-math -Werror=format -Wno-stringop-overflow, LAPACK_INFO=mkl, PERF_WITH_AVX=1, PERF_WITH_AVX2=1, PERF_WITH_AVX512=1, TORCH_VERSION=1.8.1, USE_CUDA=ON, USE_CUDNN=ON, USE_EXCEPTION_PTR=1, USE_GFLAGS=OFF, USE_GLOG=OFF, USE_MKL=ON, USE_MKLDNN=ON, USE_MPI=OFF, USE_NCCL=ON, USE_NNPACK=ON, USE_OPENMP=ON, 

TorchVision: 0.9.1+cu111
OpenCV: 4.5.1
MMCV: 1.3.2
MMCV Compiler: GCC 9.3
MMCV CUDA Compiler: 11.1
MMSegmentation: 0.9.0+fed4b96
------------------------------------------------------------

 

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `mmcv/utils/logging.py`
Content:
```
1 import logging
2 
3 import torch.distributed as dist
4 
5 logger_initialized = {}
6 
7 
8 def get_logger(name, log_file=None, log_level=logging.INFO, file_mode='w'):
9     """Initialize and get a logger by name.
10 
11     If the logger has not been initialized, this method will initialize the
12     logger by adding one or two handlers, otherwise the initialized logger will
13     be directly returned. During initialization, a StreamHandler will always be
14     added. If `log_file` is specified and the process rank is 0, a FileHandler
15     will also be added.
16 
17     Args:
18         name (str): Logger name.
19         log_file (str | None): The log filename. If specified, a FileHandler
20             will be added to the logger.
21         log_level (int): The logger level. Note that only the process of
22             rank 0 is affected, and other processes will set the level to
23             "Error" thus be silent most of the time.
24         file_mode (str): The file mode used in opening log file.
25             Defaults to 'w'.
26 
27     Returns:
28         logging.Logger: The expected logger.
29     """
30     logger = logging.getLogger(name)
31     if name in logger_initialized:
32         return logger
33     # handle hierarchical names
34     # e.g., logger "a" is initialized, then logger "a.b" will skip the
35     # initialization since it is a child of "a".
36     for logger_name in logger_initialized:
37         if name.startswith(logger_name):
38             return logger
39 
40     stream_handler = logging.StreamHandler()
41     handlers = [stream_handler]
42 
43     if dist.is_available() and dist.is_initialized():
44         rank = dist.get_rank()
45     else:
46         rank = 0
47 
48     # only rank 0 will add a FileHandler
49     if rank == 0 and log_file is not None:
50         # Here, the default behaviour of the official logger is 'a'. Thus, we
51         # provide an interface to change the file mode to the default
52         # behaviour.
53         file_handler = logging.FileHandler(log_file, file_mode)
54         handlers.append(file_handler)
55 
56     formatter = logging.Formatter(
57         '%(asctime)s - %(name)s - %(levelname)s - %(message)s')
58     for handler in handlers:
59         handler.setFormatter(formatter)
60         handler.setLevel(log_level)
61         logger.addHandler(handler)
62 
63     if rank == 0:
64         logger.setLevel(log_level)
65     else:
66         logger.setLevel(logging.ERROR)
67 
68     logger_initialized[name] = True
69 
70     return logger
71 
72 
73 def print_log(msg, logger=None, level=logging.INFO):
74     """Print a log message.
75 
76     Args:
77         msg (str): The message to be logged.
78         logger (logging.Logger | str | None): The logger to be used.
79             Some special loggers are:
80             - "silent": no message will be printed.
81             - other str: the logger obtained with `get_root_logger(logger)`.
82             - None: The `print()` method will be used to print log messages.
83         level (int): Logging level. Only available when `logger` is a Logger
84             object or "root".
85     """
86     if logger is None:
87         print(msg)
88     elif isinstance(logger, logging.Logger):
89         logger.log(level, msg)
90     elif logger == 'silent':
91         pass
92     elif isinstance(logger, str):
93         _logger = get_logger(logger)
94         _logger.log(level, msg)
95     else:
96         raise TypeError(
97             'logger should be either a logging.Logger object, str, '
98             f'"silent" or None, but got {type(logger)}')
99
```
--- 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/mmcv/utils/logging.py b/mmcv/utils/logging.py
--- a/mmcv/utils/logging.py
+++ b/mmcv/utils/logging.py
@@ -37,6 +37,17 @@
         if name.startswith(logger_name):
             return logger
 
+    # handle duplicate logs to the console
+    # Starting in 1.8.0, PyTorch DDP attaches a StreamHandler <stderr> (NOTSET)
+    # to the root logger. As logger.propagate is True by default, this root
+    # level handler causes logging messages from rank>0 processes to
+    # unexpectedly show up on the console, creating much unwanted clutter.
+    # To fix this issue, we set the root logger's StreamHandler, if any, to log
+    # at the ERROR level.
+    for handler in logger.root.handlers:
+        if type(handler) is logging.StreamHandler:
+            handler.setLevel(logging.ERROR)
+
     stream_handler = logging.StreamHandler()
     handlers = [stream_handler]

{"golden_diff": "diff --git a/mmcv/utils/logging.py b/mmcv/utils/logging.py\n--- a/mmcv/utils/logging.py\n+++ b/mmcv/utils/logging.py\n@@ -37,6 +37,17 @@\n         if name.startswith(logger_name):\n             return logger\n \n+    # handle duplicate logs to the console\n+    # Starting in 1.8.0, PyTorch DDP attaches a StreamHandler <stderr> (NOTSET)\n+    # to the root logger. As logger.propagate is True by default, this root\n+    # level handler causes logging messages from rank>0 processes to\n+    # unexpectedly show up on the console, creating much unwanted clutter.\n+    # To fix this issue, we set the root logger's StreamHandler, if any, to log\n+    # at the ERROR level.\n+    for handler in logger.root.handlers:\n+        if type(handler) is logging.StreamHandler:\n+            handler.setLevel(logging.ERROR)\n+\n     stream_handler = logging.StreamHandler()\n     handlers = [stream_handler]\n", "issue": "log repeat twice\nThe log print in screen like\r\n**`2021-04-28 17:55:36,274 - mmseg - INFO - Distributed training: True `\r\n`INFO:mmseg:Distributed training: True`**\r\nAll log messages ware printed twice in screen, but in log files, the message was only writed once. \r\nI tried to locate the bug, and found that after run `c = c.parent`(anaconda3/envs/open-mmlab/lib/python3.7/logging/__init__.py, line 1590),  c was changed to `[StreamHandler <stderr> (NOTSET)]`. And then, the message was print again.\r\n\r\n\r\n------------------------------------------------------------\r\nsys.platform: linux\r\nPython: 3.7.10 (default, Feb 26 2021, 18:47:35) [GCC 7.3.0]\r\nCUDA available: True\r\nGPU 0,1,2,3,4,5,6,7: GeForce RTX 3090\r\nCUDA_HOME: /data/lfxuan/softwares/cuda-11.1\r\nNVCC: Build cuda_11.1.TC455_06.29069683_0\r\nGCC: gcc (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0\r\nPyTorch: 1.8.1+cu111\r\nPyTorch compiling details: PyTorch built with:\r\n  - GCC 7.3\r\n  - C++ Version: 201402\r\n  - Intel(R) Math Kernel Library Version 2020.0.0 Product Build 20191122 for Intel(R) 64 architecture applications\r\n  - Intel(R) MKL-DNN v1.7.0 (Git Hash 7aed236906b1f7a05c0917e5257a1af05e9ff683)\r\n  - OpenMP 201511 (a.k.a. OpenMP 4.5)\r\n  - NNPACK is enabled\r\n  - CPU capability usage: AVX2\r\n  - CUDA Runtime 11.1\r\n  - NVCC architecture flags: -gencode;arch=compute_37,code=sm_37;-gencode;arch=compute_50,code=sm_50;-gencode;arch=compute_60,code=sm_60;-gencode;arch=compute_70,code=sm_70;-gencode;arch=compute_75,code=sm_75;-gencode;arch=compute_80,code=sm_80;-gencode;arch=compute_86,code=sm_86\r\n  - CuDNN 8.0.5\r\n  - Magma 2.5.2\r\n  - Build settings: BLAS_INFO=mkl, BUILD_TYPE=Release, CUDA_VERSION=11.1, CUDNN_VERSION=8.0.5, CXX_COMPILER=/opt/rh/devtoolset-7/root/usr/bin/c++, CXX_FLAGS= -Wno-deprecated -fvisibility-inlines-hidden -DUSE_PTHREADPOOL -fopenmp -DNDEBUG -DUSE_KINETO -DUSE_FBGEMM -DUSE_QNNPACK -DUSE_PYTORCH_QNNPACK -DUSE_XNNPACK -O2 -fPIC -Wno-narrowing -Wall -Wextra -Werror=return-type -Wno-missing-field-initializers -Wno-type-limits -Wno-array-bounds -Wno-unknown-pragmas -Wno-sign-compare -Wno-unused-parameter -Wno-unused-variable -Wno-unused-function -Wno-unused-result -Wno-unused-local-typedefs -Wno-strict-overflow -Wno-strict-aliasing -Wno-error=deprecated-declarations -Wno-stringop-overflow -Wno-psabi -Wno-error=pedantic -Wno-error=redundant-decls -Wno-error=old-style-cast -fdiagnostics-color=always -faligned-new -Wno-unused-but-set-variable -Wno-maybe-uninitialized -fno-math-errno -fno-trapping-math -Werror=format -Wno-stringop-overflow, LAPACK_INFO=mkl, PERF_WITH_AVX=1, PERF_WITH_AVX2=1, PERF_WITH_AVX512=1, TORCH_VERSION=1.8.1, USE_CUDA=ON, USE_CUDNN=ON, USE_EXCEPTION_PTR=1, USE_GFLAGS=OFF, USE_GLOG=OFF, USE_MKL=ON, USE_MKLDNN=ON, USE_MPI=OFF, USE_NCCL=ON, USE_NNPACK=ON, USE_OPENMP=ON, \r\n\r\nTorchVision: 0.9.1+cu111\r\nOpenCV: 4.5.1\r\nMMCV: 1.3.2\r\nMMCV Compiler: GCC 9.3\r\nMMCV CUDA Compiler: 11.1\r\nMMSegmentation: 0.9.0+fed4b96\r\n------------------------------------------------------------\r\n\r\n \n", "before_files": [{"content": "import logging\n\nimport torch.distributed as dist\n\nlogger_initialized = {}\n\n\ndef get_logger(name, log_file=None, log_level=logging.INFO, file_mode='w'):\n    \"\"\"Initialize and get a logger by name.\n\n    If the logger has not been initialized, this method will initialize the\n    logger by adding one or two handlers, otherwise the initialized logger will\n    be directly returned. During initialization, a StreamHandler will always be\n    added. If `log_file` is specified and the process rank is 0, a FileHandler\n    will also be added.\n\n    Args:\n        name (str): Logger name.\n        log_file (str | None): The log filename. If specified, a FileHandler\n            will be added to the logger.\n        log_level (int): The logger level. Note that only the process of\n            rank 0 is affected, and other processes will set the level to\n            \"Error\" thus be silent most of the time.\n        file_mode (str): The file mode used in opening log file.\n            Defaults to 'w'.\n\n    Returns:\n        logging.Logger: The expected logger.\n    \"\"\"\n    logger = logging.getLogger(name)\n    if name in logger_initialized:\n        return logger\n    # handle hierarchical names\n    # e.g., logger \"a\" is initialized, then logger \"a.b\" will skip the\n    # initialization since it is a child of \"a\".\n    for logger_name in logger_initialized:\n        if name.startswith(logger_name):\n            return logger\n\n    stream_handler = logging.StreamHandler()\n    handlers = [stream_handler]\n\n    if dist.is_available() and dist.is_initialized():\n        rank = dist.get_rank()\n    else:\n        rank = 0\n\n    # only rank 0 will add a FileHandler\n    if rank == 0 and log_file is not None:\n        # Here, the default behaviour of the official logger is 'a'. Thus, we\n        # provide an interface to change the file mode to the default\n        # behaviour.\n        file_handler = logging.FileHandler(log_file, file_mode)\n        handlers.append(file_handler)\n\n    formatter = logging.Formatter(\n        '%(asctime)s - %(name)s - %(levelname)s - %(message)s')\n    for handler in handlers:\n        handler.setFormatter(formatter)\n        handler.setLevel(log_level)\n        logger.addHandler(handler)\n\n    if rank == 0:\n        logger.setLevel(log_level)\n    else:\n        logger.setLevel(logging.ERROR)\n\n    logger_initialized[name] = True\n\n    return logger\n\n\ndef print_log(msg, logger=None, level=logging.INFO):\n    \"\"\"Print a log message.\n\n    Args:\n        msg (str): The message to be logged.\n        logger (logging.Logger | str | None): The logger to be used.\n            Some special loggers are:\n            - \"silent\": no message will be printed.\n            - other str: the logger obtained with `get_root_logger(logger)`.\n            - None: The `print()` method will be used to print log messages.\n        level (int): Logging level. Only available when `logger` is a Logger\n            object or \"root\".\n    \"\"\"\n    if logger is None:\n        print(msg)\n    elif isinstance(logger, logging.Logger):\n        logger.log(level, msg)\n    elif logger == 'silent':\n        pass\n    elif isinstance(logger, str):\n        _logger = get_logger(logger)\n        _logger.log(level, msg)\n    else:\n        raise TypeError(\n            'logger should be either a logging.Logger object, str, '\n            f'\"silent\" or None, but got {type(logger)}')\n", "path": "mmcv/utils/logging.py"}], "after_files": [{"content": "import logging\n\nimport torch.distributed as dist\n\nlogger_initialized = {}\n\n\ndef get_logger(name, log_file=None, log_level=logging.INFO, file_mode='w'):\n    \"\"\"Initialize and get a logger by name.\n\n    If the logger has not been initialized, this method will initialize the\n    logger by adding one or two handlers, otherwise the initialized logger will\n    be directly returned. During initialization, a StreamHandler will always be\n    added. If `log_file` is specified and the process rank is 0, a FileHandler\n    will also be added.\n\n    Args:\n        name (str): Logger name.\n        log_file (str | None): The log filename. If specified, a FileHandler\n            will be added to the logger.\n        log_level (int): The logger level. Note that only the process of\n            rank 0 is affected, and other processes will set the level to\n            \"Error\" thus be silent most of the time.\n        file_mode (str): The file mode used in opening log file.\n            Defaults to 'w'.\n\n    Returns:\n        logging.Logger: The expected logger.\n    \"\"\"\n    logger = logging.getLogger(name)\n    if name in logger_initialized:\n        return logger\n    # handle hierarchical names\n    # e.g., logger \"a\" is initialized, then logger \"a.b\" will skip the\n    # initialization since it is a child of \"a\".\n    for logger_name in logger_initialized:\n        if name.startswith(logger_name):\n            return logger\n\n    # handle duplicate logs to the console\n    # Starting in 1.8.0, PyTorch DDP attaches a StreamHandler <stderr> (NOTSET)\n    # to the root logger. As logger.propagate is True by default, this root\n    # level handler causes logging messages from rank>0 processes to\n    # unexpectedly show up on the console, creating much unwanted clutter.\n    # To fix this issue, we set the root logger's StreamHandler, if any, to log\n    # at the ERROR level.\n    for handler in logger.root.handlers:\n        if type(handler) is logging.StreamHandler:\n            handler.setLevel(logging.ERROR)\n\n    stream_handler = logging.StreamHandler()\n    handlers = [stream_handler]\n\n    if dist.is_available() and dist.is_initialized():\n        rank = dist.get_rank()\n    else:\n        rank = 0\n\n    # only rank 0 will add a FileHandler\n    if rank == 0 and log_file is not None:\n        # Here, the default behaviour of the official logger is 'a'. Thus, we\n        # provide an interface to change the file mode to the default\n        # behaviour.\n        file_handler = logging.FileHandler(log_file, file_mode)\n        handlers.append(file_handler)\n\n    formatter = logging.Formatter(\n        '%(asctime)s - %(name)s - %(levelname)s - %(message)s')\n    for handler in handlers:\n        handler.setFormatter(formatter)\n        handler.setLevel(log_level)\n        logger.addHandler(handler)\n\n    if rank == 0:\n        logger.setLevel(log_level)\n    else:\n        logger.setLevel(logging.ERROR)\n\n    logger_initialized[name] = True\n\n    return logger\n\n\ndef print_log(msg, logger=None, level=logging.INFO):\n    \"\"\"Print a log message.\n\n    Args:\n        msg (str): The message to be logged.\n        logger (logging.Logger | str | None): The logger to be used.\n            Some special loggers are:\n            - \"silent\": no message will be printed.\n            - other str: the logger obtained with `get_root_logger(logger)`.\n            - None: The `print()` method will be used to print log messages.\n        level (int): Logging level. Only available when `logger` is a Logger\n            object or \"root\".\n    \"\"\"\n    if logger is None:\n        print(msg)\n    elif isinstance(logger, logging.Logger):\n        logger.log(level, msg)\n    elif logger == 'silent':\n        pass\n    elif isinstance(logger, str):\n        _logger = get_logger(logger)\n        _logger.log(level, msg)\n    else:\n        raise TypeError(\n            'logger should be either a logging.Logger object, str, '\n            f'\"silent\" or None, but got {type(logger)}')\n", "path": "mmcv/utils/logging.py"}]}