[ Web Proxy ]
URL:
Viewing: https://raw.githubusercontent.com/cloud-orbitor/feast/master/sdk/python/feast/cli/monitor.py [Back]  [Original]

from datetime import date
from typing import List, Optional

import click

from feast.infra.offline_stores.offline_store import OfflineStore
from feast.repo_operations import create_feature_store

VALID_GRANULARITIES = OfflineStore.MONITORING_VALID_GRANULARITIES


@click.group(name="monitor")
def monitor_cmd():
    """Feature monitoring commands."""
    pass


@monitor_cmd.command("run")
@click.option(
    "--project",
    "-p",
    default=None,
    help="Feast project name. Defaults to the project in feature_store.yaml.",
)
@click.option(
    "--feature-view",
    "-v",
    default=None,
    help="Feature view name. If omitted, all feature views are computed.",
)
@click.option(
    "--feature-name",
    "-f",
    multiple=True,
    help="Feature name(s) to compute. Can be specified multiple times.",
)
@click.option(
    "--start-date",
    default=None,
    help="Start date (YYYY-MM-DD). If omitted, auto-detected from source data.",
)
@click.option(
    "--end-date",
    default=None,
    help="End date (YYYY-MM-DD). If omitted, auto-detected from source data.",
)
@click.option(
    "--granularity",
    "-g",
    default=None,
    type=click.Choice(list(VALID_GRANULARITIES)),
    help="Metric granularity. If omitted, all granularities are computed (auto mode).",
)
@click.option(
    "--set-baseline",
    is_flag=True,
    default=False,
    help="Mark this computation as the baseline for drift detection.",
)
@click.option(
    "--feature-service",
    "-s",
    default=None,
    help="Feature service name (required for --source-type log with explicit dates).",
)
@click.option(
    "--source-type",
    type=click.Choice(["batch", "log", "all"]),
    default="batch",
    help="Data source type: 'batch' (offline store), 'log' (serving logs), or 'all'.",
)
@click.pass_context
def monitor_run(
    ctx: click.Context,
    project: Optional[str],
    feature_view: Optional[str],
    feature_name: tuple,
    start_date: Optional[str],
    end_date: Optional[str],
    granularity: Optional[str],
    set_baseline: bool,
    feature_service: Optional[str],
    source_type: str,
):
    """Compute feature quality metrics.

    Without --start-date/--end-date/--granularity, runs in auto mode:
    detects date ranges from source data and computes all granularities.

    Use --source-type log to compute metrics from feature serving logs
    (requires feature services with logging configured).
    """
    store = create_feature_store(ctx)

    if project is None:
        project = store.project

    from feast.monitoring.monitoring_service import MonitoringService

    svc = MonitoringService(store)

    auto_mode = start_date is None and end_date is None and granularity is None
    feat_names: Optional[List[str]] = list(feature_name) if feature_name else None

    if source_type in ("batch", "all"):
        _run_batch_monitoring(
            svc,
            project,
            feature_view,
            feat_names,
            start_date,
            end_date,
            granularity,
            set_baseline,
            auto_mode,
        )

    if source_type in ("log", "all"):
        _run_log_monitoring(
            svc,
            project,
            feature_service,
            start_date,
            end_date,
            granularity,
            auto_mode,
        )


def _run_batch_monitoring(
    svc,
    project,
    feature_view,
    feat_names,
    start_date,
    end_date,
    granularity,
    set_baseline,
    auto_mode,
):
    if auto_mode and set_baseline and not start_date and not end_date:
        click.echo("Computing baseline from all available source data...")
        result = svc.compute_baseline(
            project=project,
            feature_view_name=feature_view,
            feature_names=feat_names,
        )
        click.echo(f"Status: {result['status']}")
        click.echo(f"Features computed: {result['computed_features']}")
        click.echo(f"Feature views computed: {result['computed_feature_views']}")
        click.echo(f"Duration: {result['duration_ms']}ms")
        click.echo("Baseline: SET")
    elif auto_mode and not set_baseline:
        click.echo("Auto-computing batch metrics for all granularities...")
        result = svc.auto_compute(
            project=project,
            feature_view_name=feature_view,
        )
        click.echo(f"Status: {result['status']}")
        click.echo(f"Feature views computed: {result['computed_feature_views']}")
        click.echo(f"Features computed: {result['computed_features']}")
        click.echo(f"Granularities: {', '.join(result['granularities'])}")
        click.echo(f"Duration: {result['duration_ms']}ms")
    else:
        start_d = date.fromisoformat(start_date) if start_date else None
        end_d = date.fromisoformat(end_date) if end_date else None

        result = svc.compute_metrics(
            project=project,
            feature_view_name=feature_view,
            feature_names=feat_names,
            start_date=start_d,
            end_date=end_d,
            granularity=granularity or "daily",
            set_baseline=set_baseline,
        )

        click.echo(f"Status: {result['status']}")
        click.echo(f"Granularity: {result['granularity']}")
        click.echo(f"Features computed: {result['computed_features']}")
        click.echo(f"Feature views computed: {result['computed_feature_views']}")
        click.echo(f"Feature services computed: {result['computed_feature_services']}")
        click.echo(f"Metric dates: {', '.join(result['metric_dates'])}")
        click.echo(f"Duration: {result['duration_ms']}ms")

        if set_baseline:
            click.echo("Baseline: SET")


def _run_log_monitoring(
    svc, project, feature_service_name, start_date, end_date, granularity, auto_mode
):
    if auto_mode:
        click.echo("Auto-computing log metrics for all granularities...")
        result = svc.auto_compute_log_metrics(
            project=project,
            feature_service_name=feature_service_name,
        )
        click.echo(f"Status: {result['status']}")
        click.echo(f"Feature services computed: {result['computed_feature_services']}")
        click.echo(f"Features computed: {result['computed_features']}")
        click.echo(f"Granularities: {', '.join(result['granularities'])}")
        click.echo(f"Duration: {result['duration_ms']}ms")
    else:
        if not feature_service_name:
            click.echo(
                "Error: --feature-service is required for log source with explicit dates."
            )
            return

        start_d = date.fromisoformat(start_date) if start_date else None
        end_d = date.fromisoformat(end_date) if end_date else None

        result = svc.compute_log_metrics(
            project=project,
            feature_service_name=feature_service_name,
            start_date=start_d,
            end_date=end_d,
            granularity=granularity or "daily",
        )

        click.echo(f"Status: {result['status']}")
        click.echo("Source: log")
        click.echo(f"Features computed: {result.get('computed_features', 0)}")
        click.echo(f"Duration: {result['duration_ms']}ms")

Web Proxy Viewer  |  New URL  |  Original Page