omdnotificationforwarder 4.0__tar.gz → 4.2__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.
Files changed (63) hide show
  1. {omdnotificationforwarder-4.0 → omdnotificationforwarder-4.2}/.gitignore +2 -0
  2. {omdnotificationforwarder-4.0 → omdnotificationforwarder-4.2}/PKG-INFO +89 -3
  3. {omdnotificationforwarder-4.0 → omdnotificationforwarder-4.2}/README.md +86 -2
  4. {omdnotificationforwarder-4.0 → omdnotificationforwarder-4.2}/bin/notificationforwarder +1 -1
  5. {omdnotificationforwarder-4.0 → omdnotificationforwarder-4.2}/pyproject.toml +4 -1
  6. {omdnotificationforwarder-4.0 → omdnotificationforwarder-4.2}/src/notificationforwarder/baseclass.py +160 -203
  7. omdnotificationforwarder-4.2/src/notificationforwarder/component_loader.py +117 -0
  8. omdnotificationforwarder-4.2/src/notificationforwarder/nostr/__init__.py +1 -0
  9. omdnotificationforwarder-4.2/src/notificationforwarder/nostr/formatter.py +66 -0
  10. omdnotificationforwarder-4.2/src/notificationforwarder/nostr/forwarder.py +141 -0
  11. omdnotificationforwarder-4.2/src/notificationforwarder/oauth2webhook/__init__.py +0 -0
  12. omdnotificationforwarder-4.2/src/notificationforwarder/oauth2webhook/forwarder.py +98 -0
  13. omdnotificationforwarder-4.2/src/notificationforwarder/runtime_config.py +110 -0
  14. omdnotificationforwarder-4.2/src/notificationforwarder/runtime_flow.py +48 -0
  15. omdnotificationforwarder-4.2/src/notificationforwarder/spool.py +83 -0
  16. {omdnotificationforwarder-4.0 → omdnotificationforwarder-4.2}/src/notificationforwarder/text/logger.py +23 -0
  17. omdnotificationforwarder-4.2/tests/test_builtin_plugins_focus.py +279 -0
  18. omdnotificationforwarder-4.2/tests/test_delivery_resilience.py +150 -0
  19. omdnotificationforwarder-4.2/tests/test_nostr.py +261 -0
  20. omdnotificationforwarder-4.2/tests/test_oauth2webhook.py +206 -0
  21. {omdnotificationforwarder-4.0 → omdnotificationforwarder-4.2}/tests/test_reporter.py +8 -3
  22. omdnotificationforwarder-4.2/tests/test_runtime_foundation.py +142 -0
  23. {omdnotificationforwarder-4.0 → omdnotificationforwarder-4.2}/src/notificationforwarder/email/formatter.py +0 -0
  24. {omdnotificationforwarder-4.0 → omdnotificationforwarder-4.2}/src/notificationforwarder/email/forwarder.py +0 -0
  25. {omdnotificationforwarder-4.0 → omdnotificationforwarder-4.2}/src/notificationforwarder/example/formatter.py +0 -0
  26. {omdnotificationforwarder-4.0 → omdnotificationforwarder-4.2}/src/notificationforwarder/example/forwarder.py +0 -0
  27. {omdnotificationforwarder-4.0 → omdnotificationforwarder-4.2}/src/notificationforwarder/json/__init__.py +0 -0
  28. {omdnotificationforwarder-4.0 → omdnotificationforwarder-4.2}/src/notificationforwarder/json/logger.py +0 -0
  29. {omdnotificationforwarder-4.0 → omdnotificationforwarder-4.2}/src/notificationforwarder/naemonlog/reporter.py +0 -0
  30. {omdnotificationforwarder-4.0 → omdnotificationforwarder-4.2}/src/notificationforwarder/rabbitmq/formatter.py +0 -0
  31. {omdnotificationforwarder-4.0 → omdnotificationforwarder-4.2}/src/notificationforwarder/rabbitmq/forwarder.py +0 -0
  32. {omdnotificationforwarder-4.0 → omdnotificationforwarder-4.2}/src/notificationforwarder/syslog/formatter.py +0 -0
  33. {omdnotificationforwarder-4.0 → omdnotificationforwarder-4.2}/src/notificationforwarder/syslog/forwarder.py +0 -0
  34. {omdnotificationforwarder-4.0 → omdnotificationforwarder-4.2}/src/notificationforwarder/telegram/forwarder.py +0 -0
  35. {omdnotificationforwarder-4.0 → omdnotificationforwarder-4.2}/src/notificationforwarder/text/__init__.py +0 -0
  36. {omdnotificationforwarder-4.0 → omdnotificationforwarder-4.2}/src/notificationforwarder/webhook/forwarder.py +0 -0
  37. {omdnotificationforwarder-4.0 → omdnotificationforwarder-4.2}/tests/pythonpath/lib/python/notificationforwarder/split1/forwarder.py +0 -0
  38. {omdnotificationforwarder-4.0 → omdnotificationforwarder-4.2}/tests/pythonpath/lib/python/notificationforwarder/split2/formatter.py +0 -0
  39. {omdnotificationforwarder-4.0 → omdnotificationforwarder-4.2}/tests/pythonpath/lib/python/notificationforwarder/split2/forwarder.py +0 -0
  40. {omdnotificationforwarder-4.0 → omdnotificationforwarder-4.2}/tests/pythonpath/lib/python/notificationforwarder/split3/formatter.py +0 -0
  41. {omdnotificationforwarder-4.0 → omdnotificationforwarder-4.2}/tests/pythonpath/lib/python/notificationforwarder/split3/forwarder.py +0 -0
  42. {omdnotificationforwarder-4.0 → omdnotificationforwarder-4.2}/tests/pythonpath/local/lib/python/notificationforwarder/alertmanager_servicenow/formatter.py +0 -0
  43. {omdnotificationforwarder-4.0 → omdnotificationforwarder-4.2}/tests/pythonpath/local/lib/python/notificationforwarder/bayern/formatter.py +0 -0
  44. {omdnotificationforwarder-4.0 → omdnotificationforwarder-4.2}/tests/pythonpath/local/lib/python/notificationforwarder/datadup/formatter.py +0 -0
  45. {omdnotificationforwarder-4.0 → omdnotificationforwarder-4.2}/tests/pythonpath/local/lib/python/notificationforwarder/datapost/formatter.py +0 -0
  46. {omdnotificationforwarder-4.0 → omdnotificationforwarder-4.2}/tests/pythonpath/local/lib/python/notificationforwarder/discard/formatter.py +0 -0
  47. {omdnotificationforwarder-4.0 → omdnotificationforwarder-4.2}/tests/pythonpath/local/lib/python/notificationforwarder/split1/formatter.py +0 -0
  48. {omdnotificationforwarder-4.0 → omdnotificationforwarder-4.2}/tests/pythonpath/local/lib/python/notificationforwarder/split2/forwarder.py +0 -0
  49. {omdnotificationforwarder-4.0 → omdnotificationforwarder-4.2}/tests/pythonpath/local/lib/python/notificationforwarder/split3/formatter.py +0 -0
  50. {omdnotificationforwarder-4.0 → omdnotificationforwarder-4.2}/tests/pythonpath/local/lib/python/notificationforwarder/split3/forwarder.py +0 -0
  51. {omdnotificationforwarder-4.0 → omdnotificationforwarder-4.2}/tests/pythonpath/local/lib/python/notificationforwarder/split4/formatter.py +0 -0
  52. {omdnotificationforwarder-4.0 → omdnotificationforwarder-4.2}/tests/pythonpath/local/lib/python/notificationforwarder/split4/forwarder.py +0 -0
  53. {omdnotificationforwarder-4.0 → omdnotificationforwarder-4.2}/tests/pythonpath/local/lib/python/notificationforwarder/ticketsystem/forwarder.py +0 -0
  54. {omdnotificationforwarder-4.0 → omdnotificationforwarder-4.2}/tests/pythonpath/local/lib/python/notificationforwarder/ticketsystem/reporter.py +0 -0
  55. {omdnotificationforwarder-4.0 → omdnotificationforwarder-4.2}/tests/pythonpath/local/lib/python/notificationforwarder/vong/formatter.py +0 -0
  56. {omdnotificationforwarder-4.0 → omdnotificationforwarder-4.2}/tests/test_alertmanager.py +0 -0
  57. {omdnotificationforwarder-4.0 → omdnotificationforwarder-4.2}/tests/test_classes.py +0 -0
  58. {omdnotificationforwarder-4.0 → omdnotificationforwarder-4.2}/tests/test_discard.py +0 -0
  59. {omdnotificationforwarder-4.0 → omdnotificationforwarder-4.2}/tests/test_formatter.py +0 -0
  60. {omdnotificationforwarder-4.0 → omdnotificationforwarder-4.2}/tests/test_logger.py +0 -0
  61. {omdnotificationforwarder-4.0 → omdnotificationforwarder-4.2}/tests/test_package.py +0 -0
  62. {omdnotificationforwarder-4.0 → omdnotificationforwarder-4.2}/tests/test_paths.py +0 -0
  63. {omdnotificationforwarder-4.0 → omdnotificationforwarder-4.2}/tests/test_webhook.py +0 -0
