Jump to content

Connect SuperML | Leeroopedia MCP: Equip your AI agents with best practices, code verification, and debugging knowledge. Powered by Leeroo — building Organizational Superintelligence. Contact us at founders@leeroo.com.

Implementation:Bentoml BentoML MonitorBase

From Leeroopedia
Revision as of 12:07, 16 February 2026 by Admin (talk | contribs) (Auto-imported from implementations/Bentoml_BentoML_MonitorBase.md)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Knowledge Sources
Domains Monitoring, Observability, Data Logging, Abstract Base Class
Last Updated 2026-02-13 15:00 GMT

Overview

Defines the MonitorBase abstract base class and NoOpMonitor implementation for the BentoML monitoring system, providing the data logging and schema export interface.

Description

This module contains the foundational classes for BentoML's monitoring framework. It uses contextvars to maintain thread-safe, request-scoped state for column schemas and logged data.

MonitorBase[DT] is a generic abstract class that all monitor implementations must subclass. It manages two context variables:

  • MON_COLUMN_VAR stores the column schema (name, role, type) discovered during the first record
  • MON_DATAS_VAR stores the logged data as a dict of collections.deque objects keyed by column name

The recording lifecycle:

  • start_record() initializes context variables; sets up the column schema dict on the first call
  • log(data, name, role, data_type) records a single data point for a named column, validating the role (feature, prediction, target) and data type (numerical, categorical, numerical_sequence) against BENTOML_MONITOR_ROLES and BENTOML_MONITOR_TYPES. Reserved column names are auto-renamed with a trailing underscore
  • log_batch(data_batch, name, role, data_type) iterates over the batch and calls log() for each element
  • log_table() is a placeholder that logs a warning and returns (not yet implemented)
  • stop_record() finalizes the record: on the first call, it captures the column schema and calls export_schema(); it validates all columns have equal length, then calls export_data()

Subclasses must implement export_schema() and export_data() to persist the schema and data to their chosen backend.

NoOpMonitor is a complete no-op implementation where all methods do nothing, used when monitoring is disabled.

Usage

Subclass MonitorBase to create custom monitoring backends. The DefaultMonitor and OTLPMonitor are built-in subclasses. The NoOpMonitor is used automatically when monitoring is disabled in configuration.

Code Reference

Source Location

Signature

BENTOML_MONITOR_ROLES = {"feature", "prediction", "target"}
BENTOML_MONITOR_TYPES = {"numerical", "categorical", "numerical_sequence"}

class MonitorBase(t.Generic[DT]):
    PRESERVED_COLUMNS: tuple[str, ...] = ()

    def __init__(self, name: str, **_: t.Any) -> None: ...

    def start_record(self): ...
    def stop_record(self) -> None: ...

    def export_schema(self, columns_schema: dict[str, dict[str, str]]) -> None: ...
    def export_data(self, datas: dict[str, collections.deque[DT]]) -> None: ...

    def log(self, data: DT, name: str, role: str, data_type: str) -> None: ...
    def log_batch(
        self, data_batch: t.Iterable[DT], name: str, role: str, data_type: str,
    ) -> None: ...
    def log_table(
        self, data: t.Iterable[t.Iterable[DT]], schema: dict[str, str],
    ) -> None: ...

class NoOpMonitor(MonitorBase[t.Any]):
    # All methods are no-ops
    ...

Import

from bentoml._internal.monitoring.base import MonitorBase
from bentoml._internal.monitoring.base import NoOpMonitor
from bentoml._internal.monitoring.base import BENTOML_MONITOR_ROLES
from bentoml._internal.monitoring.base import BENTOML_MONITOR_TYPES

I/O Contract

Inputs

Name Type Required Description
name str Yes (constructor) Name identifying this monitor instance
data DT Yes (log) A single data value to record
name (log) str Yes (log) Column name for the data point; reserved names are auto-suffixed with "_"
role str Yes (log) Data role: "feature", "prediction", or "target" (others logged with warning)
data_type str Yes (log) Data type: "numerical", "categorical", or "numerical_sequence" (others logged with warning)
data_batch Iterable[DT] Yes (log_batch) Iterable of data values to log as a single column

Outputs

Name Type Description
(side effect: export_schema) None Called once on first stop_record() with the discovered column schema dict
(side effect: export_data) None Called on each stop_record() with the logged data as dict of deques

Usage Examples

from bentoml._internal.monitoring.base import MonitorBase
import collections
import typing as t

# Implementing a custom monitor backend
class MyCustomMonitor(MonitorBase[float]):
    PRESERVED_COLUMNS = ("timestamp", "request_id")

    def __init__(self, name: str, endpoint: str = "", **kwargs):
        super().__init__(name)
        self.endpoint = endpoint

    def export_schema(self, columns_schema: dict[str, dict[str, str]]) -> None:
        # Send schema to external system
        print(f"Schema for {self.name}: {columns_schema}")

    def export_data(self, datas: dict[str, collections.deque[float]]) -> None:
        # Send data to external system
        for col_name, values in datas.items():
            print(f"  {col_name}: {list(values)}")

# Using the monitor
monitor = MyCustomMonitor("my_monitor", endpoint="http://localhost:9090")
monitor.start_record()
monitor.log(1.0, "feature_x", "feature", "numerical")
monitor.log(2.0, "feature_y", "feature", "numerical")
monitor.log(0.95, "confidence", "prediction", "numerical")
monitor.stop_record()

# Output:
# Schema for my_monitor: {
#   "feature_x": {"name": "feature_x", "role": "feature", "type": "numerical"},
#   "feature_y": {"name": "feature_y", "role": "feature", "type": "numerical"},
#   "confidence": {"name": "confidence", "role": "prediction", "type": "numerical"},
# }
#   feature_x: [1.0]
#   feature_y: [2.0]
#   confidence: [0.95]

# Using NoOpMonitor (all operations are silently ignored)
from bentoml._internal.monitoring.base import NoOpMonitor
noop = NoOpMonitor("disabled")
noop.start_record()
noop.log(42, "x", "feature", "numerical")
noop.stop_record()  # Nothing happens

Related Pages

Page Connections

Double-click a node to navigate. Hold to expand connections.
Principle
Implementation
Heuristic
Environment