We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Unicode logging entries in Windows
## Problem Definition

While checking the logs of a Windows user I noticed the following repeating multiple times inside rotki-electron.log

```--- Logging error ---
Traceback (most recent call last):
  File "logging\__init__.py", line 1086, in emit
  File "encodings\cp1252.py", line 19, in encode
UnicodeEncodeError: 'charmap' codec can't encode character '\u2728' in position 101: character maps to <undefined>
Call stack:
  File "rotkehlchen\api\rest.py", line 298, in _do_query_async
  File "rotkehlchen\api\rest.py", line 664, in _query_blockchain_balances
  File "rotkehlchen\utils\mixins\lockable.py", line 46, in wrapper
  File "rotkehlchen\utils\mixins\cacheable.py", line 97, in wrapper
  File "rotkehlchen\chain\manager.py", line 616, in query_balances
  File "rotkehlchen\utils\mixins\lockable.py", line 46, in wrapper
  File "rotkehlchen\utils\mixins\cacheable.py", line 97, in wrapper
  File "rotkehlchen\chain\manager.py", line 1150, in query_ethereum_balances
  File "rotkehlchen\chain\manager.py", line 1083, in query_ethereum_tokens
  File "rotkehlchen\chain\evm\tokens.py", line 341, in query_tokens_for_addresses
  File "rotkehlchen\chain\evm\tokens.py", line 181, in _get_multicall_token_balances
  File "logging\__init__.py", line 1800, in debug
  File "logging\__init__.py", line 1844, in log
  File "logging\__init__.py", line 1512, in log
  File "logging\__init__.py", line 1589, in _log
  File "logging\__init__.py", line 1599, in handle
  File "logging\__init__.py", line 1661, in callHandlers
  File "logging\__init__.py", line 952, in handle
  File "logging\handlers.py", line 75, in emit
  File "logging\__init__.py", line 1187, in emit
  File "logging\__init__.py", line 1091, in emit
Message: 'Greenlet-4: Found \u2728(0x714a91578624d76A209E9aA4aF9a1F55d78f9190) token balance for 0x<redacted> and balance 6.434434324'
Arguments: ()
```

I suspect there may be an issue making unicode log entries to a windows file

## Task

