aprsd 3.4.3__py3-none-any.whl → 4.0.0__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.
- aprsd/cli_helper.py +12 -5
- aprsd/client/aprsis.py +68 -17
- aprsd/client/base.py +60 -12
- aprsd/client/drivers/aprsis.py +11 -5
- aprsd/client/drivers/fake.py +15 -20
- aprsd/client/factory.py +6 -3
- aprsd/client/fake.py +5 -4
- aprsd/client/kiss.py +43 -7
- aprsd/client/stats.py +2 -22
- aprsd/cmds/completion.py +7 -4
- aprsd/cmds/dev.py +39 -43
- aprsd/cmds/fetch_stats.py +221 -69
- aprsd/cmds/healthcheck.py +7 -5
- aprsd/cmds/list_plugins.py +140 -134
- aprsd/cmds/listen.py +102 -11
- aprsd/cmds/server.py +71 -37
- aprsd/conf/__init__.py +1 -2
- aprsd/conf/client.py +3 -4
- aprsd/conf/common.py +29 -92
- aprsd/conf/log.py +2 -4
- aprsd/conf/opts.py +5 -4
- aprsd/conf/plugin_common.py +11 -121
- aprsd/exception.py +2 -0
- aprsd/log/log.py +7 -46
- aprsd/main.py +19 -9
- aprsd/packets/__init__.py +14 -4
- aprsd/packets/core.py +82 -91
- aprsd/packets/log.py +8 -8
- aprsd/packets/packet_list.py +18 -25
- aprsd/plugin.py +33 -15
- aprsd/plugins/fortune.py +2 -2
- aprsd/plugins/notify.py +1 -4
- aprsd/plugins/weather.py +10 -8
- aprsd/stats/__init__.py +0 -2
- aprsd/stats/collector.py +11 -3
- aprsd/threads/__init__.py +3 -2
- aprsd/threads/aprsd.py +57 -10
- aprsd/threads/{keep_alive.py → keepalive.py} +14 -37
- aprsd/threads/registry.py +3 -3
- aprsd/threads/rx.py +48 -17
- aprsd/threads/stats.py +2 -2
- aprsd/threads/tx.py +34 -10
- aprsd/utils/__init__.py +62 -15
- aprsd/utils/counter.py +15 -12
- aprsd/utils/json.py +9 -4
- aprsd/utils/keepalive_collector.py +55 -0
- aprsd/utils/trace.py +4 -4
- aprsd-4.0.0.dist-info/AUTHORS +1 -0
- aprsd-4.0.0.dist-info/METADATA +293 -0
- aprsd-4.0.0.dist-info/RECORD +74 -0
- {aprsd-3.4.3.dist-info → aprsd-4.0.0.dist-info}/WHEEL +1 -1
- aprsd/cmds/webchat.py +0 -674
- aprsd/conf/plugin_email.py +0 -105
- aprsd/plugins/email.py +0 -709
- aprsd/plugins/location.py +0 -179
- aprsd/threads/log_monitor.py +0 -121
- aprsd/web/__init__.py +0 -0
- aprsd/web/admin/__init__.py +0 -0
- aprsd/web/admin/static/css/index.css +0 -84
- aprsd/web/admin/static/css/prism.css +0 -4
- aprsd/web/admin/static/css/tabs.css +0 -35
- aprsd/web/admin/static/images/Untitled.png +0 -0
- aprsd/web/admin/static/images/aprs-symbols-16-0.png +0 -0
- aprsd/web/admin/static/images/aprs-symbols-16-1.png +0 -0
- aprsd/web/admin/static/images/aprs-symbols-64-0.png +0 -0
- aprsd/web/admin/static/images/aprs-symbols-64-1.png +0 -0
- aprsd/web/admin/static/images/aprs-symbols-64-2.png +0 -0
- aprsd/web/admin/static/js/charts.js +0 -235
- aprsd/web/admin/static/js/echarts.js +0 -465
- aprsd/web/admin/static/js/logs.js +0 -26
- aprsd/web/admin/static/js/main.js +0 -231
- aprsd/web/admin/static/js/prism.js +0 -12
- aprsd/web/admin/static/js/send-message.js +0 -114
- aprsd/web/admin/static/js/tabs.js +0 -28
- aprsd/web/admin/templates/index.html +0 -196
- aprsd/web/chat/static/css/chat.css +0 -115
- aprsd/web/chat/static/css/index.css +0 -66
- aprsd/web/chat/static/css/style.css.map +0 -1
- aprsd/web/chat/static/css/tabs.css +0 -41
- aprsd/web/chat/static/css/upstream/bootstrap.min.css +0 -6
- aprsd/web/chat/static/css/upstream/font.woff2 +0 -0
- aprsd/web/chat/static/css/upstream/google-fonts.css +0 -23
- aprsd/web/chat/static/css/upstream/jquery-ui.css +0 -1311
- aprsd/web/chat/static/css/upstream/jquery.toast.css +0 -28
- aprsd/web/chat/static/css/upstream/themes/default/assets/fonts/LatoLatin-Bold.woff +0 -0
- aprsd/web/chat/static/css/upstream/themes/default/assets/fonts/LatoLatin-Bold.woff2 +0 -0
- aprsd/web/chat/static/css/upstream/themes/default/assets/fonts/LatoLatin-Regular.woff +0 -0
- aprsd/web/chat/static/css/upstream/themes/default/assets/fonts/LatoLatin-Regular.woff2 +0 -0
- aprsd/web/chat/static/css/upstream/themes/default/assets/fonts/icons.woff +0 -0
- aprsd/web/chat/static/css/upstream/themes/default/assets/fonts/icons.woff2 +0 -0
- aprsd/web/chat/static/css/upstream/themes/default/assets/fonts/outline-icons.woff +0 -0
- aprsd/web/chat/static/css/upstream/themes/default/assets/fonts/outline-icons.woff2 +0 -0
- aprsd/web/chat/static/images/Untitled.png +0 -0
- aprsd/web/chat/static/images/aprs-symbols-16-0.png +0 -0
- aprsd/web/chat/static/images/aprs-symbols-16-1.png +0 -0
- aprsd/web/chat/static/images/aprs-symbols-64-0.png +0 -0
- aprsd/web/chat/static/images/aprs-symbols-64-1.png +0 -0
- aprsd/web/chat/static/images/aprs-symbols-64-2.png +0 -0
- aprsd/web/chat/static/images/globe.svg +0 -3
- aprsd/web/chat/static/js/gps.js +0 -84
- aprsd/web/chat/static/js/main.js +0 -45
- aprsd/web/chat/static/js/send-message.js +0 -585
- aprsd/web/chat/static/js/tabs.js +0 -28
- aprsd/web/chat/static/js/upstream/bootstrap.bundle.min.js +0 -7
- aprsd/web/chat/static/js/upstream/jquery-3.7.1.min.js +0 -2
- aprsd/web/chat/static/js/upstream/jquery-ui.min.js +0 -13
- aprsd/web/chat/static/js/upstream/jquery.toast.js +0 -374
- aprsd/web/chat/static/js/upstream/semantic.min.js +0 -11
- aprsd/web/chat/static/js/upstream/socket.io.min.js +0 -7
- aprsd/web/chat/templates/index.html +0 -139
- aprsd/wsgi.py +0 -315
- aprsd-3.4.3.dist-info/AUTHORS +0 -13
- aprsd-3.4.3.dist-info/METADATA +0 -793
- aprsd-3.4.3.dist-info/RECORD +0 -133
- {aprsd-3.4.3.dist-info → aprsd-4.0.0.dist-info}/LICENSE +0 -0
- {aprsd-3.4.3.dist-info → aprsd-4.0.0.dist-info}/entry_points.txt +0 -0
- {aprsd-3.4.3.dist-info → aprsd-4.0.0.dist-info}/top_level.txt +0 -0
aprsd/cmds/completion.py
CHANGED
@@ -3,12 +3,13 @@ import click.shell_completion
|
|
3
3
|
|
4
4
|
from aprsd.main import cli
|
5
5
|
|
6
|
-
|
7
6
|
CONTEXT_SETTINGS = dict(help_option_names=["-h", "--help"])
|
8
7
|
|
9
8
|
|
10
9
|
@cli.command()
|
11
|
-
@click.argument(
|
10
|
+
@click.argument(
|
11
|
+
"shell", type=click.Choice(list(click.shell_completion._available_shells))
|
12
|
+
)
|
12
13
|
def completion(shell):
|
13
14
|
"""Show the shell completion code"""
|
14
15
|
from click.utils import _detect_program_name
|
@@ -17,6 +18,8 @@ def completion(shell):
|
|
17
18
|
prog_name = _detect_program_name()
|
18
19
|
complete_var = f"_{prog_name}_COMPLETE".replace("-", "_").upper()
|
19
20
|
print(cls(cli, {}, prog_name, complete_var).source())
|
20
|
-
print(
|
21
|
+
print(
|
22
|
+
"# Add the following line to your shell configuration file to have aprsd command line completion"
|
23
|
+
)
|
21
24
|
print("# but remove the leading '#' character.")
|
22
|
-
print(f
|
25
|
+
print(f'# eval "$(aprsd completion {shell})"')
|
aprsd/cmds/dev.py
CHANGED
@@ -9,18 +9,18 @@ import click
|
|
9
9
|
from oslo_config import cfg
|
10
10
|
|
11
11
|
from aprsd import cli_helper, conf, packets, plugin
|
12
|
+
|
12
13
|
# local imports here
|
13
14
|
from aprsd.client import base
|
14
15
|
from aprsd.main import cli
|
15
16
|
from aprsd.utils import trace
|
16
17
|
|
17
|
-
|
18
18
|
CONF = cfg.CONF
|
19
|
-
LOG = logging.getLogger(
|
20
|
-
CONTEXT_SETTINGS = dict(help_option_names=[
|
19
|
+
LOG = logging.getLogger('APRSD')
|
20
|
+
CONTEXT_SETTINGS = dict(help_option_names=['-h', '--help'])
|
21
21
|
|
22
22
|
|
23
|
-
@cli.group(help=
|
23
|
+
@cli.group(help='Development type subcommands', context_settings=CONTEXT_SETTINGS)
|
24
24
|
@click.pass_context
|
25
25
|
def dev(ctx):
|
26
26
|
pass
|
@@ -29,37 +29,37 @@ def dev(ctx):
|
|
29
29
|
@dev.command()
|
30
30
|
@cli_helper.add_options(cli_helper.common_options)
|
31
31
|
@click.option(
|
32
|
-
|
33
|
-
envvar=
|
32
|
+
'--aprs-login',
|
33
|
+
envvar='APRS_LOGIN',
|
34
34
|
show_envvar=True,
|
35
|
-
help=
|
35
|
+
help='What callsign to send the message from.',
|
36
36
|
)
|
37
37
|
@click.option(
|
38
|
-
|
39
|
-
|
40
|
-
|
38
|
+
'-p',
|
39
|
+
'--plugin',
|
40
|
+
'plugin_path',
|
41
41
|
show_default=True,
|
42
42
|
default=None,
|
43
|
-
help=
|
43
|
+
help='The plugin to run. Ex: aprsd.plugins.ping.PingPlugin',
|
44
44
|
)
|
45
45
|
@click.option(
|
46
|
-
|
47
|
-
|
48
|
-
|
46
|
+
'-a',
|
47
|
+
'--all',
|
48
|
+
'load_all',
|
49
49
|
show_default=True,
|
50
50
|
is_flag=True,
|
51
51
|
default=False,
|
52
|
-
help=
|
52
|
+
help='Load all the plugins in config?',
|
53
53
|
)
|
54
54
|
@click.option(
|
55
|
-
|
56
|
-
|
57
|
-
|
55
|
+
'-n',
|
56
|
+
'--num',
|
57
|
+
'number',
|
58
58
|
show_default=True,
|
59
59
|
default=1,
|
60
|
-
help=
|
60
|
+
help='Number of times to call the plugin',
|
61
61
|
)
|
62
|
-
@click.argument(
|
62
|
+
@click.argument('message', nargs=-1, required=True)
|
63
63
|
@click.pass_context
|
64
64
|
@cli_helper.process_standard_options
|
65
65
|
def test_plugin(
|
@@ -76,7 +76,7 @@ def test_plugin(
|
|
76
76
|
|
77
77
|
if not aprs_login:
|
78
78
|
if CONF.aprs_network.login == conf.client.DEFAULT_LOGIN:
|
79
|
-
click.echo(
|
79
|
+
click.echo('Must set --aprs_login or APRS_LOGIN')
|
80
80
|
ctx.exit(-1)
|
81
81
|
return
|
82
82
|
else:
|
@@ -86,33 +86,34 @@ def test_plugin(
|
|
86
86
|
|
87
87
|
if not plugin_path:
|
88
88
|
click.echo(ctx.get_help())
|
89
|
-
click.echo(
|
90
|
-
click.echo(
|
89
|
+
click.echo('')
|
90
|
+
click.echo('Failed to provide -p option to test a plugin')
|
91
91
|
ctx.exit(-1)
|
92
92
|
return
|
93
93
|
|
94
94
|
if type(message) is tuple:
|
95
|
-
message =
|
95
|
+
message = ' '.join(message)
|
96
96
|
|
97
97
|
if CONF.trace_enabled:
|
98
|
-
trace.setup_tracing([
|
98
|
+
trace.setup_tracing(['method', 'api'])
|
99
99
|
|
100
100
|
base.APRSClient()
|
101
101
|
|
102
102
|
pm = plugin.PluginManager()
|
103
103
|
if load_all:
|
104
|
-
pm.setup_plugins()
|
104
|
+
pm.setup_plugins(load_help_plugin=CONF.load_help_plugin)
|
105
105
|
obj = pm._create_class(plugin_path, plugin.APRSDPluginBase)
|
106
106
|
if not obj:
|
107
107
|
click.echo(ctx.get_help())
|
108
|
-
click.echo(
|
108
|
+
click.echo('')
|
109
109
|
ctx.fail(f"Failed to create object from plugin path '{plugin_path}'")
|
110
110
|
ctx.exit()
|
111
111
|
|
112
112
|
# Register the plugin they wanted tested.
|
113
113
|
LOG.info(
|
114
|
-
|
115
|
-
obj.__class__,
|
114
|
+
'Testing plugin {} Version {}'.format(
|
115
|
+
obj.__class__,
|
116
|
+
obj.version,
|
116
117
|
),
|
117
118
|
)
|
118
119
|
pm.register_msg(obj)
|
@@ -125,7 +126,7 @@ def test_plugin(
|
|
125
126
|
)
|
126
127
|
LOG.info(f"P'{plugin_path}' F'{fromcall}' C'{message}'")
|
127
128
|
|
128
|
-
for
|
129
|
+
for _ in range(number):
|
129
130
|
replies = pm.run(packet)
|
130
131
|
# Plugin might have threads, so lets stop them so we can exit.
|
131
132
|
# obj.stop_threads()
|
@@ -146,17 +147,12 @@ def test_plugin(
|
|
146
147
|
elif isinstance(reply, packets.Packet):
|
147
148
|
# We have a message based object.
|
148
149
|
LOG.info(reply)
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
from_call=CONF.callsign,
|
158
|
-
to_call=fromcall,
|
159
|
-
message_text=reply,
|
160
|
-
),
|
161
|
-
)
|
150
|
+
elif reply is not packets.NULL_MESSAGE:
|
151
|
+
LOG.info(
|
152
|
+
packets.MessagePacket(
|
153
|
+
from_call=CONF.callsign,
|
154
|
+
to_call=fromcall,
|
155
|
+
message_text=reply,
|
156
|
+
),
|
157
|
+
)
|
162
158
|
pm.stop()
|
aprsd/cmds/fetch_stats.py
CHANGED
@@ -2,8 +2,8 @@
|
|
2
2
|
import logging
|
3
3
|
|
4
4
|
import click
|
5
|
-
from oslo_config import cfg
|
6
5
|
import requests
|
6
|
+
from oslo_config import cfg
|
7
7
|
from rich.console import Console
|
8
8
|
from rich.table import Table
|
9
9
|
|
@@ -11,32 +11,34 @@ from rich.table import Table
|
|
11
11
|
import aprsd
|
12
12
|
from aprsd import cli_helper
|
13
13
|
from aprsd.main import cli
|
14
|
-
|
14
|
+
from aprsd.threads.stats import StatsStore
|
15
15
|
|
16
16
|
# setup the global logger
|
17
17
|
# log.basicConfig(level=log.DEBUG) # level=10
|
18
|
-
LOG = logging.getLogger(
|
18
|
+
LOG = logging.getLogger('APRSD')
|
19
19
|
CONF = cfg.CONF
|
20
20
|
|
21
21
|
|
22
22
|
@cli.command()
|
23
23
|
@cli_helper.add_options(cli_helper.common_options)
|
24
24
|
@click.option(
|
25
|
-
|
25
|
+
'--host',
|
26
|
+
type=str,
|
26
27
|
default=None,
|
27
|
-
help=
|
28
|
+
help='IP address of the remote aprsd admin web ui fetch stats from.',
|
28
29
|
)
|
29
30
|
@click.option(
|
30
|
-
|
31
|
+
'--port',
|
32
|
+
type=int,
|
31
33
|
default=None,
|
32
|
-
help=
|
34
|
+
help='Port of the remote aprsd web admin interface to fetch stats from.',
|
33
35
|
)
|
34
36
|
@click.pass_context
|
35
37
|
@cli_helper.process_standard_options
|
36
38
|
def fetch_stats(ctx, host, port):
|
37
39
|
"""Fetch stats from a APRSD admin web interface."""
|
38
40
|
console = Console()
|
39
|
-
console.print(f
|
41
|
+
console.print(f'APRSD Fetch-Stats started version: {aprsd.__version__}')
|
40
42
|
|
41
43
|
CONF.log_opt_values(LOG, logging.DEBUG)
|
42
44
|
if not host:
|
@@ -44,113 +46,263 @@ def fetch_stats(ctx, host, port):
|
|
44
46
|
if not port:
|
45
47
|
port = CONF.admin.web_port
|
46
48
|
|
47
|
-
msg = f
|
49
|
+
msg = f'Fetching stats from {host}:{port}'
|
48
50
|
console.print(msg)
|
49
51
|
with console.status(msg):
|
50
|
-
response = requests.get(f
|
52
|
+
response = requests.get(f'http://{host}:{port}/stats', timeout=120)
|
51
53
|
if not response:
|
52
54
|
console.print(
|
53
|
-
f
|
54
|
-
style=
|
55
|
+
f'Failed to fetch stats from {host}:{port}?',
|
56
|
+
style='bold red',
|
55
57
|
)
|
56
58
|
return
|
57
59
|
|
58
60
|
stats = response.json()
|
59
61
|
if not stats:
|
60
62
|
console.print(
|
61
|
-
f
|
62
|
-
style=
|
63
|
+
f'Failed to fetch stats from aprsd admin ui at {host}:{port}',
|
64
|
+
style='bold red',
|
63
65
|
)
|
64
66
|
return
|
65
67
|
|
66
68
|
aprsd_title = (
|
67
|
-
|
68
|
-
f
|
69
|
-
f
|
70
|
-
f
|
69
|
+
'APRSD '
|
70
|
+
f'[bold cyan]v{stats["APRSDStats"]["version"]}[/] '
|
71
|
+
f'Callsign [bold green]{stats["APRSDStats"]["callsign"]}[/] '
|
72
|
+
f'Uptime [bold yellow]{stats["APRSDStats"]["uptime"]}[/]'
|
71
73
|
)
|
72
74
|
|
73
|
-
console.rule(f
|
74
|
-
console.print(
|
75
|
+
console.rule(f'Stats from {host}:{port}')
|
76
|
+
console.print('\n\n')
|
75
77
|
console.rule(aprsd_title)
|
76
78
|
|
77
79
|
# Show the connection to APRS
|
78
80
|
# It can be a connection to an APRS-IS server or a local TNC via KISS or KISSTCP
|
79
|
-
if
|
80
|
-
title = f
|
81
|
+
if 'aprs-is' in stats:
|
82
|
+
title = f'APRS-IS Connection {stats["APRSClientStats"]["server_string"]}'
|
81
83
|
table = Table(title=title)
|
82
|
-
table.add_column(
|
83
|
-
table.add_column(
|
84
|
-
for key, value in stats[
|
84
|
+
table.add_column('Key')
|
85
|
+
table.add_column('Value')
|
86
|
+
for key, value in stats['APRSClientStats'].items():
|
85
87
|
table.add_row(key, value)
|
86
88
|
console.print(table)
|
87
89
|
|
88
|
-
threads_table = Table(title=
|
89
|
-
threads_table.add_column(
|
90
|
-
threads_table.add_column(
|
91
|
-
for name, alive in stats[
|
90
|
+
threads_table = Table(title='Threads')
|
91
|
+
threads_table.add_column('Name')
|
92
|
+
threads_table.add_column('Alive?')
|
93
|
+
for name, alive in stats['APRSDThreadList'].items():
|
92
94
|
threads_table.add_row(name, str(alive))
|
93
95
|
|
94
96
|
console.print(threads_table)
|
95
97
|
|
96
|
-
packet_totals = Table(title=
|
97
|
-
packet_totals.add_column(
|
98
|
-
packet_totals.add_column(
|
99
|
-
packet_totals.add_row(
|
100
|
-
packet_totals.add_row(
|
98
|
+
packet_totals = Table(title='Packet Totals')
|
99
|
+
packet_totals.add_column('Key')
|
100
|
+
packet_totals.add_column('Value')
|
101
|
+
packet_totals.add_row('Total Received', str(stats['PacketList']['rx']))
|
102
|
+
packet_totals.add_row('Total Sent', str(stats['PacketList']['tx']))
|
101
103
|
console.print(packet_totals)
|
102
104
|
|
103
105
|
# Show each of the packet types
|
104
|
-
packets_table = Table(title=
|
105
|
-
packets_table.add_column(
|
106
|
-
packets_table.add_column(
|
107
|
-
packets_table.add_column(
|
108
|
-
for key, value in stats[
|
109
|
-
packets_table.add_row(key, str(value[
|
106
|
+
packets_table = Table(title='Packets By Type')
|
107
|
+
packets_table.add_column('Packet Type')
|
108
|
+
packets_table.add_column('TX')
|
109
|
+
packets_table.add_column('RX')
|
110
|
+
for key, value in stats['PacketList']['packets'].items():
|
111
|
+
packets_table.add_row(key, str(value['tx']), str(value['rx']))
|
110
112
|
|
111
113
|
console.print(packets_table)
|
112
114
|
|
113
|
-
if
|
114
|
-
count = len(stats[
|
115
|
-
plugins_table = Table(title=f
|
116
|
-
plugins_table.add_column(
|
117
|
-
plugins_table.add_column(
|
118
|
-
plugins_table.add_column(
|
119
|
-
plugins_table.add_column(
|
120
|
-
plugins_table.add_column(
|
121
|
-
plugins = stats[
|
122
|
-
for key,
|
115
|
+
if 'plugins' in stats:
|
116
|
+
count = len(stats['PluginManager'])
|
117
|
+
plugins_table = Table(title=f'Plugins ({count})')
|
118
|
+
plugins_table.add_column('Plugin')
|
119
|
+
plugins_table.add_column('Enabled')
|
120
|
+
plugins_table.add_column('Version')
|
121
|
+
plugins_table.add_column('TX')
|
122
|
+
plugins_table.add_column('RX')
|
123
|
+
plugins = stats['PluginManager']
|
124
|
+
for key, _ in plugins.items():
|
123
125
|
plugins_table.add_row(
|
124
126
|
key,
|
125
|
-
str(plugins[key][
|
126
|
-
plugins[key][
|
127
|
-
str(plugins[key][
|
128
|
-
str(plugins[key][
|
127
|
+
str(plugins[key]['enabled']),
|
128
|
+
plugins[key]['version'],
|
129
|
+
str(plugins[key]['tx']),
|
130
|
+
str(plugins[key]['rx']),
|
129
131
|
)
|
130
132
|
|
131
133
|
console.print(plugins_table)
|
132
134
|
|
133
|
-
seen_list
|
134
|
-
|
135
|
-
if seen_list:
|
135
|
+
if seen_list := stats.get('SeenList'):
|
136
136
|
count = len(seen_list)
|
137
|
-
seen_table = Table(title=f
|
138
|
-
seen_table.add_column(
|
139
|
-
seen_table.add_column(
|
140
|
-
seen_table.add_column(
|
137
|
+
seen_table = Table(title=f'Seen List ({count})')
|
138
|
+
seen_table.add_column('Callsign')
|
139
|
+
seen_table.add_column('Message Count')
|
140
|
+
seen_table.add_column('Last Heard')
|
141
141
|
for key, value in seen_list.items():
|
142
|
-
seen_table.add_row(key, str(value[
|
142
|
+
seen_table.add_row(key, str(value['count']), value['last'])
|
143
143
|
|
144
144
|
console.print(seen_table)
|
145
145
|
|
146
|
-
watch_list
|
147
|
-
|
148
|
-
if watch_list:
|
146
|
+
if watch_list := stats.get('WatchList'):
|
149
147
|
count = len(watch_list)
|
150
|
-
watch_table = Table(title=f
|
151
|
-
watch_table.add_column(
|
152
|
-
watch_table.add_column(
|
148
|
+
watch_table = Table(title=f'Watch List ({count})')
|
149
|
+
watch_table.add_column('Callsign')
|
150
|
+
watch_table.add_column('Last Heard')
|
153
151
|
for key, value in watch_list.items():
|
154
|
-
watch_table.add_row(key, value[
|
152
|
+
watch_table.add_row(key, value['last'])
|
155
153
|
|
156
154
|
console.print(watch_table)
|
155
|
+
|
156
|
+
|
157
|
+
@cli.command()
|
158
|
+
@cli_helper.add_options(cli_helper.common_options)
|
159
|
+
@click.option(
|
160
|
+
'--raw',
|
161
|
+
is_flag=True,
|
162
|
+
default=False,
|
163
|
+
help='Dump raw stats instead of formatted output.',
|
164
|
+
)
|
165
|
+
@click.option(
|
166
|
+
'--show-section',
|
167
|
+
default=['All'],
|
168
|
+
help='Show specific sections of the stats. '
|
169
|
+
' Choices: All, APRSDStats, APRSDThreadList, APRSClientStats,'
|
170
|
+
' PacketList, SeenList, WatchList',
|
171
|
+
multiple=True,
|
172
|
+
type=click.Choice(
|
173
|
+
[
|
174
|
+
'All',
|
175
|
+
'APRSDStats',
|
176
|
+
'APRSDThreadList',
|
177
|
+
'APRSClientStats',
|
178
|
+
'PacketList',
|
179
|
+
'SeenList',
|
180
|
+
'WatchList',
|
181
|
+
],
|
182
|
+
case_sensitive=False,
|
183
|
+
),
|
184
|
+
)
|
185
|
+
@click.pass_context
|
186
|
+
@cli_helper.process_standard_options
|
187
|
+
def dump_stats(ctx, raw, show_section):
|
188
|
+
"""Dump the current stats from the running APRSD instance."""
|
189
|
+
console = Console()
|
190
|
+
console.print(f'APRSD Dump-Stats started version: {aprsd.__version__}')
|
191
|
+
|
192
|
+
with console.status('Dumping stats'):
|
193
|
+
ss = StatsStore()
|
194
|
+
ss.load()
|
195
|
+
stats = ss.data
|
196
|
+
if raw:
|
197
|
+
if 'All' in show_section:
|
198
|
+
console.print(stats)
|
199
|
+
return
|
200
|
+
else:
|
201
|
+
for section in show_section:
|
202
|
+
console.print(f'Dumping {section} section:')
|
203
|
+
console.print(stats[section])
|
204
|
+
return
|
205
|
+
|
206
|
+
t = Table(title='APRSD Stats')
|
207
|
+
t.add_column('Key')
|
208
|
+
t.add_column('Value')
|
209
|
+
for key, value in stats['APRSDStats'].items():
|
210
|
+
t.add_row(key, str(value))
|
211
|
+
|
212
|
+
if 'All' in show_section or 'APRSDStats' in show_section:
|
213
|
+
console.print(t)
|
214
|
+
|
215
|
+
# Show the thread list
|
216
|
+
t = Table(title='Thread List')
|
217
|
+
t.add_column('Name')
|
218
|
+
t.add_column('Class')
|
219
|
+
t.add_column('Alive?')
|
220
|
+
t.add_column('Loop Count')
|
221
|
+
t.add_column('Age')
|
222
|
+
for name, value in stats['APRSDThreadList'].items():
|
223
|
+
t.add_row(
|
224
|
+
name,
|
225
|
+
value['class'],
|
226
|
+
str(value['alive']),
|
227
|
+
str(value['loop_count']),
|
228
|
+
str(value['age']),
|
229
|
+
)
|
230
|
+
|
231
|
+
if 'All' in show_section or 'APRSDThreadList' in show_section:
|
232
|
+
console.print(t)
|
233
|
+
|
234
|
+
# Show the plugins
|
235
|
+
t = Table(title='Plugin List')
|
236
|
+
t.add_column('Name')
|
237
|
+
t.add_column('Enabled')
|
238
|
+
t.add_column('Version')
|
239
|
+
t.add_column('TX')
|
240
|
+
t.add_column('RX')
|
241
|
+
for name, value in stats['PluginManager'].items():
|
242
|
+
t.add_row(
|
243
|
+
name,
|
244
|
+
str(value['enabled']),
|
245
|
+
value['version'],
|
246
|
+
str(value['tx']),
|
247
|
+
str(value['rx']),
|
248
|
+
)
|
249
|
+
|
250
|
+
if 'All' in show_section or 'PluginManager' in show_section:
|
251
|
+
console.print(t)
|
252
|
+
|
253
|
+
# Now show the client stats
|
254
|
+
t = Table(title='Client Stats')
|
255
|
+
t.add_column('Key')
|
256
|
+
t.add_column('Value')
|
257
|
+
for key, value in stats['APRSClientStats'].items():
|
258
|
+
t.add_row(key, str(value))
|
259
|
+
|
260
|
+
if 'All' in show_section or 'APRSClientStats' in show_section:
|
261
|
+
console.print(t)
|
262
|
+
|
263
|
+
# now show the packet list
|
264
|
+
packet_list = stats.get('PacketList')
|
265
|
+
t = Table(title='Packet List')
|
266
|
+
t.add_column('Key')
|
267
|
+
t.add_column('Value')
|
268
|
+
t.add_row('Total Received', str(packet_list['rx']))
|
269
|
+
t.add_row('Total Sent', str(packet_list['tx']))
|
270
|
+
|
271
|
+
if 'All' in show_section or 'PacketList' in show_section:
|
272
|
+
console.print(t)
|
273
|
+
|
274
|
+
# now show the seen list
|
275
|
+
seen_list = stats.get('SeenList')
|
276
|
+
sorted_seen_list = sorted(
|
277
|
+
seen_list.items(),
|
278
|
+
)
|
279
|
+
t = Table(title='Seen List')
|
280
|
+
t.add_column('Callsign')
|
281
|
+
t.add_column('Message Count')
|
282
|
+
t.add_column('Last Heard')
|
283
|
+
for key, value in sorted_seen_list:
|
284
|
+
t.add_row(
|
285
|
+
key,
|
286
|
+
str(value['count']),
|
287
|
+
str(value['last']),
|
288
|
+
)
|
289
|
+
|
290
|
+
if 'All' in show_section or 'SeenList' in show_section:
|
291
|
+
console.print(t)
|
292
|
+
|
293
|
+
# now show the watch list
|
294
|
+
watch_list = stats.get('WatchList')
|
295
|
+
sorted_watch_list = sorted(
|
296
|
+
watch_list.items(),
|
297
|
+
)
|
298
|
+
t = Table(title='Watch List')
|
299
|
+
t.add_column('Callsign')
|
300
|
+
t.add_column('Last Heard')
|
301
|
+
for key, value in sorted_watch_list:
|
302
|
+
t.add_row(
|
303
|
+
key,
|
304
|
+
str(value['last']),
|
305
|
+
)
|
306
|
+
|
307
|
+
if 'All' in show_section or 'WatchList' in show_section:
|
308
|
+
console.print(t)
|
aprsd/cmds/healthcheck.py
CHANGED
@@ -13,13 +13,15 @@ from oslo_config import cfg
|
|
13
13
|
from rich.console import Console
|
14
14
|
|
15
15
|
import aprsd
|
16
|
-
from aprsd import
|
17
|
-
|
16
|
+
from aprsd import ( # noqa: F401
|
17
|
+
cli_helper,
|
18
|
+
conf,
|
19
|
+
)
|
20
|
+
|
18
21
|
# local imports here
|
19
22
|
from aprsd.main import cli
|
20
23
|
from aprsd.threads import stats as stats_threads
|
21
24
|
|
22
|
-
|
23
25
|
# setup the global logger
|
24
26
|
# log.basicConfig(level=log.DEBUG) # level=10
|
25
27
|
CONF = cfg.CONF
|
@@ -63,7 +65,7 @@ def healthcheck(ctx, timeout):
|
|
63
65
|
|
64
66
|
if email_thread_last_update != "never":
|
65
67
|
d = now - email_thread_last_update
|
66
|
-
max_timeout = {"hours": 0.0, "minutes": 5, "seconds":
|
68
|
+
max_timeout = {"hours": 0.0, "minutes": 5, "seconds": 30}
|
67
69
|
max_delta = datetime.timedelta(**max_timeout)
|
68
70
|
if d > max_delta:
|
69
71
|
console.log(f"Email thread is very old! {d}")
|
@@ -74,7 +76,7 @@ def healthcheck(ctx, timeout):
|
|
74
76
|
console.log("No APRSClientStats")
|
75
77
|
sys.exit(-1)
|
76
78
|
else:
|
77
|
-
aprsis_last_update = client_stats["
|
79
|
+
aprsis_last_update = client_stats["connection_keepalive"]
|
78
80
|
d = now - aprsis_last_update
|
79
81
|
max_timeout = {"hours": 0.0, "minutes": 5, "seconds": 0}
|
80
82
|
max_delta = datetime.timedelta(**max_timeout)
|