prescale-agent 0.2.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.
Files changed (25) hide show
  1. prescale_agent-0.2.0/PKG-INFO +155 -0
  2. prescale_agent-0.2.0/README.md +107 -0
  3. prescale_agent-0.2.0/pyproject.toml +85 -0
  4. prescale_agent-0.2.0/setup.cfg +4 -0
  5. prescale_agent-0.2.0/src/prescale_agent/__init__.py +3 -0
  6. prescale_agent-0.2.0/src/prescale_agent/agent.py +245 -0
  7. prescale_agent-0.2.0/src/prescale_agent/cli.py +384 -0
  8. prescale_agent-0.2.0/src/prescale_agent/client.py +199 -0
  9. prescale_agent-0.2.0/src/prescale_agent/config.py +189 -0
  10. prescale_agent-0.2.0/src/prescale_agent/sources/__init__.py +15 -0
  11. prescale_agent-0.2.0/src/prescale_agent/sources/azure_monitor.py +190 -0
  12. prescale_agent-0.2.0/src/prescale_agent/sources/base.py +156 -0
  13. prescale_agent-0.2.0/src/prescale_agent/sources/cloudwatch.py +209 -0
  14. prescale_agent-0.2.0/src/prescale_agent/sources/datadog.py +204 -0
  15. prescale_agent-0.2.0/src/prescale_agent/sources/gcp_monitoring.py +259 -0
  16. prescale_agent-0.2.0/src/prescale_agent/sources/prometheus.py +206 -0
  17. prescale_agent-0.2.0/src/prescale_agent/sources/registry.py +111 -0
  18. prescale_agent-0.2.0/src/prescale_agent/sources/system.py +228 -0
  19. prescale_agent-0.2.0/src/prescale_agent.egg-info/PKG-INFO +155 -0
  20. prescale_agent-0.2.0/src/prescale_agent.egg-info/SOURCES.txt +23 -0
  21. prescale_agent-0.2.0/src/prescale_agent.egg-info/dependency_links.txt +1 -0
  22. prescale_agent-0.2.0/src/prescale_agent.egg-info/entry_points.txt +2 -0
  23. prescale_agent-0.2.0/src/prescale_agent.egg-info/requires.txt +32 -0
  24. prescale_agent-0.2.0/src/prescale_agent.egg-info/top_level.txt +1 -0
  25. prescale_agent-0.2.0/tests/test_agent.py +465 -0
