Observability – Ponder
Skip to content

Observability

Logs, metrics, and indexing status

Logs

Ponder produces logs to help you understand and debug your application.

Dev server logs screenshot

Log level

There are two ways to configure the minimum log level. If specified, the environment variable takes precedence over the CLI flag.

  • Set the PONDER_LOG_LEVEL environment variable
  • Use the --log-level <LEVEL>, -v (debug) or -vv (trace) CLI option
.env.local
PONDER_LOG_LEVEL=trace
Terminal
ponder dev --log-level warn
# or, use the shortcut flag for debug
ponder dev -v

Levels

Log levelExample
silent
errorUnrecoverable RPC error, SQL constraint violation
warnReorg reconciliation, malformed config
info (default)Indexing progress, real-time block processing
debugInternal service lifecycle events
traceQuery-level database logs

User logs

Logs produced by your code (e.g. console.log statements in ponder.config.ts or indexing functions) will always be written to the console. Note that Ponder does catch errors thrown by your code and emits an error log including the original error message and stack trace.

Log format

Use the --log-format <FORMAT> CLI option to set the log format.

Pretty (default)

Terminal
ponder start --log-format pretty
Output
11:54:36 AM INFO  build      Using PGlite database at .ponder/pglite (default)
11:54:36 AM INFO  database   Created table 'Account' in 'public.db'
11:54:36 AM INFO  server     Started listening on port 42069
11:54:36 AM INFO  historical Started syncing 'optimism' logs for 'weth9' with 0.0% cached
11:54:36 AM INFO  historical Started syncing 'base' logs for 'weth9' with 0.0% cached
11:54:36 AM INFO  historical Started syncing 'polygon' logs for 'weth9' with 0.0% cached

JSON

Terminal
ponder start --log-format json

The JSON log format emits newline-delimited JSON objects with properties level, time, service, msg, and (optionally) error.

Output
{"level":30,"time":1717170664426,"service":"build","msg":"Using PGlite database at .ponder/pglite (default)"}
{"level":30,"time":1717170664454,"service":"database","msg":"Created table 'Account' in 'public.db'"}
{"level":30,"time":1717170664458,"service":"server","msg":"Started listening on port 42069"}
{"level":30,"time":1717170664625,"service":"historical","msg":"Started syncing 'base' logs for 'weth9' with 0.0% cached"}
{"level":30,"time":1717170664628,"service":"historical","msg":"Started syncing 'optimism' logs for 'weth9' with 0.0% cached"}
{"level":30,"time":1717170664683,"service":"historical","msg":"Started syncing 'polygon' logs for 'weth9' with 0.0% cached"}

Metrics

Ponder apps publish Prometheus metrics at the /metrics path.

namedescriptiontype
ponder_indexing_total_secondsTotal number of seconds required for indexinggauge
ponder_indexing_completed_secondsNumber of seconds that have been completedgauge
ponder_indexing_completed_eventsNumber of events that have been processedgauge
ponder_indexing_completed_timestampTimestamp through which all events have been completedgauge
ponder_indexing_has_errorBoolean (0 or 1) indicating if there is an indexing errorgauge
ponder_indexing_function_durationDuration of indexing function executionhistogram
ponder_indexing_function_error_totalTotal number of errors encountered during indexing function executioncounter
ponder_historical_start_timestampUnix timestamp (ms) when the historical sync service startedgauge
ponder_historical_total_blocksNumber of blocks required for the historical syncgauge
ponder_historical_cached_blocksNumber of blocks that were found in the cache for the historical syncgauge
ponder_historical_completed_blocksNumber of blocks that have been processed for the historical syncgauge
ponder_realtime_is_connectedBoolean (0 or 1) indicating if the realtime sync service is connectedgauge
ponder_realtime_latest_block_numberBlock number of the latest synced blockgauge
ponder_realtime_latest_block_timestampBlock timestamp of the latest synced blockgauge
ponder_realtime_reorg_totalCount of how many re-orgs have occurredcounter
ponder_database_method_durationDuration of database operationshistogram
ponder_database_method_error_totalTotal number of errors encountered during database operationscounter
ponder_http_server_portPort that the server is listening ongauge
ponder_http_server_active_requestsNumber of active HTTP server requestsgauge
ponder_http_server_request_duration_msDuration of HTTP responses served by the serverhistogram
ponder_http_server_request_size_bytesSize of HTTP requests received by the serverhistogram
ponder_http_server_response_size_bytesSize of HTTP responses served by the serverhistogram
ponder_rpc_request_durationDuration of RPC requestshistogram
ponder_rpc_request_lagTime RPC requests spend waiting in the request queuehistogram
ponder_postgres_pool_connectionsGauge of current connections for PostgreSQL poolsgauge
ponder_postgres_query_queue_sizeCurrent size of the query queue for PostgreSQLgauge
ponder_postgres_query_totalTotal number of queries processed by PostgreSQLcounter

Indexing status

To check the indexing status of your app, use the /status endpoint or the _meta field in the GraphQL API.

Usage

Use the indexing status to quickly confirm that Ponder is working as expected. You can also poll the status to confirm that a specific block number has been ingested by Ponder before refetching a query client-side (for example, in a form submit handler).

HTTP

Request
curl http://localhost:42069/status
Response
{
  "mainnet": {
    "id": 1,
    "block": {
      "number": 20293450,
      "timestamp": 1720823759
    }
  },
  "base": {
    "id": 8453,
    "block": {
      "number": 17017206,
      "timestamp": 1720823759
    }
  }
}

GraphQL

Query
query {
  _meta {
    status
  }
}
Result
{
  "_meta": {
    "status": {
      "mainnet": {
        "id": 1,
        "block": {
          "number": 20293464,
          "timestamp": 1720823939
        }
      },
      "base": {
        "id": 8453,
        "block": null
      }
    }
  }
}

API

The response object contains a property for each chain in your app with the following fields.

fieldtypedescription
idnumberThe chain ID.
block{ number: number; timestamp: number; } | nullThe most recently indexed block, or null if historical indexing is not complete.