@@ -4,3 +4,5 @@ dist
4
4
  sdist
5
5
  *.egg
6
6
  examples/
7
+ .opencode/
8
+ notificationforwarder/tests/var/
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: omdnotificationforwarder
3
- Version: 4.0
3
+ Version: 4.2
4
4
  Summary: A framework for notification scripts for OMD
5
5
  Project-URL: Homepage, https://github.com/lausser/noteventificationforhandlerwarder
6
6
  Project-URL: Bug Tracker, https://github.com/lausser/noteventificationforhandlerwarder/issues
@@ -11,6 +11,8 @@ Classifier: Programming Language :: Python :: 3
11
11
  Requires-Python: >=3.6.1
12
12
  Requires-Dist: coshsh
13
13
  Requires-Dist: jinja2
14
+ Provides-Extra: nostr
15
+ Requires-Dist: pynostr; extra == 'nostr'
14
16
  Provides-Extra: test
15
17
  Requires-Dist: flake8; extra == 'test'
16
18
  Requires-Dist: pytest; extra == 'test'
@@ -38,6 +40,8 @@ Let me list some of the formatter/forwarder combinations which are usually found
38
40
  |json |Splunk HEC |
39
41
  |json |RabbitMQ |
40
42
 
43
+ |markdown-like Nostr note|Nostr relays |
44
+
41
45
  Of course json is not json, the attributes and values are different depending on the recipient.
