PyObservability 2.0.0__py3-none-any.whl → 2.1.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.
pyobservability/kuma.py CHANGED
@@ -1,7 +1,7 @@
1
1
  import logging
2
2
  import time
3
- from collections import defaultdict
4
- from typing import Any, Dict, List
3
+ from collections.abc import Generator
4
+ from typing import Any, Dict
5
5
  from urllib.parse import urlparse
6
6
 
7
7
  import socketio
@@ -81,18 +81,16 @@ class UptimeKumaClient:
81
81
  return self.monitors
82
82
 
83
83
 
84
- async def extract_monitors(payload: Dict[int, Dict[str, Any]]) -> List[Dict[str, Any]]:
85
- """Convert raw API payload into a list of dicts with name, url, tag_names, host.
84
+ def extract_monitors(payload: Dict[int, Dict[str, Any]]) -> Generator[Dict[str, Any]]:
85
+ """Convert raw API payload into a list of dicts with name, url, tags, host.
86
86
 
87
87
  Args:
88
88
  payload: Raw payload from Uptime Kuma server.
89
89
 
90
- Returns:
91
- List[Dict[str, Any]]:
92
- List of monitors with relevant fields.
90
+ Yields:
91
+ Dict[str, Any]:
92
+ Monitors with relevant fields.
93
93
  """
94
- monitors = []
95
-
96
94
  grouped = {}
97
95
  for monitor in payload.values():
98
96
  if children_ids := monitor.get("childrenIDs"):
@@ -104,23 +102,10 @@ async def extract_monitors(payload: Dict[int, Dict[str, Any]]) -> List[Dict[str,
104
102
  host = urlparse(url).hostname if url else None
105
103
  if not host:
106
104
  continue
107
- monitors.append(
108
- {
109
- "name": monitor.get("name"),
110
- "parent": grouped.get(monitor.get("id")),
111
- "url": url,
112
- "host": host,
113
- "tag_names": [tag.get("name") for tag in monitor.get("tags", []) if "name" in tag],
114
- }
115
- )
116
- return monitors
117
-
118
-
119
- async def group_by_host(monitors: List[Dict[str, Any]]) -> Dict[str, Any]:
120
- """Group monitors by host."""
121
- grouped = defaultdict(list)
122
-
123
- for monitor in monitors:
124
- grouped[monitor["host"]].append(monitor)
125
-
126
- return dict(grouped)
105
+ yield {
106
+ "name": monitor.get("name"),
107
+ "parent": grouped.get(monitor.get("id")),
108
+ "url": url,
109
+ "host": host,
110
+ "tags": [tag.get("name") for tag in monitor.get("tags", []) if "name" in tag],
111
+ }
pyobservability/main.py CHANGED
@@ -13,7 +13,7 @@ from fastapi.staticfiles import StaticFiles
13
13
  from fastapi.templating import Jinja2Templates
14
14
 
15
15
  from pyobservability.config import enums, settings
16
- from pyobservability.kuma import UptimeKumaClient, extract_monitors, group_by_host
16
+ from pyobservability.kuma import UptimeKumaClient, extract_monitors
17
17
  from pyobservability.transport import websocket_endpoint
18
18
  from pyobservability.version import __version__
19
19
 
@@ -41,8 +41,8 @@ async def index(request: Request):
41
41
  TemplateResponse:
42
42
  Rendered HTML template with targets and version.
43
43
  """
44
- kuma_data = {} if all((settings.env.kuma_url, settings.env.kuma_username, settings.env.kuma_password)) else None
45
- args = dict(request=request, service_map=kuma_data, targets=settings.env.targets, version=__version__)
44
+ kuma_data = [{}] if all((settings.env.kuma_url, settings.env.kuma_username, settings.env.kuma_password)) else None
45
+ args = dict(request=request, kuma_data=kuma_data, targets=settings.env.targets, version=__version__)
46
46
  if settings.env.username and settings.env.password:
47
47
  args["logout"] = uiauth.enums.APIEndpoints.fastapi_logout.value
48
48
  return templates.TemplateResponse("index.html", args)
@@ -63,9 +63,7 @@ async def kuma():
63
63
  status_code=HTTPStatus.SERVICE_UNAVAILABLE.real,
64
64
  detail="Unable to retrieve data from kuma server.",
65
65
  )
66
- json_monitors = await extract_monitors(kuma_data)
67
- LOGGER.info("Extracted JSON monitors from kuma payload.")
68
- return await group_by_host(json_monitors)
66
+ return list(extract_monitors(kuma_data))
69
67
 
70
68
 
71
69
  async def health() -> Dict[str, str]:
@@ -366,26 +366,24 @@
366
366
  });
367
367
  }
368
368
 