@@ -0,0 +1,155 @@
1
+ Metadata-Version: 2.4
2
+ Name: prescale-agent
3
+ Version: 0.2.0
4
+ Summary: Metrics collection agent for Prescale - Predictive Infrastructure Intelligence Platform
5
+ Author-email: Prescale Platform <maintainers@prescale.dev>
6
+ License: Apache-2.0
7
+ Project-URL: Homepage, https://github.com/pyjeebz/prescale
8
+ Project-URL: Repository, https://github.com/pyjeebz/prescale
9
+ Keywords: kubernetes,metrics,monitoring,prometheus,observability
10
+ Classifier: Development Status :: 4 - Beta
11
+ Classifier: Environment :: Console
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Intended Audience :: System Administrators
14
+ Classifier: License :: OSI Approved :: Apache Software License
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.9
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Topic :: System :: Monitoring
22
+ Requires-Python: >=3.9
23
+ Description-Content-Type: text/markdown
24
+ Requires-Dist: httpx>=0.24.0
25
+ Requires-Dist: click>=8.0.0
26
+ Requires-Dist: rich>=13.0.0
27
+ Requires-Dist: pyyaml>=6.0
28
+ Requires-Dist: psutil>=5.9.0
29
+ Provides-Extra: prometheus
30
+ Requires-Dist: prometheus-client>=0.17.0; extra == "prometheus"
31
+ Provides-Extra: datadog
32
+ Requires-Dist: datadog-api-client>=2.0.0; extra == "datadog"
33
+ Provides-Extra: aws
34
+ Requires-Dist: boto3>=1.26.0; extra == "aws"
35
+ Provides-Extra: azure
36
+ Requires-Dist: azure-identity>=1.12.0; extra == "azure"
37
+ Requires-Dist: azure-mgmt-monitor>=6.0.0; extra == "azure"
38
+ Provides-Extra: gcp
39
+ Requires-Dist: google-cloud-monitoring>=2.15.0; extra == "gcp"
40
+ Provides-Extra: kubernetes
41
+ Requires-Dist: kubernetes>=28.0.0; extra == "kubernetes"
42
+ Provides-Extra: all
43
+ Requires-Dist: prescale-agent[aws,azure,datadog,gcp,kubernetes,prometheus]; extra == "all"
44
+ Provides-Extra: dev
45
+ Requires-Dist: pytest>=7.0.0; extra == "dev"
46
+ Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
47
+ Requires-Dist: ruff>=0.1.0; extra == "dev"
48
+
49
+ # Prescale Agent
50
+
51
+ Metrics collection agent for [Prescale](https://github.com/pyjeebz/prescale) - Predictive Infrastructure Intelligence Platform.
52
+
53
+ ## Installation
54
+
55
+ ```bash
56
+ # Base installation (system metrics + Prometheus)
57
+ pip install prescale-platform-agent
58
+
59
+ # With specific backends
60
+ pip install prescale-platform-agent[gcp] # + GCP Cloud Monitoring
61
+ pip install prescale-platform-agent[aws] # + AWS CloudWatch
62
+ pip install prescale-platform-agent[azure] # + Azure Monitor
63
+ pip install prescale-platform-agent[datadog] # + Datadog
64
+ pip install prescale-platform-agent[all] # All backends
65
+ ```
66
+
67
+ ## Quick Start
68
+
69
+ ```bash
70
+ # Generate configuration file
71
+ prescale-agent init
72
+
73
+ # List available metric sources
74
+ prescale-agent sources
75
+
76
+ # Test configured sources
77
+ prescale-agent test
78
+
79
+ # Run the agent
80
+ prescale-agent run --config prescale-agent.yaml
81
+ ```
82
+
83
+ ## Configuration
84
+
85
+ Create a `prescale-agent.yaml` file:
86
+
87
+ ```yaml
88
+ agent:
89
+ collection_interval: 60
90
+ log_level: INFO
91
+
92
+ sources:
93
+ # System metrics (always available)
94
+ - type: system
95
+ enabled: true
96
+ config:
97
+ collect_cpu: true
98
+ collect_memory: true
99
+
100
+ # GCP Cloud Monitoring
101
+ - type: gcp-monitoring
102
+ enabled: true
103
+ config:
104
+ project_id: your-gcp-project
105
+ metrics:
106
+ - kubernetes.io/container/cpu/limit_utilization
107
+ - kubernetes.io/container/memory/limit_utilization
108
+
109
+ # Prometheus
110
+ - type: prometheus
111
+ enabled: false
112
+ config:
113
+ url: http://prometheus:9090
114
+ queries:
115
+ - name: cpu_usage
116
+ query: rate(container_cpu_usage_seconds_total[5m])
117
+
118
+ prescale:
119
+ endpoint: http://prescale-inference:8080
120
+ ```
121
+
122
+ ## Supported Sources
123
+
124
+ | Source | Description | Extra Install |
125
+ |--------|-------------|---------------|
126
+ | `system` | Local CPU, memory, disk via psutil | Built-in |
127
+ | `prometheus` | Query Prometheus server | Built-in |
128
+ | `gcp-monitoring` | GCP Cloud Monitoring | `[gcp]` |
129
+ | `cloudwatch` | AWS CloudWatch | `[aws]` |
130
+ | `azure-monitor` | Azure Monitor | `[azure]` |
131
+ | `datadog` | Datadog API | `[datadog]` |
132
+
133
+ ## CLI Commands
134
+
135
+ ```bash
136
+ prescale-agent init # Generate config file
137
+ prescale-agent run # Start collecting metrics
138
+ prescale-agent run --once # Single collection (testing)
139
+ prescale-agent run --deployment my-deployment # Associate with deployment
140
+ prescale-agent sources # List available sources
141
+ prescale-agent test # Test source connections
142
+ prescale-agent status # Show agent status
143
+ ```
144
+
145
+ ## Environment Variables
146
+
147
+ | Variable | Description |
148
+ |----------|-------------|
149
+ | `PRESCALE_CONFIG_FILE` | Path to config file (default: `./prescale-agent.yaml`) |
150
+ | `PRESCALE_ENDPOINT` | Prescale inference endpoint |
151
+ | `PRESCALE_API_KEY` | API key for authentication |
152
+
153
+ ## License
154
+
155
+ Apache 2.0 - See [LICENSE](../LICENSE)
@@ -0,0 +1,107 @@
1
+ # Prescale Agent
2
+
3
+ Metrics collection agent for [Prescale](https://github.com/pyjeebz/prescale) - Predictive Infrastructure Intelligence Platform.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ # Base installation (system metrics + Prometheus)
9
+ pip install prescale-platform-agent
10
+
11
+ # With specific backends
12
+ pip install prescale-platform-agent[gcp] # + GCP Cloud Monitoring
13
+ pip install prescale-platform-agent[aws] # + AWS CloudWatch
14
+ pip install prescale-platform-agent[azure] # + Azure Monitor
15
+ pip install prescale-platform-agent[datadog] # + Datadog
16
+ pip install prescale-platform-agent[all] # All backends
17
+ ```
18
+
19
+ ## Quick Start
20
+
21
+ ```bash
22
+ # Generate configuration file
23
+ prescale-agent init
24
+
25
+ # List available metric sources
26
+ prescale-agent sources
27
+
28
+ # Test configured sources
29
+ prescale-agent test
30
+
31
+ # Run the agent
32
+ prescale-agent run --config prescale-agent.yaml
33
+ ```
34
+
35
+ ## Configuration
36
+
37
+ Create a `prescale-agent.yaml` file:
38
+
39
+ ```yaml
40
+ agent:
41
+ collection_interval: 60
42
+ log_level: INFO
43
+
44
+ sources:
45
+ # System metrics (always available)
46
+ - type: system
47
+ enabled: true
48
+ config:
49
+ collect_cpu: true
50
+ collect_memory: true
51
+
52
+ # GCP Cloud Monitoring
53
+ - type: gcp-monitoring
54
+ enabled: true
55
+ config:
56
+ project_id: your-gcp-project
57
+ metrics:
58
+ - kubernetes.io/container/cpu/limit_utilization
59
+ - kubernetes.io/container/memory/limit_utilization
60
+
61
+ # Prometheus
62
+ - type: prometheus
63
+ enabled: false
64
+ config:
65
+ url: http://prometheus:9090
66
+ queries:
67
+ - name: cpu_usage
68
+ query: rate(container_cpu_usage_seconds_total[5m])
69
+
70
+ prescale:
71
+ endpoint: http://prescale-inference:8080
72
+ ```
73
+
74
+ ## Supported Sources
75
+
76
+ | Source | Description | Extra Install |
77
+ |--------|-------------|---------------|
78
+ | `system` | Local CPU, memory, disk via psutil | Built-in |
79
+ | `prometheus` | Query Prometheus server | Built-in |
80
+ | `gcp-monitoring` | GCP Cloud Monitoring | `[gcp]` |
81
+ | `cloudwatch` | AWS CloudWatch | `[aws]` |
82
+ | `azure-monitor` | Azure Monitor | `[azure]` |
83
+ | `datadog` | Datadog API | `[datadog]` |
84
+
85
+ ## CLI Commands
86
+
87
+ ```bash
88
+ prescale-agent init # Generate config file
89
+ prescale-agent run # Start collecting metrics
90
+ prescale-agent run --once # Single collection (testing)
91
+ prescale-agent run --deployment my-deployment # Associate with deployment
92
+ prescale-agent sources # List available sources
93
+ prescale-agent test # Test source connections
94
+ prescale-agent status # Show agent status
95
+ ```
96
+
97
+ ## Environment Variables
98
+
99
+ | Variable | Description |
100
+ |----------|-------------|
101
+ | `PRESCALE_CONFIG_FILE` | Path to config file (default: `./prescale-agent.yaml`) |
102
+ | `PRESCALE_ENDPOINT` | Prescale inference endpoint |
103
+ | `PRESCALE_API_KEY` | API key for authentication |
104
+
105
+ ## License
106
+
107
+ Apache 2.0 - See [LICENSE](../LICENSE)
@@ -0,0 +1,85 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "prescale-agent"
7
+ version = "0.2.0"
8
+ description = "Metrics collection agent for Prescale - Predictive Infrastructure Intelligence Platform"
9
+ readme = "README.md"
10
+ license = {text = "Apache-2.0"}
11
+ requires-python = ">=3.9"
12
+ authors = [
13
+ {name = "Prescale Platform", email = "maintainers@prescale.dev"}
14
+ ]
15
+ keywords = [
16
+ "kubernetes",
17
+ "metrics",
18
+ "monitoring",
19
+ "prometheus",
20
+ "observability"
21
+ ]
22
+ classifiers = [
23
+ "Development Status :: 4 - Beta",
24
+ "Environment :: Console",
25
+ "Intended Audience :: Developers",
26
+ "Intended Audience :: System Administrators",
27
+ "License :: OSI Approved :: Apache Software License",
28
+ "Operating System :: OS Independent",
29
+ "Programming Language :: Python :: 3",
30
+ "Programming Language :: Python :: 3.9",
31
+ "Programming Language :: Python :: 3.10",
32
+ "Programming Language :: Python :: 3.11",
33
+ "Programming Language :: Python :: 3.12",
34
+ "Topic :: System :: Monitoring",
35
+ ]
36
+
37
+ dependencies = [
38
+ "httpx>=0.24.0",
39
+ "click>=8.0.0",
40
+ "rich>=13.0.0",
41
+ "pyyaml>=6.0",
42
+ "psutil>=5.9.0",
43
+ ]
44
+
45
+ [project.optional-dependencies]
46
+ prometheus = [
47
+ "prometheus-client>=0.17.0",
48
+ ]
49
+ datadog = [
50
+ "datadog-api-client>=2.0.0",
51
+ ]
52
+ aws = [
53
+ "boto3>=1.26.0",
54
+ ]
55
+ azure = [
56
+ "azure-identity>=1.12.0",
57
+ "azure-mgmt-monitor>=6.0.0",
58
+ ]
59
+ gcp = [
60
+ "google-cloud-monitoring>=2.15.0",
61
+ ]
62
+ kubernetes = [
63
+ "kubernetes>=28.0.0",
64
+ ]
65
+ all = [
66
+ "prescale-agent[prometheus,datadog,aws,azure,gcp,kubernetes]",
67
+ ]
68
+ dev = [
69
+ "pytest>=7.0.0",
70
+ "pytest-asyncio>=0.21.0",
71
+ "ruff>=0.1.0",
72
+ ]
73
+
74
+ [project.scripts]
75
+ prescale-agent = "prescale_agent.cli:main"
76
+
77
+ [project.urls]
78
+ Homepage = "https://github.com/pyjeebz/prescale"
79
+ Repository = "https://github.com/pyjeebz/prescale"
80
+
81
+ [tool.setuptools.packages.find]
82
+ where = ["src"]
83
+
84
+ [tool.setuptools.package-dir]
85
+ "" = "src"
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,3 @@
1
+ """Prescale Agent - Metrics Collection for Predictive Infrastructure Intelligence."""
2
+
3
+ __version__ = "0.2.0"
@@ -0,0 +1,245 @@
1
+ """Prescale Agent - Main agent runner with unified metrics sources."""
2
+
3
+ import asyncio
4
+ import logging
5
+ import signal
6
+ from datetime import datetime, timezone
7
+ from typing import Optional
8
+
9
+ from .client import PrescaleClient
10
+ from .sources import MetricsSource, MetricSample, SourceRegistry
11
+ from .config import AgentConfig
12
+
13
+ logger = logging.getLogger(__name__)
14
+
15
+
16
+ class Agent:
17
+ """
18
+ Main Prescale metrics collection agent.
19
+
20
+ Uses a unified source interface to collect metrics from any backend:
21
+ - system: Local host metrics via psutil
22
+ - prometheus: Prometheus server
23
+ - datadog: Datadog API
24
+ - cloudwatch: AWS CloudWatch
25
+ - azure_monitor: Azure Monitor
26
+ - gcp_monitoring: Google Cloud Monitoring
27
+ """
28
+
29
+ def __init__(self, config: AgentConfig):
30
+ self.config = config
31
+ self.sources: list[MetricsSource] = []
32
+ self.client: Optional[PrescaleClient] = None
33
+ self._running = False
34
+ self._paused = False
35
+ self._interval_override: Optional[int] = None # Server-controlled interval
36
+ self._metrics_buffer: list[MetricSample] = []
37
+ self._last_flush = datetime.now(timezone.utc)
38
+
39
+ async def setup(self):
40
+ """Initialize sources and client."""
41
+ # Setup Prescale client
42
+ self.client = PrescaleClient(
43
+ endpoint=self.config.endpoint.url,
44
+ api_key=self.config.endpoint.api_key,
45
+ timeout=self.config.endpoint.timeout,
46
+ retry_attempts=self.config.endpoint.retry_attempts,
47
+ retry_delay=self.config.endpoint.retry_delay,
48
+ )
49
+
50
+ # Setup sources from config
51
+ for source_config in self.config.sources:
52
+ if not source_config.enabled:
53
+ continue
54
+
55
+ source = SourceRegistry.create(source_config)
56
+ if source is None:
57
+ logger.warning(f"Unknown source type: {source_config.type}")
58
+ continue
59
+
60
+ # Initialize the source
61
+ try:
62
+ if await source.initialize():
63
+ self.sources.append(source)
64
+ logger.info(f"Initialized source: {source.name} (type: {source_config.type})")
65
+ else:
66
+ logger.warning(f"Failed to initialize source: {source.name}")
67
+ except Exception as e:
68
+ logger.error(f"Error initializing source {source.name}: {e}")
69
+
70
+ logger.info(f"Agent initialized with {len(self.sources)} sources")
71
+ logger.info(f"Available source types: {SourceRegistry.list_types()}")
72
+
73
+ async def run(self):
74
+ """Run the agent main loop."""
75
+ self._running = True
76
+ logger.info("Starting Prescale Agent...")
77
+
78
+ # Setup signal handlers
79
+ loop = asyncio.get_running_loop()
80
+ for sig in (signal.SIGINT, signal.SIGTERM):
81
+ try:
82
+ loop.add_signal_handler(sig, lambda: asyncio.create_task(self.stop()))
83
+ except NotImplementedError:
84
+ # Windows doesn't support add_signal_handler
85
+ pass
86
+
87
+ # Check Prescale API health
88
+ if self.client:
89
+ healthy = await self.client.check_health()
90
+ if healthy:
91
+ logger.info(f"Connected to Prescale at {self.config.endpoint.url}")
92
+ else:
93
+ logger.warning(f"Could not connect to Prescale at {self.config.endpoint.url}")
94
+
95
+ # Start source collection tasks
96
+ tasks = []
97
+ for source in self.sources:
98
+ if source.is_enabled():
99
+ task = asyncio.create_task(self._run_source(source))
100
+ tasks.append(task)
101
+
102
+ # Start flush task
103
+ flush_task = asyncio.create_task(self._flush_loop())
104
+ tasks.append(flush_task)
105
+
106
+ # Wait for all tasks
107
+ try:
108
+ await asyncio.gather(*tasks)
109
+ except asyncio.CancelledError:
110
+ logger.info("Agent tasks cancelled")
111
+
112
+ async def stop(self):
113
+ """Stop the agent gracefully."""
114
+ logger.info("Stopping Prescale Agent...")
115
+ self._running = False
116
+
117
+ # Flush remaining metrics
118
+ await self._flush_metrics()
119
+
120
+ # Close sources
121
+ for source in self.sources:
122
+ try:
123
+ await source.close()
124
+ except Exception as e:
125
+ logger.warning(f"Error closing source {source.name}: {e}")
126
+
127
+ # Close client
128
+ if self.client:
129
+ await self.client.close()
130
+
131
+ async def _run_source(self, source: MetricsSource):
132
+ """Run a source collection loop."""
133
+ while self._running:
134
+ # Check if paused
135
+ if self._paused:
136
+ logger.debug(f"Agent paused, skipping collection from {source.name}")
137
+ await asyncio.sleep(5) # Check pause state every 5s
138
+ continue
139
+
140
+ try:
141
+ result = await source.collect()
142
+
143
+ if result.success:
144
+ # Convert source metrics to buffer format
145
+ self._metrics_buffer.extend(result.metrics)
146
+ logger.debug(
147
+ f"Collected {len(result.metrics)} metrics from {source.name} "
148
+ f"in {result.duration_ms:.1f}ms"
149
+ )
150
+ else:
151
+ logger.warning(f"Source {source.name} error: {result.error}")
152
+
153
+ except Exception as e:
154
+ logger.error(f"Error running source {source.name}: {e}")
155
+
156
+ # Use server-controlled interval if available, else source default
157
+ interval = self._interval_override or source.config.interval
158
+ await asyncio.sleep(interval)
159
+
160
+ async def _flush_loop(self):
161
+ """Periodically flush metrics to Prescale."""
162
+ while self._running:
163
+ await asyncio.sleep(self.config.flush_interval)
164
+ await self._flush_metrics()
165
+
166
+ async def _flush_metrics(self):
167
+ """Flush buffered metrics to Prescale."""
168
+ if not self._metrics_buffer:
169
+ return
170
+
171
+ if not self.client:
172
+ logger.warning("No Prescale client configured, discarding metrics")
173
+ self._metrics_buffer.clear()
174
+ return
175
+
176
+ # Get metrics to send
177
+ metrics_to_send = self._metrics_buffer[:self.config.batch_size]
178
+ self._metrics_buffer = self._metrics_buffer[self.config.batch_size:]
179
+
180
+ # Send metrics
181
+ result = await self.client.send_metrics(metrics_to_send)
182
+
183
+ if result is not None:
184
+ logger.info(f"Sent {len(metrics_to_send)} metrics to Prescale")
185
+
186
+ # Apply control commands from server
187
+ commands = result.get("commands")
188
+ if commands:
189
+ self._apply_commands(commands)
190
+ else:
191
+ # Re-add failed metrics to buffer (at the front)
192
+ self._metrics_buffer = metrics_to_send + self._metrics_buffer
193
+ # Trim buffer if too large
194
+ max_buffer = self.config.batch_size * 10
195
+ if len(self._metrics_buffer) > max_buffer:
196
+ dropped = len(self._metrics_buffer) - max_buffer
197
+ self._metrics_buffer = self._metrics_buffer[:max_buffer]
198
+ logger.warning(f"Buffer full, dropped {dropped} oldest metrics")
199
+
200
+ def _apply_commands(self, commands: dict):
201
+ """Apply control commands received from the server."""
202
+ if "paused" in commands:
203
+ new_paused = bool(commands["paused"])
204
+ if new_paused != self._paused:
205
+ self._paused = new_paused
206
+ state = "PAUSED" if new_paused else "RESUMED"
207
+ logger.info(f"Agent {state} by server command")
208
+
209
+ if "collection_interval" in commands:
210
+ new_interval = int(commands["collection_interval"])
211
+ if new_interval != self._interval_override:
212
+ old = self._interval_override or "default"
213
+ self._interval_override = new_interval
214
+ logger.info(f"Collection interval changed: {old} -> {new_interval}s")
215
+
216
+ async def collect_once(self) -> list[MetricSample]:
217
+ """Run all sources once and return metrics."""
218
+ all_metrics = []
219
+
220
+ for source in self.sources:
221
+ if source.is_enabled():
222
+ result = await source.collect()
223
+ if result.success:
224
+ all_metrics.extend(result.metrics)
225
+
226
+ return all_metrics
227
+
228
+ async def health_check(self) -> dict:
229
+ """Check health of all sources and client."""
230
+ status = {
231
+ "sources": {},
232
+ "client": False,
233
+ "metrics_buffered": len(self._metrics_buffer),
234
+ }
235
+
236
+ for source in self.sources:
237
+ try:
238
+ status["sources"][source.name] = await source.health_check()
239
+ except Exception:
240
+ status["sources"][source.name] = False
241
+
242
+ if self.client:
243
+ status["client"] = await self.client.check_health()
244
+
245
+ return status