eping 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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: eping
3
- Version: 4.0
3
+ Version: 4.2
4
4
  Summary: Continuous ICMP reachability monitor built on fping, with a CSV logfile analyser (epinga)
5
5
  Author-email: Ewald Jeitler <ewald@jeitler.cc>
6
6
  License: GPL-3.0-or-later
@@ -17,7 +17,7 @@ Description-Content-Type: text/markdown
17
17
  License-File: LICENSE
18
18
  Dynamic: license-file
19
19
 
20
- # eping.py 4.00
20
+ # eping.py 4.02
21
21
 
22
22
  Continuous ICMP reachability monitor built on `fping`. Scans a host list in a loop,
23
23
  reports each host UP/DOWN/NO-DNS, counts state changes. CLI (curses) or web GUI.
@@ -192,7 +192,7 @@ DOWN. Columns: hostname/IP, state, RTT (ms), last-change timestamp, change count
192
192
  | `F` | add hosts from a file |
193
193
  | `O` | sort order picker — 5 orders (see *Views and sort orders*) |
194
194
  | `T` | add comment — timestamped CSV row (logging on only) |
195
- | `S` | set reference — shown list becomes new base list |
195
+ | `S` | set reference — shown list becomes new base list (hosts not shown are removed and no longer pinged) |
196
196
  | `Z` | zero changes — reset CH-TIME/CH NO, states kept |
197
197
  | `C` | clear all hosts and state |
198
198
  | `P` | address mode picker — 4 modes (see *Address modes*) |
@@ -235,8 +235,8 @@ Single self-contained page, no external resources.
235
235
 
236
236
  - Table: CLI-style columns, filled top-down then next column right. Horizontal scroll
237
237
  if needed ("SCROLL RIGHT FOR MORE" hint in the stats bar).
238
- - Footer stats: HOSTS, RUNTIME, HOST UP/DOWN/FLAPPING, for the whole current view regardless
239
- of the match filter and the ADV FILTER (HOSTS-SHOWN = shown count). The CLI footer counts the same way. RUNTIME shows `n/a` briefly during a background round.
238
+ - Footer stats: HOSTS, RUNTIME, HOST UP/DOWN/FLAPPING always count all hosts; SHOWN is the
239
+ number of rows displayed after the view, the match filter and the ADV FILTER. The CLI footer counts the same way. RUNTIME shows `n/a` briefly during a background round.
240
240
  - Adding many hosts (`ADD`, ADD HOSTS FILE, upload) shows "added N host(s) - please wait,
241
241
  pinging ..." until they appear with a state, then `done`.
242
242
  - Font size 6–28px (slider, `A−`/`A+`, `+`/`−` keys), stored in `localStorage`.
@@ -300,9 +300,11 @@ unless lowered). `CH NO` counts changes; `Z` resets it.
300
300
 
301
301
  CLI `U` and web GUI's view select/`U` picker (see *CLI mode*) reach the same 9 views.
302
302
  The web GUI's own `U` keyboard shortcut only cycles ALL HOSTS → CURRENTLY-UP →
303
- UP+FLAPPING → ALL HOSTS (see *Web GUI* keyboard shortcuts). A view also limits what's
304
- probed — filtered hosts aren't probed until back to ALL HOSTS. Host list snapshotted at
305
- switch time. A view with no matches is rejected, previous view stays active.
303
+ UP+FLAPPING → ALL HOSTS (see *Web GUI* keyboard shortcuts). A view is a pure display
304
+ filter, evaluated live on every refresh: all hosts keep being pinged, a host that goes
305
+ DOWN leaves `CURRENTLY-UP`, a host that comes UP appears. Only SET REFERENCE removes the
306
+ hosts that are not shown from the host list (they are no longer pinged) and resets the
307
+ view to ALL HOSTS. A view with no matches is rejected, previous view stays active.
306
308
 
307
309
  `ALWAYS-UP`/`ALWAYS-DOWN`: never changed state this run (`CH NO` = 0). `NO-DNS` counts
308
310
  as DOWN for `CURRENTLY-DOWN`/`ALWAYS-DOWN`/`DOWN+FLAPPING`.
@@ -448,7 +450,7 @@ separated) · `-r` IP range (comma separated, shortened end)
448
450
  | `-sshkey` | file | agent | private key file for `-ssh` |
449
451
  | `-sshhk` | accept-new/ask/off | accept-new | host key check for `-ssh` |
450
452
  | `-ncf` | — | off | CSV: do not ping the CSV IP of a name without DNS record |
451
- | `-up` | — | 0 | learning phase: after N rounds keep only hosts seen UP |
453
+ | `-up` | — | 0 | learning phase: after N rounds show only hosts seen UP (view CURRENTLY-UP; all hosts are still pinged until SET REFERENCE) |
452
454
  | `-setref` | — | off | with `-up`: hosts seen UP become new reference list |
