Skip to content

Monitor serving requests and logged predictions

When you need it

For REST deployment and typed SQL function/ai_query calls, follow Deploy and call a model. The optional helper uses one concrete registered model version and derives SQL input/output types from its inspected package.

The generated serving_endpoint job automatically enrolls its concrete version after successful verification when payload logging is enabled and the target's monitoring_enabled variable is "true". Configure the shared monitoring catalog/schema first. For a model set it enrolls every branch; updating the endpoint disables its prior registrations while retaining history. No separate enroll_serving run is needed for this job. Send requests and run the monitoring job to create observations; enrollment itself does not populate traffic charts. prediction_delivery: endpoint keeps monitoring without a batch score job.

Set monitoring_enabled: "false" in the target variables to skip automatic enrollment while keeping endpoint logging and REST/SQL verification enabled. An absent flag also disables enrollment. The serving result reports monitoring_disabled; no monitoring namespace, reference or inventory work runs, and existing registrations remain unchanged. Only exact "true" and "false" values are accepted. When monitoring is enabled but payload logging is disabled, the result instead reports logging_disabled.

For an endpoint created outside that job, first prepare and create a pinned endpoint with full payload capture. Keep its concrete model version, endpoint name and payload view together; a registry alias can move independently of requests already logged. Endpoint creation, runtime admission and logging-mode selection are described on that serving page.

Every inventory reader sharing that monitoring namespace must run a Core release with serving support before the first serving enrollment. This includes other projects' monitoring jobs and any custom inventory readers. A reader without serving support rejects the serving fields, even in another project's entry. The score job's prepare_monitoring task does not load the shared inventory, so it is not affected. A dashboard update does not change reader runtimes. Keep training/scoring runtime changes separate when their saved artifact certificates require the original packaged source.

flowchart LR
    A["Pinned endpoint with payload logging"] --> B["Payload view"]
    B --> C["Serving job enrollment or manual enroll_serving"]
    C --> D["Scheduled monitoring job: observe"]
    D --> E["Saved serving report"]
    E --> F["Dashboard: Online serving"]

This page covers enrollment and observations. Daily serving rollout is the single policy guide for traffic increases, holds, rollback and restart.

What to edit

Match environment and project to this job's target and bundle name. The job compares them with the deployed target and project and rejects a mismatch, so an entry with "environment": "prod" works only with -t prod. Set reference_namespace to its configured monitoring catalog and schema. The source and prediction names are the same inference payload view. For CPU custom models that object is the Databricks-managed risk_payload view; its backing risk_otel_logs is a managed Delta table. Grant the monitoring job read access to both the view and its backing Delta table, plus system.serving.served_entities for actual model-version attribution. The job also needs the usual catalog/schema usage privileges and read access to the configured labels and saved training references. Do not rename, replace, alter or delete either Databricks-owned object, including its schema or internal checkpoints. Monitoring verifies the pinned view and backing Delta identity before reading; enrollment does not copy or modify the serving logs. Enrollment validates the entire list (1-100 distinct models), prepares verified training references, and saves the enrollments to the shared inventory. It does not observe, publish an observation reference, or request training in that run. Later scheduled monitoring_action=observe runs select active batch and online enrollments together and use the existing report, policy and dashboard.

For manually enrolled endpoints with two served versions, add a separate entry for each concrete version and endpoint. A model-set branch needs its own entry with model_set_name, model_set_version and model_set_branch identifying the parent release and output. Labels are provided independently in a Delta table keyed by databricks_request_id and zero-based request_row_index, with the actual target column and UTC available_at. Skyulf does not generate outcomes or write them back to the training table. Missing or late labels remain unavailable until an eligible observation; choose mode: report first and make any retraining policy an explicit later decision.

Keep performance in report mode initially. The inline online policy determines its measured verdict; automatic requests also require the deployment gate described in guarded retraining. Retraining alone does not update an endpoint. After a completed champion change, the independently configured serving handoff can submit its update job in production mode.

To retire or pause one online enrollment, resubmit its complete JSON entry with enabled: false using monitoring_action=enroll_serving. Keep the endpoint, model/version and parent branch identity unchanged. Disabling does not require loading its model or preparing references, so an unavailable model or reference cannot prevent the pause. Other batch and online enrollments remain active.

This optional bridge covers pinned serving and monitoring; it does not imply that every serving or feature lookup flow is automatically deployed.

The command

In Databricks Jobs, open the generated monitoring job and use Run now with different parameters for this enrollment action. Supply the job parameter names and complete JSON below; replace the example identities. This is a cloud operation.

Run this project's existing monitoring job once with job parameter monitoring_action=enroll_serving and monitoring_serving_enrollments set to a JSON list. One entry, for an endpoint whose telemetry prefix is risk, can be the following. It targets test, matching the run command below:

[
  {
    "environment": "test",
    "project": "risk",
    "model_name": "models.risk.churn",
    "model_version": "2",
    "serving_endpoint": "risk-v2",
    "source_table": "logs.serving.risk_payload",
    "prediction_table": "logs.serving.risk_payload",
    "execution_engine": "spark",
    "reference_namespace": "ops.monitoring",
    "label_table": "labels.production.serving_outcomes",
    "result_available_at_column": "available_at",
    "performance_policy": {
      "mode": "report",
      "metric": "f1_weighted",
      "direction": "higher",
      "baseline": {
        "kind": "training_holdout",
        "model_version": "2"
      },
      "tolerance": 0.05,
      "tolerance_mode": "absolute",
      "window_hours": 24,
      "label_delay_hours": 6,
      "minimum_labeled_rows": 20,
      "minimum_label_coverage": 0.8,
      "consecutive_windows": 3
    }
  }
]

After enrollment, run an observation from the generated project root:

databricks bundle run monitoring -t test --profile YOUR_PROFILE

Unpause the dedicated Spark monitoring schedule after enrollment. Individual HTTP requests do not launch monitoring jobs; observation reads asynchronously delivered logs on that schedule. Completed performance windows are revisited according to monitoring_revisit_windows so late logs and outcomes can update their evidence. If the target has a dashboard in deployment/monitoring.yml, its native Dashboard task refreshes the published dashboard after the monitoring flow completes with monitoring enabled; development targets never refresh. Without it, new Delta rows alone do not invalidate the dashboard's cached view. sampling_fraction: 1.0 requests full payload capture, but it does not make recorded counts a complete HTTP request count: custom-model 4xx or 5xx errors may produce no inference-log row. The dashboard reports captured successes, failures and latency. Empty or late windows can reflect asynchronous delivery; check serving endpoint telemetry separately before interpreting them.

What you should see

Online serving dashboard

All matching contexts are visible initially; choose Model to narrow them. Monitored version filters the component model's concrete version; Context narrows its monitoring registration. The identity table separately shows Endpoint, Served model, Served version and Branch. A model-set parent can have a different name/version from the monitored component. Explicit mismatched selections stay empty. Only enabled serving enrollments are included.

Table Scope
Selected model and serving scope Selection guidance and number of matching current contexts.
Endpoint and model identity Monitored model/version versus served model/version and branch.
Latest observation per context Latest full observation per matching enrollment and current configuration, ordered by window end, measurement time and report ID.
Observation history All matching saved full observations, with native pagination and an optional history window-end filter; there is no global 100-row cutoff.

Five charts above the detailed tables show captured requests, HTTP error classes, captured error rate, mean/p95 execution latency, and the latency distribution. Each model/version/context has a separate panel; Model (choose one for details), Monitored version and Context apply to all five. The history window-end control also filters the latency matrix, while the latest snapshot stays unchanged. The latency bar chart and matrix retain only the latest 12 observations per identity before the date selection; use the history table to inspect older windows.

Chart Reading the result
Captured requests per window Number of logged requests, including failed responses. One request may contain several prediction rows.
How many errors of each kind? Grouped bars with an HTTP error class legend: 4xx client (blue), 5xx server (red), and Other / class not recorded (gray). Value labels show captured counts. Zero means none captured; a missing class count stays blank. If an older report lacks complete class counts, its entire error total appears in gray. A date plus observation number keeps repeated windows separate.
Captured error rate per window Captured errors divided by captured requests in that same observation. Missing counts, failed observations and zero requests leave it unmeasured.
How long does the model take to answer? Two grouped bars per observation: blue is the average execution time and orange is approximate p95, in milliseconds per request (lower is faster). The last 12 observations per identity are shown separately, including repeated windows. Hover for p50, p99, maximum, timed sample count and exact window timestamps. Small samples can make p95 and p99 equal to the maximum; this is not a separate anomaly.
Where do captured execution times fall? Nine duration ranges across the latest 12 observations per identity. Each valid column totals 100% of non-null timings. A shared 0-100% blue scale allows comparisons; hover for exact counts and window times. Old, failed, empty or invalid summaries produce no cells.

For example, a report with ten captured requests, two 4xx responses and one 5xx response has a 30% captured error rate. If only eight requests have a recorded execution duration, latency percentiles and distribution shares use those eight, including any failed responses with durations. A p95 of 250 ms estimates the 95th percentile of those captured execution durations; it is not the slowest request or an end-to-end service guarantee.

Timings use Spark percentile_approx with accuracy 10,000. The fixed distribution boundaries are 5, 10, 25, 50, 100, 250, 500 and 1,000 ms: the first range is below 5 ms, each middle range includes its lower bound and excludes its upper bound, and the final range is at least 1,000 ms. Null timings are excluded from both the percentiles and distribution. No request payloads are read by dashboard queries; these fields come from saved aggregate reports.