42
46
 
43
47
 
@@ -260,6 +264,34 @@ There is also a SyslogFormatter, which creates the log line as:
260
264
 
261
265
  If you want a different format, then copy *lib/python/notificationforwarder/syslog/formatter.py* to *local/lib/python/notificationforwarder/syslog/formatter.py* and modify it like you want. Or, with *--formatter*, you can use whatever formatter is suitable, as long as it's payload attribute consists of a line of text.
262
266
 
267
+ ### Nostr
268
+
269
+ The Nostr plugin pair publishes an encrypted direct message with labeled lines and default monitoring tags so the alert appears in chat-oriented clients.
270
+
271
+ Install the optional Nostr support with `pip install notificationforwarder[nostr]`.
272
+
273
+ |parameter|description|default|
274
+ |---------|-----------|-------|
275
+ |relays|comma-separated relay URLs|`wss://relay.damus.io`|
276
+ |nsec|bech32 private key for signing|required|
277
+ |tags|extra Nostr tags to include|`monitoring` plus host/service/state tags|
278
+
279
+ Example:
280
+
281
+ ```bash
282
+ $USER1$/notificationforwarder \
283
+ --forwarder nostr \
284
+ --forwarderopt relays='wss://relay.damus.io,wss://nostr-pub.wellorder.net' \
285
+ --forwarderopt nsec='$NSEC$' \
286
+ --formatter nostr \
287
+ --eventopt HOSTNAME='$HOSTNAME$' \
288
+ --eventopt SERVICEDESC='$SERVICEDESC$' \
289
+ --eventopt SERVICESTATE='$SERVICESTATE$' \
290
+ --eventopt SERVICEOUTPUT='$SERVICEOUTPUT$'
291
+ ```
292
+
293
+ The recipient `p` tag can be provided through the `tags` forwarder option or custom formatter output. The message content is encrypted before relay publication, so it shows up as a DM in clients that support NIP-04 direct messages.
294
+
263
295
  ## Loggers