453
455
 
454
456
  Hard-enforced at startup and live via ADV OPTIONS (`-web` only), same bounds.
@@ -1,4 +1,4 @@
1
- # eping.py 4.00
1
+ # eping.py 4.02
2
2
 
3
3
  Continuous ICMP reachability monitor built on `fping`. Scans a host list in a loop,
4
4
  reports each host UP/DOWN/NO-DNS, counts state changes. CLI (curses) or web GUI.
@@ -173,7 +173,7 @@ DOWN. Columns: hostname/IP, state, RTT (ms), last-change timestamp, change count
173
173
  | `F` | add hosts from a file |
174
174
  | `O` | sort order picker — 5 orders (see *Views and sort orders*) |
175
175
  | `T` | add comment — timestamped CSV row (logging on only) |
176
- | `S` | set reference — shown list becomes new base list |
176
+ | `S` | set reference — shown list becomes new base list (hosts not shown are removed and no longer pinged) |
177
177
  | `Z` | zero changes — reset CH-TIME/CH NO, states kept |
178
178
  | `C` | clear all hosts and state |
179
179
  | `P` | address mode picker — 4 modes (see *Address modes*) |
@@ -216,8 +216,8 @@ Single self-contained page, no external resources.
216
216
 
217
217
  - Table: CLI-style columns, filled top-down then next column right. Horizontal scroll
218
218
  if needed ("SCROLL RIGHT FOR MORE" hint in the stats bar).
219
- - Footer stats: HOSTS, RUNTIME, HOST UP/DOWN/FLAPPING, for the whole current view regardless
220
- of the match filter and the ADV FILTER (HOSTS-SHOWN = shown count). The CLI footer counts the same way. RUNTIME shows `n/a` briefly during a background round.
219
+ - Footer stats: HOSTS, RUNTIME, HOST UP/DOWN/FLAPPING always count all hosts; SHOWN is the
220
+ number of rows displayed after the view, the match filter and the ADV FILTER. The CLI footer counts the same way. RUNTIME shows `n/a` briefly during a background round.
221
221
  - Adding many hosts (`ADD`, ADD HOSTS FILE, upload) shows "added N host(s) - please wait,
222
222
  pinging ..." until they appear with a state, then `done`.
223
223
  - Font size 6–28px (slider, `A−`/`A+`, `+`/`−` keys), stored in `localStorage`.
@@ -281,9 +281,11 @@ unless lowered). `CH NO` counts changes; `Z` resets it.
281
281
 
282
282
  CLI `U` and web GUI's view select/`U` picker (see *CLI mode*) reach the same 9 views.
283
283
  The web GUI's own `U` keyboard shortcut only cycles ALL HOSTS → CURRENTLY-UP →
284
- UP+FLAPPING → ALL HOSTS (see *Web GUI* keyboard shortcuts). A view also limits what's
285
- probed — filtered hosts aren't probed until back to ALL HOSTS. Host list snapshotted at
286
- switch time. A view with no matches is rejected, previous view stays active.
284
+ UP+FLAPPING → ALL HOSTS (see *Web GUI* keyboard shortcuts). A view is a pure display
285
+ filter, evaluated live on every refresh: all hosts keep being pinged, a host that goes
286
+ DOWN leaves `CURRENTLY-UP`, a host that comes UP appears. Only SET REFERENCE removes the
287
+ hosts that are not shown from the host list (they are no longer pinged) and resets the
288
+ view to ALL HOSTS. A view with no matches is rejected, previous view stays active.
287
289
 
288
290
  `ALWAYS-UP`/`ALWAYS-DOWN`: never changed state this run (`CH NO` = 0). `NO-DNS` counts
289
291
  as DOWN for `CURRENTLY-DOWN`/`ALWAYS-DOWN`/`DOWN+FLAPPING`.
@@ -429,7 +431,7 @@ separated) · `-r` IP range (comma separated, shortened end)
429
431
  | `-sshkey` | file | agent | private key file for `-ssh` |
430
432
  | `-sshhk` | accept-new/ask/off | accept-new | host key check for `-ssh` |
431
433
  | `-ncf` | — | off | CSV: do not ping the CSV IP of a name without DNS record |
432
- | `-up` | — | 0 | learning phase: after N rounds keep only hosts seen UP |
434
+ | `-up` | — | 0 | learning phase: after N rounds show only hosts seen UP (view CURRENTLY-UP; all hosts are still pinged until SET REFERENCE) |
433
435
  | `-setref` | — | off | with `-up`: hosts seen UP become new reference list |
434
436
 
435
437
  Hard-enforced at startup and live via ADV OPTIONS (`-web` only), same bounds.
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "eping"
7
- version = "4.00"
7
+ version = "4.02"
8
8
  description = "Continuous ICMP reachability monitor built on fping, with a CSV logfile analyser (epinga)"