Latest/history tables also show class counts, p50/p95/p99 and timed sample count. Older reports retain the fields originally recorded; missing percentiles are blank in numeric tables and produce no bar. The latency chart's detail tooltip shows Not recorded for missing p50/p95/p99 and timed sample counts; a recorded zero remains zero. Only a new monitoring observation records these fields; refreshing or redeploying the dashboard does not backfill saved reports. The monitoring environment must match the runtime recorded in the registered model artifact. Updating the Core requirement alone can fail that runtime check; prepare a compatible model artifact before upgrading its monitoring jobs.

Recomputing an old window with added serving fields can create a new report identity, so history can contain both calculations. Dashboard charts display saved measurements; traffic and promotion policy are defined on Daily serving rollout.

Observation history also shows prediction rows per captured request when saved. Its denominator includes failed captured requests. Request counts and latency stay per observation: windows may overlap, and model-set branches may describe the same parent requests. Do not sum these rows as unique traffic or average their latency means into an endpoint SLA. Observation status describes the saved monitoring result, not live endpoint availability.

Logging is asynchronous and custom-model HTTP 4xx/5xx errors may be absent, so captured counts do not measure all endpoint traffic. Latency describes model execution durations recorded by the platform, not client/network round-trip time.

Window end describes the request-time observation window; measured_at in the saved dataset is when monitoring calculated the report. Shared health freshness uses the latest captured request time for online serving and the scoring commit time for batch predictions. Neither proves that the feature values themselves are recent: a new request or scoring run can use old source data. Refreshing the dashboard rereads saved results and does not obtain new measurements.

For accuracy, open Model performance and select the matching model, version and monitoring context. Missing or immature actual outcomes remain insufficient evidence; successful HTTP requests alone do not establish prediction quality.

The Online serving dashboard page shows Requests with logging errors beside Captured errors in Latest observation per context and Observation history - windows may overlap. Hover over a point in Captured requests per window to see the same count for that observation. 0 means the saved observation recorded no logging errors; Not recorded means the saved report has no count for it. For example, an observation can have 10 captured requests, no HTTP errors and 2 requests with logging errors: those two requests remain in the request count, but their payloads are excluded from drift and performance. Logging errors are not added to the HTTP error-class chart. Model, version and context selections continue to scope these values; overlapping windows must not be added together.

Common errors and fixes

What you see Next check
awaiting_logs No applicable saved report exists. Check enrollment, the monitoring job and asynchronous log arrival; this is not a healthy measurement.
failed Inspect the saved report and monitoring task error. A failed latest observation clears earlier counts instead of showing an older success.
Blank counts or latency Check the report status and log coverage. Unavailable measurements are not zero requests or zero latency.
no_data Inspect the selected request window and captured logs. An empty window does not prove endpoint health or absence of HTTP traffic.
Captured failures or unexpected latency Inspect endpoint telemetry and serving logs for that endpoint/version. A healthy input-drift status does not certify request success or latency.

Incomplete serving payload logs

logging_error_count counts captured requests whose payload log has one or more logging_error_codes. It counts requests, not individual codes or prediction rows. A logging error can occur even when the endpoint returned a successful HTTP response; it is separate from the captured 4xx/5xx error counts.

Monitoring keeps those requests in captured-request, HTTP-status and available latency summaries. It excludes their unusable payloads from feature and performance calculations and reports the missing-log count. A window that would otherwise be healthy becomes degraded; usable remaining records can still show drift or performance loss. The request charts describe captured telemetry, not a guarantee that every production request was logged.

For traffic rollout, read the incomplete-evidence rule on Daily serving rollout. A logging failure alone is not a retraining trigger; inspect native logging codes and payload-size behavior before changing model settings.

Serving monitoring keeps captured requests with logging_error_codes in the HTTP request and status counts, but excludes their input/output payloads from drift and model-performance calculations. Exact duplicate deliveries count once; conflicting copies of the same request still fail validation. A logging error does not turn a successful HTTP response into an HTTP failure.

An otherwise healthy observation becomes degraded; measured drift and no_data retain their existing status. Capture completeness is reported separately: the saved report's serving.logging_error_count counts affected requests, not individual error codes or prediction rows. The notebook's Observation notes shows the excluded count. For example, two usable predictions and one request with a truncated log retain the two predictions' metrics, with an explicit warning about the missing payload. If every payload is excluded, drift and performance remain unavailable.

Metrics on the retained subset may not represent the missing requests. Logging errors alone do not block retraining: statistically supported drift or a measured performance-policy breach can still request training, subject to the existing minimum data, label coverage, consecutive-window and cooldown checks. Candidate comparison still decides whether a newly trained model qualifies for promotion. The notebook's Performance policy evidence shows the affected request count for that policy's own window and warns when it uses a partial population. With no usable predictions or sufficient labels, the policy remains unavailable.

Missing identity, timestamps or HTTP status, and capture sampling other than 100%, still reject the observation. Old reports are not rewritten; recomputing a window with new summary fields can produce a new report identity. Captured counts describe saved logs rather than every endpoint request.