> ## Documentation Index
> Fetch the complete documentation index at: https://nikita-shkoda.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Observability + DX + Testing

> How unified events, logging, DX helpers, and offline/stub clients fit together.

This page ties together Observability, DX helpers, and Testing patterns for a cohesive workflow.

## Observability recap

* Unified events via <code>ActiveSupport::Notifications</code>:
  <code>search\_engine.search</code>, <code>search\_engine.multi\_search</code>, `search_engine.schema.*`, `indexer.*`, and compile‑time summaries (joins/grouping/selection/facets/highlight/synonyms/geo/vector/hit limits).
* Redaction policy ensures no secrets or raw filter literals are logged. Use <code>params\_preview</code> and <code>filter\_hash</code>.
* Optional subscribers:
  * <strong>LoggingSubscriber</strong> (<code>config.logging.mode = :compact|:json</code>)
  * <strong>OpenTelemetry</strong> adapter (<code>config.opentelemetry.enabled = true</code>)

See: <a href="/projects/search-engine-for-typesense/v30/observability">Observability</a>

## DX helpers

* <code>to\_params\_json</code> — redacted JSON, stable keys
* <code>to\_curl</code> — one‑liner with redacted API key
* <code>dry\_run!</code> — compile only; returns `{ url:, body:, url_opts: }`
* <code>explain</code> — extended overview (grouping, joins, presets/curation, conflicts, predicted events)

See: <a href="/projects/search-engine-for-typesense/v30/dx">DX</a>

## Testing offline

* Automatic offline mode: `SearchEngine.client` returns
  `SearchEngine::Test::OfflineClient` in test mode (Rails test or `RACK_ENV=test`)
* Stub client: <code>SearchEngine::Test::StubClient</code> for programmable responses
* Queue responses per verb and assert on captured calls
  (URL, redaction flags, redacted body)
* Event assertions with RSpec or Minitest helpers
* Use `SearchEngine.client` to access the configured client instance

See: <a href="/projects/search-engine-for-typesense/v30/testing">Testing</a>

## Putting it together

```ruby theme={null}
rel = SearchEngine::Book.where(active: true).select(:id, :name).per(5)

# DX preview (no I/O)
rel.dry_run!
puts rel.explain

# Observability: subscribe in tests
events = capture_events { rel.to_a }

# Testing: stub and enqueue
SearchEngine.configure do |c|
  c.client = SearchEngine::Test::StubClient.new
end
stub = SearchEngine.client
stub.enqueue_response(:search, { 'hits' => [], 'found' => 0, 'out_of' => 0 })
rel.to_a
```

## Troubleshooting

* Missing events: enable subscriber/logging or OTel and wrap calls
* Redaction gaps: use <code>params\_preview</code>, never log raw bodies
* DX helpers performing I/O: re‑check call site; helpers are pure

Backlinks: <a href="/projects/search-engine-for-typesense/v30/observability">Observability</a> · <a href="/projects/search-engine-for-typesense/v30/dx">DX</a> · <a href="/projects/search-engine-for-typesense/v30/testing">Testing</a>
