mirror of
https://github.com/openobserve/openobserve.git
synced 2026-11-05 16:10:43 +00:00
### **PR Type** Enhancement ___ ### **Description** - Introduce `timeStart`/`timeEnd` in filters - Enable baseline-only and comparison modes - Conditional single vs comparison query logic - Always show Insights button and update translations ___ ### Diagram Walkthrough ```mermaid flowchart LR start["Open analysis"] start -- "Has time filters?" --> comp["Comparison mode"] start -- "No time filters" --> base["Baseline-only mode"] comp -- "Query both ranges" --> merge["Merge & score"] base -- "Use baseline only" --> sort["Sort by baseline percent"] ``` <details> <summary><h3> File Walkthrough</h3></summary> <table><thead><tr><th></th><th align="left">Relevant files</th></tr></thead><tbody><tr><td><strong>Enhancement</strong></td><td><details><summary>3 files</summary><table> <tr> <td><strong>useLatencyInsightsAnalysis.ts</strong><dd><code>Support time-based filters and baseline-only mode</code> </dd></td> <td><a href="https://github.com/openobserve/openobserve/pull/10304/files#diff-343474bc1f120f5ecebfc595bf0d3151b2db096d9226369c496b7a0cfaa33899">+87/-54</a> </td> </tr> <tr> <td><strong>useLatencyInsightsDashboard.ts</strong><dd><code>Conditional single/comparison query generation</code> </dd></td> <td><a href="https://github.com/openobserve/openobserve/pull/10304/files#diff-960dec4a653d7c079157499a2473d0e87bd8b61463e1c3f633e7682ba763a4b1">+58/-7</a> </td> </tr> <tr> <td><strong>TracesMetricsDashboard.vue</strong><dd><code>Always show Insights button and update labels</code> </dd></td> <td><a href="https://github.com/openobserve/openobserve/pull/10304/files#diff-7b6f29a2737d9501b18dbd8622eba4965e4bc2b92115627ae7d2e70cc3382087">+68/-54</a> </td> </tr> </table></details></td></tr><tr><td><strong>Documentation</strong></td><td><details><summary>11 files</summary><table> <tr> <td><strong>de.json</strong><dd><code>Add `volumeInsights.insightsButtonLabel` translation</code> </dd></td> <td><a href="https://github.com/openobserve/openobserve/pull/10304/files#diff-78f24ecb2dbcfc38fdf3ec22b2559a5b40d236ea689d1c55f5d3e87168310264">+3/-1</a> </td> </tr> <tr> <td><strong>en.json</strong><dd><code>Add insights translation keys to English</code> </dd></td> <td><a href="https://github.com/openobserve/openobserve/pull/10304/files#diff-892aa3d75ab6e129ef9116aa21bec1b9a15ba69ce5366d2a19128078c690d824">+2/-0</a> </td> </tr> <tr> <td><strong>es.json</strong><dd><code>Add insights translation keys to Spanish</code> </dd></td> <td><a href="https://github.com/openobserve/openobserve/pull/10304/files#diff-ac2a2167b8b973e3f776f9fe3b43bef4576470d8ad33f3d7cfaff6edff0e5778">+3/-1</a> </td> </tr> <tr> <td><strong>fr.json</strong><dd><code>Add insights translation keys to French</code> </dd></td> <td><a href="https://github.com/openobserve/openobserve/pull/10304/files#diff-db80e762b88ddf183820c050cdc6b215e6b02b365b5e73f5152af46b0d26f1a2">+3/-1</a> </td> </tr> <tr> <td><strong>it.json</strong><dd><code>Add insights translation keys to Italian</code> </dd></td> <td><a href="https://github.com/openobserve/openobserve/pull/10304/files#diff-2de78074a5f887afddce60d694ead9322e6ab223eb70251c13819f3028bdc70d">+3/-1</a> </td> </tr> <tr> <td><strong>ja.json</strong><dd><code>Add insights translation keys to Japanese</code> </dd></td> <td><a href="https://github.com/openobserve/openobserve/pull/10304/files#diff-092e49c5f9fbc1b539ab9c2866d108d0ce1d314022b4c294eb4611b285e7bbd3">+3/-1</a> </td> </tr> <tr> <td><strong>ko.json</strong><dd><code>Add insights translation keys to Korean</code> </dd></td> <td><a href="https://github.com/openobserve/openobserve/pull/10304/files#diff-50e27ca1b4825a5026f3a251bfcf79c97cab07cfade2ebd512d332453d707c48">+3/-1</a> </td> </tr> <tr> <td><strong>nl.json</strong><dd><code>Add insights translation keys to Dutch</code> </dd></td> <td><a href="https://github.com/openobserve/openobserve/pull/10304/files#diff-a1706021687ae5d8a1c006c49eab3946174fecd895f9b70a89c2e76d97250906">+3/-1</a> </td> </tr> <tr> <td><strong>pt.json</strong><dd><code>Add insights translation keys to Portuguese</code> </dd></td> <td><a href="https://github.com/openobserve/openobserve/pull/10304/files#diff-38e804f64cb5e0e451849fc84e9b46e53c954a4a4263d51c18665ad45f4b4815">+3/-1</a> </td> </tr> <tr> <td><strong>tr.json</strong><dd><code>Add insights translation keys to Turkish</code> </dd></td> <td><a href="https://github.com/openobserve/openobserve/pull/10304/files#diff-6f0f131e9e2591480c4c5d1eaffc72d02dc31cbd8d3f90d8f012f08cabac8818">+3/-1</a> </td> </tr> <tr> <td><strong>zh.json</strong><dd><code>Add insights translation keys to Chinese</code> </dd></td> <td><a href="https://github.com/openobserve/openobserve/pull/10304/files#diff-8818055db58f83230aeea4ebfd4cec31d924e8c47b6f91298e356959ab25339e">+3/-1</a> </td> </tr> </table></details></td></tr></tr></tbody></table> </details> ___ --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
113 lines
3.6 KiB
Python
113 lines
3.6 KiB
Python
import requests
|
|
import pytest
|
|
import os
|
|
import random
|
|
import string
|
|
import logging
|
|
from pathlib import Path
|
|
import base64
|
|
|
|
# Configure logging
|
|
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
|
|
|
BASE_URL = os.environ["ZO_BASE_URL"]
|
|
DEFAULT_ORG_ID = os.environ.get("TEST_ORG_ID", "default")
|
|
root_dir = Path(__file__).parent.parent.parent
|
|
|
|
@pytest.fixture(scope="module")
|
|
def random_string():
|
|
"""Generate a random string of specified length."""
|
|
def _generate(length=5):
|
|
# ascii_letters consist of alphabets for 'a' to 'z' and 'A' to 'Z'
|
|
# digits consist of '0' to '9'
|
|
characters = string.ascii_letters + string.digits
|
|
return "".join(random.choices(characters, k=length))
|
|
return _generate
|
|
|
|
def _create_session_inner():
|
|
s = requests.Session()
|
|
username = os.environ["ZO_ROOT_USER_EMAIL"]
|
|
password = os.environ["ZO_ROOT_USER_PASSWORD"]
|
|
s.auth = (username, password)
|
|
resp = s.post(BASE_URL)
|
|
return s
|
|
|
|
|
|
def _create_session_inner_v2():
|
|
s = requests.Session()
|
|
username = os.environ["ZO_ROOT_USER_EMAIL"]
|
|
password = os.environ["ZO_ROOT_USER_PASSWORD"]
|
|
# Set Authorization header for all requests
|
|
basic_auth = base64.b64encode(f"{username}:{password}".encode()).decode()
|
|
s.headers.update({"Authorization": f"Basic {basic_auth}"})
|
|
return s
|
|
|
|
|
|
@pytest.fixture(scope="module")
|
|
def create_session():
|
|
"""Create a session and return it."""
|
|
return _create_session_inner_v2()
|
|
|
|
|
|
@pytest.fixture(scope="module")
|
|
def base_url():
|
|
"""Return the base URL."""
|
|
return BASE_URL
|
|
|
|
|
|
@pytest.fixture(scope="module")
|
|
def org_id():
|
|
"""Return the organization ID for testing.
|
|
|
|
Can be overridden via TEST_ORG_ID environment variable.
|
|
"""
|
|
return DEFAULT_ORG_ID
|
|
|
|
|
|
@pytest.fixture(scope="session", autouse=True)
|
|
def ingest_data():
|
|
"""Ingest data into the openobserve running instance."""
|
|
import time
|
|
|
|
# Use v2 session for consistent auth header
|
|
session = _create_session_inner_v2()
|
|
|
|
# Ingest main test data
|
|
with open(root_dir / "test-data/logs_data.json") as f:
|
|
data = f.read()
|
|
|
|
stream_name = "stream_pytest_data"
|
|
org = DEFAULT_ORG_ID
|
|
url = f"{BASE_URL}api/{org}/{stream_name}/_json"
|
|
resp1 = session.post(url, data=data, headers={"Content-Type": "application/json"})
|
|
logging.info("Main data ingested successfully, status code: %s", resp1.status_code)
|
|
assert resp1.status_code == 200, \
|
|
f"Failed to ingest main test data: {resp1.status_code} - {resp1.text[:500]}"
|
|
|
|
# Ingest camel case test data
|
|
with open(root_dir / "test-data/match_all.json") as f:
|
|
camel_data = f.read()
|
|
|
|
resp2 = session.post(url, data=camel_data, headers={"Content-Type": "application/json"})
|
|
logging.info("Camel case data ingested successfully, status code: %s", resp2.status_code)
|
|
assert resp2.status_code == 200, \
|
|
f"Failed to ingest camel case test data: {resp2.status_code} - {resp2.text[:500]}"
|
|
|
|
# Flush data to ensure it's indexed
|
|
flush_url = f"{BASE_URL}node/flush"
|
|
logging.info("Flushing data to ensure indexing...")
|
|
flush_resp = session.put(flush_url)
|
|
|
|
if flush_resp.status_code == 200:
|
|
logging.info("Data flushed successfully")
|
|
elif flush_resp.status_code == 404:
|
|
# Node is not an ingester in local mode, data will be indexed automatically
|
|
logging.info("Flush not needed (local mode), waiting for auto-indexing...")
|
|
time.sleep(3)
|
|
else:
|
|
logging.warning("Flush request returned status %s: %s", flush_resp.status_code, flush_resp.text[:200])
|
|
|
|
# Give a small buffer for flush to complete
|
|
time.sleep(2)
|
|
|
|
return True |