264
296
 
265
297
  The framework uses a modular logging architecture similar to formatters, forwarders, and reporters. By default, notificationforwarder uses **text format logging** - you don't need to do anything, logging works exactly as it did before. The traditional text format is backward compatible with all existing installations.
@@ -349,6 +381,62 @@ class MyloggerLogger(NotificationLogger):
349
381
  pass
350
382
  ```
351
383
 
384
+ ## Runtime Architecture
385
+
386
+ The runtime keeps the historical CLI and plugin model, but the core flow is now split into clearer responsibilities instead of concentrating everything in one large class.
387
+
388
+ - `baseclass.new(...)`: compatibility entrypoint that creates a configured forwarder instance.
389
+ - `runtime_config.py`: normalizes runtime options, default values, log naming, and spool-related paths.
390
+ - `component_loader.py`: resolves and loads forwarders, formatters, reporters, and loggers using the established naming rules.
391
+ - `runtime_flow.py`: enriches raw events and applies the common forwarding/reporting result flow.
392
+ - `spool.py`: owns sqlite spool persistence, replay batches, and flush-lock retry behavior.
393
+
394
+ ### Forwarding Flow
395
+
396
+ The runtime flow is:
397
+
398
+ 1. Normalize runtime configuration and initialize logging.
399
+ 2. Load the forwarder implementation.
400
+ 3. Enrich the raw event with OMD/site metadata.
401
+ 4. Load the formatter and build a `FormattedEvent`.
402
+ 5. Attempt delivery.
403
+ 6. If delivery fails, spool the raw event for retry unless it is a heartbeat.
404
+ 7. If a reporter is configured, attach forwarding context and call the reporter.
405
+
406
+ ### Extension Contracts
407
+
408
+ Custom extensions still follow the existing filesystem and naming conventions:
409
+
410
+ - Forwarder: `notificationforwarder/<name>/forwarder.py` with class `<Name>Forwarder`
411
+ - Formatter: `notificationforwarder/<name>/formatter.py` with class `<Name>Formatter`
412
+ - Reporter: `notificationforwarder/<name>/reporter.py` with class `<Name>Reporter`
413
+ - Logger: `notificationforwarder/<name>/logger.py` with class `<Name>Logger`
414
+
415
+ If you pass a dotted class path instead of a simple name, the runtime uses it as an explicit module/class reference. Otherwise it derives the class name by capitalizing the plugin name and appending the expected suffix.
416
+
417
+ ### Runtime Guarantees
418
+
419
+ - Text logging remains the default and fallback logger.
420
+ - Unknown logger implementations fall back to the text logger and emit a warning.
421
+ - Failed deliveries are spooled in sqlite when possible.
422
+ - Spooled events are retried on later executions before the new event is sent, as long as they have not expired.
423
+ - Expired spool entries are dropped during flush and logged as outdated events.
424
+ - Concurrent flush attempts for the same forwarder are suppressed with a lock file.
425
+
426
+ ## Contributor Verification
427
+
428
+ When changing runtime code, run the relevant tests at minimum:
429
+
430
+ ```bash
431
+ pytest tests/test_runtime_foundation.py tests/test_delivery_resilience.py tests/test_classes.py
432
+ ```
433
+
434
+ For broader confidence, run the full suite:
435
+
436
+ ```bash
437
+ pytest
438
+ ```
439
+
352
440
  ## Reporters
353
441
 
354
442
  Like *forwarder* and *formatter*, a *reporter* is an instance of a *NotificationReporter* class defined in a file named *reporter.py*. There is one class coming with notificationforwarder, the *NaemonlogReporter*. It's purpose it to write a message to the Naemon logfile. When notificationforwarder is run as a standalone script (and not triggered as a notificationhandler by Naemon), the *NaemonlogReporter* can nevertheless leave a line in the Naemon log.
@@ -375,5 +463,3 @@ define command{
375
463
  >> $USER4$/var/log/notificationforwarder_errors.log 2>&1
376
464
  }
377
465
  ```
