## Summary
Design at: #11532
Closes
[#11532](https://github.com/openobserve/openobserve/issues/11532).
Adds a new reset component so operators can re-run compaction over a
stream's
historical file_list:
```
./openobserve reset -c file-list-jobs [-t <microseconds>]
```
The command performs three things:
1. **Safety check** — calls `infra::cluster::list_nodes()` and aborts
with an
error if any dedicated compactor node is online (the operator must stop
them first). If a `single_node` (Role::All) node is online, prints a
warning that it must be restarted after the reset so its in-memory
compact state is cleared.
2. **Reset compact offsets** — `db::compact::files::reset_offset(time)`
lists
every `/compact/files/` key in meta and rewrites its value to `time`
(defaulting to `0`), then clears the in-process offset cache.
3. **Re-queue jobs** — calls `infra_file_list::set_job_pending(&[])`,
which
now treats an empty ids slice as "reset all rows", flipping every
`file_list_jobs` row back to `Pending` and clearing `node`,
`started_at`, `updated_at`.
`set_job_pending` previously returned `Result<()>`; it now returns
`Result<u64>` so callers (and the new CLI output) can report rows
affected.
The existing call site in `service/compact/mod.rs` is unaffected because
it
ignores the Ok value.
## Test plan
- [x] `./openobserve reset -c file-list-jobs` against a stack with no
compactor running — verify offsets are 0 and all jobs are Pending
- [x] `./openobserve reset -c file-list-jobs -t 1700000000000000` —
verify
offsets are written as the supplied microsecond timestamp
- [x] Run while a compactor is online — verify the command errors with
the
offending node name
- [x] Run on a single_node deployment — verify the warning is shown and
operation still completes
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Design at: #11518
## Summary
- Add `llm_input` and `llm_output` to the default SQL full text search
field list so LLM-related streams get FTS out of the box without needing
to set `feature_fulltext_extra_fields`.
## Test plan
- [x] Verify a stream with `llm_input` / `llm_output` columns is
searchable via `match_all` without extra config.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
## Summary
- Replace `SELECT *` Q2 with grouped aggregations so per-trace
enrichment is bounded by N rows instead of total span count.
- Q2a aggregates per `trace_id`: span count, error count, min/max times,
max duration, root span labels (with first-by-timestamp fallback), and
`approx_distinct(service_name)` to gate Q2b.
- Q2b runs only for multi-service traces, returning per-`(trace_id,
service_name)` count and max duration.
## Root cause
When a user filters Traces by Duration, Q2 ran `SELECT * FROM stream
WHERE trace_id IN (...)` and aggregated spans in Rust. For traces with
tens of thousands of spans, the search-service row cap was hit before
every `trace_id` got at least one span back. The un-enriched entries
were still sent to the FE with `spans=[0,0]`, `duration=0`,
`first_event=null` — the blank rows in the screenshot on the issue.
The new Q2a returns one row per `trace_id` (≤ N rows total), so it
cannot trip the row cap. Single-service traces are fully populated from
Q2a alone; only multi-service traces require Q2b. Response shape
(`TraceResponseItem`) is unchanged — `first_event` is now built as a
synthetic `{service_name, operation_name}` object so the FE in
`web/src/composables/useTraces.ts` keeps working unchanged.
Applied to both `get_latest_traces` and `process_latest_traces_stream`.
Closes#11505
## Test plan
- [ ] Open Traces, pick a stream with traces that have many spans (≥10K
spans/trace).
- [ ] Filter by Duration `<= Max value`. Confirm no blank rows; every
row has a service icon, service name, non-zero duration, and a span
count.
- [ ] Single-service stream: confirm the services list under each trace
is correct.
- [ ] Multi-service trace (e.g., a trace that crosses several services):
confirm the per-service breakdown still appears (Q2b path).
- [ ] Sort by duration ASC and DESC.
- [ ] Sort by start_time ASC and DESC.
- [ ] LLM stream: confirm LLM token / cost columns still populate.
- [ ] Pagination: page 1, page 2, page N — every page has fully
populated rows.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Hengfei Yang <undefined@users.noreply.github.com>
Build frontend and Rust binary in parallel using /tmp/dist trick
Remove VITE_COVERAGE/COVERAGE env vars and coverage instrumentation
Remove generate_coverage_report job and all nyc upload/report steps
Rename artifact debug-binary → release-ci-binary, add frontend-dist
artifact
Update playwright_summary needs to drop generate_coverage_report
---------
Co-authored-by: Shrinath Rao <shnath@openobserve.ai>
Currently alerts/reports/scheduled pipelines get triggered immediately
when updated or enabled or created. Instead, it should follow the cron
expression (if given) instead of triggering immediately.
Currently, through api, you can keep adding same schema field to UDS, or
full text search settings etc. because the backend simply extends
existing settings with the given payload, instead of checking if the
field already exists in the same config (e.g. uds). This pr fixes this.
## Summary
- Adds `github.event.pull_request.base.ref == 'main'` guard to the "Add
milestone to PR" step
- PRs opened against non-main branches (feature, release, etc.) will no
longer receive auto-assigned milestones
- Issue milestone logic is unchanged (issues don't have a target branch)
## Test plan
- [ ] PR opened against `main` → milestone is assigned (existing
behavior preserved)
- [ ] PR opened against a non-`main` branch (e.g., `feature/xyz`) →
milestone step is skipped
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
## Summary
- Change `detect_llm_stream` to accept `impl Fn(&str) -> bool` instead
of `&HashMap<String, json::Value>`, so the same helper works for both
`HashMap` (span attributes path) and `json::Map` (JSON ingest path)
without cloning or wrapping.
- Update the two callers in `src/service/traces/mod.rs` to pass `|k|
map.contains_key(k)`.
- Add unit tests covering empty input, no-match, and each LLM attribute
family (GenAi, O2, Langfuse) for both `HashMap` and `json::Map`.
## Test plan
- [x] `cargo check -p openobserve`
- [x] `cargo test -p openobserve --lib
service::traces::tests::test_detect_llm_stream` (7 passed)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
## Summary
- When auto-UDS is triggered, the persisted `defined_schema_fields`
includes `_timestamp`. The UI hides `_timestamp` from the UDS selector
so the user can never deselect it.
- A "remove all UDS fields" action from the frontend therefore leaves
`defined_schema_fields = [\"_timestamp\"]` on the backend, which is
still treated as UDS enabled — making it impossible to disable UDS
through the UI even after raising `ZO_SCHEMA_MAX_FIELDS_TO_ENABLE_UDS`.
- Fix: in `update_stream_settings`, after applying the remove diff, if
only `_timestamp` is left, clear `defined_schema_fields` so UDS is
disabled.
Refs: openobserve/o2-enterprise#1570
## Test plan
- [x] On a stream where auto-UDS is enabled, open Schema settings and
switch to the User Defined Schema tab.
- [x] Select all visible UDS fields and delete them, then save.
- [x] Verify the response/stored settings have `defined_schema_fields =
[]` and the stream falls back to all fields (no `_timestamp`-only UDS
lingering).
- [x] Re-add fields to UDS and confirm the normal add path still works.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Currently, the v2 list api for reports with `cache=true` uri params
fails with the following error -
```
Query Error: error returned from database: operator does not exist: json = jsonb
```
This pr fixes the issue #11450
We observed that during auto UDF execution, the _timestamp field was
being included both in the schema and the user-defined schema. The UI
was not designed to handle this duplication. This issue does not occur
when users manually add fields through the Stream page, as _timestamp is
not added to the user-defined schema in that flow. We have now handled
this scenario.
---------
Co-authored-by: Bhargav <BJP232004@GMAIL.COM>
#11446
Traces in the Logs correlation panel were showing wrong durations
because they were read from /latest (cached summaries). Using
/latest_stream delivers the actual trace records with correct duration
data.
#11463
Updated FlameGraphView.vue so that spans with a computed width below
0.1% of the total trace duration are rendered with a minimum 0.1% width
instead of being dropped — ensuring all spans remain visible regardless
of how short they are.
## Summary
- In `playwright_summary`, `merge_and_upload_reports` result of
`failure` is now treated as non-blocking (same as `success`/`skipped`)
- The Playwright summary check will pass even if the TestDino
merge/upload job fails (e.g. network issues, bad token, API outage)
- Actual test results (`build_binary`, `ui_integration_tests`) still
gate the summary as before
## Why
The TestDino upload is observability/reporting infrastructure — it
should never cause a PR's required check to fail when the tests
themselves passed. Previously a transient TestDino failure would block
merges.
## Test plan
- [ ] Verify `playwright_summary` passes when `merge_and_upload_reports`
succeeds (existing behavior)
- [ ] Verify `playwright_summary` passes when `merge_and_upload_reports`
fails (new behavior)
- [ ] Verify `playwright_summary` still fails when
`ui_integration_tests` fails (unchanged)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
## Summary
- Auto-assigns the PR creator as assignee when a PR is opened or marked
ready for review
- Auto-assigns the issue creator if no assignee is set when an issue is
opened
- Adds both PRs and issues to org Project (number 19)
- Sets the lowest open milestone on PRs (non-draft) and issues that
don't already have one set
**Milestone selection logic:**
- Prefers the lowest semver milestone whose due date has not yet passed
(milestones with no due date are treated as not expired)
- If all milestones are past due, falls back to the most recently
expired one
Uses `ORG_ADMIN_TOKEN` (fine-grained PAT) for all operations. Workflow
uses `pull_request_target` so fork PRs also get metadata without needing
checkout.
## Test plan
- [ ] Open a non-draft PR → creator assigned, lowest non-expired
milestone set, added to project
- [ ] Open a PR when all milestones are past due →
least-recently-expired milestone is set
- [ ] Open a PR that already has a milestone → milestone not overwritten
- [ ] Open an issue with no assignee → creator assigned, milestone set,
added to project
- [ ] Open an issue with an existing assignee → assignee not overwritten