|
| 1 | +--- |
| 2 | +title: "Monitor LanceDB with OpenTelemetry" |
| 3 | +sidebarTitle: "Monitoring" |
| 4 | +description: "Export LanceDB object store request counts, bytes, latency, errors, and throttles to any OpenTelemetry backend." |
| 5 | +icon: "chart-line" |
| 6 | +keywords: ["monitoring", "observability", "opentelemetry", "otel", "metrics", "prometheus", "object store"] |
| 7 | +--- |
| 8 | + |
| 9 | +LanceDB emits internal metrics — currently object store request counts, bytes transferred, request latency, retryable errors, and throttles — and can bridge them into any [OpenTelemetry](https://opentelemetry.io/) backend. Use this to watch how your application interacts with S3, GCS, Azure Blob, or the local filesystem in production: spot latency regressions, catch retry storms, and size your storage tier from real workload data. |
| 10 | + |
| 11 | +The bridge is available in the Python and TypeScript SDKs. It is a thin wrapper over LanceDB's `metrics` recorder; your application supplies and configures the OpenTelemetry SDK. |
| 12 | + |
| 13 | +<Note> |
| 14 | +This page covers LanceDB OSS. LanceDB Enterprise clusters emit their own Prometheus/OpenTelemetry metrics from the server side — see the [Enterprise overview](/enterprise/) for that flow. |
| 15 | +</Note> |
| 16 | + |
| 17 | +## What you get |
| 18 | + |
| 19 | +Once instrumented, LanceDB registers one observable instrument per metric on your `MeterProvider`. The current catalog covers the object store layer: |
| 20 | + |
| 21 | +| Metric | Kind | Description | |
| 22 | +|--------|------|-------------| |
| 23 | +| `lance_object_store_requests_total` | Counter | Total object store requests, labelled by `operation` and `base` (store scheme). | |
| 24 | +| `lance_object_store_request_duration_seconds` | Histogram | Request latency in seconds. | |
| 25 | +| `lance_object_store_bytes_transferred_total` | Counter | Bytes read from or written to the store. | |
| 26 | +| `lance_object_store_retryable_responses_total` | Counter | Requests that returned a retryable error (throttles, transient failures). | |
| 27 | +| `lance_object_store_in_flight_requests` | Gauge | Currently outstanding object store requests. | |
| 28 | + |
| 29 | +The recorder is process-global and pull-based: your configured `MetricReader` collects on its own schedule, so there is no hot-path overhead beyond the atomic aggregation that LanceDB does anyway. |
| 30 | + |
| 31 | +<Note> |
| 32 | +**Histograms are exported Prometheus-style.** OpenTelemetry has no asynchronous histogram instrument, so each histogram surfaces as three observable counters: `<name>_bucket` (with an `le` attribute per bucket boundary, including `+Inf`), `<name>_count`, and `<name>_sum`. Only `_sum` carries the histogram's unit; `_bucket` and `_count` are cumulative sample counts. |
| 33 | +</Note> |
| 34 | + |
| 35 | +## Python |
| 36 | + |
| 37 | +Install LanceDB with the `otel` extra to pull in the OpenTelemetry API, plus an OpenTelemetry SDK of your choice. The SDK is intentionally not bundled — you configure it, its readers, and its exporters however your platform expects. |
| 38 | + |
| 39 | +```bash |
| 40 | +pip install "lancedb[otel]" opentelemetry-sdk |
| 41 | +``` |
| 42 | + |
| 43 | +Call `instrument_lancedb_metrics()` once at startup, before opening any tables. It returns `True` when the recorder is installed and instruments are registered. |
| 44 | + |
| 45 | +```python Python icon="python" |
| 46 | +import lancedb |
| 47 | +from lancedb.otel import instrument_lancedb_metrics |
| 48 | +from opentelemetry.sdk.metrics import MeterProvider |
| 49 | +from opentelemetry.sdk.metrics.export import ( |
| 50 | + PeriodicExportingMetricReader, |
| 51 | +) |
| 52 | +from opentelemetry.exporter.otlp.proto.grpc.metric_exporter import ( |
| 53 | + OTLPMetricExporter, |
| 54 | +) |
| 55 | + |
| 56 | +reader = PeriodicExportingMetricReader(OTLPMetricExporter()) |
| 57 | +provider = MeterProvider(metric_readers=[reader]) |
| 58 | + |
| 59 | +instrument_lancedb_metrics(provider) |
| 60 | + |
| 61 | +# Any object store activity from this point on is now recorded. |
| 62 | +db = lancedb.connect("s3://my-bucket/lancedb") |
| 63 | +``` |
| 64 | + |
| 65 | +If you omit `meter_provider`, LanceDB uses the global provider returned by `opentelemetry.metrics.get_meter_provider()`. |
| 66 | + |
| 67 | +<Warning> |
| 68 | +`instrument_lancedb_metrics()` returns `False` and emits a warning if another `metrics`-crate recorder is already installed in the process. Only one global recorder is permitted, so instrument LanceDB before any other library that installs its own recorder. |
| 69 | +</Warning> |
| 70 | + |
| 71 | +## TypeScript |
| 72 | + |
| 73 | +The Node SDK depends on `@opentelemetry/api` directly, so no extra install step is needed to expose the entry point. You still need an OpenTelemetry SDK to actually export. |
| 74 | + |
| 75 | +```bash |
| 76 | +npm install @opentelemetry/sdk-metrics @opentelemetry/exporter-metrics-otlp-grpc |
| 77 | +``` |
| 78 | + |
| 79 | +```typescript TypeScript icon="square-js" |
| 80 | +import { connect, instrumentLanceDbMetrics } from "@lancedb/lancedb"; |
| 81 | +import { MeterProvider, PeriodicExportingMetricReader } from "@opentelemetry/sdk-metrics"; |
| 82 | +import { OTLPMetricExporter } from "@opentelemetry/exporter-metrics-otlp-grpc"; |
| 83 | + |
| 84 | +const reader = new PeriodicExportingMetricReader({ |
| 85 | + exporter: new OTLPMetricExporter(), |
| 86 | +}); |
| 87 | +const provider = new MeterProvider({ readers: [reader] }); |
| 88 | + |
| 89 | +instrumentLanceDbMetrics(provider); |
| 90 | + |
| 91 | +const db = await connect("s3://my-bucket/lancedb"); |
| 92 | +``` |
| 93 | + |
| 94 | +`instrumentLanceDbMetrics()` also accepts no arguments, in which case it uses the global provider from `@opentelemetry/api`. Calling it more than once is safe: instruments are created only on the first successful call. |
| 95 | + |
| 96 | +## What to watch |
| 97 | + |
| 98 | +A few starting points for dashboards and alerts: |
| 99 | + |
| 100 | +- **Request rate by operation** — `rate(lance_object_store_requests_total[1m])` broken down by `operation` shows read vs. write pressure and helps size ingestion vs. serving traffic separately. |
| 101 | +- **Tail latency** — histogram quantiles over `lance_object_store_request_duration_seconds_bucket` catch object store slowdowns before they surface as query timeouts. |
| 102 | +- **Retryable responses** — a rising `lance_object_store_retryable_responses_total` typically means you are being throttled and should back off or shard writes. |
| 103 | +- **In-flight requests** — a growing `lance_object_store_in_flight_requests` gauge without a matching rise in throughput indicates queueing. |
| 104 | + |
| 105 | +## Where to go next |
| 106 | + |
| 107 | +<Columns cols={2}> |
| 108 | + <Card title="Performance tips" icon="gauge-high" href="/performance"> |
| 109 | + Tune ingestion, indexing, and query patterns once metrics highlight a hot spot. |
| 110 | + </Card> |
| 111 | + <Card title="Storage configuration" icon="wrench" href="/storage/configuration"> |
| 112 | + Configure the object store backends whose requests these metrics measure. |
| 113 | + </Card> |
| 114 | +</Columns> |
0 commit comments