command_watcher 0.6.0__tar.gz → 0.7.0__tar.gz
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.
- {command_watcher-0.6.0 → command_watcher-0.7.0}/PKG-INFO +5 -1
- {command_watcher-0.6.0 → command_watcher-0.7.0}/README.rst +4 -0
- command_watcher-0.7.0/pyproject.toml +51 -0
- command_watcher-0.6.0/pyproject.toml → command_watcher-0.7.0/pyproject.toml.orig +3 -2
- {command_watcher-0.6.0 → command_watcher-0.7.0}/src/command_watcher/__init__.py +20 -25
- {command_watcher-0.6.0 → command_watcher-0.7.0}/src/command_watcher/channels/beep.py +4 -3
- {command_watcher-0.6.0 → command_watcher-0.7.0}/src/command_watcher/channels/icinga.py +8 -10
- {command_watcher-0.6.0 → command_watcher-0.7.0}/src/command_watcher/config.py +5 -6
- {command_watcher-0.6.0 → command_watcher-0.7.0}/src/command_watcher/log.py +7 -9
- {command_watcher-0.6.0 → command_watcher-0.7.0}/src/command_watcher/message.py +16 -16
- {command_watcher-0.6.0 → command_watcher-0.7.0}/src/command_watcher/report.py +2 -4
- {command_watcher-0.6.0 → command_watcher-0.7.0}/src/command_watcher/channels/base_channel.py +0 -0
- {command_watcher-0.6.0 → command_watcher-0.7.0}/src/command_watcher/channels/email.py +0 -0
- {command_watcher-0.6.0 → command_watcher-0.7.0}/src/command_watcher/py.typed +0 -0
- {command_watcher-0.6.0 → command_watcher-0.7.0}/src/command_watcher/utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: command_watcher
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.7.0
|
|
4
4
|
Summary: Module to watch the execution of shell scripts. Both streams (`stdout` and `stderr`) are captured.
|
|
5
5
|
Author: Josef Friedrich
|
|
6
6
|
Author-email: Josef Friedrich <josef@friedrich.rocks>
|
|
@@ -37,6 +37,10 @@ command_watcher
|
|
|
37
37
|
Module to watch the execution of shell scripts. Both streams (`stdout`
|
|
38
38
|
and `stderr`) are captured.
|
|
39
39
|
|
|
40
|
+
The watcher's loggers print each message once and do not propagate it to
|
|
41
|
+
Python's root logger. Command output is also stored on the command executor
|
|
42
|
+
and, unless ``log=False`` is passed to ``watch.run()``, on the watcher.
|
|
43
|
+
|
|
40
44
|
.. code:: python
|
|
41
45
|
|
|
42
46
|
watch = Watch()
|
|
@@ -12,6 +12,10 @@ command_watcher
|
|
|
12
12
|
Module to watch the execution of shell scripts. Both streams (`stdout`
|
|
13
13
|
and `stderr`) are captured.
|
|
14
14
|
|
|
15
|
+
The watcher's loggers print each message once and do not propagate it to
|
|
16
|
+
Python's root logger. Command output is also stored on the command executor
|
|
17
|
+
and, unless ``log=False`` is passed to ``watch.run()``, on the watcher.
|
|
18
|
+
|
|
15
19
|
.. code:: python
|
|
16
20
|
|
|
17
21
|
watch = Watch()
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "command_watcher"
|
|
3
|
+
version = "0.7.0"
|
|
4
|
+
description = "Module to watch the execution of shell scripts. Both streams (`stdout` and `stderr`) are captured."
|
|
5
|
+
requires-python = ">=3.12,<4"
|
|
6
|
+
readme = "README.rst"
|
|
7
|
+
license = "MIT"
|
|
8
|
+
classifiers = [
|
|
9
|
+
"Development Status :: 5 - Production/Stable",
|
|
10
|
+
"License :: OSI Approved :: MIT License",
|
|
11
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
12
|
+
"Programming Language :: Python :: 3",
|
|
13
|
+
"Programming Language :: Python :: 3.12",
|
|
14
|
+
"Programming Language :: Python :: 3.13",
|
|
15
|
+
"Programming Language :: Python :: 3.14",
|
|
16
|
+
]
|
|
17
|
+
dependencies = [
|
|
18
|
+
"pretiac>=0.6.0",
|
|
19
|
+
"pydantic>=2.12.5",
|
|
20
|
+
"pyyaml>=6.0.3",
|
|
21
|
+
"termcolor>=3.3.0",
|
|
22
|
+
"types-pyyaml>=6.0.12.20250915",
|
|
23
|
+
"types-requests>=2.32.4.20260107",
|
|
24
|
+
"types-termcolor>=1.1.6.2",
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
[[project.authors]]
|
|
28
|
+
name = "Josef Friedrich"
|
|
29
|
+
email = "josef@friedrich.rocks"
|
|
30
|
+
|
|
31
|
+
[project.urls]
|
|
32
|
+
Repository = "https://github.com/Josef-Friedrich/command-watcher"
|
|
33
|
+
|
|
34
|
+
[dependency-groups]
|
|
35
|
+
dev = [
|
|
36
|
+
"mypy>=1.0",
|
|
37
|
+
"pytest>=9.0.2",
|
|
38
|
+
"stdout-stderr-capturing>=0.2.1",
|
|
39
|
+
]
|
|
40
|
+
|
|
41
|
+
[tool.uv.sources.pretiac]
|
|
42
|
+
git = "https://github.com/Josef-Friedrich/PREtty-Typed-Icinga2-Api-Client_py.git"
|
|
43
|
+
|
|
44
|
+
[tool.pytest.ini_options]
|
|
45
|
+
verbosity_assertions = 2
|
|
46
|
+
truncation_limit_lines = 999999
|
|
47
|
+
truncation_limit_chars = 999999
|
|
48
|
+
|
|
49
|
+
[build-system]
|
|
50
|
+
requires = ["uv_build>=0.13.7,<0.14.0"]
|
|
51
|
+
build-backend = "uv_build"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "command_watcher"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.7.0"
|
|
4
4
|
description = "Module to watch the execution of shell scripts. Both streams (`stdout` and `stderr`) are captured."
|
|
5
5
|
authors = [{ name = "Josef Friedrich", email = "josef@friedrich.rocks" }]
|
|
6
6
|
requires-python = ">=3.12,<4"
|
|
@@ -30,6 +30,7 @@ Repository = "https://github.com/Josef-Friedrich/command-watcher"
|
|
|
30
30
|
|
|
31
31
|
[dependency-groups]
|
|
32
32
|
dev = [
|
|
33
|
+
"mypy>=1.0",
|
|
33
34
|
"pytest>=9.0.2",
|
|
34
35
|
"stdout-stderr-capturing>=0.2.1",
|
|
35
36
|
]
|
|
@@ -40,7 +41,7 @@ dev = [
|
|
|
40
41
|
pretiac = { git = "https://github.com/Josef-Friedrich/PREtty-Typed-Icinga2-Api-Client_py.git" }
|
|
41
42
|
|
|
42
43
|
[build-system]
|
|
43
|
-
requires = ["uv_build>=0.
|
|
44
|
+
requires = ["uv_build>=0.13.7,<0.14.0"]
|
|
44
45
|
build-backend = "uv_build"
|
|
45
46
|
|
|
46
47
|
[tool.pytest.ini_options]
|
|
@@ -17,14 +17,10 @@ from typing import (
|
|
|
17
17
|
IO,
|
|
18
18
|
Any,
|
|
19
19
|
Literal,
|
|
20
|
-
Optional,
|
|
21
|
-
Tuple,
|
|
22
20
|
TypedDict,
|
|
23
|
-
|
|
21
|
+
Unpack,
|
|
24
22
|
)
|
|
25
23
|
|
|
26
|
-
from typing_extensions import Unpack
|
|
27
|
-
|
|
28
24
|
from command_watcher.channels.base_channel import BaseChannel
|
|
29
25
|
from command_watcher.channels.beep import BeepChannel
|
|
30
26
|
from command_watcher.channels.email import EmailChannel
|
|
@@ -64,10 +60,10 @@ class Timer:
|
|
|
64
60
|
"""Measure the execution time of a command run."""
|
|
65
61
|
|
|
66
62
|
stop: float
|
|
67
|
-
"""
|
|
63
|
+
"""The time when the timer stops. (UNIX timestamp)"""
|
|
68
64
|
|
|
69
65
|
start: float
|
|
70
|
-
"""
|
|
66
|
+
"""The start time. (UNIX timestamp)"""
|
|
71
67
|
|
|
72
68
|
interval: float
|
|
73
69
|
"""The time interval between start and stop."""
|
|
@@ -84,15 +80,15 @@ class Timer:
|
|
|
84
80
|
:return: A formatted string displaying the result."""
|
|
85
81
|
self.stop = time.time()
|
|
86
82
|
self.interval = self.stop - self.start
|
|
87
|
-
return "{:.3f}s"
|
|
83
|
+
return f"{self.interval:.3f}s"
|
|
88
84
|
|
|
89
85
|
|
|
90
86
|
# Main code ###################################################################
|
|
91
87
|
|
|
92
|
-
Arg =
|
|
88
|
+
Arg = str | Path
|
|
93
89
|
"""Command line argument"""
|
|
94
90
|
|
|
95
|
-
Args =
|
|
91
|
+
Args = Arg | list[Arg] | tuple[Arg]
|
|
96
92
|
"""Command line arguments"""
|
|
97
93
|
|
|
98
94
|
|
|
@@ -123,7 +119,7 @@ class CommandExecutor:
|
|
|
123
119
|
args: Args
|
|
124
120
|
"""Process arguments in various types."""
|
|
125
121
|
|
|
126
|
-
_queue:
|
|
122
|
+
_queue: queue.Queue[tuple[bytes, Stream] | None]
|
|
127
123
|
|
|
128
124
|
log: ExtendedLogger
|
|
129
125
|
"""A ready to go and configured logger."""
|
|
@@ -135,7 +131,7 @@ class CommandExecutor:
|
|
|
135
131
|
def __init__(
|
|
136
132
|
self,
|
|
137
133
|
args: Args,
|
|
138
|
-
master_logger:
|
|
134
|
+
master_logger: ExtendedLogger | None = None,
|
|
139
135
|
**kwargs: Unpack[ProcessArgs],
|
|
140
136
|
) -> None:
|
|
141
137
|
# self.args: typing.Union[str, list, tuple] = args
|
|
@@ -217,12 +213,10 @@ class CommandExecutor:
|
|
|
217
213
|
with pipe:
|
|
218
214
|
for line in iter(pipe.readline, b""):
|
|
219
215
|
self._queue.put((line, stream))
|
|
220
|
-
except Exception:
|
|
221
|
-
pass
|
|
222
216
|
finally:
|
|
223
217
|
self._queue.put(None)
|
|
224
218
|
|
|
225
|
-
def _start_thread(self, pipe:
|
|
219
|
+
def _start_thread(self, pipe: IO[bytes] | None, stream: Stream) -> None:
|
|
226
220
|
"""
|
|
227
221
|
:param object pipe: ``process.stdout`` or ``process.stdout``
|
|
228
222
|
"""
|
|
@@ -249,7 +243,7 @@ class Watch:
|
|
|
249
243
|
_service_name: str
|
|
250
244
|
"""A name of the watched service."""
|
|
251
245
|
|
|
252
|
-
_service_display_name:
|
|
246
|
+
_service_display_name: str | None
|
|
253
247
|
"""A human readable form of the *service name*."""
|
|
254
248
|
|
|
255
249
|
log: ExtendedLogger
|
|
@@ -262,7 +256,7 @@ class Watch:
|
|
|
262
256
|
:py:class:`Process`. Everytime you use the method
|
|
263
257
|
`run()` the process object is appened in the list."""
|
|
264
258
|
|
|
265
|
-
_config:
|
|
259
|
+
_config: Config | None
|
|
266
260
|
|
|
267
261
|
_raise_exceptions: bool
|
|
268
262
|
"""Raise exceptions"""
|
|
@@ -271,12 +265,12 @@ class Watch:
|
|
|
271
265
|
|
|
272
266
|
def __init__(
|
|
273
267
|
self,
|
|
274
|
-
config_file:
|
|
268
|
+
config_file: str | Path | None = None,
|
|
275
269
|
service_name: str = "command_watcher",
|
|
276
|
-
service_display_name:
|
|
270
|
+
service_display_name: str | None = None,
|
|
277
271
|
raise_exceptions: bool = True,
|
|
278
|
-
config:
|
|
279
|
-
report_channels:
|
|
272
|
+
config: Config | None = None,
|
|
273
|
+
report_channels: list[BaseChannel] | None = None,
|
|
280
274
|
) -> None:
|
|
281
275
|
self._hostname = HOSTNAME
|
|
282
276
|
|
|
@@ -330,7 +324,7 @@ class Watch:
|
|
|
330
324
|
self.log.debug(beep_reporter)
|
|
331
325
|
|
|
332
326
|
else:
|
|
333
|
-
reporter.channels =
|
|
327
|
+
reporter.channels = list(report_channels)
|
|
334
328
|
|
|
335
329
|
self.processes = []
|
|
336
330
|
|
|
@@ -352,7 +346,7 @@ class Watch:
|
|
|
352
346
|
self,
|
|
353
347
|
args: Args,
|
|
354
348
|
log: bool = True,
|
|
355
|
-
ignore_exceptions: list[int] =
|
|
349
|
+
ignore_exceptions: list[int] | None = None,
|
|
356
350
|
**kwargs: Unpack[ProcessArgs],
|
|
357
351
|
) -> CommandExecutor:
|
|
358
352
|
"""
|
|
@@ -366,6 +360,8 @@ class Watch:
|
|
|
366
360
|
:param ignore_exceptions: A list of none-zero exit codes, which is
|
|
367
361
|
ignored by this method.
|
|
368
362
|
"""
|
|
363
|
+
if ignore_exceptions is None:
|
|
364
|
+
ignore_exceptions = []
|
|
369
365
|
if log:
|
|
370
366
|
master_logger = self.log
|
|
371
367
|
else:
|
|
@@ -406,6 +402,5 @@ class Watch:
|
|
|
406
402
|
if "performance_data" not in data_dict:
|
|
407
403
|
data_dict["performance_data"] = {}
|
|
408
404
|
data_dict["performance_data"]["execution_time"] = timer_result
|
|
409
|
-
|
|
410
|
-
del data_dict["status"]
|
|
405
|
+
data_dict.pop("status", None)
|
|
411
406
|
return self.report(status=status, **data_dict)
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import shutil
|
|
2
2
|
import subprocess
|
|
3
|
-
from typing import Union
|
|
4
3
|
|
|
5
4
|
from command_watcher.channels.base_channel import BaseChannel
|
|
6
5
|
from command_watcher.message import Message
|
|
@@ -9,7 +8,7 @@ from command_watcher.message import Message
|
|
|
9
8
|
class BeepChannel(BaseChannel):
|
|
10
9
|
"""Send beep sounds."""
|
|
11
10
|
|
|
12
|
-
cmd:
|
|
11
|
+
cmd: str | None
|
|
13
12
|
|
|
14
13
|
def __init__(self) -> None:
|
|
15
14
|
self.cmd = shutil.which("beep")
|
|
@@ -29,7 +28,9 @@ class BeepChannel(BaseChannel):
|
|
|
29
28
|
:param length: Length in milliseconds.
|
|
30
29
|
"""
|
|
31
30
|
# TODO: Use self.cmd -> Fix tests
|
|
32
|
-
subprocess.run(
|
|
31
|
+
subprocess.run(
|
|
32
|
+
["beep", "-f", str(float(frequency)), "-l", str(float(length))], check=False
|
|
33
|
+
)
|
|
33
34
|
|
|
34
35
|
def report(self, message: Message) -> None:
|
|
35
36
|
"""Send a beep sounds.
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
from typing import Optional
|
|
2
|
-
|
|
3
1
|
from pretiac.client import Client
|
|
4
2
|
from pretiac.config import Config
|
|
5
3
|
|
|
@@ -11,22 +9,22 @@ from command_watcher.utils import HOSTNAME
|
|
|
11
9
|
class IcingaChannel(BaseChannel):
|
|
12
10
|
service_name: str
|
|
13
11
|
|
|
14
|
-
service_display_name:
|
|
12
|
+
service_display_name: str | None
|
|
15
13
|
|
|
16
14
|
__client: Client
|
|
17
15
|
|
|
18
|
-
api_endpoint_host:
|
|
19
|
-
api_endpoint_port:
|
|
20
|
-
http_basic_username:
|
|
21
|
-
client_certificate:
|
|
22
|
-
client_private_key:
|
|
23
|
-
ca_certificate:
|
|
16
|
+
api_endpoint_host: str | None
|
|
17
|
+
api_endpoint_port: int | None
|
|
18
|
+
http_basic_username: str | None
|
|
19
|
+
client_certificate: str | None
|
|
20
|
+
client_private_key: str | None
|
|
21
|
+
ca_certificate: str | None
|
|
24
22
|
|
|
25
23
|
def __init__(
|
|
26
24
|
self,
|
|
27
25
|
service_name: str,
|
|
28
26
|
config: Config,
|
|
29
|
-
service_display_name:
|
|
27
|
+
service_display_name: str | None = None,
|
|
30
28
|
) -> None:
|
|
31
29
|
self.service_name = service_name
|
|
32
30
|
self.service_display_name = service_display_name
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
from pathlib import Path
|
|
2
|
-
from typing import Optional, Union
|
|
3
2
|
|
|
4
3
|
import yaml
|
|
5
4
|
from pretiac.config import Config as IcingaConfig
|
|
@@ -36,17 +35,17 @@ class BeepConfig:
|
|
|
36
35
|
|
|
37
36
|
@dataclass
|
|
38
37
|
class Config:
|
|
39
|
-
email:
|
|
38
|
+
email: EmailConfig | None = None
|
|
40
39
|
|
|
41
|
-
icinga:
|
|
40
|
+
icinga: IcingaConfig | None = None
|
|
42
41
|
|
|
43
|
-
beep:
|
|
42
|
+
beep: BeepConfig | None = None
|
|
44
43
|
|
|
45
44
|
|
|
46
|
-
_config:
|
|
45
|
+
_config: Config | None = None
|
|
47
46
|
|
|
48
47
|
|
|
49
|
-
def load_config(config_file:
|
|
48
|
+
def load_config(config_file: str | Path | None = None) -> Config:
|
|
50
49
|
if config_file is None:
|
|
51
50
|
config_file = "/etc/command-watcher.yml"
|
|
52
51
|
global _config
|
|
@@ -3,7 +3,7 @@ import sys
|
|
|
3
3
|
import time
|
|
4
4
|
import uuid
|
|
5
5
|
from logging.handlers import BufferingHandler
|
|
6
|
-
from typing import Any,
|
|
6
|
+
from typing import Any, cast
|
|
7
7
|
|
|
8
8
|
import termcolor
|
|
9
9
|
|
|
@@ -29,9 +29,9 @@ DATEFMT = "%Y%m%d_%H%M%S"
|
|
|
29
29
|
class LoggingHandler(BufferingHandler):
|
|
30
30
|
"""Store of all logging records in the memory. Print all records on emit."""
|
|
31
31
|
|
|
32
|
-
_master_logger:
|
|
32
|
+
_master_logger: logging.Logger | None
|
|
33
33
|
|
|
34
|
-
def __init__(self, master_logger:
|
|
34
|
+
def __init__(self, master_logger: logging.Logger | None = None):
|
|
35
35
|
BufferingHandler.__init__(self, capacity=1000000)
|
|
36
36
|
self._master_logger = master_logger
|
|
37
37
|
|
|
@@ -84,15 +84,12 @@ class LoggingHandler(BufferingHandler):
|
|
|
84
84
|
else:
|
|
85
85
|
stream = sys.stdout
|
|
86
86
|
|
|
87
|
-
created = "{}_{:03d}"
|
|
88
|
-
time.strftime(DATEFMT, time.localtime(record.created)),
|
|
89
|
-
int(record.msecs),
|
|
90
|
-
)
|
|
87
|
+
created = f"{time.strftime(DATEFMT, time.localtime(record.created))}_{int(record.msecs):03d}"
|
|
91
88
|
|
|
92
89
|
print(
|
|
93
90
|
"{} {} {}".format(
|
|
94
91
|
created,
|
|
95
|
-
termcolor.colored(" {:<8} "
|
|
92
|
+
termcolor.colored(f" {level:<8} ", color, attrs=reverse),
|
|
96
93
|
termcolor.colored(record.msg, color, attrs=normal),
|
|
97
94
|
),
|
|
98
95
|
file=stream,
|
|
@@ -161,7 +158,7 @@ logging.Logger.stderr = _log_stderr # type: ignore
|
|
|
161
158
|
|
|
162
159
|
|
|
163
160
|
def setup_logging(
|
|
164
|
-
master_logger:
|
|
161
|
+
master_logger: logging.Logger | None = None,
|
|
165
162
|
) -> tuple[ExtendedLogger, LoggingHandler]:
|
|
166
163
|
"""Setup a fresh logger for each watch action.
|
|
167
164
|
|
|
@@ -178,4 +175,5 @@ def setup_logging(
|
|
|
178
175
|
# the root logger is created with level WARNING.
|
|
179
176
|
logger.setLevel(1)
|
|
180
177
|
logger.addHandler(handler)
|
|
178
|
+
logger.propagate = False
|
|
181
179
|
return (cast(ExtendedLogger, logger), handler)
|
|
@@ -2,9 +2,7 @@ import os
|
|
|
2
2
|
import pwd
|
|
3
3
|
import socket
|
|
4
4
|
import textwrap
|
|
5
|
-
from typing import TYPE_CHECKING, Any,
|
|
6
|
-
|
|
7
|
-
from typing_extensions import Unpack
|
|
5
|
+
from typing import TYPE_CHECKING, Any, Literal, TypedDict, Unpack
|
|
8
6
|
|
|
9
7
|
if TYPE_CHECKING:
|
|
10
8
|
from . import CommandExecutor
|
|
@@ -25,7 +23,7 @@ class MinimalMessageParams(TypedDict, total=False):
|
|
|
25
23
|
body: str
|
|
26
24
|
""" A longer report text."""
|
|
27
25
|
|
|
28
|
-
performance_data:
|
|
26
|
+
performance_data: dict[str, Any]
|
|
29
27
|
""" A dictionary like
|
|
30
28
|
`{'perf_1': 1, 'perf_2': 'test'}`"""
|
|
31
29
|
|
|
@@ -44,14 +42,16 @@ class MessageParams(MinimalMessageParams, total=False):
|
|
|
44
42
|
log_records: str
|
|
45
43
|
"""Log records separated by new lines"""
|
|
46
44
|
|
|
47
|
-
processes:
|
|
45
|
+
processes: list["CommandExecutor"]
|
|
48
46
|
|
|
49
47
|
|
|
50
48
|
class BaseClass:
|
|
51
|
-
def _obj_to_str(self, attributes:
|
|
49
|
+
def _obj_to_str(self, attributes: list[str] | None = None) -> str:
|
|
50
|
+
if attributes is None:
|
|
51
|
+
attributes = []
|
|
52
52
|
if not attributes:
|
|
53
53
|
attributes = dir(self)
|
|
54
|
-
output:
|
|
54
|
+
output: list[str] = []
|
|
55
55
|
for attribute in attributes:
|
|
56
56
|
if not attribute.startswith("_") and not callable(getattr(self, attribute)):
|
|
57
57
|
value = getattr(self, attribute)
|
|
@@ -109,11 +109,11 @@ class Message(BaseClass):
|
|
|
109
109
|
"""
|
|
110
110
|
performance_data = self._data.get("performance_data")
|
|
111
111
|
if performance_data:
|
|
112
|
-
pairs:
|
|
112
|
+
pairs: list[str] = []
|
|
113
113
|
key: str
|
|
114
114
|
value: Any
|
|
115
115
|
for key, value in performance_data.items():
|
|
116
|
-
pairs.append("{!s}={!s}"
|
|
116
|
+
pairs.append(f"{key!s}={value!s}")
|
|
117
117
|
return " ".join(pairs)
|
|
118
118
|
return ""
|
|
119
119
|
|
|
@@ -135,7 +135,7 @@ class Message(BaseClass):
|
|
|
135
135
|
output.append(self.service_name.upper())
|
|
136
136
|
output.append(self.status_text)
|
|
137
137
|
if self.custom_message:
|
|
138
|
-
output.append("- {
|
|
138
|
+
output.append(f"- {self.custom_message}")
|
|
139
139
|
return " ".join(output)
|
|
140
140
|
|
|
141
141
|
@property
|
|
@@ -146,13 +146,13 @@ class Message(BaseClass):
|
|
|
146
146
|
output.append(self.service_name.upper())
|
|
147
147
|
output.append(self.status_text)
|
|
148
148
|
if self.custom_message:
|
|
149
|
-
output.append("- {
|
|
149
|
+
output.append(f"- {self.custom_message}")
|
|
150
150
|
return " ".join(output)
|
|
151
151
|
|
|
152
152
|
@property
|
|
153
153
|
def message_monitoring(self) -> str:
|
|
154
154
|
"""plugin_output + performance_data"""
|
|
155
|
-
output:
|
|
155
|
+
output: list[str] = []
|
|
156
156
|
output.append(self.plugin_output)
|
|
157
157
|
if self.performance_data:
|
|
158
158
|
output.append("|")
|
|
@@ -162,7 +162,7 @@ class Message(BaseClass):
|
|
|
162
162
|
@property
|
|
163
163
|
def body(self) -> str:
|
|
164
164
|
"""Text body for the e-mail message."""
|
|
165
|
-
output:
|
|
165
|
+
output: list[str] = []
|
|
166
166
|
output.append(f"Host: {HOSTNAME}")
|
|
167
167
|
output.append(f"User: {USERNAME}")
|
|
168
168
|
output.append(f"Service name: {self.service_name}")
|
|
@@ -185,8 +185,8 @@ class Message(BaseClass):
|
|
|
185
185
|
return "\n".join(output)
|
|
186
186
|
|
|
187
187
|
@property
|
|
188
|
-
def processes(self) ->
|
|
189
|
-
output:
|
|
188
|
+
def processes(self) -> str | None:
|
|
189
|
+
output: list[str] = []
|
|
190
190
|
processes = self._data.get("processes")
|
|
191
191
|
if processes:
|
|
192
192
|
for process in processes:
|
|
@@ -197,4 +197,4 @@ class Message(BaseClass):
|
|
|
197
197
|
|
|
198
198
|
@property
|
|
199
199
|
def user(self) -> str:
|
|
200
|
-
return "[user:{}]"
|
|
200
|
+
return f"[user:{USERNAME}]"
|
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
from typing import
|
|
2
|
-
|
|
3
|
-
from typing_extensions import Unpack
|
|
1
|
+
from typing import Literal, Unpack
|
|
4
2
|
|
|
5
3
|
from command_watcher.channels.base_channel import BaseChannel
|
|
6
4
|
from command_watcher.message import Message, MessageParams
|
|
@@ -11,7 +9,7 @@ Status = Literal[0, 1, 2, 3]
|
|
|
11
9
|
class Reporter:
|
|
12
10
|
"""Collect all channels."""
|
|
13
11
|
|
|
14
|
-
channels:
|
|
12
|
+
channels: list[BaseChannel]
|
|
15
13
|
|
|
16
14
|
def __init__(self) -> None:
|
|
17
15
|
self.channels = []
|
{command_watcher-0.6.0 → command_watcher-0.7.0}/src/command_watcher/channels/base_channel.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|