Commit Graph
384 Commits
Author SHA1 Message Date
Ashish Kolhe 7e00c41e06 feat(workflows): call any workflow over an authenticated HTTP endpoint (#15706) 2026-11-03 16:06:09 +00:00
Huaijin 1f710bb22c fix(self-profiles): build CPU self-profiles without jemalloc and tag them with the cluster name (#16070) 2026-10-30 12:03:14 +00:00
HuaijinandHengfei Yang 4d7e566c50 chore(deps): upgrade vortex to 0.90.0 (#15836)
Co-authored-by: Hengfei Yang <hengfei.yang@gmail.com>
2026-10-27 13:21:26 +08:00
Huaijin 613a71d627 fix(promql): read a label the stream lacks as "" in matchers (#15785) 2026-10-26 04:19:05 +00:00
05f1c5a701 feat: Fleet management for OpenTelemetry collectors (#15653)
Co-authored-by: Prabhat Sharma <prabhat@openobserve.ai>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-10-23 14:49:52 +00:00
Ashish Kolheandgithub-actions[bot] ed1b8de97e feat: two-way Slack app (ask OpenObserve from Slack, instance workspace) (#15553)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-10-21 16:07:27 +00:00
Hengfei Yang 1731a15918 chore(deps): upgrade tantivy to 0.27.0 and drop the openobserve fork (#15491) 2026-10-17 15:18:25 +00:00
Huaijin 6664c7a910 chore: upgrade zip to 9.0.3 (#15455) 2026-10-16 11:17:41 +00:00
Huaijin 9e274395aa perf(search): patch sqlparser 0.62 to parse nested function calls in linear time (#15336) 2026-10-14 06:34:22 +00:00
HuaijinandHengfei Yang 7ba60fd5e2 fix: replace promql-parser fork with upstream (#15187)
Co-authored-by: Hengfei Yang <hengfei.yang@gmail.com>
2026-10-08 16:31:19 +08:00
Hengfei Yang 8538e9f787 refactor(metrics): locate MIDX regions from a tail trailer (#14860) 2026-09-24 11:45:00 +00:00
Ashish Kolhe 088aee43e3 fix: close sensitive-data, audit-trail and retention compliance gaps (#14833) 2026-09-24 10:50:04 +00:00
Hengfei YangandHuaijin 6785abe1f8 feat(metrics): generate sample blocks in MIDX during compaction (#14711)
Co-authored-by: Huaijin <haohuaijin@gmail.com>
2026-09-23 16:58:11 +08:00
Hengfei Yang 1313a7a826 chore: move profiling deps behind openobserve-core/profiling (#14785) 2026-09-23 05:22:31 +00:00
IluckySiandHengfei Yang b3e86895f3 feat: ingest OpenObserve self CPU and memory profiles into _meta (#14701)
Co-authored-by: Hengfei Yang <hengfei.yang@gmail.com>
2026-09-23 03:06:27 +00:00
Hengfei Yang 9c33123325 fix(tracing): mark cross-process spans as client and server via tower middleware (#14709) 2026-09-22 00:45:51 +00:00
Huaijin 1685682318 fix(search): keep integer dictionary encoding in the Vortex write strategy (#14511) 2026-09-16 02:43:10 +00:00
Huaijin a7dd30a379 chore: upgrade DataFusion to 55.1.0 and Vortex (#14480) 2026-09-15 08:55:48 +00:00
IluckySiandHengfei Yang 2df66c4494 feat: support profile ingestion and storage (#13831)
Co-authored-by: Hengfei Yang <hengfei.yang@gmail.com>
2026-09-04 03:05:26 +00:00
Ashish Kolheandgithub-actions[bot] 07807995e4 feat: public status pages built on synthetics checks (#13974)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-08-31 11:45:51 +00:00
Huaijin 732f721d04 fix: vortex Utf8-typed string statistics broke Utf8View interval analysis (#14011) 2026-08-28 08:48:15 +00:00
Huaijin 37e5f55684 feat(metrics): .midx series index for TSID-major files and PromQL pruning through it (#13899)
The query half of the TSID-major layout: #13882 wrote `tsid-major-v3-*`
files ordered by `(__hash__, _timestamp)`; this PR adds the `.midx`
series index next to them and makes PromQL prune through it. Supersedes
the remaining scope of #13839.

## Write side

- Every `tsid-major-v3-*` file written by the hour-end merge gets a
`.midx` series index (Arrow IPC + zstd), stored like the Tantivy index
under a derived root distinct from the data tree:
`files/{org}/metrics/{stream}/{date}/{hour}/tsid-major-v3-{id}.parquet`
→ `files/{org}/midx/{stream}/{date}/{hour}/tsid-major-v3-{id}.midx`
(Tantivy: `files/{org}/index/{stream}_{type}/…/{id}.ttv`): **one row per
contiguous TSID run** — its `row_count: u32` plus the label columns of
the run's first row (source types preserved). Runs tile the data file,
so each run's starting row is the prefix sum of the preceding counts and
is not stored; `__hash__` is excluded (matchers never reference it). The
whole index is one ZSTD-compressed IPC batch. Runs crossing an input
RecordBatch boundary appear as two adjacent entries; query-time range
coalescing makes that representation equivalent without buffering
samples. File and row-group boundaries stay independent of TSID
boundaries.
- `TsidSeriesIndexWriter` lives inside
`search/datafusion/merge/tsid_major.rs` and collects run entries
alongside the Parquet writer (one buffered row per run), encoding and
compressing once at finish. `MergedFile` carries `series_index:
Option<Vec<u8>>`; the compactor uploads it to the `midx/` tree
(compliance mode included).
- `.midx` is intentionally **not** tracked in `file_list`; its path is
derived from the data file's key
(`MetricsFileLayout::series_index_path`) and it is deleted together with
the parent in the delayed-deletion pass (`deleted.rs`); like the
`index/` tree, the `midx/` day directories are covered by retention's
local-disk deletion and the gc tool.

## Query side (PromQL)

- `promql_service::…::tsid_series_index::search` runs where Tantivy used
to, before the metrics table is registered: for each TSID-major file it
loads the `.midx` (concurrent, `2×target_partitions ≤ 64`), projects the
row-range columns plus the matched labels **by name against each series
index's own schema** (label sets / column orders differ between files),
builds the matcher filter **per series index** with
`physical_expr::create_physical_expr` — the exact same predicates as
`apply_matchers` (`matcher_predicates`) — evaluates it over the run
rows, coalesces adjacent/overlapping ranges and attaches them as
`FileSelection::RowRanges` (converted into a Parquet access plan by the
generic helper from #13861, no per-row bitmap).
- **Applied per file**: files of any other layout in the same query
(still-open hours, legacy data, late arrivals) are left in place and
scanned in full. A matched label missing from a series index
over-selects that file; a query whose matchers cannot be evaluated at
all selects the whole file; any series index failure logs and falls back
to a full scan. The final PromQL matchers are always applied, so results
are exact in every case.
- Evaluated selections are cached (LRU, 256 MiB) keyed by account +
series index path + the full matcher set.
- The Tantivy path in the PromQL storage scan is removed
(`convert_matchers_to_index_condition`, index-field plumbing,
`is_add_filter_back` bookkeeping). SQL search is untouched.

## Benchmark (from the #13839 POC, same layout + series index)

478,144,896 rows, 7 CPUs, one-hour PromQL range, step 15s, result cache
off, release + mimalloc:

| Layout | Filter steady median | No-filter steady median | Data files |
Total storage |
|---|---:|---:|---:|---:|
| main, 2 GiB | 695.709 ms | 4.638 s | 88 | 4,925.81 MiB |
| TSID-major + `.midx` | 269.496 ms | 2.793 s | 80 | 1,294.61 MiB |

## Validation

- `cargo fmt --check`; `cargo check` / `clippy` on config, search,
compaction, promql-service, jobs, search_service (`--tests`) clean
- `config tsid_layout` 3 passed (incl. `series_index_path`); `search
tsid_major mode:: merge::` 10 passed (rotation test now also asserts the
series index, exact-run and coalescing series index tests); `compaction
merge deleted` 33 passed; `promql-service` 20 passed + 1 pre-existing
wall-clock flake (`cache::test_promql_cache_set_and_get`, fails
intermittently on main too)
- End-to-end on the #13839 branch (same code paths): hour-end merge
writes N `tsid-major-v3-*` + `.midx`; PromQL takes the series index path
(`selected 39 ranges across 4/4 files`), counts/sums match the synthetic
data, cold-cache identical after restart; a mixed hour (3 major + 1 late
`tsid-sorted`) reports `1 files without a series index left to
tantivy/full scan` with unchanged results; delayed deletion removes
`.parquet` **and** `.midx`
2026-08-21 10:05:46 +00:00
0f4b606e8e feat(synthetics): super-cluster support, then move synthetics to OSS (#13795)
> ### ⚠️ This PR carries four changes — review alongside
openobserve/o2-enterprise#2420
>
> 1. **Super-cluster support (consumer half)** — `8ceb041c43 …
5885c57b3a`.
> 2. **Synthetics OSS migration** — `3a380087a3 … 2596300dbf`, nine
commits — one per build-order step, plus a ninth for fixes found by
running the binary. Moves synthetics out of `o2_enterprise` into
`src/synthetics` (`openobserve-synthetics`), leaving only the
private-VPC-agent path enterprise: `job_api::lease`, `agent/*`, private
locations and the agent-setup install flow. Paired with
openobserve/o2-enterprise#2420.
>
> 3. **Last-check columns read from the results stream** — `6af411e808`,
`e7a3f2c759`. Outside the region whose scheduler runs a check, the list
showed a stale status and a blank Last check / response time:
`last_check_status` replicates only on change, `last_triggered_at` is a
runtime column that does not replicate, and `last_response_ms` was never
populated anywhere. The `synthetics_results` stream already carries all
three and is federated, so the list API reads it instead of replicating
the columns — no queue traffic, no schema change. Best-effort: any miss
keeps the stored DB values, so search being unavailable cannot take the
list down. OSS-only; no enterprise counterpart.
>
> 4. **Check secrets are readable in every region** — `d47a6b2345` (+
o2-enterprise `da71d7ec`). The per-org DEK is minted by each region for
itself, so a check created outside the scheduler region replicated fine
and then silently never ran — `resolve` could not decrypt its
credentials (o2-enterprise#2451). Secrets now cross the queue **in
clear** and the applier re-encrypts them under its own DEK on arrival,
fixing the class at the replication boundary with no key to distribute
or keep in sync.
>
> ⚠️ **This puts customer secrets in plaintext on the inter-region bus**
— a deliberate, recorded trade-off (`o2oi_` ingest tokens and probe
tokens already travel it in clear). Securing the bus itself (TLS on the
gateway links, short retention on secret-carrying subjects) is the real
fix and is **not** in this PR.
>
> ⚠️ **Deploy consumers before producers.** The payload's bytes did not
change, only the meaning of the secret strings, so an un-upgraded
consumer handed the new payload would write customer passwords to disk
in clear. The plaintext-carrying messages therefore use new variant
names (old ones retired as `CreateEncrypted`/`UpdateEncrypted`), so an
old region fails serde and redelivers until upgraded instead of silently
persisting plaintext.
>
> An OSS build can now create, schedule, dispatch to Lambda, take
`resolve`/`ack` and report a check. 7 393 lines moved into the new
crate; 679 lines stay enterprise.
>
> **🛑 Deployment prerequisite (2 of 2).** `ZO_SYNTHETICS_ENCRYPTION_KEY`
must be set to the **same** base64 64-byte value in every region of a
super cluster. Without it synthetics falls back to the per-org DEK and
checks carrying secrets silently fail to run outside the scheduler
region. It is read once at startup and pinned — changing it later
requires a restart, and changing it at all orphans every secret already
encrypted under the old value.
>
> **🛑 Deployment prerequisite (1 of 2).** 14 `O2_SYNTHETICS_*` env vars
are hard-renamed to `ZO_SYNTHETICS_*` with **no fallback read**, and
`ZO_SYNTHETICS_ENABLED` defaults to `false`. A deployment still setting
the old names does not lose tuning — **synthetics stops running
entirely, and the first symptom is checks silently not firing.** Update
env vars *before* rolling the binary.
>
> #### Things a reviewer should look at first
>
> - **`super_cluster_queue` does not depend on
`openobserve-synthetics`** (`cargo tree` → 0), which is what keeps the
applier's loop-prevention guarantee a property of the crate graph rather
than a convention. `a7d5fdd969` adds the assertion that fires if that
ever changes.
> - **`job_upload` was skipping authorization in OSS builds**
(`4c3a0b8f0d`). Unreachable before, because no synthetics route was
registered in OSS; registering it would have made it an unauthenticated
artifact upload. `authorize_probe` is ungated and the bypass is gone.
> - **The dependency edge had to reverse in a single commit**
(`3247d4093f`). Cargo rejects an `o2_enterprise` ↔ OSS package cycle at
the manifest level — `optional` and feature gating do not help — so the
two edges could never coexist, and everything needed for the reversal
lands together. This is why the spec's steps 4 and 5 are one commit and
the config moved earlier than planned.
>
> #### Accepted OSS limitations, all documented in the commits
>
> - No notifications: `notify_check_result` ends in
`alerts::alert::dispatch_notification`, which is enterprise. An OSS
build runs the check and records the run; it has nowhere to send an
alert, exactly as for alerts themselves.
> - No per-resource RBAC on synthetics, and no OpenFGA ownership tuples
— both are enterprise capabilities across the platform.
> - Private locations are refused with a message rather than created.
> - Agent-served public `net-*` pools are unavailable, so an OSS user
needs a Lambda for every public pool (spec §1).

---

Consumer half of synthetics super-cluster support. **Depends on
openobserve/o2-enterprise#2420** (producer, message types, queue struct)
— and **this side must deploy first**: `MessageType` bytes 83–85 hit a
panicking `unreachable!()` in `From<u8>` on a consumer that does not
know them, which takes down the subscriber task rather than failing one
message.

Based on `fix/lease-claimed-by-2270` (#13785), not `main`, so the diff
is only this work.

## What this fixes

Synthetics writes are not querier routes, so a create lands on ingesters
in whichever region received the request and commits to that region's
Postgres. There is no synthetics topic on the super-cluster queue, so a
check created in a region that runs no scheduler is never seen by the
region that does: the UI shows it enabled, the scheduler has never heard
of it, and nothing reports the gap.

## Commits

| commit | what |
| --- | --- |
| `8ceb041c43` | orphan-detection query + metrics |
| `1c3e10da48` | apply replicated check config |
| `79e6abc052` | apply replicated locations and probe tokens |
| `16d4fa0fde` | render unknown live status instead of a false pending |
| `5885c57b3a` | share the job-cluster predicate |

## Design notes worth reviewing

**Config columns only, and the list is not restated.**
`synthetics_checks::update` rebuilds its `ActiveModel` from the row
already in this region, and `update_mutable_fields` writes only
user-editable columns — so `next_run_at` and the alerting counters keep
local values for free. Hand-listing them in the consumer would duplicate
a list that already exists and let the two drift. A test asserts every
runtime column comes back `Unchanged`.

**`put()` is deliberately unused.** Its insert branch builds from
`build_active_model`, which ends in `..Default::default()` and never
assigns `owner`, `tz_offset` or `next_run_at` — a replicated create
through it would drop the owner and fire a scheduled-later check
immediately.

**`create()` gains `use_given_id`**, matching `table::alerts::create`.
It generated its own uuid, which would have made every region invent a
different primary key for the same check.

**Consumers apply through `infra::table` only.** The publish lives one
layer up in the enterprise service, and `infra` cannot reach the
enterprise crate — that layering is what stops a region re-broadcasting
what it just applied. `source_cluster` does not cover this: it only
stops a region re-consuming its *own* message. Each consumer greps its
own source to keep this true.

**Runtime tables are never replicated** — `synthetics_jobs`,
`synthetics_runs`, `synthetics_agents`, and the locations
`down_notified_at` claim. Asserted at both producer and consumer.

## Known gaps, named not hidden

- If two regions mint a token (or location) with the same name for one
org before either message crosses, the UNIQUE constraint rejects the
arriving row. Local row wins, logged loudly. Erroring would redeliver to
dead-letter, which is worse.
- Pre-existing and untouched:
`write_triggers_stream`/`write_results_stream` in the enterprise reaper
post to `_meta` with the *org's* ingest token, which 401s, and neither
checks response status. Orphan detection fixes this in its own path
only.
- Pre-existing: `create` never sets `tz_offset`, so a new check gets DB
default 0 until its first edit. Replicates identically everywhere, so it
causes no divergence.

## Spec corrections

The spec (`docs/synthetics-lcl/2026-08-11-p1-3-super-cluster-spec.md`,
local notes) is wrong in five places, all found by reading the tree:
§1's invariant evidence (see the enterprise PR), §10's never-run guard,
§4's column list (and it lists six runtime columns — there are seven,
`alerting` is missing), §3's "private rows read-only when remote", and
§7's claim that non-scheduler regions render OFFLINE (they render
`pending`).

## Verification

infra 42, super_cluster_queue 32, jobs 21, web 111/111 vitest +
type-check + design lint, `cargo fmt --check` and clippy clean, full
`--features enterprise` build.

Pre-existing failures on this branch, unrelated and untouched:
`super_cluster_queue::schemas::tests::test_parse_key_{valid,metrics}`,
`infra::table::ratelimit::tests::test_add_batch_missing_rule_id`, and 8
web vitest failures in `buildPayload.spec.ts`/`payloadContract.spec.ts`.

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-20 05:40:34 +00:00
Hengfei Yang 238b0d5262 fix: support zstd-compressed HTTP requests (#13728)
## Summary

- enable tower-http zstd request decompression
- add a router middleware regression test using a real zstd-compressed
JSON payload
- update decompression documentation to list zstd support

## Root cause

The Axum router uses `RequestDecompressionLayer`, but the workspace did
not enable tower-http's `decompression-zstd` feature. Requests from
clients such as Vector configured with `compression: "zstd"` were
therefore rejected with `415 Unsupported Media Type` before reaching the
ingestion handler.

## User impact

Vector HTTP sinks can continue using zstd compression when sending
batches to OpenObserve ingestion endpoints.

## Validation

- `cargo fmt --all -- --check`
- `cargo test -p openobserve-api-http
handler::http::router::decompression::tests`
- `git diff --check`

Fixes #13726
2026-08-11 10:33:44 +00:00
Pinguladora 575e8ea4d5 feat: add zstd compression on OTLP gRPC ingest (#13703)
Design at: #13702 / inline in PR description

Add the `zstd` feature to tonic and enable `accept_compressed(Zstd)` on
the OTLP logs, metrics and trace gRPC services in both `run_common` and
run_router`.

Closes #13702 

## Out of scope
- Response compression  on `send_compressed(Zstd)`
- OTLP/HTTP path (tower-http zstd features)
- snappy would be the better choice under CPU pressure, but tonic has no
snappy support.
2026-08-09 06:02:22 +00:00
Huaijin aaed33543c refactor(search): group DataFusion and Tantivy feature configs (#13664)
## Summary

- add ZO_FEATURE_METRICS_PUSHDOWN_FILTER_ENABLED as an opt-in filter
pushdown switch for metrics queries
- group DataFusion and Tantivy feature configuration under the search
config struct
- move inverted-index result cache sizing, footer caches, skip
threshold, TopN group limit, and bloom footer cache settings from limit
to search
- preserve the moved cache settings' environment variable names and
defaults
- apply the metrics-specific setting to object storage, WAL, and Flight
query contexts

## Testing

- cargo fmt --all -- --check
- cargo check for config, infra, search, tantivy_utils, search_service,
and promql-service
- cargo test -p config every_env_config_default_parses --lib
- cargo test -p config inverted_index_config --lib
- cargo test -p search test_create_session_config --lib
- cargo clippy for all affected crates with -D warnings
2026-08-06 12:05:09 +00:00
Ashish Kolhe 58c7dafa55 fix: notification templates v2 — rich content templates + alert chart images (#13640)
## Summary

Two coupled alerting features:

**1. Notification Templates v2 ("content" templates)**
- New `kind: content` template type: a structured spec (title, body
markdown, fields, links, rows, per-channel title overrides,
severity-filtered visibility) rendered natively per channel — existing
`custom` (raw body) templates are untouched and byte-identical on the
send path.
- Per-channel renderers: Slack Block Kit, Teams (Adaptive Card +
MessageCard), Discord embeds, PagerDuty Events v2, Opsgenie, ServiceNow,
SNS, HTML/text email, and a stable machine `webhook` envelope.
- Escaping is renderer-owned (mrkdwn entities, HTML encoding, markdown
stripping) with a shared URL-scheme allowlist; golden-fixture tests per
channel.
- Template editor UI: guided content form (fields/links row tables,
compact rows config, channel title overrides), live preview panel with
per-channel preview + payload tab, test-send (rate-limited,
`[TEST]`-marked).
- Migration `m20260802_000001_add_template_kind`; prebuilt default
template + org backfill.

**2. Alert chart images (stateless, storage-free)**
- Alerts can attach a metric-history chart PNG rendered from the
triggers self-reporting stream (`actual_value` per evaluation), with
warn/crit threshold lines and the firing point appended.
- Zero storage: the chart URL *is* the data — deflate+base64url payload
signed with truncated HMAC-SHA256 (org-bound, expiry embedded), rendered
on fetch by the HTTP-terminating node (`GET
/api/v2/{org}/alerts/charts/render`). Signature verified before inflate
(decompression-bomb guard), uniform 404s, per-node render semaphore +
per-minute query budget + small LRU.
- Renderer: plotters + embedded DejaVu Sans (Bitstream Vera license
included), gap-broken line segments so sparse evaluation history doesn't
draw false plateaus.
- Channel delivery: Slack image block, email inline CID (no remote
fetch), Discord multipart attachment, Teams/PagerDuty image URLs;
per-destination opt-in via template chart flag.
- Slack layout live-A/B'd on a real channel: content + buttons/chart
split across two same-colored attachments so the severity stripe spans
everything while staying under Slack's "Show more" fold; clickable link
title; "View in OpenObserve" keeps a reserved primary-button slot.
- Slack image-delivery fallback: Slack validates image URLs server-side
and rejects the ENTIRE message with `400 invalid_attachments` when its
proxy can't fetch the chart (VPN-only/private `ZO_WEB_URL`) —
live-verified. On that rejection the send strips the image blocks and
resends once (alert always delivers), sets a process-wide flag so later
sends pre-strip (reachability is deployment-wide, not per-destination),
and re-probes hourly. Zero config; observable via `slack_image_rejected`
/ `slack_image_pre_stripped` metric events.

## Testing
- 147 notification unit tests (resolve/render/preview/test-send incl.
per-channel goldens and hostile-input/injection coverage), 8 chart
payload tests, renderer PNG tests.
- Live-verified end to end: Slack (Slackbot chart fetches ~100ms,
cache-immutable semantics), SES email inline image, multi-severity
firing scenario (warning→critical) with correct threshold lines.
- FE: AddTemplate/ContentTemplateForm/preview specs; UX audit pass with
fixes.
- `cargo clippy -D warnings` clean in both OSS and enterprise
arrangements.

## Enterprise pairing
Must merge together with openobserve/o2-enterprise#2353 (workspace
twin-manifest mirror for the new OSS deps).
2026-08-06 04:47:02 +00:00
Huaijin 872ceb724a refactor: move search and compaction optimizations to OSS (#13583)
## Summary

- move optimized Tantivy simple and multi histogram collectors into the
open-source config crate
- move general broadcast join eligibility, rewrite, execution, TmpExec
codec, and shared async state into open-source search
- enable enrichment-table broadcast join in OSS, including join
reordering, remote-scan rewriting, EnrichmentExec, and its physical-plan
codec
- move AggregateTopkExec, its heap/sort streams, physical optimizer
rule, and codec into open-source search
- replace the enterprise-only Aggregate TopK settings with OSS-owned
`ZO_DF_USE_AGG_TOPK_HEAP` and `ZO_DF_TOPK_HEAP_MAX_LIMIT` settings
- move `approx_topk` and `approx_topk_distinct` UDAFs into open-source
search and register them in both OSS and enterprise builds
- omit the Aggregate TopK benchmark, benchmark documentation, and
data-generator example from OSS
- move Bloom term extraction, post-merge build, `.bf` writing, and
orphan cleanup into the OSS compaction crate
- run the Bloom build path after compaction in both OSS and enterprise
builds, with non-fatal fallback to regular Tantivy search
- move the direct `tantivy` and `object_store` dependency ownership
required by Bloom building into OSS compaction
- enable sorted timestamp, block, RANK, broadcast join, Aggregate TopK,
approximate TopK, and Bloom paths in both OSS and enterprise builds
- retain cross-super-cluster TmpExec fetching behind the enterprise
feature
- remove feature-gated enterprise imports and use the shared OSS
implementations
- add fastdivide for histogram bucket computation
- resolve the duplicated SLO test attribute warning and remove an unused
test-only alert-state migration helper

## Tests

- `cargo fmt --all -- --check` (OSS and enterprise)
- `cargo clippy --locked -p search --lib -- -D warnings`
- `cargo clippy --locked -p compaction --lib -- -D warnings`
- `cargo clippy --locked -p o2_enterprise --lib -- -D warnings`
- `cargo test -p config tantivy::query::histogram_collector --lib` (21
passed)
- `cargo test -p search tantivy::search::tests --lib` (9 passed)
- `cargo test -p search enrichment --lib` (2 passed)
- `cargo test -p search broadcast_join --lib` (7 passed)
- `cargo test -p search join_reorder --lib` (8 passed)
- `cargo test -p search datafusion::distributed_plan::codec::tmp_exec
--lib` (1 passed)
- `cargo test -p search aggregate_topk --lib` (7 passed)
- `cargo test --locked -p search approx_topk --lib` (8 passed)
- `cargo test --locked -p config meta::slo --lib` (371 passed)
- `cargo test --locked -p infra bloom --lib` (30 passed)
- `cargo check --locked -p config --tests`
- `cargo check --locked -p infra --tests`
- `cargo check --locked -p search --lib`
- `cargo check --locked -p compaction --lib`
- `cargo check --locked` (OSS root package)
- `cargo check --locked --workspace` (enterprise workspace)
- `cargo check --offline -p compaction --lib --features enterprise` with
the paired repositories
- `cargo check --offline -p openobserve --no-default-features --features
enterprise` with the paired repositories

Companion enterprise cleanup PR:
https://github.com/openobserve/o2-enterprise/pull/2326
2026-08-03 06:20:37 +00:00
Huaijin 015a20a184 refactor: remove HTTP API compatibility re-exports (#13560)
## Summary

- remove the HTTP request/model compatibility re-exports introduced by
the domain crate split
- migrate router, OpenAPI, enterprise action-server, and
integration-test callers to the crates that own each API
- remove the ingest Content-Type re-export and declare the direct
root/test dependencies
- delete the pure `handler::http::models` facade module

## Validation

- `cargo fmt --all -- --check`
- `cargo clippy -p openobserve-api-ingest -p openobserve-api-http -- -D
warnings`
- `cargo test --test integration_test --no-run`
- `cargo check -p openobserve --no-default-features`
- enterprise overlay: `cargo test --offline --workspace
--no-default-features --features enterprise --no-run`
- cloud overlay: `cargo test --offline --workspace --no-default-features
--features cloud --no-run`
- `git diff --check`
2026-07-31 06:24:43 +00:00
Huaijin 6c029f7a2c chore(deps): bump vortex to 1cb48912 (#13540)
Bumps the `openobserve/vortex` pin from `57ffbf2b` to `1cb48912` in the
workspace manifest.

## Upstream API changes handled

- Arrow interop moved into a dedicated `vortex-arrow` crate, surfaced as
`vortex::arrow`. `vortex::array::arrow::*` and `vortex::dtype::arrow::*`
no longer exist, so `FromArrowArray`, `FromArrowType`, `ToArrowType` and
`ArrowSessionExt` are now imported from `vortex::arrow`.
- `ToArrowType` is no longer in scope implicitly; added the explicit
import where `DType::to_arrow_schema()` is called.
- The `vortex::compressor` facade narrowed to `BtrBlocksCompressor`,
`BtrBlocksCompressorBuilder`, `Scheme`, `SchemeId`. `SchemeExt` and the
scheme list are no longer re-exported there, so `search` takes a direct
`vortex-btrblocks` dependency (same git rev) for `SchemeExt` /
`schemes::integer::IntDictScheme`, which the UTF8 compressor uses to
exclude the int-dict scheme.

No behavior change intended — the compressor configuration and write
strategies are identical.

## Verification

- `cargo check --workspace --all-targets` clean
- `cargo fmt --all -- --check` clean
- `cargo test -p search --lib datafusion::vortex` — 6 passed
- `cargo test -p tantivy_utils --lib vortex` — 3 passed
- `cargo test -p config --lib utils::parquet` — 21 passed

Paired enterprise PR (same branch name):
https://github.com/openobserve/o2-enterprise/pull/2303
2026-07-29 12:42:44 +00:00
Huaijin ef3617f157 refactor: split HTTP APIs by domain (#13479)
## Summary

- organize API crates under
`src/api/{common,grpc,http,ingest,management,pipelines,search}`
- keep ingest, management, pipelines, and search independent from one
another; compose them only in the HTTP frontend
- move pattern APIs into search and simplify `main.rs` wiring
- update workspace manifests, lockfile, integration tests, and
cargo-deny entries
- keep `web/` unchanged

## Validation

- `cargo fmt --all -- --check`
- `cargo clippy --all-targets -- -D warnings`
- `cargo deny check licenses`
- enterprise overlay: `cargo build --no-default-features --features
enterprise`
- enterprise overlay: `cargo build --no-default-features --features
cloud`
- enterprise overlay: `cargo clippy --all-targets -- -D warnings`

The matching `o2-enterprise` overlay PR will be linked after creation.
2026-07-27 12:12:59 +00:00
Huaijin d165299bcd refactor: extract TLS and node services from core (#13449)
## Summary

- extract TLS certificate loading and client configuration from
openobserve-core into openobserve-tls
- extract node discovery, cluster information, ingester gRPC channel
selection, and Tokio runtime metrics into openobserve-node
- update Core, API, API Management, Jobs, and the root binary to depend
on the new crates directly
- preserve one-way dependencies: openobserve-core depends on
openobserve-node, while openobserve-node does not depend on Core
- register both crates in the enterprise workspace overlay

## Validation

- cargo test -p openobserve-node --lib
- CARGO_INCREMENTAL=0 cargo clippy -p openobserve-node -p
openobserve-core -p openobserve-jobs -p openobserve-api-management -p
openobserve-api -p openobserve -- -D warnings
- RUSTFLAGS="--cfg tokio_unstable" cargo check -p openobserve-node
- enterprise overlay: CARGO_INCREMENTAL=0 cargo clippy -p openobserve
--no-default-features --features enterprise -- -D warnings
- cargo deny check licenses --hide-inclusion-graph
- cargo fmt --all -- --check
- git diff --check

Companion enterprise PR: openobserve/o2-enterprise#2267
2026-07-24 16:56:37 +00:00
Huaijin 3f9ce27542 refactor: split service dependencies out of core (#13446)
## Summary

- decouple stream cleanup from enrichment-data and remove the transitive
compaction/DataFusion dependency from stream
- extract sourcemaps and organization storage services from core into
dedicated crates
- extract GitHub built-in regex access and model pricing into
openobserve-builtins
- rename pipeline and organization-storage persistence modules from
store to db
- remove now-unused direct dependencies from core
- synchronize the enterprise workspace overlay in
openobserve/o2-enterprise#2266

## Validation

OSS:

- cargo check -p openobserve-builtins -p openobserve-core -p
openobserve-jobs -p openobserve-api
- cargo test -p openobserve-builtins --lib
- cargo test -p openobserve-builtins --doc
- cargo clippy -p openobserve-builtins -- -D warnings
- cargo check -p openobserve-org-storage --features enterprise

Enterprise overlay:

- copied ../o2-enterprise/Cargo.toml.openobserve over Cargo.toml
- cargo fmt --all -- --check
- cargo check --all-targets --no-default-features --features enterprise
- cargo clippy --all-targets --no-default-features --features enterprise
-- -D warnings

The default enterprise + vectorscan build was attempted and reached
vectorscan-rs-sys, but the validation host does not have cmake
installed. The enterprise-only build and clippy run completed
successfully.
2026-07-24 09:15:14 +00:00
Huaijin df9d35c3d3 feat(search): move vortex support from enterprise into open source (#13434)
## Summary

Moves Vortex file-format support out of the enterprise build and makes
it a core, always-compiled capability in open source.

- **Code move**: the enterprise `search/vortex.rs` module
(`Utf8Compressor`, `VORTEX_RUNTIME`, `write_vortex`,
`generate_vortex_access_plan`, plus its unit tests) now lives at
`src/search/src/datafusion/vortex.rs`; the three call sites
(`merge/downsampling.rs`, `merge/mod.rs`, `table_provider/helpers.rs`)
reference the local module.
- **Feature removal**: the `vortex` cargo feature is deleted from the
root and all 11 sub-crate manifests. All `#[cfg(feature = "vortex")]` /
`#[cfg(all(feature = "enterprise", feature = "vortex"))]` gates and
their "requires the vortex feature" error branches are gone —
`FileFormat::Vortex` match arms compile unconditionally in config,
search, and tantivy_utils.
- **Dependencies**: `vortex` / `vortex-datafusion` are now direct git
dependencies (`openobserve/vortex` rev `57ffbf2b`, the same rev the
enterprise workspace pinned); the empty dependency-resolution stub
crates under `src/enterprise/vortex{,-datafusion}` are deleted.

Companion PR in o2-enterprise removes the vortex module/feature there
and syncs `Cargo.toml.openobserve`; that PR should merge together with
(or right after) this one, since its template relies on this repo no
longer declaring the feature.

## Verification

- `cargo check --workspace` (OSS, default features) passes
- `cargo check -p search -p tantivy_utils -p config --all-targets`
passes (vortex tests compile)
- Enterprise combined workspace (`Cargo.toml.openobserve` swapped in)
`cargo check -p openobserve` passes
- `cargo fmt` applied to touched crates
2026-07-24 04:08:59 +00:00
Huaijin 15275ae7cf refactor: split core foundation services (#13405)
## Summary

This PR begins decomposing `openobserve-core` into focused service
crates while preserving the existing application behavior and dependency
direction.

It extracts six independently owned areas:

- `ingestion-common`: shared ingestion contracts and response types
- `schema`: schema inference, validation, evolution, and persistence
helpers
- `compaction`: merge, retention, and compaction services
- `enrichment-data`: enrichment-table lifecycle and runtime support
- `promql-service`: PromQL service orchestration
- `stream`: stream metadata, settings, retention, and lifecycle
operations

## What changed

- registered the extracted crates in the workspace and propagated
enterprise/cloud/vectorscan/vortex features
- moved implementations out of Core and updated API, Jobs, query, and
queue consumers to use the new crates
- removed Core facade aliases for extracted crates and converted
remaining callers to direct crate paths
- retained the small cross-service stream-delete coordinator in Core for
now because it still coordinates Pipeline and Alert cleanup
- restored required root/Core dependencies after validating the full
enterprise build
- added the missing `anyhow` dependency for enterprise-only
`search_service::search_jobs`
- updated the lockfile for the new crate dependency graph

## Dependency direction

The extracted crates do not depend on `openobserve-core`. Core remains a
temporary upper-level consumer while the remaining domain services are
split incrementally.

```text
ingestion-common -> common/config
schema           -> ingestion-common/db/infra
stream           -> schema/enrichment-data/db/infra
compaction       -> schema/search/search-service/db/infra
openobserve-core -> ingestion-common/schema/stream/compaction/...
api/jobs         -> openobserve-core + extracted services
```

## Enterprise compatibility

The private OpenObserve manifest was updated in
openobserve/o2-enterprise#2257 to register the extracted workspace
members and dependencies.

Related Enterprise PR:
https://github.com/openobserve/o2-enterprise/pull/2257

## Validation

OSS manifest:

- `cargo fmt --all -- --check`
- `cargo clippy -- -D warnings`

Using `o2-enterprise/Cargo.toml.openobserve` as the OpenObserve root
manifest:

- `cargo check --no-default-features --features enterprise`
- `cargo check --no-default-features --features cloud`
- `cargo clippy --workspace --no-default-features --features enterprise
-- -D warnings`
- `cargo clippy --workspace --no-default-features --features cloud -- -D
warnings`

Enterprise repository:

- `cargo fmt --all -- --check`
- `cargo clippy -- -A clippy::question-mark -D warnings`

All checks above pass in the development profile.
2026-07-23 15:47:07 +00:00
Huaijin eec3207c24 refactor: decouple API compilation from web assets (#13403)
## Summary

- move embedded UI routing from `openobserve-api` into the existing
`web` crate
- inject `web::ui_routes` into the API router while preserving the
existing `ui_enabled` and missing-`dist` behavior
- make `openobserve-api` and `web` sibling dependencies so they can
compile independently

## Validation

- `cargo fmt --all --check`
- Enterprise manifest: `cargo clippy --workspace --no-default-features
--features enterprise,mimalloc -- -D warnings`
- `cargo clippy --workspace -- -D warnings`
- `cargo clippy -p web --all-targets -- -D warnings`
- `cargo test -p web`
- `cargo deny check licenses`
2026-07-23 09:13:32 +00:00
Huaijin 6adcae3a1f refactor: remove crate compatibility re-exports (#13381)
## Summary

- remove compatibility re-exports introduced during the recent crate
refactors
- migrate callers to the crates that own each API
- delete five pure facade modules and add the required direct crate
dependencies
- keep OSS and enterprise manifests aligned

## Validation

- cargo fmt --all -- --check
- cargo clippy --workspace -- -D warnings
- cargo test --locked --workspace --no-run
- enterprise overlay: cargo test --offline --workspace
--no-default-features --features enterprise --no-run
- enterprise overlay: cargo clippy --offline --workspace
--no-default-features --features enterprise -- -D warnings
- git diff --check

Companion enterprise PR uses the same branch name:
codex/remove-refactor-reexports.

## TODO / Follow-ups

- [ ] **Re-establish the pipeline write-guardrail lost with
`db::pipeline`.** That module was not a pure facade: it re-exported only
the six read-only accessors from `infra::pipeline` and its doc comment
recorded the invariant that *mutations must go through
`service::pipeline::store`* (which keeps the `ExecutablePipeline` caches
and the coordinator/super-cluster watch events in sync). Deleting it
points callers straight at `infra::pipeline`, which also exposes
`put`/`delete`/`drop_table` with no guardrail. Decide the layering and
enforce it:
- **Reads** may hit `infra` directly (raw persistence, no side effects).
- **Writes** must go through the wrapper that persists *and* emits the
coordinator/super-cluster event + refreshes the in-memory cache. That
wrapper is `db::<entity>::{set,delete}` for most entities (e.g.
`db::alerts::alert::set` →
`infra::coordinator::alerts::emit_put_event`), but for pipeline it is
`core::pipeline::store` (not `db`), because the
`STREAM_EXECUTABLE_PIPELINES` cache it maintains is a core-level
construct the `db` crate cannot build. The super-cluster receiver
(`super_cluster_queue::pipelines`) is the one sanctioned caller of
`infra::pipeline::{put,delete}` directly, and it manually pairs each
with `emit_*_event` to avoid a re-broadcast loop.
- Net invariant to protect: never call `infra::pipeline::{put,delete}`
without emitting the coordinator event — i.e. nowhere outside
`core::pipeline::store` and the super-cluster handler. A bare `infra`
write leaves in-memory caches stale until restart (see the warning
comment still live at `src/core/src/org_cleanup.rs:484`).
- [ ] Consider whether the pipeline write-wrapper living in
`core::pipeline::store` while every other entity's lives in
`db::<entity>` is worth unifying, or at least documenting as an
intentional exception.
2026-07-23 02:24:31 +00:00
Huaijin f6560d7d02 refactor: decouple search from core (#13338)
## Summary
- extract search orchestration from core into the `search_service` crate
- keep the existing low-level `search` crate and directory names
unchanged
- extract usage reporting and audit services into dedicated crates
- replace global async function pointers with narrow publisher traits
- keep compatibility re-exports while updating workspace dependencies
and feature propagation

Companion enterprise PR:
https://github.com/openobserve/o2-enterprise/pull/2229

## Validation
- `cargo check --workspace`
- `cargo check -p search --tests`
- `cargo test -p search_service --lib` (184 passed)
- enterprise non-release build with the paired `o2-enterprise` manifest
- `cargo fmt --all -- --check`
- `git diff --check`
2026-07-22 10:36:09 +00:00
Huaijin e236c7e653 refactor: extract database layer into db crate (#13340)
## Summary

- extract persistence, cache, watcher data access, and DB service
modules from openobserve-core into a standalone workspace db crate
- keep application orchestration that depends on search, organization
provisioning, and other Core services behind the existing Core db facade
- preserve existing call paths through re-exports while making the
dependency direction openobserve-core -> db
- move HTTP error mapping back to the Core/API boundary so db has no
direct axum dependency
- avoid provider/provisioner callback traits and function-pointer hooks

## Validation

- cargo fmt --all
- cargo check --all-targets
- cargo check -p db --all-targets
- Enterprise workspace: cargo check --all-targets --offline
- Enterprise workspace: cargo check -p db --all-targets --features
enterprise --offline

Companion Enterprise manifest PR: openobserve/o2-enterprise#2230.
2026-07-22 07:21:34 +00:00
Huaijin b835ff2f86 refactor: consolidate vrl/js into transform crate and extract super_cluster_queue crate (#13324)
## Summary

Two crate-split refactors continuing the workspace decomposition:

**1. `transform` crate (renamed from `openobserve-vrl`, `src/vrl` →
`src/transform`)**
- Now the only crate depending on `vrl`, `vector-enrichment` and
`rquickjs` directly; downstream crates use `transform::vrl::` /
`transform::vector_enrichment::` re-export paths and drop their direct
dependencies
- The QuickJS runtime (`common/utils/js.rs`) moved into `transform::js`
(js_security checks gated behind the crate's `enterprise` feature);
`apply_vrl_fn`, `convert_to_vrl`/`convert_from_vrl` and
`TRANSFORM_FAILED` moved from core
- Exception: `src/config` keeps its direct `vrl` dependency (it sits
below `transform` in the dependency graph)

**2. `super_cluster_queue` extracted from the root crate into a
workspace member**
- Only depends on `openobserve-core`, `infra`, `config` and
`o2_enterprise`, so it builds in parallel with `api` and edits no longer
recompile the root crate (which re-embeds `web/dist` on every rebuild)
- Gated behind its own `enterprise` feature — compiles as an empty crate
in OSS builds so `cargo --workspace` keeps working against the
`o2_enterprise` stub; `vectorscan` wired through for `re_pattern.rs`
- Root `lib.rs` re-exports the crate, so
`openobserve::super_cluster_queue::init()` in `main.rs` is unchanged

Pairs with the `Cargo.toml.openobserve` template sync PR in
o2-enterprise (must merge together).

## Test plan

- `cargo check --workspace --all-targets` (OSS) passes
- `cargo check -p openobserve --no-default-features --features
enterprise` with the synced enterprise template passes
- `cargo clippy -p super_cluster_queue --features enterprise,vectorscan`
— zero warnings
- `cargo clippy -- -D warnings` (CI invocation) passes; `cargo fmt
--all` clean
2026-07-21 08:14:25 +00:00
Hengfei Yang 33d1da9b6e feat: move MCP server to OSS (#13272)
## Summary

- move the MCP protocol, tool discovery, schema simplification,
execution, and response filtering implementation into a new OSS
`openobserve-mcp` workspace crate
- enable the real MCP POST, GET, and DELETE handlers in community builds
- initialize the MCP tool catalog from the OpenAPI document for every
edition
- keep OAuth authorization-server discovery enterprise-only because it
depends on Dex
- add OSS handler and OpenAPI initialization coverage

Closes #13266
Design at: #13266

## Impact

Community users can connect MCP clients directly to OpenObserve and use
the OpenAPI-backed tool catalog. Enterprise builds continue to use the
same MCP implementation from the OSS workspace crate.

Companion PR openobserve/o2-enterprise#2206 removes the old private copy
and updates the enterprise workspace overlay.
2026-07-20 09:21:05 +00:00
Huaijin 88c41fda6b chore: update cargo.toml (#13271) 2026-07-20 04:47:05 +00:00
Huaijin 3b44da3eee refactor: extract shared common crate (#13252)
## Summary

- introduce a `common` workspace crate for shared metadata,
infrastructure helpers, and utilities
- keep service-backed code in `openobserve-core` while preserving the
existing `common` compatibility namespace
- flatten `src/core/src/service/` into the standard `src/core/src/`
module layout without using `#[path]`
- retain `service::*` as compatibility re-exports from `service.rs`
- move cipher request/response types from core into the search crate
while preserving `openobserve_core::cipher`
- remove unused Cargo dependencies from workspace crates

Enterprise companion:
https://github.com/openobserve/o2-enterprise/pull/2202

## Validation

- `cargo check --workspace --all-targets`
- `cargo clippy -p common -p openobserve-core -p search --lib -- -D
warnings`
- common crate unit tests: 271 passed, 4 ignored
- enterprise overlay: `cargo check -p openobserve-core --features cloud`
- migrated cipher tests: 8 passed
- `cargo deny check licenses`
- `cargo fmt --all -- --check`
- `git diff --check`
2026-07-17 13:58:24 +00:00
Huaijin 66ca3d2439 refactor: extract PromQL evaluator into dedicated crate (#13239)
## Summary

- add a dedicated promql workspace crate for parsing and evaluation
- keep cluster routing, cache, WAL, file-list, and request orchestration
in openobserve-core
- preserve existing service::promql call sites through a compatibility
facade; the facade re-exports an explicit item list (not a glob), and
the promql search orchestration in core depends on the promql crate
directly
- inject enterprise query cancellation through TableProvider instead of
coupling the evaluator to core search state
- replace the core regex-UDF dependency with DataFusion regexp_like
expressions

## Companion PR

- openobserve/o2-enterprise#2198 updates the enterprise workspace
override for the new promql crate

## Validation

- cargo fmt --all -- --check
- cargo check --workspace
- cargo clippy -p promql --all-targets -- -D warnings
- cargo clippy -p openobserve-core
- cargo test -p promql: 363 passed
- verified the promql dependency tree has no openobserve-core or search
dependency
- cargo check -p o2_enterprise --lib in the paired private workspace

## Notes

The evaluator moves atomically in this PR. The existing
service::promql::search subtree remains in core because it owns
OpenObserve-specific orchestration rather than PromQL evaluation.

The two web/ file changes only update source-path references in comments
that pointed at the moved Rust files (src/service/promql/... ->
src/promql/src/...).
2026-07-17 02:46:02 +00:00
Huaijin 059058519e refactor: make search engine sources crate-independent (#13234)
## Summary

- add `src/vrl` as a leaf package named `openobserve-vrl` with Rust path
`openobserve_vrl`
- move `QUERY_FUNCTIONS`, enrichment-table ownership, GeoIP/MaxMind
table registration, VRL compiler configuration, and shared runtime
helpers into `openobserve-vrl`
- let ingestion, jobs, core, and search use the shared VRL integration
without depending on one another
- keep DataFusion UDF registration direct through `Sql.org_id`; no
`QueryExecutionContext`, `PreparedQueryTransform`, or
`prepare_query_transforms`
- move the cipher registry, query parameters, and file-cache helpers to
`search`
- move the generic file downloader implementation to `infra`
- add feature forwarding for the `search` crate
- keep compatibility re-exports for existing API, ingestion, gRPC, jobs,
and Enterprise call sites

Enterprise companion:
https://github.com/openobserve/o2-enterprise/pull/2196
2026-07-16 13:50:35 +00:00
Huaijin d6166aac49 perf: speed up embedded web asset compilation (#13233)
## Summary

- upgrade rust-embed-for-web from 11.3 to 11.4.1
- disable unused compile-time gzip and Brotli generation for embedded UI
assets
- keep browser response compression through the global tower-http
CompressionLayer

Related enterprise PR:
https://github.com/openobserve/o2-enterprise/pull/2192

## Benchmark

Clean release-profiling build with mimalloc:

- before: 21m 13s
- after: 15m 45s
- improvement: 5m 28s, or 25.8%

Focused web crate compilation improved from 546.66s to 98.55s.

## Testing

- cargo metadata --locked --no-deps --format-version 1
- cargo clean
- cargo build --features mimalloc --profile release-profiling
2026-07-16 10:44:10 +00:00
Huaijin 5dc22a0ee8 refactor: establish search crate boundary (#13217)
## Summary

- add the minimal `openobserve-search` workspace crate and move shared
search/cache types into it
- move the concrete enrichment table type and cache ownership to the
search crate while retaining normal compatibility re-exports
- move trace schema constants to `config` so the SQL engine no longer
reaches into the traces service
- expose concrete enrichment read functions from `infra` and make
DataFusion call them directly
- construct the stateless VRL runtime directly in the transform UDF
- keep search execution and orchestration in `openobserve-core` for the
later physical moves
- do not introduce `SearchRuntime`, provider traits, callbacks,
`#[path]`, or a search-to-core dependency

This combines the original crate-boundary step with the dependency
cleanup needed before SQL/DataFusion files can move safely.

## Validation

- `cargo test -p openobserve-search --lib` (11 passed)
- `cargo test -p openobserve-core service::enrichment::tests --lib` (19
passed)
- `cargo check -p openobserve --features mimalloc`
- enterprise + mimalloc check using the o2-enterprise overlay
- cloud + mimalloc check using the o2-enterprise overlay
- `cargo fmt --all -- --check`
- strict all-target clippy for `openobserve-search` and
`openobserve-core`
- strict library clippy for `infra`
- dependency check confirms `openobserve-search` does not depend on
`openobserve-core`

`infra --all-targets` currently reports three pre-existing inconsistent
digit-grouping warnings in
`src/infra/src/table/entity/alert_dedup_state.rs`; they are unrelated to
this change and are not included here.
2026-07-16 06:50:01 +00:00
Huaijin 3559d483ae refactor: move web UI asset embedding into a dedicated leaf crate (#13211)
## Problem

Every rebuild of `openobserve-api` re-runs the `RustEmbed` macro
expansion, which embeds `web/dist` (53MB, 1035 files) and compresses
every file with gzip + brotli(q11) — single-threaded, non-incremental,
and it peaks at 8GB RSS. `-Ztime-passes` attributes ~540s of the 769s
api compile to `expand_crate`. Net effect: touching one file in
`openobserve-core` costs a **16m45s** rebuild on an M-series laptop, and
neither incremental compilation nor codegen-unit tuning can help,
because macro expansion happens before both.

## Fix

Move the `#[derive(RustEmbed)]` into a new `src/web` leaf crate with no
workspace dependencies. The embed + compression now only recompiles when
`web/dist` changes; edits anywhere in the backend no longer pay for it.

**Measured (same machine, default profile settings, `--profile
release-profiling`):**

| | before | after |
|---|---|---|
| `openobserve-api` compile | 769s | 231s |
| touch `src/core` → binary | 16m45s | **6m44s** |

## Also in this PR

- **`src/web/build.rs`**: the derive has no file tracking, so a rebuilt
`web/dist` silently shipped stale embedded assets until something else
dirtied the api crate. `rerun-if-changed` on the embed folder fixes
that. The folder is parsed from the `#[folder]` attribute rather than
hardcoded, so it stays correct when the e2e workflows rewrite it. A
missing `index.html` now prints a build warning instead of silently
embedding nothing (the #13197 failure mode).
- **Playwright workflows**: the embed-folder `sed` now targets
`src/web/src/lib.rs` and is guarded with `grep -q`, so a future path
drift fails at the sed step instead of silently shipping an empty UI and
failing at the login page (see openobserve/o2-enterprise#2175 for that
incident).
- **`deny.toml`**: allow the new crate's AGPL-3.0 license (CI runs
`cargo deny check licenses`, which requires a per-crate exception).

## Validation

- `cargo deny check licenses` passes
- Smoke-tested the binary: `/healthz` ok, `/web/` serves `index.html`,
JS assets return 200 from the embedded bundle
- Enterprise overlay resolves: `cargo metadata` passes with the
companion `Cargo.toml.openobserve` change

## Companion

openobserve/o2-enterprise#2184 carries the overlay + e2e workflow sync
on the **same branch name** (`perf/web-embed-crate`); the two should
merge together.
2026-07-16 01:33:42 +00:00
Huaijin bcea47f644 refactor: extract management API crate (#13202)
## Summary

- add the `openobserve-api-management` crate under `src/api_management`
- physically move management handlers, models, and authentication
helpers out of `openobserve-api`
- preserve the existing API module paths through re-exports
- move shared stream permission checking into `openobserve-core` to
avoid a management-to-query dependency
- allow the new crate's `AGPL-3.0` license in `deny.toml` (fixes the
cargo-deny `check` job)
- keep router, OpenAPI generation, and rate-limit path mapping in
`openobserve-api`

## Dependency boundary

`openobserve-api-management` depends on `openobserve-api-common` and
`openobserve-core`; it does not depend on `openobserve-api-query`.

## Note on `split-debuginfo`

Removing `split-debuginfo = "packed"` from `[profile.release-profiling]`
is intentional (not a formatting artifact): profiling builds now keep
DWARF debuginfo embedded in the binary, so profiling artifacts can be
symbolized at runtime without shipping a separate debuginfo file. The
o2-enterprise overlay `Cargo.toml.openobserve` is kept in sync.

## Companion PR

- openobserve/o2-enterprise#2175

## Validation

- OSS check with `mimalloc`
- OSS strict clippy with all targets
- enterprise check and strict clippy
- cloud check and strict clippy
- `cargo test -p openobserve-api-management --lib`: 300 passed
- `cargo deny check licenses`
- `cargo fmt --all`
- `git diff --check`

Build-time benchmarking is intentionally deferred for this stage.
2026-07-15 07:10:41 +00:00
Huaijin cd8610cafa refactor: extract shared and query API crates (#13199)
## Summary

- add `openobserve-api-common` for HTTP extractors and request DTOs
shared across API domain crates
- add `openobserve-api-query` and physically move the search, PromQL,
and traces handlers (about 16.4K lines)
- preserve the existing `handler::http::request::{search,promql,traces}`
paths through re-exports so routing, Swagger generation, and rate-limit
metadata remain compatible
- forward enterprise, cloud, vectorscan, and vortex features through the
new crate boundary
- avoid `#[path]` source inclusion

## Enterprise overlay

Requires openobserve/o2-enterprise#2174, which registers the two new
workspace crates in `Cargo.toml.openobserve`.

## Validation

- `cargo check -p openobserve --features mimalloc`
- enterprise check with `--no-default-features --features
enterprise,mimalloc`
- cloud check with `--no-default-features --features cloud,mimalloc`
- OSS and cloud/enterprise all-targets Clippy with `-D warnings`
- `openobserve-api-common`: 9 tests passed
- `openobserve-api-query`: 136 independent tests passed single-threaded;
the unchanged DB-dependent saved-view test was excluded because
standalone crate tests do not initialize the infra database
- `cargo fmt --all -- --check`

Build-time benchmarking is intentionally deferred until the crate-split
series is ready for a controlled `release-profiling` comparison.
2026-07-15 04:22:55 +00:00