9
9
  readme = "README.md"
10
10
  license = { text = "GPL-3.0-or-later" }
@@ -7,7 +7,7 @@
7
7
  # I knew how it worked.
8
8
  # Now, only god knows it!
9
9
  # - - - - - - - - - - - - - - - - - - - - - - - -
10
- VERSION = '4.00'
10
+ VERSION = '4.02'
11
11
  version = VERSION # legacy alias (kept for existing references)
12
12
 
13
13
  # --- scaling limits ---
@@ -96,9 +96,9 @@ DOWN_SLICES_DEF = 4 # DOWN hosts are spread over this many rounds (1 =
96
96
  FLAP_WINDOW_MAX = 72000 # minutes = 50 days - see -fw validation
97
97
  FLAP_WINDOW_DEF = FLAP_WINDOW_MAX
98
98
 
99
- # [U] cycles through these views. Like before, the filter also shrinks what is pinged,
100
- # which is what makes UP-ONLY shorten the cycle. Hosts filtered away are not probed and
101
- # therefore cannot come back until the view is switched to ALL again.
99
+ # [U] cycles through these views. A view is a pure display filter, evaluated live on
100
+ # every refresh (see view_hosts()): all hosts keep being pinged. Only SET REFERENCE
101
+ # drops the hosts that are not shown from the host list.
102
102
  FILTER_MODES = [
103
103
  ('ALL HOSTS', 'ALL', 'ALL'),
104
104
  ('UP', 'UP', 'UP'),
@@ -1710,6 +1710,19 @@ def apply_match_filter(rows, pattern):
1710
1710
  return [r for r in rows
1711
1711
  if host_visible(pattern, r[0], r[8] if len(r) > 8 and r[8] else '')]
1712
1712
 
1713
+ def view_hosts(mode, hosts, host_state, tz_offset, flap_window=FLAP_WINDOW_DEF):
1714
+ """Hosts of 'hosts' shown by the view 'mode' (live; mode 0 = all, list unchanged)."""
1715
+ if mode <= 0:
1716
+ return hosts
1717
+ return filter_hosts(mode, hosts, host_state, tz_offset, flap_window)
1718
+
1719
+ def view_rows(rows, mode, host_state, tz_offset, flap_window=FLAP_WINDOW_DEF):
1720
+ """Rows (from build_display) of the hosts shown by the view 'mode' (live)."""
1721
+ if mode <= 0:
1722
+ return rows
1723
+ keep = set(filter_hosts(mode, [r[0] for r in rows], host_state, tz_offset, flap_window))
1724
+ return [r for r in rows if r[0] in keep]
1725
+
1713
1726
  def filter_hosts(mode, original_hosts_list, host_state, tz_offset,
1714
1727
  flap_window=FLAP_WINDOW_DEF, up_seen=None):
1715
1728
  """Host list for the given view mode - a snapshot, taken when the view switches.
@@ -3427,7 +3440,7 @@ WEB_INDEX_HTML = r"""<!DOCTYPE html>
3427
3440
  <span id="ctrls">
3428
3441
  <span class="ctrls-row" id="ctrlsRow1">
3429
3442
  <span id="ctrlsMain">
3430
- <select id="selFilter" title="choose which hosts are shown and pinged - a host outside the current view is not checked until a view including it is selected again">
3443
+ <select id="selFilter" title="display filter: choose which hosts are shown (evaluated live) - all hosts keep being pinged until SET REFERENCE removes the hosts that are not shown">
3431
3444
  <option value="0">ALL HOSTS</option>
3432
3445
  <option value="1">CURRENTLY-UP</option>
3433
3446
  <option value="3">ALWAYS-UP</option>
@@ -3445,7 +3458,7 @@ WEB_INDEX_HTML = r"""<!DOCTYPE html>
3445
3458
  <option value="3">FLAP/UP/DOWN</option>
3446
3459
  <option value="4">FLAP/DOWN/UP</option>
3447
3460
  </select>
3448
- <button id="btnSetRef" title="use the hosts currently shown as the new reference list">SET REFERENCE</button>
3461
+ <button id="btnSetRef" title="use the hosts currently shown as the new reference list - all other hosts are removed and no longer pinged">SET REFERENCE</button>
3449
3462
  <button id="btnZero" title="reset CH-TIME and CH NO for all hosts">ZERO CHANGES</button>
3450
3463
  <button id="btnClear" class="danger" title="remove every host from the list, resets all state">CLEAR ALL</button>
3451
3464
  <select id="selAddrMode" title="Deduplication when the same host is entered as both a hostname and its IP: hostname &amp; ip keeps both as given (no dedup) | prefer hostname: skip a raw IP already covered by a hostname | prefer ip address: skip a hostname already covered by a raw IP | ip only: resolve every hostname to its IP and ping/track it by address">
@@ -3518,8 +3531,8 @@ WEB_INDEX_HTML = r"""<!DOCTYPE html>
3518
3531
  <span class="u">HOSTS-UP: <b id="sUp">0</b></span>
3519
3532
  <span class="d">HOSTS-DOWN: <b id="sDown">0</b></span>
3520
3533
  <span>FLAPPING: <b id="sFlap">0</b></span>
3521
- <span title="hosts matching the display filter, out of the totals above"
3522
- id="sShownWrap">HOSTS-SHOWN: <b id="sShown">0</b></span>
3534
+ <span title="hosts shown by the view and display filters, out of all hosts"
3535
+ id="sShownWrap">SHOWN: <b id="sShown">0</b></span>
3523
3536
  <span id="sLog"></span>
3524
3537
  <span class="msg" id="msg"></span>
3525
3538
  <span id="scrollHint"></span>
@@ -5600,7 +5613,7 @@ function poll(){
5600
5613
  document.getElementById('sFlap').textContent = s.hosts_flap;
5601
5614
  var swrap = document.getElementById('sShownWrap');
5602
5615
  var advOn = !!(s.adv_filter && Object.keys(s.adv_filter).length);
5603
- swrap.style.display = (s.match_filter || advOn) ? '' : 'none';
5616
+ swrap.style.display = ''; // SHOWN is always visible
5604
5617
  lastAdv = {values: s.adv_values || {}, filter: s.adv_filter || {}};
5605
5618
  document.getElementById('btnAdvFilter').className = advOn ? 'on' : '';
5606
5619
  document.getElementById('sShown').textContent = s.hosts_shown;
@@ -7309,7 +7322,6 @@ def run_web_mode(original_hosts_list, host_state, args, logfile_file_name,
7309
7322
  tz_offset, flap_window, up_seen)
7310
7323
  if next_list or next_mode == 0:
7311
7324
  filter_mode = next_mode
7312
- active_hosts_list = apply_addr_mode(next_list)
7313
7325
  message = 'view: ' + FILTER_MODES[filter_mode][0]
7314
7326
  write_log_info(args.disable_logging, logfile_file_name,
7315
7327
  'FILTER ' + FILTER_MODES[filter_mode][0], tz_offset)
@@ -7327,7 +7339,6 @@ def run_web_mode(original_hosts_list, host_state, args, logfile_file_name,
7327
7339
  tz_offset, flap_window, up_seen)
7328
7340
  if target_list or target_mode == 0:
7329
7341
  filter_mode = target_mode
7330
- active_hosts_list = apply_addr_mode(target_list)
7331
7342
  message = 'view: ' + WEB_VIEW_MODES[filter_mode][0]
7332
7343
  write_log_info(args.disable_logging, logfile_file_name,
7333
7344
  'FILTER ' + WEB_VIEW_MODES[filter_mode][0], tz_offset)
@@ -7359,9 +7370,7 @@ def run_web_mode(original_hosts_list, host_state, args, logfile_file_name,
7359
7370
  # IP ONLY is active - see the startup (-ipo) path above
7360
7371
  active_hosts_list = [h for h in active_hosts_list if is_ip_host(h)]
7361
7372
  else:
7362
- base_list = filter_hosts(filter_mode, original_hosts_list,
7363
- host_state, tz_offset, flap_window, up_seen)
7364
- active_hosts_list = apply_addr_mode(base_list)
7373
+ active_hosts_list = apply_addr_mode(list(original_hosts_list))
7365
7374
  message = 'address mode: ' + ADDR_MODE_LABELS[addr_mode]
7366
7375
  elif cmd == 'get_names':
7367
7376
  if gn_thread is not None and gn_thread.is_alive():
@@ -7508,7 +7517,7 @@ def run_web_mode(original_hosts_list, host_state, args, logfile_file_name,
7508
7517
  # what is actually shown becomes the new reference list - the view
7509
7518
  # filter (active_hosts_list) AND the [M]/display filter (display_list
7510
7519
  # narrows it further) both apply, see quick/quick_rows just below
7511
- shown_hosts = [o[0] for o in build_display(active_hosts_list, host_state,
7520
+ shown_hosts = [o[0] for o in build_display(view_hosts(filter_mode, active_hosts_list, host_state, tz_offset, flap_window), host_state,
7512
7521
  sort_mode, tz_offset, flap_window)]
7513
7522
  if match_filter_re is not None or adv_filter:
7514
7523
  shown_hosts = [h for h in shown_hosts
@@ -7734,10 +7743,13 @@ def run_web_mode(original_hosts_list, host_state, args, logfile_file_name,
7734
7743
  if cmds or gn_just_finished:
7735
7744
  # view and order are pure display changes - show them at once instead of
7736
7745
  # letting the browser wait for the running round, same as the CLI does
7737
- quick = build_display(active_hosts_list, host_state, sort_mode,
7738
- tz_offset, flap_window)
7739
- quick_up = sum(1 for e in quick if 'UP' in e[1])
7740
- quick_total = len(quick)
7746
+ # HOSTS / HOSTS-UP / HOSTS-DOWN count all hosts, the view and the display
7747
+ # filters only narrow what is SHOWN
7748
+ quick_all = build_display(active_hosts_list, host_state, sort_mode,
7749
+ tz_offset, flap_window)
7750
+ quick_up = sum(1 for e in quick_all if 'UP' in e[1])
7751
+ quick_total = len(quick_all)
7752
+ quick = view_rows(quick_all, filter_mode, host_state, tz_offset, flap_window)
7741
7753
  if match_filter_re is not None or adv_filter:
7742
7754
  quick = apply_match_filter(quick, match_filter_re)
7743
7755
  with web_lock:
@@ -7774,15 +7786,18 @@ def run_web_mode(original_hosts_list, host_state, args, logfile_file_name,
7774
7786
  learning_phase = False
7775
7787
  else:
7776
7788
  learning_done = True
7777
- active_hosts_list = sorted(up_seen, key=lambda h: (
7778
- int(ipaddress.ip_address(h)) if is_ip_host(h) else float('inf')))
7779
- active_hosts_list = apply_addr_mode(active_hosts_list)
7780
7789
  if args.set_reference:
7781
7790
  # -setref: same as the 'set_ref' web command, once learning ends
7782
- _keep = set(active_hosts_list) # once, not per element (was O(n^2))
7791
+ _up_list = apply_addr_mode(sorted(up_seen, key=lambda h: (
7792
+ int(ipaddress.ip_address(h)) if is_ip_host(h) else float('inf'))))
7793
+ _keep = set(_up_list) # once, not per element (was O(n^2))
7783
7794
  prune_dropped_hosts([h for h in original_hosts_list if h not in _keep],
7784
7795
  host_state, up_seen, down_streak)
7785
- original_hosts_list = list(active_hosts_list)
7796
+ original_hosts_list = list(_up_list)
7797
+ active_hosts_list = _up_list
7798
+ filter_mode = 0
7799
+ else:
7800
+ filter_mode = 1 # UP view (display filter), every host is still pinged
7786
7801
  learning_phase = True
7787
7802
  else:
7788
7803
  learning_phase = True
@@ -7831,16 +7846,15 @@ def run_web_mode(original_hosts_list, host_state, args, logfile_file_name,
7831
7846
  phase['state'] = time.time() - _t
7832
7847
 
7833
7848
  _t = time.time()
7834
- display_list = build_display(active_hosts_list, host_state, sort_mode,
7835
- tz_offset, flap_window)
7836
- # HOSTS/HOSTS-UP/HOSTS-DOWN are the totals for the whole current view - a
7837
- # [M] display filter narrows what's SHOWN, not what's actually being pinged,
7838
- # so it must not make these look like only 2 hosts exist. hosts_count_shown
7839
- # is the post-filter count, reported separately (HOSTS-SHOWN in the web GUI).
7840
- hosts_count_up = sum(1 for e in display_list if 'UP' in e[1])
7841
- hosts_count_down = len(display_list) - hosts_count_up
7842
- hosts_count_flap = sum(1 for e in display_list
7849
+ display_all = build_display(active_hosts_list, host_state, sort_mode,
7850
+ tz_offset, flap_window)
7851
+ # HOSTS/HOSTS-UP/HOSTS-DOWN/FLAPPING count all hosts - the view and the [M] /
7852
+ # ADV display filters only narrow what is SHOWN (hosts_count_shown below).
7853
+ hosts_count_up = sum(1 for e in display_all if 'UP' in e[1])
7854
+ hosts_count_down = len(display_all) - hosts_count_up
7855
+ hosts_count_flap = sum(1 for e in display_all
7843
7856
  if host_is_flapping(e, now_local(tz_offset), flap_window))
7857
+ display_list = view_rows(display_all, filter_mode, host_state, tz_offset, flap_window)
7844
7858
  if match_filter_re is not None or adv_filter:
7845
7859
  display_list = apply_match_filter(display_list, match_filter_re)
7846
7860
  hosts_count_shown = len(display_list)
@@ -9281,9 +9295,6 @@ if __name__=='__main__':
9281
9295
  tz_offset, flap_window, up_seen)
9282
9296
  if next_list or next_mode == 0:
9283
9297
  filter_mode = next_mode
9284
- active_hosts_list = (apply_prefer_ip(next_list, int(args.dns_ttl)) if prefer_ip
9285
- else apply_prefer_hostname(next_list, int(args.dns_ttl))
9286
- if prefer_hostname else next_list)
9287
9298
  screen.clear()
9288
9299
  write_log_info(args.disable_logging, logfile_file_name,
9289
9300
  'FILTER ' + WEB_VIEW_MODES[filter_mode][0], tz_offset)
@@ -9302,9 +9313,6 @@ if __name__=='__main__':
9302
9313
  tz_offset, flap_window, up_seen)
9303
9314
  if target_list or target_mode == 0:
9304
9315
  filter_mode = target_mode
9305
- active_hosts_list = (apply_prefer_ip(target_list, int(args.dns_ttl)) if prefer_ip
9306
- else apply_prefer_hostname(target_list, int(args.dns_ttl))
9307
- if prefer_hostname else target_list)
9308
9316
  screen.clear()
9309
9317
  write_log_info(args.disable_logging, logfile_file_name,
9310
9318
  'FILTER ' + WEB_VIEW_MODES[filter_mode][0], tz_offset)
@@ -9338,11 +9346,10 @@ if __name__=='__main__':
9338
9346
  notice(io_msg.upper(), 2)
9339
9347
  message = io_msg
9340
9348
  else:
9341
- base_list = filter_hosts(filter_mode, original_hosts_list, host_state,
9342
- tz_offset, flap_window, up_seen)
9343
- active_hosts_list = (apply_prefer_ip(base_list, int(args.dns_ttl)) if prefer_ip
9344
- else apply_prefer_hostname(base_list, int(args.dns_ttl))
9345
- if prefer_hostname else base_list)
9349
+ _full = list(original_hosts_list)
9350
+ active_hosts_list = (apply_prefer_ip(_full, int(args.dns_ttl)) if prefer_ip
9351
+ else apply_prefer_hostname(_full, int(args.dns_ttl))
9352
+ if prefer_hostname else _full)
9346
9353
  message = 'address mode: ' + ADDR_MODE_LABELS[target_mode]
9347
9354
  elif not (0 <= target_mode < len(ADDR_MODE_LABELS)):
9348
9355
  message = 'invalid address mode'
@@ -9775,6 +9782,7 @@ if __name__=='__main__':
9775
9782
  hosts_count_up = 0
9776
9783
  hosts_count_down = 0
9777
9784
  hosts_count_flap = 0
9785
+ hosts_count_shown = 0
9778
9786
  run_time = '0.00'
9779
9787
  phase = {}
9780
9788
  used_scan = ''
@@ -9857,17 +9865,20 @@ if __name__=='__main__':
9857
9865
  so they can take effect at once instead of after the next scan round.
9858
9866
  """
9859
9867
  global display_list, hosts_count_up, hosts_count_down, hosts_count_flap
9860
- display_list = build_display(active_hosts_list, host_state, sort_mode,
9861
- tz_offset, flap_window)
9862
- # HOSTS/UP/DOWN/FLAPPING are the totals of the whole view - [M] and ADV FILTER
9863
- # only narrow what is shown, every host is still pinged
9868
+ global hosts_count_shown
9869
+ display_all = build_display(active_hosts_list, host_state, sort_mode,
9870
+ tz_offset, flap_window)
9871
+ # HOSTS/UP/DOWN/FLAPPING count all hosts - the view, [M] and ADV FILTER only
9872
+ # narrow what is shown (SHOWN), every host is still pinged
9864
9873
  _now_ref = now_local(tz_offset)
9865
- hosts_count_up = sum(1 for e in display_list if 'UP' in e[1])
9866
- hosts_count_down = len(display_list) - hosts_count_up
9867
- hosts_count_flap = sum(1 for e in display_list
9874
+ hosts_count_up = sum(1 for e in display_all if 'UP' in e[1])
9875
+ hosts_count_down = len(display_all) - hosts_count_up
9876
+ hosts_count_flap = sum(1 for e in display_all
9868
9877
  if host_is_flapping(e, _now_ref, flap_window))
9878
+ display_list = view_rows(display_all, filter_mode, host_state, tz_offset, flap_window)
9869
9879
  if match_filter_re is not None or adv_filter:
9870
9880
  display_list = apply_match_filter(display_list, match_filter_re)
9881
+ hosts_count_shown = len(display_list)
9871
9882
 
9872
9883
  def draw_screen():
9873
9884
  """Paint the whole screen from the data of the last completed round.
@@ -9987,11 +9998,13 @@ if __name__=='__main__':
9987
9998
  screen_output(rows - 1, 67, 'DOWN: ', 1, 1)
9988
9999
  screen_output(rows - 1, 73, hosts_down, 3, 1)
9989
10000
  screen_output(rows - 1, 79, 'FLAPPING: ', 1, 1)
9990
- screen_output(rows - 1, 89, hosts_flap.rstrip() + ' |', 1, 1)
10001
+ screen_output(rows - 1, 89, hosts_flap.rstrip(), 1, 1)
10002
+ screen_output(rows - 1, 96, 'SHOWN: ', 1, 1)
10003
+ screen_output(rows - 1, 103, ('{m: <6}'.format(m=hosts_count_shown)).rstrip() + ' |', 1, 1)
9991
10004
  if args.disable_logging:
9992
- screen_output(rows - 1, 99, 'LOGGING-ON: ' + logfile_file_name, 1, 1)
10005
+ screen_output(rows - 1, 113, 'LOGGING-ON: ' + logfile_file_name, 1, 1)
9993
10006
  else:
9994
- screen_output(rows - 1, 99, 'LOGGING-OFF', 1, 1)
10007
+ screen_output(rows - 1, 113, 'LOGGING-OFF', 1, 1)
9995
10008
  if num_of_hosts > 0 and maxhosts < num_of_hosts:
9996
10009
  tts_text = ' | TERMINAL TOO SMALL '
9997
10010
  screen_output(rows - 1, cols - len(tts_text), tts_text, 3, 2)
@@ -10232,9 +10245,6 @@ if __name__=='__main__':
10232
10245
  tz_offset, flap_window, up_seen)
10233
10246
  if new_list or new_mode == 0:
10234
10247
  filter_mode = new_mode
10235
- active_hosts_list = (apply_prefer_ip(new_list, int(args.dns_ttl)) if prefer_ip
10236
- else apply_prefer_hostname(new_list, int(args.dns_ttl))
10237
- if prefer_hostname else new_list)
10238
10248
  screen.clear()
10239
10249
  write_log_info(args.disable_logging, logfile_file_name,
10240
10250
  'FILTER ' + WEB_VIEW_MODES[filter_mode][0], tz_offset)
@@ -10285,11 +10295,10 @@ if __name__=='__main__':
10285
10295
  ip_only_mode = True
10286
10296
  notice(io_msg.upper(), 2)
10287
10297
  else:
10288
- base_list = filter_hosts(filter_mode, original_hosts_list, host_state,
10289
- tz_offset, flap_window, up_seen)
10290
- active_hosts_list = (apply_prefer_ip(base_list, int(args.dns_ttl)) if prefer_ip
10291
- else apply_prefer_hostname(base_list, int(args.dns_ttl))
10292
- if prefer_hostname else base_list)
10298
+ _full = list(original_hosts_list)
10299
+ active_hosts_list = (apply_prefer_ip(_full, int(args.dns_ttl)) if prefer_ip
10300
+ else apply_prefer_hostname(_full, int(args.dns_ttl))
10301
+ if prefer_hostname else _full)
10293
10302
  notice('ADDRESS MODE: ' + items[picked], 2)
10294
10303
  elif cmd == 'GET_NAMES':
10295
10304
  if gn_thread is not None and gn_thread.is_alive():
@@ -10513,20 +10522,23 @@ if __name__=='__main__':
10513
10522
  learning_phase = False
10514
10523
  else:
10515
10524
  learning_done = True
10516
- active_hosts_list = sorted(up_seen, key=lambda h: (
10517
- int(ipaddress.ip_address(h)) if is_ip_host(h) else float('inf')
10518
- ))
10519
- active_hosts_list = (apply_prefer_ip(active_hosts_list, int(args.dns_ttl)) if prefer_ip
10520
- else apply_prefer_hostname(active_hosts_list, int(args.dns_ttl))
10521
- if prefer_hostname else active_hosts_list)
10522
10525
  if args.set_reference:
10523
10526
  # -setref: same as pressing [S]/SET REFERENCE once learning ends
10524
- _keep = set(active_hosts_list) # once, not per element (was O(n^2))
10527
+ _up_list = sorted(up_seen, key=lambda h: (
10528
+ int(ipaddress.ip_address(h)) if is_ip_host(h) else float('inf')
10529
+ ))
10530
+ _up_list = (apply_prefer_ip(_up_list, int(args.dns_ttl)) if prefer_ip
10531
+ else apply_prefer_hostname(_up_list, int(args.dns_ttl))
10532
+ if prefer_hostname else _up_list)
10533
+ _keep = set(_up_list) # once, not per element (was O(n^2))
10525
10534
  prune_dropped_hosts([h for h in original_hosts_list if h not in _keep],
10526
10535
  host_state, up_seen, down_streak)
10527
- original_hosts_list = list(active_hosts_list)
10536
+ original_hosts_list = list(_up_list)
10537
+ active_hosts_list = _up_list
10538
+ filter_mode = 0
10539
+ else:
10540
+ filter_mode = 1 # UP view (display filter), every host is still pinged
10528
10541
  screen.clear()
10529
- filter_mode = 1 # the learning phase leaves an UP-only view
10530
10542
  learning_phase = True
10531
10543
  # same as after a command: the list changed, repaint at once
10532
10544
  if have_data:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: eping
3
- Version: 4.0
3
+ Version: 4.2
4
4
  Summary: Continuous ICMP reachability monitor built on fping, with a CSV logfile analyser (epinga)
5
5
  Author-email: Ewald Jeitler <ewald@jeitler.cc>
6
6
  License: GPL-3.0-or-later
@@ -17,7 +17,7 @@ Description-Content-Type: text/markdown
17
17
  License-File: LICENSE
18
18
  Dynamic: license-file
19
19
 
20
- # eping.py 4.00
20
+ # eping.py 4.02
21
21
 
22
22
  Continuous ICMP reachability monitor built on `fping`. Scans a host list in a loop,
23
23
  reports each host UP/DOWN/NO-DNS, counts state changes. CLI (curses) or web GUI.
@@ -192,7 +192,7 @@ DOWN. Columns: hostname/IP, state, RTT (ms), last-change timestamp, change count
192
192
  | `F` | add hosts from a file |
193
193
  | `O` | sort order picker — 5 orders (see *Views and sort orders*) |
194
194
  | `T` | add comment — timestamped CSV row (logging on only) |
195
- | `S` | set reference — shown list becomes new base list |
195
+ | `S` | set reference — shown list becomes new base list (hosts not shown are removed and no longer pinged) |
196
196
  | `Z` | zero changes — reset CH-TIME/CH NO, states kept |
197
197
  | `C` | clear all hosts and state |
198
198
  | `P` | address mode picker — 4 modes (see *Address modes*) |
@@ -235,8 +235,8 @@ Single self-contained page, no external resources.
235
235
 
236
236
  - Table: CLI-style columns, filled top-down then next column right. Horizontal scroll
237
237
  if needed ("SCROLL RIGHT FOR MORE" hint in the stats bar).
238
- - Footer stats: HOSTS, RUNTIME, HOST UP/DOWN/FLAPPING, for the whole current view regardless
239
- of the match filter and the ADV FILTER (HOSTS-SHOWN = shown count). The CLI footer counts the same way. RUNTIME shows `n/a` briefly during a background round.
238
+ - Footer stats: HOSTS, RUNTIME, HOST UP/DOWN/FLAPPING always count all hosts; SHOWN is the
239
+ number of rows displayed after the view, the match filter and the ADV FILTER. The CLI footer counts the same way. RUNTIME shows `n/a` briefly during a background round.
240
240
  - Adding many hosts (`ADD`, ADD HOSTS FILE, upload) shows "added N host(s) - please wait,
241
241
  pinging ..." until they appear with a state, then `done`.
242
242
  - Font size 6–28px (slider, `A−`/`A+`, `+`/`−` keys), stored in `localStorage`.
@@ -300,9 +300,11 @@ unless lowered). `CH NO` counts changes; `Z` resets it.
300
300
 
301
301
  CLI `U` and web GUI's view select/`U` picker (see *CLI mode*) reach the same 9 views.
302
302
  The web GUI's own `U` keyboard shortcut only cycles ALL HOSTS → CURRENTLY-UP →
303
- UP+FLAPPING → ALL HOSTS (see *Web GUI* keyboard shortcuts). A view also limits what's
304
- probed — filtered hosts aren't probed until back to ALL HOSTS. Host list snapshotted at
305
- switch time. A view with no matches is rejected, previous view stays active.
303
+ UP+FLAPPING → ALL HOSTS (see *Web GUI* keyboard shortcuts). A view is a pure display
304
+ filter, evaluated live on every refresh: all hosts keep being pinged, a host that goes
305
+ DOWN leaves `CURRENTLY-UP`, a host that comes UP appears. Only SET REFERENCE removes the
306
+ hosts that are not shown from the host list (they are no longer pinged) and resets the
307
+ view to ALL HOSTS. A view with no matches is rejected, previous view stays active.
306
308
 
307
309
  `ALWAYS-UP`/`ALWAYS-DOWN`: never changed state this run (`CH NO` = 0). `NO-DNS` counts
308
310
  as DOWN for `CURRENTLY-DOWN`/`ALWAYS-DOWN`/`DOWN+FLAPPING`.
@@ -448,7 +450,7 @@ separated) · `-r` IP range (comma separated, shortened end)
448
450
  | `-sshkey` | file | agent | private key file for `-ssh` |
449
451
  | `-sshhk` | accept-new/ask/off | accept-new | host key check for `-ssh` |
450
452
  | `-ncf` | — | off | CSV: do not ping the CSV IP of a name without DNS record |
451
- | `-up` | — | 0 | learning phase: after N rounds keep only hosts seen UP |
453
+ | `-up` | — | 0 | learning phase: after N rounds show only hosts seen UP (view CURRENTLY-UP; all hosts are still pinged until SET REFERENCE) |
452
454
  | `-setref` | — | off | with `-up`: hosts seen UP become new reference list |
453
455
 
454
456
  Hard-enforced at startup and live via ADV OPTIONS (`-web` only), same bounds.
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes