aprsd 1.0.0__py3-none-any.whl → 3.4.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (140) hide show
  1. aprsd/__init__.py +6 -4
  2. aprsd/cli_helper.py +151 -0
  3. aprsd/client/__init__.py +13 -0
  4. aprsd/client/aprsis.py +132 -0
  5. aprsd/client/base.py +105 -0
  6. aprsd/client/drivers/__init__.py +0 -0
  7. aprsd/client/drivers/aprsis.py +228 -0
  8. aprsd/client/drivers/fake.py +73 -0
  9. aprsd/client/drivers/kiss.py +119 -0
  10. aprsd/client/factory.py +88 -0
  11. aprsd/client/fake.py +48 -0
  12. aprsd/client/kiss.py +103 -0
  13. aprsd/client/stats.py +38 -0
  14. aprsd/cmds/__init__.py +0 -0
  15. aprsd/cmds/completion.py +22 -0
  16. aprsd/cmds/dev.py +162 -0
  17. aprsd/cmds/fetch_stats.py +156 -0
  18. aprsd/cmds/healthcheck.py +86 -0
  19. aprsd/cmds/list_plugins.py +319 -0
  20. aprsd/cmds/listen.py +231 -0
  21. aprsd/cmds/send_message.py +171 -0
  22. aprsd/cmds/server.py +137 -0
  23. aprsd/cmds/webchat.py +674 -0
  24. aprsd/conf/__init__.py +56 -0
  25. aprsd/conf/client.py +131 -0
  26. aprsd/conf/common.py +301 -0
  27. aprsd/conf/log.py +65 -0
  28. aprsd/conf/opts.py +80 -0
  29. aprsd/conf/plugin_common.py +182 -0
  30. aprsd/conf/plugin_email.py +105 -0
  31. aprsd/exception.py +13 -0
  32. aprsd/log/__init__.py +0 -0
  33. aprsd/log/log.py +138 -0
  34. aprsd/main.py +104 -867
  35. aprsd/packets/__init__.py +20 -0
  36. aprsd/packets/collector.py +79 -0
  37. aprsd/packets/core.py +823 -0
  38. aprsd/packets/log.py +161 -0
  39. aprsd/packets/packet_list.py +110 -0
  40. aprsd/packets/seen_list.py +49 -0
  41. aprsd/packets/tracker.py +103 -0
  42. aprsd/packets/watch_list.py +119 -0
  43. aprsd/plugin.py +474 -284
  44. aprsd/plugin_utils.py +86 -0
  45. aprsd/plugins/__init__.py +0 -0
  46. aprsd/plugins/email.py +709 -0
  47. aprsd/plugins/fortune.py +61 -0
  48. aprsd/plugins/location.py +179 -0
  49. aprsd/plugins/notify.py +61 -0
  50. aprsd/plugins/ping.py +31 -0
  51. aprsd/plugins/time.py +115 -0
  52. aprsd/plugins/version.py +31 -0
  53. aprsd/plugins/weather.py +405 -0
  54. aprsd/stats/__init__.py +20 -0
  55. aprsd/stats/app.py +49 -0
  56. aprsd/stats/collector.py +37 -0
  57. aprsd/threads/__init__.py +11 -0
  58. aprsd/threads/aprsd.py +119 -0
  59. aprsd/threads/keep_alive.py +131 -0
  60. aprsd/threads/log_monitor.py +121 -0
  61. aprsd/threads/registry.py +56 -0
  62. aprsd/threads/rx.py +354 -0
  63. aprsd/threads/stats.py +44 -0
  64. aprsd/threads/tx.py +255 -0
  65. aprsd/utils/__init__.py +218 -0
  66. aprsd/utils/counter.py +51 -0
  67. aprsd/utils/json.py +80 -0
  68. aprsd/utils/objectstore.py +123 -0
  69. aprsd/utils/ring_buffer.py +40 -0
  70. aprsd/utils/trace.py +180 -0
  71. aprsd/web/__init__.py +0 -0
  72. aprsd/web/admin/__init__.py +0 -0
  73. aprsd/web/admin/static/css/index.css +84 -0
  74. aprsd/web/admin/static/css/prism.css +4 -0
  75. aprsd/web/admin/static/css/tabs.css +35 -0
  76. aprsd/web/admin/static/images/Untitled.png +0 -0
  77. aprsd/web/admin/static/images/aprs-symbols-16-0.png +0 -0
  78. aprsd/web/admin/static/images/aprs-symbols-16-1.png +0 -0
  79. aprsd/web/admin/static/images/aprs-symbols-64-0.png +0 -0
  80. aprsd/web/admin/static/images/aprs-symbols-64-1.png +0 -0
  81. aprsd/web/admin/static/images/aprs-symbols-64-2.png +0 -0
  82. aprsd/web/admin/static/js/charts.js +235 -0
  83. aprsd/web/admin/static/js/echarts.js +465 -0
  84. aprsd/web/admin/static/js/logs.js +26 -0
  85. aprsd/web/admin/static/js/main.js +231 -0
  86. aprsd/web/admin/static/js/prism.js +12 -0
  87. aprsd/web/admin/static/js/send-message.js +114 -0
  88. aprsd/web/admin/static/js/tabs.js +28 -0
  89. aprsd/web/admin/templates/index.html +196 -0
  90. aprsd/web/chat/static/css/chat.css +115 -0
  91. aprsd/web/chat/static/css/index.css +66 -0
  92. aprsd/web/chat/static/css/style.css.map +1 -0
  93. aprsd/web/chat/static/css/tabs.css +41 -0
  94. aprsd/web/chat/static/css/upstream/bootstrap.min.css +6 -0
  95. aprsd/web/chat/static/css/upstream/font.woff2 +0 -0
  96. aprsd/web/chat/static/css/upstream/google-fonts.css +23 -0
  97. aprsd/web/chat/static/css/upstream/jquery-ui.css +1311 -0
  98. aprsd/web/chat/static/css/upstream/jquery.toast.css +28 -0
  99. aprsd/web/chat/static/css/upstream/themes/default/assets/fonts/LatoLatin-Bold.woff +0 -0
  100. aprsd/web/chat/static/css/upstream/themes/default/assets/fonts/LatoLatin-Bold.woff2 +0 -0
  101. aprsd/web/chat/static/css/upstream/themes/default/assets/fonts/LatoLatin-Regular.woff +0 -0
  102. aprsd/web/chat/static/css/upstream/themes/default/assets/fonts/LatoLatin-Regular.woff2 +0 -0
  103. aprsd/web/chat/static/css/upstream/themes/default/assets/fonts/icons.woff +0 -0
  104. aprsd/web/chat/static/css/upstream/themes/default/assets/fonts/icons.woff2 +0 -0
  105. aprsd/web/chat/static/css/upstream/themes/default/assets/fonts/outline-icons.woff +0 -0
  106. aprsd/web/chat/static/css/upstream/themes/default/assets/fonts/outline-icons.woff2 +0 -0
  107. aprsd/web/chat/static/images/Untitled.png +0 -0
  108. aprsd/web/chat/static/images/aprs-symbols-16-0.png +0 -0
  109. aprsd/web/chat/static/images/aprs-symbols-16-1.png +0 -0
  110. aprsd/web/chat/static/images/aprs-symbols-64-0.png +0 -0
  111. aprsd/web/chat/static/images/aprs-symbols-64-1.png +0 -0
  112. aprsd/web/chat/static/images/aprs-symbols-64-2.png +0 -0
  113. aprsd/web/chat/static/images/globe.svg +3 -0
  114. aprsd/web/chat/static/js/gps.js +84 -0
  115. aprsd/web/chat/static/js/main.js +45 -0
  116. aprsd/web/chat/static/js/send-message.js +585 -0
  117. aprsd/web/chat/static/js/tabs.js +28 -0
  118. aprsd/web/chat/static/js/upstream/bootstrap.bundle.min.js +7 -0
  119. aprsd/web/chat/static/js/upstream/jquery-3.7.1.min.js +2 -0
  120. aprsd/web/chat/static/js/upstream/jquery-ui.min.js +13 -0
  121. aprsd/web/chat/static/js/upstream/jquery.toast.js +374 -0
  122. aprsd/web/chat/static/js/upstream/semantic.min.js +11 -0
  123. aprsd/web/chat/static/js/upstream/socket.io.min.js +7 -0
  124. aprsd/web/chat/templates/index.html +139 -0
  125. aprsd/wsgi.py +315 -0
  126. aprsd-3.4.2.dist-info/AUTHORS +13 -0
  127. aprsd-3.4.2.dist-info/LICENSE +175 -0
  128. aprsd-3.4.2.dist-info/METADATA +793 -0
  129. aprsd-3.4.2.dist-info/RECORD +133 -0
  130. {aprsd-1.0.0.dist-info → aprsd-3.4.2.dist-info}/WHEEL +1 -1
  131. aprsd-3.4.2.dist-info/entry_points.txt +8 -0
  132. aprsd/fake_aprs.py +0 -83
  133. aprsd/utils.py +0 -166
  134. aprsd-1.0.0.dist-info/AUTHORS +0 -6
  135. aprsd-1.0.0.dist-info/METADATA +0 -181
  136. aprsd-1.0.0.dist-info/RECORD +0 -13
  137. aprsd-1.0.0.dist-info/entry_points.txt +0 -4
  138. aprsd-1.0.0.dist-info/pbr.json +0 -1
  139. /aprsd/{fuzzyclock.py → utils/fuzzyclock.py} +0 -0
  140. {aprsd-1.0.0.dist-info → aprsd-3.4.2.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,182 @@
1
+ from oslo_config import cfg
2
+
3
+
4
+ aprsfi_group = cfg.OptGroup(
5
+ name="aprs_fi",
6
+ title="APRS.FI website settings",
7
+ )
8
+ query_group = cfg.OptGroup(
9
+ name="query_plugin",
10
+ title="Options for the Query Plugin",
11
+ )
12
+ avwx_group = cfg.OptGroup(
13
+ name="avwx_plugin",
14
+ title="Options for the AVWXWeatherPlugin",
15
+ )
16
+ owm_wx_group = cfg.OptGroup(
17
+ name="owm_weather_plugin",
18
+ title="Options for the OWMWeatherPlugin",
19
+ )
20
+
21
+ location_group = cfg.OptGroup(
22
+ name="location_plugin",
23
+ title="Options for the LocationPlugin",
24
+ )
25
+
26
+ aprsfi_opts = [
27
+ cfg.StrOpt(
28
+ "apiKey",
29
+ help="Get the apiKey from your aprs.fi account here:"
30
+ "http://aprs.fi/account",
31
+ ),
32
+ ]
33
+
34
+ owm_wx_opts = [
35
+ cfg.StrOpt(
36
+ "apiKey",
37
+ help="OWMWeatherPlugin api key to OpenWeatherMap's API."
38
+ "This plugin uses the openweathermap API to fetch"
39
+ "location and weather information."
40
+ "To use this plugin you need to get an openweathermap"
41
+ "account and apikey."
42
+ "https://home.openweathermap.org/api_keys",
43
+ ),
44
+ ]
45
+
46
+ avwx_opts = [
47
+ cfg.StrOpt(
48
+ "apiKey",
49
+ help="avwx-api is an opensource project that has"
50
+ "a hosted service here: https://avwx.rest/"
51
+ "You can launch your own avwx-api in a container"
52
+ "by cloning the githug repo here:"
53
+ "https://github.com/avwx-rest/AVWX-API",
54
+ ),
55
+ cfg.StrOpt(
56
+ "base_url",
57
+ default="https://avwx.rest",
58
+ help="The base url for the avwx API. If you are hosting your own"
59
+ "Here is where you change the url to point to yours.",
60
+ ),
61
+ ]
62
+
63
+ location_opts = [
64
+ cfg.StrOpt(
65
+ "geopy_geocoder",
66
+ choices=[
67
+ "ArcGIS", "AzureMaps", "Baidu", "Bing", "GoogleV3", "HERE",
68
+ "Nominatim", "OpenCage", "TomTom", "USGov", "What3Words", "Woosmap",
69
+ ],
70
+ default="Nominatim",
71
+ help="The geopy geocoder to use. Default is Nominatim."
72
+ "See https://geopy.readthedocs.io/en/stable/#module-geopy.geocoders"
73
+ "for more information.",
74
+ ),
75
+ cfg.StrOpt(
76
+ "user_agent",
77
+ default="APRSD",
78
+ help="The user agent to use for the Nominatim geocoder."
79
+ "See https://geopy.readthedocs.io/en/stable/#module-geopy.geocoders"
80
+ "for more information.",
81
+ ),
82
+ cfg.StrOpt(
83
+ "arcgis_username",
84
+ default=None,
85
+ help="The username to use for the ArcGIS geocoder."
86
+ "See https://geopy.readthedocs.io/en/latest/#arcgis"
87
+ "for more information."
88
+ "Only used for the ArcGIS geocoder.",
89
+ ),
90
+ cfg.StrOpt(
91
+ "arcgis_password",
92
+ default=None,
93
+ help="The password to use for the ArcGIS geocoder."
94
+ "See https://geopy.readthedocs.io/en/latest/#arcgis"
95
+ "for more information."
96
+ "Only used for the ArcGIS geocoder.",
97
+ ),
98
+ cfg.StrOpt(
99
+ "azuremaps_subscription_key",
100
+ help="The subscription key to use for the AzureMaps geocoder."
101
+ "See https://geopy.readthedocs.io/en/latest/#azuremaps"
102
+ "for more information."
103
+ "Only used for the AzureMaps geocoder.",
104
+ ),
105
+ cfg.StrOpt(
106
+ "baidu_api_key",
107
+ help="The API key to use for the Baidu geocoder."
108
+ "See https://geopy.readthedocs.io/en/latest/#baidu"
109
+ "for more information."
110
+ "Only used for the Baidu geocoder.",
111
+ ),
112
+ cfg.StrOpt(
113
+ "bing_api_key",
114
+ help="The API key to use for the Bing geocoder."
115
+ "See https://geopy.readthedocs.io/en/latest/#bing"
116
+ "for more information."
117
+ "Only used for the Bing geocoder.",
118
+ ),
119
+ cfg.StrOpt(
120
+ "google_api_key",
121
+ help="The API key to use for the Google geocoder."
122
+ "See https://geopy.readthedocs.io/en/latest/#googlev3"
123
+ "for more information."
124
+ "Only used for the Google geocoder.",
125
+ ),
126
+ cfg.StrOpt(
127
+ "here_api_key",
128
+ help="The API key to use for the HERE geocoder."
129
+ "See https://geopy.readthedocs.io/en/latest/#here"
130
+ "for more information."
131
+ "Only used for the HERE geocoder.",
132
+ ),
133
+ cfg.StrOpt(
134
+ "opencage_api_key",
135
+ help="The API key to use for the OpenCage geocoder."
136
+ "See https://geopy.readthedocs.io/en/latest/#opencage"
137
+ "for more information."
138
+ "Only used for the OpenCage geocoder.",
139
+ ),
140
+ cfg.StrOpt(
141
+ "tomtom_api_key",
142
+ help="The API key to use for the TomTom geocoder."
143
+ "See https://geopy.readthedocs.io/en/latest/#tomtom"
144
+ "for more information."
145
+ "Only used for the TomTom geocoder.",
146
+ ),
147
+ cfg.StrOpt(
148
+ "what3words_api_key",
149
+ help="The API key to use for the What3Words geocoder."
150
+ "See https://geopy.readthedocs.io/en/latest/#what3words"
151
+ "for more information."
152
+ "Only used for the What3Words geocoder.",
153
+ ),
154
+ cfg.StrOpt(
155
+ "woosmap_api_key",
156
+ help="The API key to use for the Woosmap geocoder."
157
+ "See https://geopy.readthedocs.io/en/latest/#woosmap"
158
+ "for more information."
159
+ "Only used for the Woosmap geocoder.",
160
+ ),
161
+ ]
162
+
163
+
164
+ def register_opts(config):
165
+ config.register_group(aprsfi_group)
166
+ config.register_opts(aprsfi_opts, group=aprsfi_group)
167
+ config.register_group(query_group)
168
+ config.register_group(owm_wx_group)
169
+ config.register_opts(owm_wx_opts, group=owm_wx_group)
170
+ config.register_group(avwx_group)
171
+ config.register_opts(avwx_opts, group=avwx_group)
172
+ config.register_group(location_group)
173
+ config.register_opts(location_opts, group=location_group)
174
+
175
+
176
+ def list_opts():
177
+ return {
178
+ aprsfi_group.name: aprsfi_opts,
179
+ owm_wx_group.name: owm_wx_opts,
180
+ avwx_group.name: avwx_opts,
181
+ location_group.name: location_opts,
182
+ }
@@ -0,0 +1,105 @@
1
+ from oslo_config import cfg
2
+
3
+
4
+ email_group = cfg.OptGroup(
5
+ name="email_plugin",
6
+ title="Options for the APRSD Email plugin",
7
+ )
8
+
9
+ email_opts = [
10
+ cfg.StrOpt(
11
+ "callsign",
12
+ help="(Required) Callsign to validate for doing email commands."
13
+ "Only this callsign can check email. This is also where the "
14
+ "email notifications for new emails will be sent.",
15
+ ),
16
+ cfg.BoolOpt(
17
+ "enabled",
18
+ default=False,
19
+ help="Enable the Email plugin?",
20
+ ),
21
+ cfg.BoolOpt(
22
+ "debug",
23
+ default=False,
24
+ help="Enable the Email plugin Debugging?",
25
+ ),
26
+ ]
27
+
28
+ email_imap_opts = [
29
+ cfg.StrOpt(
30
+ "imap_login",
31
+ help="Login username/email for IMAP server",
32
+ ),
33
+ cfg.StrOpt(
34
+ "imap_password",
35
+ secret=True,
36
+ help="Login password for IMAP server",
37
+ ),
38
+ cfg.HostnameOpt(
39
+ "imap_host",
40
+ help="Hostname/IP of the IMAP server",
41
+ ),
42
+ cfg.PortOpt(
43
+ "imap_port",
44
+ default=993,
45
+ help="Port to use for IMAP server",
46
+ ),
47
+ cfg.BoolOpt(
48
+ "imap_use_ssl",
49
+ default=True,
50
+ help="Use SSL for connection to IMAP Server",
51
+ ),
52
+ ]
53
+
54
+ email_smtp_opts = [
55
+ cfg.StrOpt(
56
+ "smtp_login",
57
+ help="Login username/email for SMTP server",
58
+ ),
59
+ cfg.StrOpt(
60
+ "smtp_password",
61
+ secret=True,
62
+ help="Login password for SMTP server",
63
+ ),
64
+ cfg.HostnameOpt(
65
+ "smtp_host",
66
+ help="Hostname/IP of the SMTP server",
67
+ ),
68
+ cfg.PortOpt(
69
+ "smtp_port",
70
+ default=465,
71
+ help="Port to use for SMTP server",
72
+ ),
73
+ cfg.BoolOpt(
74
+ "smtp_use_ssl",
75
+ default=True,
76
+ help="Use SSL for connection to SMTP Server",
77
+ ),
78
+ ]
79
+
80
+ email_shortcuts_opts = [
81
+ cfg.ListOpt(
82
+ "email_shortcuts",
83
+ help="List of email shortcuts for checking/sending email "
84
+ "For Exmaple: wb=walt@walt.com,cl=cl@cl.com\n"
85
+ "Means use 'wb' to send an email to walt@walt.com",
86
+ ),
87
+ ]
88
+
89
+ ALL_OPTS = (
90
+ email_opts
91
+ + email_imap_opts
92
+ + email_smtp_opts
93
+ + email_shortcuts_opts
94
+ )
95
+
96
+
97
+ def register_opts(config):
98
+ config.register_group(email_group)
99
+ config.register_opts(ALL_OPTS, group=email_group)
100
+
101
+
102
+ def list_opts():
103
+ return {
104
+ email_group.name: ALL_OPTS,
105
+ }
aprsd/exception.py ADDED
@@ -0,0 +1,13 @@
1
+ class MissingConfigOptionException(Exception):
2
+ """Missing a config option."""
3
+ def __init__(self, config_option):
4
+ self.message = f"Option '{config_option}' was not in config file"
5
+
6
+
7
+ class ConfigOptionBogusDefaultException(Exception):
8
+ """Missing a config option."""
9
+ def __init__(self, config_option, default_fail):
10
+ self.message = (
11
+ f"Config file option '{config_option}' needs to be "
12
+ f"changed from provided default of '{default_fail}'"
13
+ )
aprsd/log/__init__.py ADDED
File without changes
aprsd/log/log.py ADDED
@@ -0,0 +1,138 @@
1
+ import logging
2
+ from logging.handlers import QueueHandler
3
+ import queue
4
+ import sys
5
+
6
+ from loguru import logger
7
+ from oslo_config import cfg
8
+
9
+ from aprsd.conf import log as conf_log
10
+
11
+
12
+ CONF = cfg.CONF
13
+ # LOG = logging.getLogger("APRSD")
14
+ LOG = logger
15
+
16
+
17
+ class QueueLatest(queue.Queue):
18
+ """Custom Queue to keep only the latest N items.
19
+
20
+ This prevents the queue from blowing up in size.
21
+ """
22
+ def put(self, *args, **kwargs):
23
+ try:
24
+ super().put(*args, **kwargs)
25
+ except queue.Full:
26
+ self.queue.popleft()
27
+ super().put(*args, **kwargs)
28
+
29
+
30
+ logging_queue = QueueLatest(maxsize=200)
31
+
32
+
33
+ class InterceptHandler(logging.Handler):
34
+ def emit(self, record):
35
+ # get corresponding Loguru level if it exists
36
+ try:
37
+ level = logger.level(record.levelname).name
38
+ except ValueError:
39
+ level = record.levelno
40
+
41
+ # find caller from where originated the logged message
42
+ frame, depth = sys._getframe(6), 6
43
+ while frame and frame.f_code.co_filename == logging.__file__:
44
+ frame = frame.f_back
45
+ depth += 1
46
+
47
+ logger.opt(depth=depth, exception=record.exc_info).log(level, record.getMessage())
48
+
49
+
50
+ # Setup the log faciility
51
+ # to disable log to stdout, but still log to file
52
+ # use the --quiet option on the cmdln
53
+ def setup_logging(loglevel=None, quiet=False):
54
+ if not loglevel:
55
+ log_level = CONF.logging.log_level
56
+ else:
57
+ log_level = conf_log.LOG_LEVELS[loglevel]
58
+
59
+ # intercept everything at the root logger
60
+ logging.root.handlers = [InterceptHandler()]
61
+ logging.root.setLevel(log_level)
62
+
63
+ imap_list = [
64
+ "imapclient.imaplib", "imaplib", "imapclient",
65
+ "imapclient.util",
66
+ ]
67
+ aprslib_list = [
68
+ "aprslib",
69
+ "aprslib.parsing",
70
+ "aprslib.exceptions",
71
+ ]
72
+ webserver_list = [
73
+ "werkzeug",
74
+ "werkzeug._internal",
75
+ "socketio",
76
+ "urllib3.connectionpool",
77
+ "chardet",
78
+ "chardet.charsetgroupprober",
79
+ "chardet.eucjpprober",
80
+ "chardet.mbcharsetprober",
81
+ ]
82
+
83
+ # We don't really want to see the aprslib parsing debug output.
84
+ disable_list = imap_list + aprslib_list + webserver_list
85
+
86
+ # remove every other logger's handlers
87
+ # and propagate to root logger
88
+ for name in logging.root.manager.loggerDict.keys():
89
+ logging.getLogger(name).handlers = []
90
+ if name in disable_list:
91
+ logging.getLogger(name).propagate = False
92
+ else:
93
+ logging.getLogger(name).propagate = True
94
+
95
+ if CONF.webchat.disable_url_request_logging:
96
+ for name in webserver_list:
97
+ logging.getLogger(name).handlers = []
98
+ logging.getLogger(name).propagate = True
99
+ logging.getLogger(name).setLevel(logging.ERROR)
100
+
101
+ handlers = [
102
+ {
103
+ "sink": sys.stdout,
104
+ "serialize": False,
105
+ "format": CONF.logging.logformat,
106
+ "colorize": True,
107
+ "level": log_level,
108
+ },
109
+ ]
110
+ if CONF.logging.logfile:
111
+ handlers.append(
112
+ {
113
+ "sink": CONF.logging.logfile,
114
+ "serialize": False,
115
+ "format": CONF.logging.logformat,
116
+ "colorize": False,
117
+ "level": log_level,
118
+ },
119
+ )
120
+
121
+ if CONF.email_plugin.enabled and CONF.email_plugin.debug:
122
+ for name in imap_list:
123
+ logging.getLogger(name).propagate = True
124
+
125
+ if CONF.admin.web_enabled:
126
+ qh = QueueHandler(logging_queue)
127
+ handlers.append(
128
+ {
129
+ "sink": qh, "serialize": False,
130
+ "format": CONF.logging.logformat,
131
+ "level": log_level,
132
+ "colorize": False,
133
+ },
134
+ )
135
+
136
+ # configure loguru
137
+ logger.configure(handlers=handlers)
138
+ logger.level("DEBUG", color="<fg #BABABA>")