Modal logo

Programmatic observability

After deploying an App, you may want to check whether it is receiving traffic, whether calls are succeeding, or whether GPU containers are still running after traffic stops.

The CLI and SDKs expose commands for querying configuration, statistics, metrics, call and request history, and logs. Use these tools to investigate from your terminal or build your own scripts for observability.

This guide covers five types of commands, each answering a different question:

CommandQuestion
infoWhat is deployed, and how is it configured?
statsIs my deployment healthy?
metricsHow has the deployment behaved over time?
calls / requestsWhich calls or requests did the deployment handle?
logsWhat happened inside the containers?

The examples below use a deployed App named example-app with a Function named func and a Server named Server. Replace these names with your own.

What is deployed? 

Start with info to see which Functions and Servers belong to your App:

modal app info example-app

App information includes its Functions and Servers, state, deployment version, creation and deployment times, and the users who created and deployed it.

Next, inspect an individual Function or Server. The CLI commands accept either an APP_NAME/NAME identifier or the fu-... object ID returned by info.

modal function info example-app/func
modal server info example-app/Server

Function and Server information includes the Modal Image, requested hardware resources, execution settings, autoscaling configuration, and any configured networking settings.

Is my deployment healthy? 

Once you have checked the configuration, use stats for a summary of activity over a time window. The default window is the most recent hour; these examples use the last 15 minutes:

modal function stats example-app/func --since 15m
modal server stats example-app/Server --since 15m

For Functions, stats reports counts of successful, failed, and timed-out inputs, along with distributions of execution time and end-to-end latency. Use these statistics to spot increases in errors or slower calls.

The stats command also shows how many containers started or errored during the window, how many were still being created at its end, and distributions of container startup time. These can help you investigate repeated container failures or slow startup.

For Servers, stats reports the same container statistics, along with request latency distributions and request counts by HTTP status code. Servers running supported LLM inference engines, such as SGLang or vLLM, also report inference metrics such as time to first token.

How has the deployment behaved over time? 

While stats summarizes a time window, metrics returns time series for a deployed Function or Server. These show how measurements, such as successful Function calls or GPU utilization, change within that window. Compare series to investigate questions such as whether GPUs are under-utilized during traffic spikes.

First, discover the available series and their units:

modal function metrics example-app/func
modal server metrics example-app/Server

The default CLI output lists the available metrics and their units. To export measurements, select metric groups with --group and choose --json or --csv. We recommend piping the output of this command to a file, especially when called in an agent harness, to prevent exhausting the context with raw data.

In the Python and JavaScript SDKs, use schema() to discover Function metrics and export() to fetch their measurements. In Go, use Metrics.Schema() and Metrics.Export():

modal function metrics example-app/func \
    --group calls --group containers --group cpu \
    --since 1h --bucket-size 1m --json > function-metrics.json
modal server metrics example-app/Server \
    --group requests --group containers --group gpu \
    --since 1h --bucket-size 1m --csv > server-metrics.csv

These examples export the last hour of measurements in one-minute buckets. Each bucket summarizes measurements from that minute.

SDK results contain a series mapping (Series in Go) keyed by metric name. Each series includes its unit, description, and points. A point’s time is the bucket’s start time, and its value is None (Python), null (JavaScript), or nil (Go) when no observation is available.

Which calls or requests did the deployment handle? 

To investigate individual calls or requests, use calls for Functions and requests for Servers:

  • calls lists Function inputs with their statuses, execution times, and container IDs. Add --show-function-call-id to include Function call IDs.
  • requests lists Server HTTP requests with their paths, status codes, and timing information.

List the 10 most recent inputs or requests:

modal function calls example-app/func --tail 10
modal server requests example-app/Server --tail 10

To investigate a specific time window, use --since and, optionally, --until. Add --json to return structured output for use in scripts:

modal function calls example-app/func --since 15m --json
modal server requests example-app/Server --since 15m --json

What happened inside the containers? 

Once you have identified a failure or unexpected behavior, use logs to look for details. Logs contain messages written by your code, exceptions, and system output. These examples fetch logs from the last 15 minutes:

modal function logs example-app/func --since 15m --timestamps
modal server logs example-app/Server --since 15m --timestamps

To fetch the most recent logs instead use --tail in the CLI or logs.tail (Logs.Tail) in Go. to change the count, or --since and --until to select a historical interval.

To watch new logs as they arrive, use --follow in the CLI or logs.stream() (Logs.Stream() in Go). The CLI will follow until explicitly stopped via Ctrl+C; the SDKs expose a timeout parameter.

modal function logs example-app/func --follow --timestamps

SDK streams wait indefinitely by default. To stop after a period without new entries, pass timeout (in seconds) in Python, timeoutMs in JavaScript, or Timeout in Go’s modal.LogStreamParams. Go streams also stop when their context is canceled.

Putting it together 

Monitoring a deployment involves moving from the broad to the specific. For example:

  1. List apps in your environment with modal app list
  2. For a given app, get its info
  3. For one of its Functions, get its stats
  4. If something looks off, like many failed function calls, get the recent calls
  5. Look at the logs for a given call with logs --function-call-id

This is just a suggested workflow; the CLI and SDK features have been designed to be general tools that can be combined to perform arbitrary analyses.