Reproduce and fix

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `rotkehlchen/logging.py`
Content:
```
1 import argparse
2 import logging.config
3 import re
4 import sys
5 from pathlib import Path
6 from typing import TYPE_CHECKING, Any, Dict, MutableMapping, Optional, Tuple
7 
8 import gevent
9 
10 from rotkehlchen.utils.misc import timestamp_to_date, ts_now
11 
12 PYWSGI_RE = re.compile(r'\[(.*)\] ')
13 
14 TRACE = logging.DEBUG - 5
15 
16 
17 def add_logging_level(
18         level_name: str,
19         level_num: int,
20         method_name: Optional[str] = None,
21 ) -> None:
22     """
23     Comprehensively adds a new logging level to the `logging` module and the
24     currently configured logging class.
25 
26     `level_name` becomes an attribute of the `logging` module with the value
27     `level_num`. `method_name` becomes a convenience method for both `logging`
28     itself and the class returned by `logging.getLoggerClass()` (usually just
29     `logging.Logger`). If `method_name` is not specified, `level_name.lower()` is
30     used.
31 
32     To avoid accidental clobberings of existing attributes, this method will
33     raise an `AttributeError` if the level name is already an attribute of the
34     `logging` module or if the method name is already present
35 
36     Example
37     -------
38     >>> add_logging_level('TRACE', logging.DEBUG - 5)
39     >>> logging.getLogger(__name__).setLevel("TRACE")
40     >>> logging.getLogger(__name__).trace('that worked')
41     >>> logging.trace('so did this')
42     >>> logging.TRACE
43     5
44 
45     taken from: https://stackoverflow.com/a/35804945/110395
46     """
47     if not method_name:
48         method_name = level_name.lower()
49 
50     if hasattr(logging, level_name):
51         raise AttributeError('{} already defined in logging module'.format(level_name))
52     if hasattr(logging, method_name):
53         raise AttributeError('{} already defined in logging module'.format(method_name))
54     if hasattr(logging.getLoggerClass(), method_name):
55         raise AttributeError('{} already defined in logger class'.format(method_name))
56 
57     # This method was inspired by the answers to Stack Overflow post
58     # http://stackoverflow.com/q/2183233/2988730, especially
59     # http://stackoverflow.com/a/13638084/2988730
60     def log_for_level(self: logging.Logger, message: str, *args: Any, **kwargs: Any) -> None:
61         if self.isEnabledFor(level_num):
62             self._log(level_num, message, args, **kwargs)  # pylint:disable=protected-access
63 
64     def log_to_root(message: str, *args: Any, **kwargs: Any) -> None:
65         logging.log(level_num, message, *args, **kwargs)
66 
67     logging.addLevelName(level_num, level_name)
68     setattr(logging, level_name, level_num)
69     setattr(logging.getLoggerClass(), method_name, log_for_level)
70     setattr(logging, method_name, log_to_root)
71 
72 
73 if TYPE_CHECKING:
74     class RotkehlchenLogger(logging.Logger):
75         """Just for typing. Have not found another way to do correct type checking
76         for custom log level loggers"""
77 
78         def trace(self, msg: str, *args: Any, **kwargs: Any) -> None:  # pylint: disable=unused-argument  # noqa: E501
79             ...
80 
81 
82 class RotkehlchenLogsAdapter(logging.LoggerAdapter):
83 
84     def __init__(self, logger: logging.Logger):
85         super().__init__(logger, extra={})
86 
87     def process(self, given_msg: Any, kwargs: MutableMapping[str, Any]) -> Tuple[str, Dict]:
88         """
89         This is the main post-processing function for rotki logs
90 
91         This function:
92         - appends all kwargs to the final message
93         - appends the greenlet id in the log message
94         """
95         msg = str(given_msg)
96         greenlet = gevent.getcurrent()
97         if greenlet.parent is None:
98             greenlet_name = 'Main Greenlet'
99         else:
100             try:
101                 greenlet_name = greenlet.name
102             except AttributeError:  # means it's a raw greenlet
103                 greenlet_name = f'Greenlet with id {id(greenlet)}'
104 
105         msg = greenlet_name + ': ' + msg + ','.join(' {}={}'.format(a[0], a[1]) for a in kwargs.items())  # noqa: E501
106         return msg, {}
107 
108     def trace(self, msg: str, *args: Any, **kwargs: Any) -> None:
109         """
110         Delegate a trace call to the underlying logger.
111         """
112         self.log(TRACE, msg, *args, **kwargs)
113 
114 
115 class PywsgiFilter(logging.Filter):
116     def filter(self, record: logging.LogRecord) -> bool:
117         """Filter out the additional timestamp put in by pywsgi
118 
119         This is really a hack to fix https://github.com/rotki/rotki/issues/1192
120 
121         It seems that the way they do the logging in pywsgi they create the log
122         entry completely on their own. So the %message part of the entry contains
123         everything and is hence not properly customizale via normal python logging.
124 
125         Other options apart from using this filter would be:
126         - Ignore it and just have the timestamp two times in the logs
127         - Completely disable pywsgi logging and perhaps move it all to the
128         rest api.
129         """
130         record.msg = PYWSGI_RE.sub('', record.msg)
131         return True
132 
133 
134 def configure_logging(args: argparse.Namespace) -> None:
135     loglevel = args.loglevel.upper()
136     formatters = {
137         'default': {
138             'format': '[%(asctime)s] %(levelname)s %(name)s %(message)s',
139             'datefmt': '%d/%m/%Y %H:%M:%S %Z',
140         },
141     }
142     handlers = {
143         'console': {
144             'class': 'logging.StreamHandler',
145             'level': loglevel,
146             'formatter': 'default',
147         },
148     }
149 
150     if args.max_logfiles_num < 0:
151         backups_num = 0
152     else:
153         backups_num = args.max_logfiles_num - 1
154 
155     if args.logtarget == 'file':
156         given_filepath = Path(args.logfile)
157         filepath = given_filepath
158         if not getattr(sys, 'frozen', False):
159             # not packaged -- must be in develop mode. Append date to each file
160             date = timestamp_to_date(
161                 ts=ts_now(),
162                 formatstr='%Y%m%d_%H%M%S',
163                 treat_as_local=True,
164             )
165             filepath = given_filepath.parent / f'{date}_{given_filepath.name}'
166 
167         selected_handlers = ['file']
168         single_log_max_bytes = int(
169             (args.max_size_in_mb_all_logs * 1024 * 1000) / args.max_logfiles_num,
170         )
171         handlers['file'] = {
172             'class': 'logging.handlers.RotatingFileHandler',
173             'filename': filepath,
174             'mode': 'a',
175             'maxBytes': single_log_max_bytes,
176             'backupCount': backups_num,
177             'level': loglevel,
178             'formatter': 'default',
179         }
180     else:
181         selected_handlers = ['console']
182 
183     filters = {
184         'pywsgi': {
185             '()': PywsgiFilter,
186         },
187     }
188     loggers: Dict[str, Any] = {
189         '': {  # root logger
190             'level': loglevel,
191             'handlers': selected_handlers,
192         },
193         'rotkehlchen.api.server.pywsgi': {
194             'level': loglevel,
195             'handlers': selected_handlers,
196             'filters': ['pywsgi'],
197             'propagate': False,
198         },
199     }
200     logging.config.dictConfig({
201         'version': 1,
202         'disable_existing_loggers': False,
203         'filters': filters,
204         'formatters': formatters,
205         'handlers': handlers,
206         'loggers': loggers,
207     })
208 
209     if not args.logfromothermodules:
210         logging.getLogger('urllib3').setLevel(logging.CRITICAL)
211         logging.getLogger('urllib3.connectionpool').setLevel(logging.CRITICAL)
212         logging.getLogger('substrateinterface.base').setLevel(logging.CRITICAL)
213         logging.getLogger('eth_hash').setLevel(logging.CRITICAL)
214
```
--- 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/rotkehlchen/logging.py b/rotkehlchen/logging.py
--- a/rotkehlchen/logging.py
+++ b/rotkehlchen/logging.py
@@ -176,6 +176,7 @@
             'backupCount': backups_num,
             'level': loglevel,
             'formatter': 'default',
