mirror of
https://github.com/volcengine/OpenViking.git
synced 2026-10-01 01:38:07 +08:00
* feat(metrics): add vikingbot feedback observability * fix(bot): align feedback observability contracts * fix(metrics): decouple feedback collector bootstrap
127 lines
5.0 KiB
Python
127 lines
5.0 KiB
Python
# Copyright (c) 2026 Beijing Volcano Engine Technology Co., Ltd.
|
|
# SPDX-License-Identifier: AGPL-3.0
|
|
|
|
"""
|
|
Default metrics bootstrap.
|
|
|
|
This module wires DataSources and Collectors into a CollectorManager that is invoked
|
|
before each Prometheus scrape (`/metrics`).
|
|
|
|
The registered collectors are intentionally split into two categories:
|
|
- Per-scrape refresh (no TTL): cheap, purely in-process reads (e.g., queue/lock counters).
|
|
- TTL/SWR protected: collectors that may touch slower or less reliable subsystems
|
|
(e.g., service/model probes, vikingdb state, aggregated model usage).
|
|
|
|
If you add a new collector:
|
|
- Prefer low cardinality labels.
|
|
- Decide whether it needs TTL refresh control.
|
|
- Add/extend tests under `tests/metrics`.
|
|
|
|
Notes:
|
|
- Default-enabled collectors must keep refresh best-effort: `/metrics` should remain available
|
|
even if one subsystem is down.
|
|
- For aggregated collectors where a "failure default" is not meaningful, export `valid=1/0`
|
|
(or a similar validity gauge) so dashboards/alerts can distinguish stale data.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from pathlib import Path
|
|
|
|
from openviking.metrics.collectors import (
|
|
AsyncSystemProbeCollector,
|
|
CollectorManager,
|
|
EncryptionProbeCollector,
|
|
FeedbackCollector,
|
|
LockCollector,
|
|
ModelProviderProbeCollector,
|
|
ModelUsageCollector,
|
|
ObserverHealthCollector,
|
|
ObserverStateCollector,
|
|
QueueCollector,
|
|
RetrievalBackendProbeCollector,
|
|
ServiceProbeCollector,
|
|
StorageProbeCollector,
|
|
TaskTrackerCollector,
|
|
VikingDBCollector,
|
|
)
|
|
from openviking.metrics.datasources.encryption import EncryptionProbeDataSource
|
|
from openviking.metrics.datasources.model_usage import ModelUsageDataSource
|
|
from openviking.metrics.datasources.observer_state import (
|
|
LockStateDataSource,
|
|
ObserverStateDataSource,
|
|
VikingDBStateDataSource,
|
|
)
|
|
from openviking.metrics.datasources.probes import (
|
|
AsyncSystemProbeDataSource,
|
|
ModelProviderProbeDataSource,
|
|
RetrievalBackendProbeDataSource,
|
|
ServiceProbeDataSource,
|
|
StorageProbeDataSource,
|
|
)
|
|
from openviking.metrics.datasources.queue import QueuePipelineStateDataSource
|
|
from openviking.metrics.datasources.task import TaskStateDataSource
|
|
from openviking_cli.utils.config.open_viking_config import get_openviking_config
|
|
|
|
|
|
def create_default_collector_manager(*, app=None, service=None, config=None) -> CollectorManager:
|
|
"""
|
|
Build the default `CollectorManager` used by the server's Prometheus endpoint.
|
|
|
|
The default manager mixes lightweight state collectors, probe collectors, and a few
|
|
aggregated collectors that rely on TTL/SWR behavior inside `CollectorManager`.
|
|
|
|
Args:
|
|
app: FastAPI application instance needed by certain readiness probes.
|
|
service: Service object that exposes in-process state and subsystem handles preferred by
|
|
several collectors and datasources.
|
|
|
|
Returns:
|
|
A `CollectorManager` with the standard OpenViking collector set registered in the order
|
|
expected by the metrics bootstrap path.
|
|
"""
|
|
manager = CollectorManager()
|
|
manager.register(QueueCollector(data_source=QueuePipelineStateDataSource()))
|
|
manager.register(TaskTrackerCollector(data_source=TaskStateDataSource()))
|
|
feedback_bot_data_path = _resolve_feedback_bot_data_path(config)
|
|
if feedback_bot_data_path is not None:
|
|
manager.register(FeedbackCollector(bot_data_path=feedback_bot_data_path))
|
|
manager.register(ObserverHealthCollector(data_source=ObserverStateDataSource(service=service)))
|
|
manager.register(ObserverStateCollector(data_source=ObserverStateDataSource(service=service)))
|
|
manager.register(LockCollector(data_source=LockStateDataSource()))
|
|
manager.register(VikingDBCollector(data_source=VikingDBStateDataSource(service=service)))
|
|
manager.register(
|
|
ModelUsageCollector(
|
|
data_source=ModelUsageDataSource(config_provider=get_openviking_config, service=service)
|
|
)
|
|
)
|
|
manager.register(
|
|
ServiceProbeCollector(data_source=ServiceProbeDataSource(app=app, service=service))
|
|
)
|
|
manager.register(StorageProbeCollector(data_source=StorageProbeDataSource()))
|
|
manager.register(
|
|
RetrievalBackendProbeCollector(data_source=RetrievalBackendProbeDataSource(service=service))
|
|
)
|
|
manager.register(
|
|
ModelProviderProbeCollector(
|
|
data_source=ModelProviderProbeDataSource(config_provider=get_openviking_config)
|
|
)
|
|
)
|
|
manager.register(AsyncSystemProbeCollector(data_source=AsyncSystemProbeDataSource()))
|
|
manager.register(
|
|
EncryptionProbeCollector(
|
|
data_source=EncryptionProbeDataSource(config_provider=get_openviking_config)
|
|
)
|
|
)
|
|
return manager
|
|
|
|
|
|
def _resolve_feedback_bot_data_path(config) -> Path | None:
|
|
if config is None:
|
|
return None
|
|
metrics_config = getattr(getattr(config, "observability", None), "metrics", None)
|
|
bot_data_path = getattr(metrics_config, "bot_data_path", None)
|
|
if not bot_data_path:
|
|
return None
|
|
return Path(bot_data_path)
|