378
-
379
-
@@ -18,6 +18,8 @@ Let me list some of the formatter/forwarder combinations which are usually found
18
18
  |json |Splunk HEC |
19
19
  |json |RabbitMQ |
20
20
 
21
+ |markdown-like Nostr note|Nostr relays |
22
+
21
23
  Of course json is not json, the attributes and values are different depending on the recipient.
22
24
 
23
25
 
@@ -240,6 +242,34 @@ There is also a SyslogFormatter, which creates the log line as:
240
242
 
241
243
  If you want a different format, then copy *lib/python/notificationforwarder/syslog/formatter.py* to *local/lib/python/notificationforwarder/syslog/formatter.py* and modify it like you want. Or, with *--formatter*, you can use whatever formatter is suitable, as long as it's payload attribute consists of a line of text.
242
244
 
245
+ ### Nostr
246
+
247
+ The Nostr plugin pair publishes an encrypted direct message with labeled lines and default monitoring tags so the alert appears in chat-oriented clients.
248
+
249
+ Install the optional Nostr support with `pip install notificationforwarder[nostr]`.
250
+
251
+ |parameter|description|default|
252
+ |---------|-----------|-------|
253
+ |relays|comma-separated relay URLs|`wss://relay.damus.io`|
254
+ |nsec|bech32 private key for signing|required|
255
+ |tags|extra Nostr tags to include|`monitoring` plus host/service/state tags|
256
+
257
+ Example:
258
+
259
+ ```bash
260
+ $USER1$/notificationforwarder \
261
+ --forwarder nostr \
262
+ --forwarderopt relays='wss://relay.damus.io,wss://nostr-pub.wellorder.net' \
263
+ --forwarderopt nsec='$NSEC$' \
264
+ --formatter nostr \
265
+ --eventopt HOSTNAME='$HOSTNAME$' \
266
+ --eventopt SERVICEDESC='$SERVICEDESC$' \
267
+ --eventopt SERVICESTATE='$SERVICESTATE$' \
268
+ --eventopt SERVICEOUTPUT='$SERVICEOUTPUT$'
269
+ ```
270
+
271
+ The recipient `p` tag can be provided through the `tags` forwarder option or custom formatter output. The message content is encrypted before relay publication, so it shows up as a DM in clients that support NIP-04 direct messages.
272
+
243
273
  ## Loggers
244
274
 
245
275
  The framework uses a modular logging architecture similar to formatters, forwarders, and reporters. By default, notificationforwarder uses **text format logging** - you don't need to do anything, logging works exactly as it did before. The traditional text format is backward compatible with all existing installations.
@@ -329,6 +359,62 @@ class MyloggerLogger(NotificationLogger):
329
359
  pass