+            'encoding': 'utf-8',
         }
     else:
         selected_handlers = ['console']

{"golden_diff": "diff --git a/rotkehlchen/logging.py b/rotkehlchen/logging.py\n--- a/rotkehlchen/logging.py\n+++ b/rotkehlchen/logging.py\n@@ -176,6 +176,7 @@\n             'backupCount': backups_num,\n             'level': loglevel,\n             'formatter': 'default',\n+            'encoding': 'utf-8',\n         }\n     else:\n         selected_handlers = ['console']\n", "issue": "Unicode logging entries in Windows\n## Problem Definition\r\n\r\nWhile checking the logs of a Windows user I noticed the following repeating multiple times inside rotki-electron.log\r\n\r\n```--- Logging error ---\r\nTraceback (most recent call last):\r\n  File \"logging\\__init__.py\", line 1086, in emit\r\n  File \"encodings\\cp1252.py\", line 19, in encode\r\nUnicodeEncodeError: 'charmap' codec can't encode character '\\u2728' in position 101: character maps to <undefined>\r\nCall stack:\r\n  File \"rotkehlchen\\api\\rest.py\", line 298, in _do_query_async\r\n  File \"rotkehlchen\\api\\rest.py\", line 664, in _query_blockchain_balances\r\n  File \"rotkehlchen\\utils\\mixins\\lockable.py\", line 46, in wrapper\r\n  File \"rotkehlchen\\utils\\mixins\\cacheable.py\", line 97, in wrapper\r\n  File \"rotkehlchen\\chain\\manager.py\", line 616, in query_balances\r\n  File \"rotkehlchen\\utils\\mixins\\lockable.py\", line 46, in wrapper\r\n  File \"rotkehlchen\\utils\\mixins\\cacheable.py\", line 97, in wrapper\r\n  File \"rotkehlchen\\chain\\manager.py\", line 1150, in query_ethereum_balances\r\n  File \"rotkehlchen\\chain\\manager.py\", line 1083, in query_ethereum_tokens\r\n  File \"rotkehlchen\\chain\\evm\\tokens.py\", line 341, in query_tokens_for_addresses\r\n  File \"rotkehlchen\\chain\\evm\\tokens.py\", line 181, in _get_multicall_token_balances\r\n  File \"logging\\__init__.py\", line 1800, in debug\r\n  File \"logging\\__init__.py\", line 1844, in log\r\n  File \"logging\\__init__.py\", line 1512, in log\r\n  File \"logging\\__init__.py\", line 1589, in _log\r\n  File \"logging\\__init__.py\", line 1599, in handle\r\n  File \"logging\\__init__.py\", line 1661, in callHandlers\r\n  File \"logging\\__init__.py\", line 952, in handle\r\n  File \"logging\\handlers.py\", line 75, in emit\r\n  File \"logging\\__init__.py\", line 1187, in emit\r\n  File \"logging\\__init__.py\", line 1091, in emit\r\nMessage: 'Greenlet-4: Found \\u2728(0x714a91578624d76A209E9aA4aF9a1F55d78f9190) token balance for 0x<redacted> and balance 6.434434324'\r\nArguments: ()\r\n```\r\n\r\nI suspect there may be an issue making unicode log entries to a windows file\r\n\r\n## Task\r\n\r\nReproduce and fix\n", "before_files": [{"content": "import argparse\nimport logging.config\nimport re\nimport sys\nfrom pathlib import Path\nfrom typing import TYPE_CHECKING, Any, Dict, MutableMapping, Optional, Tuple\n\nimport gevent\n\nfrom rotkehlchen.utils.misc import timestamp_to_date, ts_now\n\nPYWSGI_RE = re.compile(r'\\[(.*)\\] ')\n\nTRACE = logging.DEBUG - 5\n\n\ndef add_logging_level(\n        level_name: str,\n        level_num: int,\n        method_name: Optional[str] = None,\n) -> None:\n    \"\"\"\n    Comprehensively adds a new logging level to the `logging` module and the\n    currently configured logging class.\n\n    `level_name` becomes an attribute of the `logging` module with the value\n    `level_num`. `method_name` becomes a convenience method for both `logging`\n    itself and the class returned by `logging.getLoggerClass()` (usually just\n    `logging.Logger`). If `method_name` is not specified, `level_name.lower()` is\n    used.\n\n    To avoid accidental clobberings of existing attributes, this method will\n    raise an `AttributeError` if the level name is already an attribute of the\n    `logging` module or if the method name is already present\n\n    Example\n    -------\n    >>> add_logging_level('TRACE', logging.DEBUG - 5)\n    >>> logging.getLogger(__name__).setLevel(\"TRACE\")\n    >>> logging.getLogger(__name__).trace('that worked')\n    >>> logging.trace('so did this')\n    >>> logging.TRACE\n    5\n\n    taken from: https://stackoverflow.com/a/35804945/110395\n    \"\"\"\n    if not method_name:\n        method_name = level_name.lower()\n\n    if hasattr(logging, level_name):\n        raise AttributeError('{} already defined in logging module'.format(level_name))\n    if hasattr(logging, method_name):\n        raise AttributeError('{} already defined in logging module'.format(method_name))\n    if hasattr(logging.getLoggerClass(), method_name):\n        raise AttributeError('{} already defined in logger class'.format(method_name))\n\n    # This method was inspired by the answers to Stack Overflow post\n    # http://stackoverflow.com/q/2183233/2988730, especially\n    # http://stackoverflow.com/a/13638084/2988730\n    def log_for_level(self: logging.Logger, message: str, *args: Any, **kwargs: Any) -> None:\n        if self.isEnabledFor(level_num):\n            self._log(level_num, message, args, **kwargs)  # pylint:disable=protected-access\n\n    def log_to_root(message: str, *args: Any, **kwargs: Any) -> None:\n        logging.log(level_num, message, *args, **kwargs)\n\n    logging.addLevelName(level_num, level_name)\n    setattr(logging, level_name, level_num)\n    setattr(logging.getLoggerClass(), method_name, log_for_level)\n    setattr(logging, method_name, log_to_root)\n\n\nif TYPE_CHECKING:\n    class RotkehlchenLogger(logging.Logger):\n        \"\"\"Just for typing. Have not found another way to do correct type checking\n        for custom log level loggers\"\"\"\n\n        def trace(self, msg: str, *args: Any, **kwargs: Any) -> None:  # pylint: disable=unused-argument  # noqa: E501\n            ...\n\n\nclass RotkehlchenLogsAdapter(logging.LoggerAdapter):\n\n    def __init__(self, logger: logging.Logger):\n        super().__init__(logger, extra={})\n\n    def process(self, given_msg: Any, kwargs: MutableMapping[str, Any]) -> Tuple[str, Dict]:\n        \"\"\"\n        This is the main post-processing function for rotki logs\n\n        This function:\n        - appends all kwargs to the final message\n        - appends the greenlet id in the log message\n        \"\"\"\n        msg = str(given_msg)\n        greenlet = gevent.getcurrent()\n        if greenlet.parent is None:\n            greenlet_name = 'Main Greenlet'\n        else:\n            try:\n                greenlet_name = greenlet.name\n            except AttributeError:  # means it's a raw greenlet\n                greenlet_name = f'Greenlet with id {id(greenlet)}'\n\n        msg = greenlet_name + ': ' + msg + ','.join(' {}={}'.format(a[0], a[1]) for a in kwargs.items())  # noqa: E501\n        return msg, {}\n\n    def trace(self, msg: str, *args: Any, **kwargs: Any) -> None:\n        \"\"\"\n        Delegate a trace call to the underlying logger.\n        \"\"\"\n        self.log(TRACE, msg, *args, **kwargs)\n\n\nclass PywsgiFilter(logging.Filter):\n    def filter(self, record: logging.LogRecord) -> bool:\n        \"\"\"Filter out the additional timestamp put in by pywsgi\n\n        This is really a hack to fix https://github.com/rotki/rotki/issues/1192\n\n        It seems that the way they do the logging in pywsgi they create the log\n        entry completely on their own. So the %message part of the entry contains\n        everything and is hence not properly customizale via normal python logging.\n\n        Other options apart from using this filter would be:\n        - Ignore it and just have the timestamp two times in the logs\n        - Completely disable pywsgi logging and perhaps move it all to the\n        rest api.\n        \"\"\"\n        record.msg = PYWSGI_RE.sub('', record.msg)\n        return True\n\n\ndef configure_logging(args: argparse.Namespace) -> None:\n    loglevel = args.loglevel.upper()\n    formatters = {\n        'default': {\n            'format': '[%(asctime)s] %(levelname)s %(name)s %(message)s',\n            'datefmt': '%d/%m/%Y %H:%M:%S %Z',\n        },\n    }\n    handlers = {\n        'console': {\n            'class': 'logging.StreamHandler',\n            'level': loglevel,\n            'formatter': 'default',\n        },\n    }\n\n    if args.max_logfiles_num < 0:\n        backups_num = 0\n    else:\n        backups_num = args.max_logfiles_num - 1\n\n    if args.logtarget == 'file':\n        given_filepath = Path(args.logfile)\n        filepath = given_filepath\n        if not getattr(sys, 'frozen', False):\n            # not packaged -- must be in develop mode. Append date to each file\n            date = timestamp_to_date(\n                ts=ts_now(),\n                formatstr='%Y%m%d_%H%M%S',\n                treat_as_local=True,\n            )\n            filepath = given_filepath.parent / f'{date}_{given_filepath.name}'\n\n        selected_handlers = ['file']\n        single_log_max_bytes = int(\n            (args.max_size_in_mb_all_logs * 1024 * 1000) / args.max_logfiles_num,\n        )\n        handlers['file'] = {\n            'class': 'logging.handlers.RotatingFileHandler',\n            'filename': filepath,\n            'mode': 'a',\n            'maxBytes': single_log_max_bytes,\n            'backupCount': backups_num,\n            'level': loglevel,\n            'formatter': 'default',\n        }\n    else:\n        selected_handlers = ['console']\n\n    filters = {\n        'pywsgi': {\n            '()': PywsgiFilter,\n        },\n    }\n    loggers: Dict[str, Any] = {\n        '': {  # root logger\n            'level': loglevel,\n            'handlers': selected_handlers,\n        },\n        'rotkehlchen.api.server.pywsgi': {\n            'level': loglevel,\n            'handlers': selected_handlers,\n            'filters': ['pywsgi'],\n            'propagate': False,\n        },\n    }\n    logging.config.dictConfig({\n        'version': 1,\n        'disable_existing_loggers': False,\n        'filters': filters,\n        'formatters': formatters,\n        'handlers': handlers,\n        'loggers': loggers,\n    })\n\n    if not args.logfromothermodules:\n        logging.getLogger('urllib3').setLevel(logging.CRITICAL)\n        logging.getLogger('urllib3.connectionpool').setLevel(logging.CRITICAL)\n        logging.getLogger('substrateinterface.base').setLevel(logging.CRITICAL)\n        logging.getLogger('eth_hash').setLevel(logging.CRITICAL)\n", "path": "rotkehlchen/logging.py"}], "after_files": [{"content": "import argparse\nimport logging.config\nimport re\nimport sys\nfrom pathlib import Path\nfrom typing import TYPE_CHECKING, Any, Dict, MutableMapping, Optional, Tuple\n\nimport gevent\n\nfrom rotkehlchen.utils.misc import timestamp_to_date, ts_now\n\nPYWSGI_RE = re.compile(r'\\[(.*)\\] ')\n\nTRACE = logging.DEBUG - 5\n\n\ndef add_logging_level(\n        level_name: str,\n        level_num: int,\n        method_name: Optional[str] = None,\n) -> None:\n    \"\"\"\n    Comprehensively adds a new logging level to the `logging` module and the\n    currently configured logging class.\n\n    `level_name` becomes an attribute of the `logging` module with the value\n    `level_num`. `method_name` becomes a convenience method for both `logging`\n    itself and the class returned by `logging.getLoggerClass()` (usually just\n    `logging.Logger`). If `method_name` is not specified, `level_name.lower()` is\n    used.\n\n    To avoid accidental clobberings of existing attributes, this method will\n    raise an `AttributeError` if the level name is already an attribute of the\n    `logging` module or if the method name is already present\n\n    Example\n    -------\n    >>> add_logging_level('TRACE', logging.DEBUG - 5)\n    >>> logging.getLogger(__name__).setLevel(\"TRACE\")\n    >>> logging.getLogger(__name__).trace('that worked')\n    >>> logging.trace('so did this')\n    >>> logging.TRACE\n    5\n\n    taken from: https://stackoverflow.com/a/35804945/110395\n    \"\"\"\n    if not method_name:\n        method_name = level_name.lower()\n\n    if hasattr(logging, level_name):\n        raise AttributeError('{} already defined in logging module'.format(level_name))\n    if hasattr(logging, method_name):\n        raise AttributeError('{} already defined in logging module'.format(method_name))\n    if hasattr(logging.getLoggerClass(), method_name):\n        raise AttributeError('{} already defined in logger class'.format(method_name))\n\n    # This method was inspired by the answers to Stack Overflow post\n    # http://stackoverflow.com/q/2183233/2988730, especially\n    # http://stackoverflow.com/a/13638084/2988730\n    def log_for_level(self: logging.Logger, message: str, *args: Any, **kwargs: Any) -> None:\n        if self.isEnabledFor(level_num):\n            self._log(level_num, message, args, **kwargs)  # pylint:disable=protected-access\n\n    def log_to_root(message: str, *args: Any, **kwargs: Any) -> None:\n        logging.log(level_num, message, *args, **kwargs)\n\n    logging.addLevelName(level_num, level_name)\n    setattr(logging, level_name, level_num)\n    setattr(logging.getLoggerClass(), method_name, log_for_level)\n    setattr(logging, method_name, log_to_root)\n\n\nif TYPE_CHECKING:\n    class RotkehlchenLogger(logging.Logger):\n        \"\"\"Just for typing. Have not found another way to do correct type checking\n        for custom log level loggers\"\"\"\n\n        def trace(self, msg: str, *args: Any, **kwargs: Any) -> None:  # pylint: disable=unused-argument  # noqa: E501\n            ...\n\n\nclass RotkehlchenLogsAdapter(logging.LoggerAdapter):\n\n    def __init__(self, logger: logging.Logger):\n        super().__init__(logger, extra={})\n\n    def process(self, given_msg: Any, kwargs: MutableMapping[str, Any]) -> Tuple[str, Dict]:\n        \"\"\"\n        This is the main post-processing function for rotki logs\n\n        This function:\n        - appends all kwargs to the final message\n        - appends the greenlet id in the log message\n        \"\"\"\n        msg = str(given_msg)\n        greenlet = gevent.getcurrent()\n        if greenlet.parent is None:\n            greenlet_name = 'Main Greenlet'\n        else:\n            try:\n                greenlet_name = greenlet.name\n            except AttributeError:  # means it's a raw greenlet\n                greenlet_name = f'Greenlet with id {id(greenlet)}'\n\n        msg = greenlet_name + ': ' + msg + ','.join(' {}={}'.format(a[0], a[1]) for a in kwargs.items())  # noqa: E501\n        return msg, {}\n\n    def trace(self, msg: str, *args: Any, **kwargs: Any) -> None:\n        \"\"\"\n        Delegate a trace call to the underlying logger.\n        \"\"\"\n        self.log(TRACE, msg, *args, **kwargs)\n\n\nclass PywsgiFilter(logging.Filter):\n    def filter(self, record: logging.LogRecord) -> bool:\n        \"\"\"Filter out the additional timestamp put in by pywsgi\n\n        This is really a hack to fix https://github.com/rotki/rotki/issues/1192\n\n        It seems that the way they do the logging in pywsgi they create the log\n        entry completely on their own. So the %message part of the entry contains\n        everything and is hence not properly customizale via normal python logging.\n\n        Other options apart from using this filter would be:\n        - Ignore it and just have the timestamp two times in the logs\n        - Completely disable pywsgi logging and perhaps move it all to the\n        rest api.\n        \"\"\"\n        record.msg = PYWSGI_RE.sub('', record.msg)\n        return True\n\n\ndef configure_logging(args: argparse.Namespace) -> None:\n    loglevel = args.loglevel.upper()\n    formatters = {\n        'default': {\n            'format': '[%(asctime)s] %(levelname)s %(name)s %(message)s',\n            'datefmt': '%d/%m/%Y %H:%M:%S %Z',\n        },\n    }\n    handlers = {\n        'console': {\n            'class': 'logging.StreamHandler',\n            'level': loglevel,\n            'formatter': 'default',\n        },\n    }\n\n    if args.max_logfiles_num < 0:\n        backups_num = 0\n    else:\n        backups_num = args.max_logfiles_num - 1\n\n    if args.logtarget == 'file':\n        given_filepath = Path(args.logfile)\n        filepath = given_filepath\n        if not getattr(sys, 'frozen', False):\n            # not packaged -- must be in develop mode. Append date to each file\n            date = timestamp_to_date(\n                ts=ts_now(),\n                formatstr='%Y%m%d_%H%M%S',\n                treat_as_local=True,\n            )\n            filepath = given_filepath.parent / f'{date}_{given_filepath.name}'\n\n        selected_handlers = ['file']\n        single_log_max_bytes = int(\n            (args.max_size_in_mb_all_logs * 1024 * 1000) / args.max_logfiles_num,\n        )\n        handlers['file'] = {\n            'class': 'logging.handlers.RotatingFileHandler',\n            'filename': filepath,\n            'mode': 'a',\n            'maxBytes': single_log_max_bytes,\n            'backupCount': backups_num,\n            'level': loglevel,\n            'formatter': 'default',\n            'encoding': 'utf-8',\n        }\n    else:\n        selected_handlers = ['console']\n\n    filters = {\n        'pywsgi': {\n            '()': PywsgiFilter,\n        },\n    }\n    loggers: Dict[str, Any] = {\n        '': {  # root logger\n            'level': loglevel,\n            'handlers': selected_handlers,\n        },\n        'rotkehlchen.api.server.pywsgi': {\n            'level': loglevel,\n            'handlers': selected_handlers,\n            'filters': ['pywsgi'],\n            'propagate': False,\n        },\n    }\n    logging.config.dictConfig({\n        'version': 1,\n        'disable_existing_loggers': False,\n        'filters': filters,\n        'formatters': formatters,\n        'handlers': handlers,\n        'loggers': loggers,\n    })\n\n    if not args.logfromothermodules:\n        logging.getLogger('urllib3').setLevel(logging.CRITICAL)\n        logging.getLogger('urllib3.connectionpool').setLevel(logging.CRITICAL)\n        logging.getLogger('substrateinterface.base').setLevel(logging.CRITICAL)\n        logging.getLogger('eth_hash').setLevel(logging.CRITICAL)\n", "path": "rotkehlchen/logging.py"}]}