mirror of
https://github.com/openobserve/openobserve.git
synced 2026-11-05 16:10:43 +00:00
155 lines
9.1 KiB
Markdown
155 lines
9.1 KiB
Markdown
# OpenObserve — project rules
|
|
|
|
## Engineering guidelines
|
|
|
|
- [.agents/engineering-guidelines.md](.agents/engineering-guidelines.md) governs judgment: task
|
|
tiers, what counts as a hack / over-engineering / over-complication, TDD and the review loop.
|
|
Read it before any change bigger than a one-cause patch; reviewers apply its §2 tests. On
|
|
anything mechanical (ordering, comments, lint thresholds, schema, PR rules) this file wins.
|
|
|
|
## Build & workflow
|
|
|
|
- Build with `cargo build` (debug). Never use `--release` unless explicitly asked.
|
|
- Skip UI build steps (`npm run build`) when working on backend tasks.
|
|
- `.env` in the project root overrides process env; check it before running the server.
|
|
- Before finishing a task: run `cargo fmt --all` and make the CI clippy command
|
|
pass: `cargo clippy --workspace --all-targets -- -W clippy::too_many_lines
|
|
-W clippy::cognitive_complexity -W clippy::excessive_nesting -D warnings`.
|
|
|
|
## Frontend (web/)
|
|
|
|
- After every change under `web/`, run `npm run format:check` from `web/`
|
|
before considering the task done. If it flags a file, fix it with
|
|
`npx prettier --write <file>` (not a full-repo `--write`) and re-run
|
|
`format:check` to confirm it's clean.
|
|
- New UI features fetch search results over the HTTP streaming endpoints, not
|
|
the one-shot ones. Logs and other SQL searches use
|
|
`POST /api/{org}/_search_stream`, or `_search_multi_stream` for several
|
|
streams. Traces use `GET /api/{org}/{stream}/traces/latest_stream`. Call them
|
|
through `useHttpStreaming` in `web/src/composables/useStreamingSearch.ts`,
|
|
which handles chunking, cancellation and the `trace_id`. Do not add new UI
|
|
callers of `_search`, `_search_multi` or `traces/latest`. Wherever a
|
|
streaming endpoint is supported for a call, the UI uses it, in existing code
|
|
as well as new code. The one-shot endpoints are for the public API and for
|
|
the few UI calls that have no streaming equivalent yet.
|
|
|
|
## Rust code organization
|
|
|
|
Item order inside a file/module, top to bottom (clippy's default grouping):
|
|
`mod`/`pub mod` declarations → `use` imports → macros → `const`/`static` → types (`struct`/`enum`/`trait`/`type`), each immediately followed by its own `impl` blocks (inherent impl first, then trait impls) → functions.
|
|
|
|
- A type and its `impl` blocks stay together. Do not collect all types at the top and all
|
|
`impl` blocks below them; a reader must see a struct's methods right under its fields.
|
|
Types that only serve another type (private helper structs/enums) go after the type that
|
|
uses them, again followed by their own impls. No lint enforces adjacency, review does.
|
|
|
|
- Function length, cognitive complexity, and nesting depth are capped by the
|
|
thresholds in clippy.toml (set just above the worst existing code). They only
|
|
ratchet down — if CI flags your function, split it instead of raising the
|
|
threshold.
|
|
- Never insert a function above the file's constants or type definitions.
|
|
- Keep `pub` and private functions grouped. Do not drop a private helper into the
|
|
middle of the pub API block, or a pub fn into a run of private helpers. Place
|
|
new functions next to related functions within the correct group.
|
|
- `#[cfg(test)] mod tests` is always the LAST item in a file. CI enforces this
|
|
(clippy `items_after_test_module` runs under `--all-targets -- -D warnings`).
|
|
- The module-level order above matches clippy's `arbitrary_source_item_ordering`
|
|
lint with the `source-item-ordering = ["module"]` config in clippy.toml. The
|
|
lint is opt-in (too much pre-existing debt to enable repo-wide); hold the code
|
|
you add to this order even though nothing enforces it yet.
|
|
|
|
## Comments
|
|
|
|
STRICT, and enforced in review — a comment that breaks these is deleted, not
|
|
reworded:
|
|
|
|
- **One line, or none.** A comment is at most a single line. No multi-line
|
|
comment blocks in code (the license header is the only exception). If the
|
|
point needs more than one line, it does not belong in a comment.
|
|
- **Only logical comments — explain WHY.** The single allowed reason to write a
|
|
comment is to state a non-obvious constraint, invariant, or gotcha the code
|
|
itself cannot express. If a comment is not explaining logic, do not write it;
|
|
no comment is better than a filler one.
|
|
- **Banned outright** (remove on sight): styling/visual narration (layout,
|
|
spacing, `px`, "matches the header height"), change/modification notes ("now
|
|
we...", "changed to...", "was X"), and narration that restates what the code
|
|
plainly does.
|
|
- `///` / JSDoc doc comments on public APIs: one summary sentence, and only when
|
|
the behaviour is non-obvious; never to restate the signature.
|
|
|
|
## Database schema (migrations / SeaORM entities)
|
|
|
|
Applies to every NEW table and column (SQLite and PostgreSQL alike):
|
|
|
|
- MySQL is not a supported meta store. Support was removed in #10522
|
|
(`src/infra/src/db/mysql.rs` is gone). Do not add MySQL branches, MySQL-only
|
|
migrations, MySQL feature flags or MySQL test matrices. Remaining `mysql`
|
|
mentions in the tree belong to the database monitoring feature, which watches
|
|
customers' MySQL servers, not to the meta store.
|
|
|
|
- No `json` / `jsonb` columns (sea-orm `.json()` / `.json_binary()`). JSON is
|
|
stored in a `.text()` column holding the serialized string; Rust
|
|
(`serde_json`) parses it. Never push JSON operators or extraction into SQL.
|
|
- No `timestamp` / `datetime` / `date` columns (sea-orm `.timestamp()`,
|
|
`.date_time()`, `.date()`). A time field is a Unix timestamp in MICROSECONDS
|
|
stored as `.big_integer()` (Rust `i64`), the same unit `_timestamp` uses
|
|
everywhere else.
|
|
- Existing columns that break these rules are legacy; do not add new ones next
|
|
to them, and do not migrate them as part of an unrelated change.
|
|
|
|
## Feature-owned internal streams
|
|
|
|
- Any new feature that uses OpenObserve itself to ingest and query its own
|
|
operational or result data must name its feature-owned streams with the
|
|
`_o2_` prefix. Existing examples: `_o2_dbm_server` (`DBM_SERVER_STREAM` in
|
|
`src/config/src/meta/db_monitoring.rs`), `_o2_ai_chat_events`
|
|
(`AI_CHAT_EVENTS_STREAM` in `src/config/src/meta/self_reporting/ai_chat.rs`)
|
|
and `_o2_alert_calibration_digests` (`DIGEST_STREAM` in
|
|
`src/core/src/alerts/alert_calibration/sink.rs`). Apply this to every stream
|
|
the feature creates, including execution-level and step-level results.
|
|
- Reuse shared stream-name constants within each code layer. Keep writers,
|
|
readers, runner configuration, ingestion grants and internal-stream
|
|
classification consistent. Verify that the actual ingestion path accepts
|
|
authorized writes to the reserved prefix.
|
|
- Writers into feature-owned streams must authenticate with an org-based
|
|
ingestion token from the `org_ingestion_tokens` table. Do not use a user
|
|
passcode, a RUM token, a service-account login or a root credential. Create or
|
|
look up the token per org when the feature is enabled, and scope it to that
|
|
org. Rotate and revoke it together with the other ingestion tokens of the org.
|
|
- Before renaming an existing stream, assess existing customers, saved queries,
|
|
dashboards, alerts, historical analytics, in-flight jobs and older runners.
|
|
State the history and rollout impact explicitly and choose a compatibility
|
|
plan. When continuous history is required, read legacy and new streams during
|
|
the transition and retain legacy write permissions until old writers drain.
|
|
Preserve existing data under its retention policy unless deletion or migration
|
|
is explicitly requested.
|
|
- This convention applies to feature-owned internal data, not customer-chosen
|
|
stream names or externally standardized names such as
|
|
`traces_service_graph_*`. Do not rename shared streams as an incidental change.
|
|
Internal-stream naming/classification is not an access-control or billing rule.
|
|
|
|
## PR conventions
|
|
|
|
- CI runs on a PR only while it carries the `ready-for-ci` label and is not a draft
|
|
(no label or draft = nothing runs except `ci-gate`, and no red checks). Add the
|
|
label when you want the run, not when you open the PR; clicking "Merge when
|
|
ready" adds it automatically if it is missing. Which suites run is decided by
|
|
path detection, never by a label. The merge queue only compiles and unit-tests the merged code, so the
|
|
labelled PR run is the one that has to be green.
|
|
- PR titles starting with `feat:` require `Design at: #xxx` as the FIRST line
|
|
of the description (enforced by `.github/workflows/feat-design-checker.yml`);
|
|
`fix:`/`chore:`/`test:` PRs skip the check.
|
|
|
|
## Enterprise-gated code
|
|
|
|
- Default features do NOT compile `#[cfg(feature = "enterprise")]` code, so a
|
|
green local check proves nothing about it, and `--features enterprise` does
|
|
not work in this repo (the local `src/enterprise/*` stubs don't provide it).
|
|
With access to the o2-enterprise repo, verify by swapping in its
|
|
`Cargo.toml.openobserve` and running `cargo check --all-targets`, then
|
|
restore `Cargo.toml` (never commit the swap). Without access, say so in the PR.
|
|
- A change needing paired PRs in openobserve and o2-enterprise must use the
|
|
SAME branch name in both repos — CI checks out the paired side by branch name.
|
|
- When changing this repo's root `Cargo.toml`, mirror the change into
|
|
`Cargo.toml.openobserve` in the o2-enterprise repo.
|