330
360
  ```
331
361
 
362
+ ## Runtime Architecture
363
+
364
+ The runtime keeps the historical CLI and plugin model, but the core flow is now split into clearer responsibilities instead of concentrating everything in one large class.
365
+
366
+ - `baseclass.new(...)`: compatibility entrypoint that creates a configured forwarder instance.
367
+ - `runtime_config.py`: normalizes runtime options, default values, log naming, and spool-related paths.
368
+ - `component_loader.py`: resolves and loads forwarders, formatters, reporters, and loggers using the established naming rules.
369
+ - `runtime_flow.py`: enriches raw events and applies the common forwarding/reporting result flow.
370
+ - `spool.py`: owns sqlite spool persistence, replay batches, and flush-lock retry behavior.
371
+
372
+ ### Forwarding Flow
373
+
374
+ The runtime flow is:
375
+
376
+ 1. Normalize runtime configuration and initialize logging.
377
+ 2. Load the forwarder implementation.
378
+ 3. Enrich the raw event with OMD/site metadata.
379
+ 4. Load the formatter and build a `FormattedEvent`.
380
+ 5. Attempt delivery.
381
+ 6. If delivery fails, spool the raw event for retry unless it is a heartbeat.
382
+ 7. If a reporter is configured, attach forwarding context and call the reporter.
383
+
384
+ ### Extension Contracts
385
+
386
+ Custom extensions still follow the existing filesystem and naming conventions:
387
+
388
+ - Forwarder: `notificationforwarder/<name>/forwarder.py` with class `<Name>Forwarder`
389
+ - Formatter: `notificationforwarder/<name>/formatter.py` with class `<Name>Formatter`
390
+ - Reporter: `notificationforwarder/<name>/reporter.py` with class `<Name>Reporter`
391
+ - Logger: `notificationforwarder/<name>/logger.py` with class `<Name>Logger`
392
+
393
+ If you pass a dotted class path instead of a simple name, the runtime uses it as an explicit module/class reference. Otherwise it derives the class name by capitalizing the plugin name and appending the expected suffix.
394
+
395
+ ### Runtime Guarantees
396
+
397
+ - Text logging remains the default and fallback logger.
398
+ - Unknown logger implementations fall back to the text logger and emit a warning.
399
+ - Failed deliveries are spooled in sqlite when possible.
400
+ - Spooled events are retried on later executions before the new event is sent, as long as they have not expired.
401
+ - Expired spool entries are dropped during flush and logged as outdated events.
402
+ - Concurrent flush attempts for the same forwarder are suppressed with a lock file.
403
+
404
+ ## Contributor Verification
405
+
406
+ When changing runtime code, run the relevant tests at minimum:
407
+
408
+ ```bash
409
+ pytest tests/test_runtime_foundation.py tests/test_delivery_resilience.py tests/test_classes.py
410
+ ```
411
+
412
+ For broader confidence, run the full suite:
413
+
414
+ ```bash
415
+ pytest
416
+ ```
417
+
332
418
  ## Reporters
333
419
 
334
420
  Like *forwarder* and *formatter*, a *reporter* is an instance of a *NotificationReporter* class defined in a file named *reporter.py*. There is one class coming with notificationforwarder, the *NaemonlogReporter*. It's purpose it to write a message to the Naemon logfile. When notificationforwarder is run as a standalone script (and not triggered as a notificationhandler by Naemon), the *NaemonlogReporter* can nevertheless leave a line in the Naemon log.
@@ -355,5 +441,3 @@ define command{
355
441
  >> $USER4$/var/log/notificationforwarder_errors.log 2>&1
356
442
  }
357
443
  ```
358
-
359
-
@@ -78,7 +78,7 @@ Example for an HTTP-based reporter:
78
78
  help='Logger type: text (default) or json, or custom logger module',
79
79
  default='text')
80
80
  parser.add_argument('--version', action='version',
81
- version=f'%(prog)s 4.0')
81
+ version=f'%(prog)s 4.2')
82
82
 
83
83
  args = parser.parse_args()
84
84
  if not hasattr(args, 'formatter'):
@@ -21,7 +21,7 @@ packages = ["src/notificationforwarder"]
21
21
 
22
22
  [project]
23
23
  name = "omdnotificationforwarder"
24
- version = "4.0"
24
+ version = "4.2"
25
25
  authors = [
26
26
  { name="Gerhard Lausser", email="lausser@yahoo.com" },
27
27
  ]
@@ -39,6 +39,9 @@ dependencies = [
39
39
  ]
40
40
 
41
41
  [project.optional-dependencies]
42
+ nostr = [
43
+ "pynostr",
44
+ ]
42
45
  test = [
43
46
  "requests",
44
47
  "flake8",