369
- function normalizeServiceMap(serviceMap) {
369
+ function normalizeKumaMap(monitors) {
370
370
  const rows = [];
371
- Object.entries(serviceMap || {}).forEach(([host, services]) => {
372
- services.forEach(svc => {
373
- rows.push({
374
- Node: host,
375
- Name: svc.name || "",
376
- Parent: svc.parent || "",
377
- Tags: (svc.tag_names || []).join(", "),
378
- URL: `<a href="${svc.url}" target="_blank">${svc.url}</a>`
379
- });
371
+ monitors.forEach(monitor => {
372
+ rows.push({
373
+ Node: monitor.host,
374
+ Name: monitor.name,
375
+ Parent: monitor.parent || "",
376
+ Tags: (monitor.tags || []).join(", "),
377
+ URL: `<a href="${monitor.url}" target="_blank">${monitor.url}</a>`
380
378
  });
381
379
  });
382
380
  return rows;
383
381
  }
384
382
 
385
383
  function renderEndpoints() {
386
- if (!window.SERVICE_MAP) return;
384
+ if (!window.KUMA_DATA) return;
387
385
 
388
- const rows = normalizeServiceMap(window.SERVICE_MAP);
386
+ const rows = normalizeKumaMap(window.KUMA_DATA);
389
387
  const columns = ["Node", "Name", "Parent", "Tags", "URL"];
390
388
 
391
389
  PAG_ENDPOINTS.setData(rows, columns);
@@ -1197,12 +1195,12 @@
1197
1195
 
1198
1196
  try {
1199
1197
  const response = await fetch('/kuma');
1200
- if (!response.ok) throw new Error('Failed to fetch service map');
1198
+ if (!response.ok) throw new Error('Failed to fetch kuma map');
1201
1199
 
1202
1200
  kumaMapData = await response.json();
1203
1201
  kumaMapLoaded = true;
1204
1202
 
1205
- allKumaRows = normalizeServiceMap(kumaMapData);
1203
+ allKumaRows = normalizeKumaMap(kumaMapData);
1206
1204
  PAG_KUMA_TAB.setData(allKumaRows, ["Node", "Name", "Parent", "Tags", "URL"]);
1207
1205
  } catch (err) {
1208
1206
  console.error("Error loading Kuma map:", err);
@@ -19,7 +19,7 @@
19
19
  <header class="topbar">
20
20
  <div class="brand">Node Monitor</div>
21
21
 
22
- {% if service_map is not none %}
22
+ {% if kuma_data is not none %}
23
23
  <div class="tab-navigation">
24
24
  <button id="nodes-tab" class="tab-btn active">Nodes</button>
25
25
  <button id="kuma-tab" class="tab-btn">Uptime Kuma</button>
@@ -293,9 +293,9 @@
293
293
  window.MONITOR_TARGETS = {{ targets | tojson }};
294
294
  </script>
295
295
 
296
- {% if service_map is not none %}
296
+ {% if kuma_data is not none %}
297
297
  <script>
298
- window.SERVICE_MAP = {{ service_map | tojson }};
298
+ window.KUMA_DATA = {{ kuma_data | tojson }};
299
299
  </script>
300
300
  {% endif %}
301
301
 
@@ -1 +1 @@
1
- __version__ = "2.0.0"
1
+ __version__ = "2.1.0"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: PyObservability
3
- Version: 2.0.0
3
+ Version: 2.1.0
4
4
  Summary: Lightweight OS-agnostic observability UI for PyNinja
5
5
  Author-email: Vignesh Rao <svignesh1793@gmail.com>
6
6
  License: MIT License
@@ -43,7 +43,7 @@ Description-Content-Type: text/markdown
43
43
  License-File: LICENSE
44
44
  Requires-Dist: aiohttp==3.13.*
45
45
  Requires-Dist: fastapi==0.128.*
46
- Requires-Dist: FastAPI-UI-Auth==0.2.1
46
+ Requires-Dist: FastAPI-UI-Auth==0.2.*
47
47
  Requires-Dist: Jinja2==3.1.*
48
48
  Requires-Dist: pydantic==2.12.*
49
49
  Requires-Dist: pydantic-settings==2.12.*
@@ -0,0 +1,17 @@
1
+ pyobservability/__init__.py,sha256=yVBLyTohBiBKp0Otyl04IggPh8mhg3Er25u6eFyxMto,2618
2
+ pyobservability/kuma.py,sha256=4sB1M7-exzrObGGIh1yYQ22P40kHwsTfv4G1Xj9YYWw,3260
3
+ pyobservability/main.py,sha256=c2sA-gGuAS9flO7FgeyQyzTMSHmZqhaeQAm1mWCUi9E,5992
4
+ pyobservability/monitor.py,sha256=i_Xf_DB-qLOp1b9wryekjwHIM8AnMrGTkuEg7e08bcM,7539
5
+ pyobservability/transport.py,sha256=S-84mgf-9yMj0H7VSAmueW9yosX_1XxdyNJC2EuQHQQ,8493
6
+ pyobservability/version.py,sha256=Xybt2skBZamGMNlLuOX1IG-h4uIxqUDGAO8MIGWrJac,22
7
+ pyobservability/config/enums.py,sha256=rQZh2Q4-9ItQTQgxsYjqw-jNePpWHhvQUrbrQJBG5CI,313
8
+ pyobservability/config/settings.py,sha256=aCz1tZEg8fUA5gHCCDN_m3fgrH1axz2fvdalj4bszGs,6121
9
+ pyobservability/static/app.js,sha256=XTy4lE2WxYDnJCjaigAOXde8-wZ36Wt_580HWlE3JFo,48557
10
+ pyobservability/static/styles.css,sha256=P6Xg-IAXO3WNeBLGH9Q5HAdNeDMRbFcM5P_cq60Jf00,9405
11
+ pyobservability/templates/index.html,sha256=aqvHrxP_D2gSxYmsUkNMi1QH07pQNXh4VuXc51KBo5c,11826
12
+ pyobservability-2.1.0.dist-info/licenses/LICENSE,sha256=_sOIKJWdD2o1WwwDIwYB2qTP2nlSWqT5Tyg9jr1Xa4w,1070
13
+ pyobservability-2.1.0.dist-info/METADATA,sha256=aUlk5iphyiJ9WYIUXQQVrzWBvgFrp2Q1OnSYvv7Xsug,7026
14
+ pyobservability-2.1.0.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
15
+ pyobservability-2.1.0.dist-info/entry_points.txt,sha256=DSGIr_VA8Tb3FYa2iNUYpf55eAvuFCAoInNS4ngXaME,57
16
+ pyobservability-2.1.0.dist-info/top_level.txt,sha256=p20T0EmihDYW1uMintRXr7X9bg3XWYKyoSbBHOVC1xI,16
17
+ pyobservability-2.1.0.dist-info/RECORD,,
@@ -1,17 +0,0 @@
1
- pyobservability/__init__.py,sha256=yVBLyTohBiBKp0Otyl04IggPh8mhg3Er25u6eFyxMto,2618
2
- pyobservability/kuma.py,sha256=RL6ZsK6ZE3vUufsUQ3r4gnH8uka0k8ARd41GP5YozbU,3634
3
- pyobservability/main.py,sha256=EbP6xkOvj2cV1cOEmmq6E6QsLOhbvKI_jdpfcWjSz-M,6124
4
- pyobservability/monitor.py,sha256=i_Xf_DB-qLOp1b9wryekjwHIM8AnMrGTkuEg7e08bcM,7539
5
- pyobservability/transport.py,sha256=S-84mgf-9yMj0H7VSAmueW9yosX_1XxdyNJC2EuQHQQ,8493
6
- pyobservability/version.py,sha256=_7OlQdbVkK4jad0CLdpI0grT-zEAb-qgFmH5mFzDXiA,22
7
- pyobservability/config/enums.py,sha256=rQZh2Q4-9ItQTQgxsYjqw-jNePpWHhvQUrbrQJBG5CI,313
8
- pyobservability/config/settings.py,sha256=aCz1tZEg8fUA5gHCCDN_m3fgrH1axz2fvdalj4bszGs,6121
9
- pyobservability/static/app.js,sha256=lE-Oybq50FNr_0SrZJFiJihiXyIcyhw7-SNbGA81ySQ,48675
10
- pyobservability/static/styles.css,sha256=P6Xg-IAXO3WNeBLGH9Q5HAdNeDMRbFcM5P_cq60Jf00,9405
11
- pyobservability/templates/index.html,sha256=WQNOT_uHfAvVqOnYc1olYdyrjM11tDpeKwTkbPQ853Q,11834
12
- pyobservability-2.0.0.dist-info/licenses/LICENSE,sha256=_sOIKJWdD2o1WwwDIwYB2qTP2nlSWqT5Tyg9jr1Xa4w,1070
13
- pyobservability-2.0.0.dist-info/METADATA,sha256=hu_7k6rRxUXitpfLhkAB6GZxMYQNDeqGaQAHJDKa0Ss,7026
14
- pyobservability-2.0.0.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
15
- pyobservability-2.0.0.dist-info/entry_points.txt,sha256=DSGIr_VA8Tb3FYa2iNUYpf55eAvuFCAoInNS4ngXaME,57
16
- pyobservability-2.0.0.dist-info/top_level.txt,sha256=p20T0EmihDYW1uMintRXr7X9bg3XWYKyoSbBHOVC1xI,16
17
- pyobservability-2.0.0.dist-info/RECORD,,