diff --git a/docs/api/index.md b/docs/api/index.md index 87ddf65a..4cdc901e 100644 --- a/docs/api/index.md +++ b/docs/api/index.md @@ -22,9 +22,9 @@ Make sure that you are sending the requests over HTTPS. 1. [Schema](stream/schema) 1. [Setting](stream/setting) 1. [Ingestion](ingestion/) - 1. [Bulk](ingestion/bulk) - 1. [Json](ingestion/json) - 1. [Multi](ingestion/multi) + 1. [Bulk](ingestion/logs/bulk) + 1. [Json](ingestion/logs/json) + 1. [Multi](ingestion/logs/multi) 1. [Search](search/) 1. [Function](function/) 1. [User](user/) diff --git a/docs/api/user/add_user.md b/docs/api/user/add_user.md index 731da2fd..deddc354 100644 --- a/docs/api/user/add_user.md +++ b/docs/api/user/add_user.md @@ -3,7 +3,7 @@ description: >- Add an existing user to an OpenObserve organization with a specified role using a simple POST request. Supports admin and user roles. --- -# Add exiting user to org +# Add existing user to org Endpoint: `POST /api/{organization}/users/{user_email}` diff --git a/docs/assets/close-icon.svg b/docs/assets/close-icon.svg new file mode 100644 index 00000000..f6f83d2b --- /dev/null +++ b/docs/assets/close-icon.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/assets/moon.svg b/docs/assets/moon.svg index 6bd2db16..4345aa4b 100644 --- a/docs/assets/moon.svg +++ b/docs/assets/moon.svg @@ -2,12 +2,12 @@ - - + + - - + + - + \ No newline at end of file diff --git a/docs/environment-variables.md b/docs/environment-variables.md index 5fe0f32f..9ba6481b 100644 --- a/docs/environment-variables.md +++ b/docs/environment-variables.md @@ -3,11 +3,680 @@ description: >- Configure OpenObserve with flexible environment variables for roles, storage, performance, and scaling across open source and enterprise deployments. --- -> Applicable to open source & enterprise version +> Applicable to both Open Source and Enterprise editions. -OpenObserve is configured through the use of below environment variables. +OpenObserve is configured using the following environment variables. -## Common +## Basic Configuration +| Environment Variable | Default Value | Description | +|---------------------|---------------|-------------| +| ZO_ROOT_USER_EMAIL | - | Email ID of the root user. | +| ZO_ROOT_USER_PASSWORD | - | Password for the root user. | +| ZO_LOCAL_MODE | true | If local mode is set to true, OpenObserve becomes single node deployment.If it is set to false, it indicates cluster mode deployment which supports multiple nodes with different roles. For local mode one needs to configure SQLite DB, for cluster mode one needs to configure PostgreSQL (recommended) or MySQL. | +| ZO_LOCAL_MODE_STORAGE | disk | Applicable only for local mode. By default, local disk is used as storage. OpenObserve supports both disk and S3 in local mode. | +| ZO_NODE_ROLE | all | Node role assignment. Possible values are ingester, querier, router, compactor, alertmanager, and all. A single node can have multiple roles by specifying them as a comma-separated list. For example, compactor, alertmanager. | +| ZO_NODE_HEARTBEAT_TTL | 30 | Time-to-live (TTL) for node heartbeats in seconds. | +| ZO_INSTANCE_NAME | - | In the cluster mode, each node has a instance name. Default is instance hostname. | +| ZO_CLUSTER_COORDINATOR | nats | Defines how nodes in the cluster discover each other. | +| ZO_APP_NAME | openobserve | Application name for the OpenObserve instance. | + +## Network and Communication +| Environment Variable | Default Value | Description | +|---------------------|---------------|-------------| +| ZO_HTTP_PORT | 5080 | Port number on which the OpenObserve server listens for HTTP requests. | +| ZO_HTTP_ADDR | | IP address on which the OpenObserve server listens for HTTP requests. | +| ZO_HTTP_IPV6_ENABLED | false | Set this to true to enable IPv6 support for HTTP. | +| ZO_HTTP_WORKER_NUM | 0 | Number of threads for HTTP services. Default is equal to the number of CPU cores (cpu_num). | +| ZO_HTTP_WORKER_MAX_BLOCKING | 1024 | Maximum number of blocking connections allowed per HTTP thread. | +| ZO_GRPC_PORT | 5081 | Port number on which the OpenObserve server listens for gRPC requests. | +| ZO_GRPC_ADDR | | IP address on which the OpenObserve server listens for gRPC requests. | +| ZO_GRPC_ORG_HEADER_KEY | openobserve-org-id | Header key for sending organization information in traces using OTLP over gRPC. | +| ZO_GRPC_STREAM_HEADER_KEY | stream-name | Header key for sending stream name information in traces using OTLP over gRPC. | +| ZO_GRPC_MAX_MESSAGE_SIZE | 16 | Maximum gRPC message size in MB. Default is 16 MB. | +| ZO_GRPC_CONNECT_TIMEOUT | 5 | Timeout in seconds for connecting to the gRPC server. | +| ZO_ROUTE_TIMEOUT | 600 | Timeout value for the router node in seconds. | +| ZO_ROUTE_MAX_CONNECTIONS | 1024 | Sets the maximum number of simultaneous connections per type of scheme for the Router node role. | + + +## Data Storage and Directories +| Environment Variable | Default Value | Description | +|---------------------|---------------|-------------| +| ZO_DATA_DIR | ./data/openobserve/ | Defaults to "data" folder in current working directory if not provided. | +| ZO_DATA_DB_DIR | ./data/openobserve/db/ | Directory for storing the metadata database locally. | +| ZO_DATA_WAL_DIR | ./data/openobserve/wal/ | Directory for storing Write-Ahead Log (WAL) data. | +| ZO_DATA_STREAM_DIR | ./data/openobserve/stream/ | Directory for storing stream data locally. Applicable only in local mode. | +| ZO_DATA_IDX_DIR | | Local WAL Idx directory. | + + +## Ingestion and Schema Management +| Environment Variable | Default Value | Description | +|---------------------|---------------|-------------| +| ZO_COLS_PER_RECORD_LIMIT | 1000 | Maximum number of fields allowed per record during ingestion. Records with more fields than this limit are discarded. | +| ZO_WIDENING_SCHEMA_EVOLUTION | true | If set to false, user can add new columns to the ingested data, but changes to existing column data types are not supported. | +| ZO_SKIP_SCHEMA_VALIDATION | false | By default, every ingested record is validated against the schema. If the schema is fixed, validation can be skipped to double ingestion performance. | +| ZO_ALLOW_USER_DEFINED_SCHEMAS | false | When set to true, allows users to define user-defined schemas for a stream. | +| ZO_SKIP_FORMAT_STREAM_NAME | false | When set to true, it skips formatting stream name while ingestion. | +| ZO_CONCATENATED_SCHEMA_FIELD_NAME | _all | Field name where all fields, after applying user-defined schema rules and flattening, are stored as a single field. The default value is _all. For example, if the processed data is {a:5, b:"abc"}, an additional field _all is added as {a:5, b:"abc", _all:"{a:5,b:"abc"}"}. This field is used for full-text search, allowing match_all queries to run across all data instead of being limited to a single field. | +| ZO_INGEST_ALLOWED_UPTO | 5 | Discards events older than the specified number of hours. By default, OpenObserve accepts data only if it is not older than 5 hours from the current ingestion time. | +| ZO_INGEST_ALLOWED_IN_FUTURE | 24 | Discards events dated beyond the specified number of future hours. By default, OpenObserve accepts data only if it is not timestamped more than 24 hours into the future. | +| ZO_INGEST_BUFFER_QUEUE_NUM | 5 | Number of queues to buffer ingestion requests. ZO_FEATURE_INGEST_BUFFER_ENABLED must be true | +| ZO_INGEST_FLATTEN_LEVEL | 3 | The level of flatten ingestion json data, if you want flatten everything you can simple set it to 0, or you can set it to N to limit the flatten level. | +| ZO_FEATURE_INGEST_BUFFER_ENABLED | false | Enables ingestion requests to be enqueued for background processing, improving responsiveness of ingestion endpoints. | +| ZO_INGEST_BLOCKED_STREAMS | - | Comma-separated list of streams blocked from ingestion. | +| ZO_FORMAT_STREAM_NAME_TO_LOWERCASE | true | Converts stream names to lowercase. | +| ZO_MEM_TABLE_STREAMS | - | Comma-separated list of streams that use dedicated MemTables. | +| ZO_INGEST_DEFAULT_HEC_STREAM | - | Default stream used for HEC ingestion. | + + +## File Management, WAL, and Memtable +| Environment Variable | Default Value | Description | +|---------------------|---------------|-------------| +| ZO_MAX_FILE_SIZE_ON_DISK | 64 | Maximum WAL log file size in MB before creating a new log file. Default is 64 MB. WAL files are created per organization and stream type. | +| ZO_MAX_FILE_SIZE_IN_MEMORY | 256 | Maximum memtable size in MB before it becomes immutable and is written to disk. Default is 256 MB. | +| ZO_MAX_FILE_RETENTION_TIME | 600 | Maximum retention time in seconds for a WAL log file or memtable. Default is 600 seconds (10 minutes). When this limit is reached, a new WAL file is created and the memtable is written to disk. | +| ZO_FILE_PUSH_INTERVAL | 60 | Interval in seconds at which WAL files are moved to storage. Default is 60 seconds. | +| ZO_FILE_PUSH_LIMIT | 0 | Maximum number of WAL files that can be pushed to storage in a single cycle. | +| ZO_FILE_MOVE_THREAD_NUM | - | Number of threads used by the ingester to move WAL files to storage. Default equals the number of CPU cores. | +| ZO_MEM_DUMP_THREAD_NUM | - | Number of threads used by the ingester to dump memtables to disk. Default equals the number of CPU cores. | +| ZO_FILE_MERGE_THREAD_NUM | - | Number of threads used by the compactor to merge WAL files to storage. Default equals the number of CPU cores. | +| ZO_FILE_MOVE_FIELDS_LIMIT | 2000 | Field count threshold per WAL file. If exceeded, merging is skipped on the ingester. | +| ZO_MEM_TABLE_MAX_SIZE | 0 | Total size limit of all memtables. Multiple memtables exist for different organizations and stream types. Each memtable cannot exceed ZO_MAX_FILE_SIZE_IN_MEMORY, and the combined size cannot exceed this limit. If exceeded, the system returns a MemoryTableOverflowError to prevent out-of-memory conditions. Default is 50 percent of total memory. | +| ZO_MEM_PERSIST_INTERVAL | 5 | Interval in seconds at which immutable memtables are persisted from memory to disk. Default is 5 seconds. | + + +## Indexing +| Environment Variable | Default Value | Description | +|---------------------|---------------|-------------| +| ZO_FEATURE_FULLTEXT_EXTRA_FIELDS | - | Automatically enables global full-text indexing on the specified fields if they exist in the ingested log data. By default, OpenObserve applies full-text indexing to the following global fields: log, message, msg, content, data, and JSON. Example: field1,field2 | +| ZO_FEATURE_INDEX_EXTRA_FIELDS | - | Automatically enables global secondary indexing on the specified fields if they exist in the ingested log data. Example: field1,field2 | +| ZO_FEATURE_QUERY_PARTITION_STRATEGY | file_num | Query partition strategy. Possible values are file_num, file_size, file_hash. | +| ZO_ENABLE_INVERTED_INDEX | true | Enables inverted index creation. | + +## Compaction and Data Retention +| Environment Variable | Default Value | Description | +|---------------------|---------------|-------------| +| ZO_COMPACT_ENABLED | true | Enables compact for small files. | +| ZO_COMPACT_INTERVAL | 60 | The interval at which job compacts small files into larger files. default is 60s, unit: second | +| ZO_COMPACT_MAX_FILE_SIZE | 256 | Max file size for a single compacted file, after compaction all files will be below this value. Default is 256MB, unit: MB | +| ZO_COMPACT_DATA_RETENTION_DAYS | 3650 | Data retention days, default is 10 years. Minimal 3. eg: 30, it means will auto delete the data older than 30 days. You also can set data retention for stream in the UI. | +| ZO_COMPACT_SYNC_TO_DB_INTERVAL | 1800 | The interval time in seconds after which compactor sync cache to db is run. | +| ZO_COMPACT_DELETE_FILES_DELAY_HOURS | 2 | The number of hours to delay to delete the pending deleted files by compactor. Value can not be less than 1. | +| ZO_COMPACT_DATA_RETENTION_HISTORY | false | When enabled, this will move the file_list into file_list_history and not delete files from storage. | +| ZO_COMPACT_BLOCKED_ORGS | | Use comma to split multiple orgs. Blocked organizations will not be able to ingest data | +| ZO_COMPACT_FAST_MODE | true |Enables fast compaction mode. Uses more memory but improves performance. Disabling reduces memory usage by about 50 percent. | +| ZO_COMPACT_OLD_DATA_INTERVAL | 3600 | Interval to compact old data in seconds. | +| ZO_COMPACT_STRATEGY | file_time | Compaction strategy. Allowed values are file_size, file_time, time_range. | +| ZO_COMPACT_EXTENDED_DATA_RETENTION_DAYS | 3650 | Extended data retention period in days. | +| ZO_COMPACT_OLD_DATA_STREAMS | - | Comma-separated stream list to treat as old data. | +| ZO_COMPACT_OLD_DATA_MAX_DAYS | 7 | Maximum age of data to qualify as old in days. | +| ZO_COMPACT_OLD_DATA_MIN_HOURS | 2 | Minimum age of data to qualify as old in hours. | +| ZO_COMPACT_OLD_DATA_MIN_RECORDS | 100 | Minimum record count to compact old data. | +| ZO_COMPACT_OLD_DATA_MIN_FILES | 10 | Minimum file count to compact old data. | +| ZO_COMPACT_BATCH_SIZE | 0 | Batch size for fetching pending compaction jobs. | +| ZO_COMPACT_JOB_RUN_TIMEOUT | 600 | Time limit for one compaction job in seconds. Jobs that exceed this time are marked as failed. | +| ZO_COMPACT_JOB_CLEAN_WAIT_TIME | 7200 | Minimum age of finished jobs before cleanup in seconds. | +| ZO_COMPACT_PENDING_JOBS_METRIC_INTERVAL | 300 | Interval to publish pending job metrics in seconds. | +| ZO_COMPACT_MAX_GROUP_FILES | 10000 | Maximum number of files allowed in a compaction group. | + +## UI and Web +| Environment Variable | Default Value | Description | +|---------------------|---------------|-------------| +| ZO_UI_SQL_BASE64_ENABLED | false | Enable base64 encoding for SQL in UI. | +| ZO_WEB_URL | - | UI access URL. For example, http://localhost:5080 is used as redirect URL and alert URL. | +| ZO_BASE_URI | - | If OpenObserve is hosted under a subpath, set the path prefix. Use this for deployments with a Kubernetes NGINX ingress or any reverse proxy that serves OpenObserve under a subpath such as www.example.com/openobserve. | +| ZO_SWAGGER_ENABLED | true | Generate SWAGGER API documentation by default. | + +## Dashboard +| Environment Variable | Default Value | Description | +| ------------------------------------ | ------------- | ------------------------------------------------- | +| ZO_DASHBOARD_SHOW_SYMBOL_ENABLED | false | Shows the symbol selector in dashboards. | +| ZO_DASHBOARD_PLACEHOLDER | `_o2_all_` | Placeholder stream name used in dashboards. | +| ZO_MIN_AUTO_REFRESH_INTERVAL | 5 | Minimum allowed auto refresh interval in seconds. | + +## Payload Limits +| Environment Variable | Default Value | Description | +|---------------------|---------------|-------------| +| ZO_JSON_LIMIT | 209715200 | The max payload size of JSON. | +| ZO_PAYLOAD_LIMIT | 209715200 | The max payload size of http request body. | + +## Actix Server +| Environment Variable | Default Value | Description | +|---------------------|---------------|-------------| +| ZO_ACTIX_REQ_TIMEOUT | 30 | Sets actix server client timeout in seconds for first request. | +| ZO_ACTIX_KEEP_ALIVE | 30 | Sets actix server keep-alive preference in seconds. | +| ZO_ACTIX_SHUTDOWN_TIMEOUT | | Sets timeout for graceful worker shutdown of actix workers. | + +## Cookies +| Environment Variable | Default Value | Description | +|---------------------|---------------|-------------| +| ZO_COOKIE_SAME_SITE_LAX | true | If true, same site "lax" cookie is set by the server while authentication. | +| ZO_COOKIE_SECURE_ONLY | false | If true, secure flag is enabled for the cookie set by the server while authentication. | + +## Telemetry and Monitoring +| Environment Variable | Default Value | Description | +|---------------------|---------------|-------------| +| ZO_TELEMETRY | true | Sends anonymous telemetry data to help improve OpenObserve. Set to false to disable telemetry. | +| ZO_TELEMETRY_URL | https://e1.zinclabs.dev | OpenTelemetry report URL. You can report to your own server. | +| ZO_HEARTBEAT_INTERVAL | 30 | OpenTelemetry report frequency. Default is 30 minutes | +| ZO_PROMETHEUS_ENABLED | false | Enables prometheus metrics on /metrics endpoint | +| ZO_CALCULATE_STATS_INTERVAL | 600 | In seconds. How often stream stats (total size) is calculated | + +## File Retention +| Environment Variable | Default Value | Description | +|---------------------|---------------|-------------| +| ZO_LOGS_FILE_RETENTION | hourly | Default time partition level for log streams. Supported values are hourly and daily. | +| ZO_TRACES_FILE_RETENTION | hourly | Default time partition level for trace streams. Supported values are hourly and daily. | +| ZO_METRICS_FILE_RETENTION | daily | Default time partition level for metric streams. Supported values are hourly and daily. | + +## Metrics +| Environment Variable | Default Value | Description | +|---------------------|---------------|-------------| +| ZO_METRICS_DEDUP_ENABLED | true | Enable de-duplication for metrics | +| ZO_METRICS_LEADER_PUSH_INTERVAL | 15 | Interval at which current leader information is updated to metadata store , default 15s, unit: second | +| ZO_METRICS_LEADER_ELECTION_INTERVAL | 30 | Interval after which new leader for metrics will be elected, when data is not received from current leader, default: 30, unit: second. | +| ZO_SELF_METRIC_CONSUMPTION_ENABLED | false | Self-consumption metrics generated by OpenObserve. | +| ZO_SELF_METRIC_CONSUMPTION_INTERVAL | 60 | Interval in seconds for self-consumption of metrics. | +| ZO_SELF_METRIC_CONSUMPTION_ACCEPTLIST | - | Comma-separated list of metrics to self-consume. | + + +## Distinct Values +| Environment Variable | Default Value | Description | +|---------------------|---------------|-------------| +| ZO_DISTINCT_VALUES_INTERVAL | 10s | Controls how often distinct values for a stream are written from memory to disk. Distinct values are automatically collected when data is ingested. Instead of writing every value to disk immediately, the system waits for this interval. This prevents the system from frequently writing very small chunks of data to disk. Example: If the interval is 10 seconds, distinct values ingested within that 10-second window are combined and written once. | +| ZO_DISTINCT_VALUES_HOURLY | false | Enables additional deduplication at an hourly level. When enabled, distinct values that repeat within the same hour are merged again, and the system logs a count instead of storing duplicate entries. The collected distinct values are stored in a special stream named distinct_values. Example: Suppose request IDs 123 appear multiple times in one hour. Instead of separate entries, they are merged into one record like: request_id: 123, count: 3 | + +## Alerts and Reports +| Environment Variable | Default Value | Description | +|---------------------|---------------|-------------| +| ZO_ALERT_SCHEDULE_INTERVAL | 10s | Defines how often the alert manager checks for scheduled jobs such as alerts, reports, or scheduled pipelines. The default value is 10 seconds. This means the alert manager fetches and processes alerts, reports, and pipelines every 10 seconds. | +| ZO_ALERT_SCHEDULE_TIMEOUT | 90 | The maximum expected time duration in seconds within which the processing of alert by the alert manager should be complete. If the processing of the alert is not complete within the timeframe, the alert will become available again for other alert managers to pick. | +| ZO_SCHEDULER_WATCH_INTERVAL | 30 | The scheduler frequently watches if there are any scheduled jobs which are in processing state for more than the `ZO_ALERT_SCHEDULE_TIMEOUT`/`ZO_REPORT_SCHEDULE_TIMEOUT`, if so it increases their `retries` field by 1 and marks them as available for processing again by alert managers. | +| ZO_ALERT_SCHEDULE_CONCURRENCY | 5 | The number of scheduled jobs the the alert manager will pull at a time from the scheduler for processing | +| ZO_CHROME_ENABLED | false | When true, it looks for chromium executable. Required for dashboard reports. | +| ZO_CHROME_PATH | - | If chrome is enabled, custom chrome executable path can be specified. If not specified, it looks for chrome executable in default locations. If still not found, it automatically downloads a good known version of chromium. | +| ZO_CHROME_CHECK_DEFAULT_PATH | true | If false, it skips default locations (e.g. CHROME env, usual chrome file path etc.) when looking for chrome executable. | +| ZO_CHROME_NO_SANDBOX | false | If true, it launches chromium in no-sandbox environment. | +| ZO_CHROME_SLEEP_SECS | 20 | Specify the number of timeout seconds the headless chrome will wait until all the dashboard data is loaded. | +| ZO_CHROME_WITH_HEAD | false | If true, it launches the chromium browser in non-headless mode. | +| ZO_CHROME_WINDOW_WIDTH | 1370 | Specifies the width of the headless chromium browser. | +| ZO_CHROME_WINDOW_HEIGHT | 730 | Specifies the height of the headless chromium browser. | +| ZO_CHROME_AUTO_DOWNLOAD | false | Only used by the report-server. If true, the report-server automatically downloads a good known version of chromium if chromium is not found in the system. **Note:** If auto download of chromium is desired, make sure that the system has all the required dependency libraries of chromium already installed. | +| ZO_SCHEDULER_MAX_RETRIES | 3 | The maximum number of times the scheduler will retry processing the alert/report. If exceeded, the scheduler will skip to the next trigger time of the alert/report. | +| ZO_SCHEDULER_CLEAN_INTERVAL | 30 | The interval in seconds after which the scheduler will clean up the completed scheduled jobs. | +| ZO_REPORT_USER_NAME | | The username that will be used by the headless chromium to login into openobserve and generate report. | +| ZO_REPORT_USER_PASSWORD | | The password that will be used by the headless chromium to login into openobserve and generate report. | +| ZO_ENABLE_EMBEDDED_REPORT_SERVER | false | If true, the alert manager (for which this ENV is enabled) spawns a new report-server running on PORT `5082` (default, can be changed through `ZO_REPORT_SERVER_HTTP_PORT`). | +| ZO_REPORT_SERVER_HTTP_PORT | `5082` | The port used by the newly spawned report-server. | +| ZO_REPORT_SERVER_HTTP_ADDR | `127.0.0.1` | The ip address used by the newly spawned report-server. | +| ZO_REPORT_SERVER_URL | `localhost:5082` | The report server server URL. E.g. - `https://report-server.example.com/api`. | +| ZO_REPORT_SERVER_SKIP_TLS_VERIFY | false| If true, it will skip tls verification while making request to report-server from alert manager. | + +## Enrichment Tables +| Environment Variable | Default Value | Description | +|---------------------|---------------|-------------| +| ZO_ENRICHMENT_TABLE_LIMIT | 256 | Controls the maximum size of an enrichment table. If the enrichment table exceeds this limit, you cannot append additional records. OpenObserve returns an error when the size threshold is reached. | +| ZO_ENRICHMENT_TABLE_CACHE_DIR | - | Local cache directory for enrichment tables. | +| ZO_ENRICHMENT_TABLE_MERGE_THRESHOLD_MB | 60 | Size threshold to merge small files before uploading to S3 in megabytes. | +| ZO_ENRICHMENT_TABLE_MERGE_INTERVAL | 600 | Background sync and merge interval in seconds. | + +## File List Dump +| Environment Variable | Default Value | Description | +| ---------------------------------- | ------------- | ------------------------------------------- | +| ZO_FILE_LIST_DUMP_ENABLED | false | Enables file list dump. | +| ZO_FILE_LIST_DUMP_DUAL_WRITE | true | Enables dual write for file list dump. | +| ZO_FILE_LIST_DUMP_MIN_HOUR | 2 | Minimum hour of day to run file list dump. | +| ZO_FILE_LIST_DUMP_DEBUG_CHECK | true | Enables debug checks during file list dump. | + +## Queue +| Environment Variable | Default Value | Description | +|---------------------|---------------|-------------| +| ZO_QUEUE_STORE | | Set to "nats" to enable internal queuing through NATS for coordinating rate limiting. | + + +## Query Execution and Optimization +| Environment Variable | Default Value | Description | +|---------------------|---------------|-------------| +| ZO_UTF8_VIEW_ENABLED | true | When set to true , this environment variable activates DataFusion's StringView optimization in OpenObserve, which automatically converts UTF8 string fields to the more efficient UTF8View data type during query processing. | +| ZO_SEARCH_INSPECTOR_ENABLED | false | Controls search inspector feature for detailed search operation tracing. When enabled, tracks search operations with trace_id and generates extensive logs for debugging. | + + +## Logs + Environment Variable | Default Value | Description | +| ---------------------------- | -------------------------------------------- | ------------------------------------------------------------------------- | +| ZO_LOG_JSON_FORMAT | false | Emits logs in JSON format. | +| ZO_LOG_FILE_DIR | - | Directory for log files. | +| ZO_LOG_FILE_NAME_PREFIX | - | Prefix for log file names. | +| ZO_LOG_LOCAL_TIME_FORMAT | - | Local timestamp format for logs. Use a strftime-compatible format string. | +| ZO_EVENTS_ENABLED | false | Enables internal debug events publishing. | +| ZO_EVENTS_AUTH | cm9vdEBleGFtcGxlLmNvbTpUZ0ZzZFpzTUZQdzg2SzRK | Basic authentication value used for events publishing. | +| ZO_EVENTS_BATCH_SIZE | 10 | Number of events per publish batch. | +| ZO_PRINT_KEY_CONFIG | false | Print key config information in logs. | +| ZO_PRINT_KEY_SQL | false | Print key sql in logs. | +| RUST_LOG | info | Log level, also supports: error, warn, info, debug, trace. | +| ZO_FEATURE_QUICK_MODE_FIELDS | - | Comma-separated list of field names to use when quick mode is enabled. Overrides the default quick mode fields. | + +## Caching + +| Environment Variable | Default Value | Description | +|---------------------|---------------|-------------| +| ZO_DATA_CACHE_DIR | ./data/openobserve/cache/ | local query cache storage directory, applicable only for cluster mode. | +| ZO_MEMORY_CACHE_ENABLED | true | enable in-memory caching for files, default is true, the latest files are cached for accelerated queries. | +| ZO_CACHE_LATEST_FILES_ENABLED | false | Enables or disables latest file caching. | +| ZO_CACHE_LATEST_FILES_PARQUET | true | Enables caching of latest parquet files. | +| ZO_CACHE_LATEST_FILES_INDEX | true | Enables caching of index files. | +| ZO_CACHE_LATEST_FILES_DELETE_MERGE_FILES | false | Controls whether merged files should be deleted from cache. | +| ZO_CACHE_LATEST_FILES_DOWNLOAD_FROM_NODE | false | Downloads latest files from a peer node instead of object storage. | +| ZO_CACHE_LATEST_FILES_DOWNLOAD_NODE_SIZE | 100 | Threshold size in megabytes for node to node download. | +| ZO_MEMORY_CACHE_SKIP_DISK_CHECK | false | Skips free disk space checks during cache operations. | +| ZO_DISK_RESULT_CACHE_MAX_SIZE | 0 | Maximum disk cache size for query results in megabytes. | +| ZO_DISK_AGGREGATION_CACHE_MAX_SIZE | 0 | Maximum disk cache size for aggregation results in megabytes. | +| ZO_DISK_CACHE_MULTI_DIR | - | Comma-separated list of disk cache directories. When set, OpenObserve uses multiple directories for the disk cache. For example, ZO_DISK_CACHE_MULTI_DIR: "ssdpvc1,ssdpvc2" | +| ZO_DISK_CACHE_GC_SIZE | 100 | Amount of data to release during disk cache garbage collection in megabytes. | +| ZO_DISK_CACHE_GC_INTERVAL | 60 | Interval to check whether the disk cache is full and to run garbage collection in seconds. | +| ZO_SCHEMA_CACHE_COMPRESS_ENABLED | - | Removed. No longer supported. | +| ZO_DISK_CACHE_BUCKET_NUM | 0 | Disk data cache bucket num, multiple bucket means multiple locker, default is 0 | +| ZO_DISK_CACHE_ENABLED | true | Enable in-disk caching for files, default is true, the latest files are cached for accelerated queries. when the memory cache is not enough will try to cache in local disk, you can consider the memory cache is first level, disk cache is second level. | +| ZO_DISK_CACHE_MAX_SIZE | - | Default 50% of the total free disk for in-disk cache, one can set it to desired amount unit: MB | +| ZO_DISK_CACHE_SKIP_SIZE | - | Default 80% of the total disk cache size, A query will skip disk cache if it need more than this value. one can set it to desired amount unit: MB | +| ZO_DISK_CACHE_RELEASE_SIZE | - | Default drop 1% entries from in-disk cache as cache is full, one can set it to desired amount unit: MB | +| ZO_DISK_CACHE_STRATEGY | lru | Disk data cache strategy, values are lru, time_lru, fifo | + + +## HTTP TLS +| Environment Variable | Default Value | Description | +| --------------------------------- | ------------- | ------------------------------------------------------------------------------------------------- | +| ZO_HTTP_TLS_ENABLED | false | Enables TLS for HTTP. | +| ZO_HTTP_TLS_CERT_PATH | - | Path to the TLS certificate file for HTTP. | +| ZO_HTTP_TLS_KEY_PATH | - | Path to the TLS key file for HTTP. | +| ZO_HTTP_TLS_MIN_VERSION | - | Minimum TLS version for HTTP. Supported values are 1.2 or 1.3. Empty uses all supported versions. | +| ZO_HTTP_TLS_ROOT_CERTIFICATES | webpki | Root certificate store to use. Supported values are webpki and native. | + +## gRPC TLS and Authentication +| Environment Variable | Default Value | Description | +| ---------------------------------- | ------------- | ------------------------------------------ | +| ZO_INTERNAL_GRPC_TOKEN | - | Internal gRPC authentication token. | +| ZO_GRPC_CHANNEL_CACHE_DISABLED | false | Disables the gRPC channel cache. | +| ZO_GRPC_TLS_ENABLED | false | Enables TLS for gRPC. | +| ZO_GRPC_TLS_CERT_DOMAIN | - | Expected TLS server name for gRPC. | +| ZO_GRPC_TLS_CERT_PATH | - | Path to the TLS certificate file for gRPC. | +| ZO_GRPC_TLS_KEY_PATH | - | Path to the TLS key file for gRPC. | + + +## Router +| Environment Variable | Default Value | Description | +| -------------------- | ------------- | ------------------------------------------------------------ | +| ZO_ROUTE_STRATEGY | workload | Dispatch strategy. Supported values are workload and random. | + + +## Authentication +| Environment Variable | Default Value | Description | +| ------------------------- | ------------- | -------------------------------------- | +| ZO_ROOT_USER_TOKEN | - | Root user token. | +| ZO_CLI_USER_COOKIE | - | Cookie value used by the CLI user. | +| ZO_COOKIE_MAX_AGE | 2592000 | Cookie max age in seconds. | +| ZO_EXT_AUTH_SALT | openobserve | Salt used for external authentication. | +| O2_ACTION_SERVER_TOKEN | - | Token used by the action server. | + +## NATS +| Environment Variable | Default Value | Description | +| -------------------------- | ------------- | ------------------------------------------------------------------------------------- | +| ZO_NATS_ADDR | `localhost:4222` |NATS server address - If not stated explicitly the `nats://` schema and port `4222` is assumed.| +| ZO_NATS_PREFIX | `o2_` | NATS prefix for openobserve. | +| ZO_NATS_USER | - | NATS user name. | +| ZO_NATS_PASSWORD | - | NATS user password. | +| ZO_NATS_REPLICAS | 3 | Number of replicas for NATS. | +| ZO_NATS_CONNECT_TIMEOUT | 5 | NATS connection timeout in seconds. | +| ZO_NATS_COMMAND_TIMEOUT | 10 | NATS command timeout in seconds. | +| ZO_NATS_LOCK_WAIT_TIMEOUT | 3600 | NATS lock wait timeout in seconds. | +| ZO_NATS_QUEUE_MAX_AGE | 60 | NATS queue maximum age in days. | +| ZO_NATS_HISTORY | 3 | Number of historical entries to keep in NATS key value buckets. | +| ZO_NATS_DELIVER_POLICY | all | Starting point in the stream for message delivery. Allowed values are all, last, new. | +| ZO_NATS_SUB_CAPACITY | 65535 | Maximum subscription capacity. | +| ZO_NATS_QUEUE_MAX_SIZE | 2048 | Maximum queue size in megabytes. | + + +## S3 and Object Storage +| Environment Variable | Default Value | Description | +| -------------------------------------- | ------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| ZO_S3_SERVER_URL | - | Default for aws s3 & leave it empty, but for `minIO`, `gcs` one should configure it. | +| ZO_S3_REGION_NAME | - | Region name | +| ZO_S3_ACCESS_KEY | - | Access key | +| ZO_S3_SECRET_KEY | - | Secret key | +| ZO_S3_BUCKET_NAME | - | Bucket name | +| ZO_S3_BUCKET_PREFIX | - | You can store data in a sub directory, like: `openobserve/` | +| ZO_S3_PROVIDER | s3 | S3 provider name, like: aws, gcs, gcp, oss, minio, swift | +| ZO_S3_FEATURE_FORCE_HOSTED_STYLE | false | Feature: `force_hosted_style`, default enable for provider `minio` and `swift`. | +| AWS_EC2_METADATA_DISABLED | false | Feature, default enable for `swift`. | +| ZO_S3_FEATURE_BULK_DELETE | false | Enables bulk deletion of streams in object stores that support stream deletion. If your object store supports stream delete, you can enable this variable. AWS S3 and Azure ObjectStore are known to support it. When set to **true**, OpenObserve issues a single operation to delete all files under the stream’s storage prefix, reducing deletion time and API usage. | +| ZO_S3_ACCOUNTS | - | Comma-separated list of account identifiers. | +| ZO_S3_STREAM_STRATEGY | - | Stream to account selection strategy. Empty uses the default account. Other values are file_hash, stream_hash, and explicit mappings in the form stream1:account1. | +| ZO_S3_CONNECT_TIMEOUT | 10 | Connect timeout in seconds. | +| ZO_S3_REQUEST_TIMEOUT | 3600 | Request timeout in seconds. | +| ZO_S3_ALLOW_INVALID_CERTIFICATES | false | Allows invalid TLS certificates. | +| ZO_S3_SYNC_TO_CACHE_INTERVAL | 600 | Interval to sync object storage state to cache in seconds. | +| ZO_S3_MAX_RETRIES | 10 | Maximum number of retries for S3 operations. | +| ZO_S3_MAX_IDLE_PER_HOST | 0 | Maximum idle connections per host. | +| ZO_S3_CONNECTION_KEEPALIVE_TIMEOUT | 20 | Keepalive timeout in seconds for S3 connections. | +| ZO_S3_MULTI_PART_UPLOAD_SIZE | 100 | File size threshold for switching to multi part upload in megabytes. | +| ZO_S3_FEATURE_HTTP1_ONLY | false | Uses HTTP 1 only for S3 client connections. | +| ZO_S3_FEATURE_HTTP2_ONLY | false | Uses HTTP 2 only for S3 client connections. | + +## SNS +| Environment Variable | Default Value | Description | +| --------------------------- | ------------- | ----------------------------- | +| ZO_SNS_ENDPOINT | - | SNS endpoint URL. | +| ZO_SNS_CONNECT_TIMEOUT | 10 | Connect timeout in seconds. | +| ZO_SNS_OPERATION_TIMEOUT | 30 | Operation timeout in seconds. | + +## Real User Monitoring (RUM) +| Environment Variable | Default Value | Description | +| --------------------------------- | ------------- | ------------------------------------ | +| ZO_RUM_ENABLED | false | Enables Real User Monitoring. | +| ZO_RUM_CLIENT_TOKEN | - | Client token used by the RUM SDK. | +| ZO_RUM_APPLICATION_ID | - | RUM application identifier. | +| ZO_RUM_SITE | - | RUM site or domain. | +| ZO_RUM_SERVICE | - | Service name reported by RUM. | +| ZO_RUM_ENV | - | Environment name reported by RUM. | +| ZO_RUM_VERSION | - | Version string reported by RUM. | +| ZO_RUM_ORGANIZATION_IDENTIFIER | - | Organization identifier used by RUM. | +| ZO_RUM_API_VERSION | - | API version for RUM. | +| ZO_RUM_INSECURE_HTTP | false | Allows HTTP for RUM endpoints. | + + +## Pipeline +| Environment Variable | Default Value | Description | +| ------------------------------------------------- | ------------- | --------------------------------------------------------------------------------------------------------------------------------- | +| ZO_PIPELINE_REMOTE_STREAM_WAL_DIR | - | Directory for remote stream WAL files. Used to separate remote WAL from local WAL. | +| ZO_PIPELINE_REMOTE_STREAM_CONCURRENT_COUNT | 30 | Concurrent send count for remote stream WAL. | +| ZO_PIPELINE_OFFSET_FLUSH_INTERVAL | 10 | Interval to flush the sent offset for remote stream WAL in seconds. | +| ZO_PIPELINE_REMOTE_REQUEST_TIMEOUT | 600 | Request timeout for pipeline exporters in seconds. | +| ZO_PIPELINE_REMOTE_REQUEST_MAX_RETRY_TIME | 86400 | Maximum total retry time for pipeline exporters in seconds. | +| ZO_PIPELINE_WAL_SIZE_LIMIT | 0 | Data size limit for the pipeline WAL directory in MB. When set to zero the default is 50 percent of available local volume space. | +| ZO_PIPELINE_MAX_CONNECTIONS | 1024 | Maximum number of HTTP connections for the pipeline exporter client. | +| ZO_PIPELINE_BATCH_ENABLED | false | Enables batching of entries before sending HTTP requests. | +| ZO_PIPELINE_BATCH_SIZE | 100 | Maximum number of entries per batch. | +| ZO_PIPELINE_BATCH_TIMEOUT_MS | 1000 | Maximum time to wait for a batch to fill up in milliseconds. | +| ZO_PIPELINE_BATCH_SIZE_BYTES | 10485760 | Maximum batch size in bytes. | +| ZO_PIPELINE_BATCH_RETRY_MAX_ATTEMPTS | 3 | Maximum number of retry attempts for batch flush. | +| ZO_PIPELINE_BATCH_RETRY_INITIAL_DELAY_MS | 1000 | Initial delay for batch flush retries in milliseconds. | +| ZO_PIPELINE_BATCH_RETRY_MAX_DELAY_MS | 30000 | Maximum delay for batch flush retries in milliseconds. | +| ZO_PIPELINE_USE_SHARED_HTTP_CLIENT | false | Uses shared HTTP client instances to improve connection pooling. | +| ZO_PIPELINE_REMOVE_FILE_AFTER_MAX_RETRY | true | Removes the WAL file after reaching the maximum retry count. | +| ZO_PIPELINE_MAX_RETRY_COUNT | 10 | Maximum number of retries for pipeline exporters. | +| ZO_PIPELINE_MAX_RETRY_TIME_IN_HOURS | 24 | Maximum retry time for pipeline exporters in hours. | +| ZO_PIPELINE_MAX_FILE_SIZE_ON_DISK_MB | 128 | Maximum file size on disk for pipeline files in megabytes. | +| ZO_PIPELINE_MAX_FILE_RETENTION_TIME_SECONDS | 600 | Maximum retention time for pipeline files in seconds. | + +## Encryption +| Environment Variable | Default Value | Description | +| --------------------------------- | ------------- | --------------------------------------- | +| ZO_MASTER_ENCRYPTION_ALGORITHM | - | Master encryption algorithm identifier. | +| ZO_MASTER_ENCRYPTION_KEY | - | Master encryption key material. | + +## Health Check +| Environment Variable | Default Value | Description | +| -------------------------------- | ------------- | ------------------------------------------------------------------------------- | +| ZO_HEALTH_CHECK_ENABLED | true | Enables node health checks. | +| ZO_HEALTH_CHECK_TIMEOUT | 5 | Health check timeout in seconds. | +| ZO_HEALTH_CHECK_FAILED_TIMES | 3 | Removes the node from the consistent hash after this many consecutive failures. | + +## Search Group Resource Allocation +| Environment Variable | Default Value | Description | +| ------------------------------------------ | ------------- | -------------------------------------------------- | +| O2_SEARCH_GROUP_LONG_MAX_CPU | 0.8 | The percentage of CPU allocated to long queries | +| O2_SEARCH_GROUP_LONG_MAX_MEMORY | 0.8 | The percentage of memory allocated to long queries | +| O2_SEARCH_GROUP_LONG_MAX_CONCURRENCY | 2 | Maximum number of concurrent long queries. | +| O2_SEARCH_GROUP_SHORT_MAX_CPU | 0.2 | Percentage of CPU allocated to short queries. | +| O2_SEARCH_GROUP_SHORT_MAX_CONCURRENCY | 4 | Maximum number of concurrent short queries. | +| O2_SEARCH_GROUP_SHORT_MAX_MEMORY | 0.2 | Percentage of memory allocated to short queries. | + +## Organization Management +| Environment Variable | Default Value | Description | +| --------------------------------------------------- | ------------- | --------------------------------------------------------------------------- | +| ZO_USE_STREAM_SETTINGS_FOR_PARTITIONS_ENABLED | false | Uses stream settings for partitions for all streams. | +| ZO_ADDITIONAL_REPORTING_ORGS | - | Additional organizations included in reporting. | +| ZO_CREATE_ORG_THROUGH_INGESTION | true | Allows automatic organization creation through ingestion for the root user. | +| ZO_ORG_INVITE_EXPIRY | 7 | Number of days an invite token remains valid. | + + +## Elasticsearch Compatibility +| Environment Variable | Default Value | Description | +| --------------------- | ------------- | ------------------------------------- | +| ZO_FAKE_ES_VERSION | - | Fake Elasticsearch version to report. | +| ZO_ES_VERSION | - | Elasticsearch version to report. | +| ZO_BULK_RESPONSE_INCLUDE_ERRORS_ONLY | false | When using _bulk API which is compatible with Elasticsearch do not respond with records that succeeded. This allows for higher performance by returing smaller amount of data. | + + +## Prometheus Integration +| Environment Variable | Default Value | Description | +| ----------------------------- | ------------- | ---------------------------------------------- | +| ZO_DEFAULT_SCRAPE_INTERVAL | 15 | Default Prometheus scrape interval in seconds. | +| ZO_PROMETHEUS_HA_CLUSTER | cluster | For Prometheus cluster deduplication. | +| ZO_PROMETHEUS_HA_REPLICA | `__replica__` | For Prometheus cluster deduplication. | + +## Traces +| Environment Variable | Default Value | Description | +| ------------------------------------------- | ------------- | ----------------------------------------- | +| ZO_TRACES_SPAN_METRICS_ENABLED | false | Enables span metrics for traces. | +| ZO_TRACES_SPAN_METRICS_EXPORT_INTERVAL | 60 | Span metrics export interval in seconds. | +| ZO_TRACES_SPAN_METRICS_CHANNEL_BUFFER | 100000 | Buffer size for the span metrics channel. | +| ZO_TRACING_SEARCH_ENABLED | false | Enables tracing for search operations. | +| ZO_TRACING_ENABLED | false | enable it to send traces to remote trace server. | +| ZO_TRACING_HEADER_KEY | Authorization| Remote trace server endpoint authentication header key. | +| ZO_TRACING_HEADER_VALUE | - / e.g. Basic gjdsgfksgkfjgdskfgsdlfglsjdg | remote trace server endpoint authentication header value. | +| ZO_TRACING_SEARCH_ENABLED | false | Enables tracing for search operations. | +| OTEL_OTLP_HTTP_ENDPOINT | - / e.g. https://api.openobserve.ai/api/default | Remote trace server endpoint. | + +## Tokio Console +| Environment Variable | Default Value | Description | +| -------------------------------- | ------------- | --------------------------------------------------- | +| ZO_TOKIO_CONSOLE_SERVER_ADDR | 0.0.0.0 | Address for the Tokio console server. | +| ZO_TOKIO_CONSOLE_SERVER_PORT | 6699 | Port for the Tokio console server. | +| ZO_TOKIO_CONSOLE_RETENTION | 60 | Retention period in seconds for Tokio console data. | + +## Profiling +| Environment Variable | Default Value | Description | +| ---------------------------------- | ---------------------------------------------- | --------------------------------------------- | +| ZO_PROF_PPROF_ENABLED | false | Enables profiling with pprof-rs. | +| ZO_PROF_PPROF_PROTOBUF_ENABLED | false | Exports pprof-rs profiles in protobuf format. | +| ZO_PROF_PPROF_FLAMEGRAPH_PATH | - | Path to save flamegraph output. | +| ZO_PROF_PYROSCOPE_ENABLED | false | Enables profiling with pyroscope-rs. | +| ZO_PROF_PYROSCOPE_SERVER_URL | [http://localhost:4040](http://localhost:4040) | Pyroscope server URL. | +| ZO_PROF_PYROSCOPE_PROJECT_NAME | openobserve | Pyroscope project name. | + +## Tantivy Index +| Environment Variable | Default Value | Description | +| ----------------------------------------------------- | ------------- | ------------------------------------------------------------------------ | +| ZO_INVERTED_INDEX_RESULT_CACHE_ENABLED | false | Enables Tantivy result cache. | +| ZO_INVERTED_INDEX_OLD_FORMAT | false | Uses the old index format that generates the same stream name for index. | +| ZO_INVERTED_INDEX_CAMEL_CASE_TOKENIZER_DISABLED | false | Disables camel case tokenizer for inverted index. | +| ZO_INVERTED_INDEX_COUNT_OPTIMIZER_ENABLED | true | Enables inverted index count optimizer. | + + +## MaxMind GeoIP +| Environment Variable | Default Value | Description | +| -------------------------------------- | -------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- | +| ZO_MMDB_DISABLE_DOWNLOAD | true | By default, auto download of MMDB is disabled. To enable it, set this to false. | +| ZO_MMDB_DATA_DIR | ./data/openobserve/mmdb/ | Defines the local directory path where OpenObserve looks for MaxMind database files. | +| ZO_MMDB_UPDATE_DURATION_DAYS | 30 | Update interval for MMDB downloads in days. | +| ZO_MMDB_GEOLITE_CITYDB_URL | [https://geoip.zinclabs.dev/GeoLite2-City.mmdb](https://geoip.zinclabs.dev/GeoLite2-City.mmdb) | GeoLite City database URL. | +| ZO_MMDB_GEOLITE_ASNDB_URL | [https://geoip.zinclabs.dev/GeoLite2-ASN.mmdb](https://geoip.zinclabs.dev/GeoLite2-ASN.mmdb) | GeoLite ASN database URL. | +| ZO_MMDB_GEOLITE_CITYDB_SHA256_URL | [https://geoip.zinclabs.dev/GeoLite2-City.sha256](https://geoip.zinclabs.dev/GeoLite2-City.sha256) | GeoLite City database SHA-256 URL. | +| ZO_MMDB_GEOLITE_ASNDB_SHA256_URL | [https://geoip.zinclabs.dev/GeoLite2-ASN.sha256](https://geoip.zinclabs.dev/GeoLite2-ASN.sha256) | GeoLite ASN database SHA-256 URL. | + +## Meta Storage +| Environment Variable | Default Value | Description | +| ------------------------------------- | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| ZO_META_STORE | - | Default is sqlite for local mode, postgres or mysql for cluster mode. and supported values are: sqlite, postgres, mysql. Note that sqlite is supported only for local mode. | +| ZO_META_TRANSACTION_LOCK_TIMEOUT | 600 | Timeout (in seconds) of transaction lock in meta table. | +| ZO_META_TRANSACTION_RETRIES | 3 | Maximum time the transaction in the meta table will be retried. | +| ZO_META_POSTGRES_DSN | - | If you enable postgres as meta store, you need configure the database source address, like this: postgres://postgres:12345678@localhost:5432/openobserve | +| ZO_META_MYSQL_DSN | - | set this if you want to use MySQL as metadata and filelist store. | +| ZO_META_CONNECTION_POOL_MIN_SIZE | - | Minimum number of connections created in the connection pool size for postgres, sqlite, and mysql. Defaults to cpu_limits | +| ZO_META_CONNECTION_POOL_MAX_SIZE | - | Maximum number of connections created in the connection pool size for postgres, sqlite, and mysql. Defaults to `cpu_limits * 2` | + +> For local mode, OpenObserve use SQLite as the metadata store. +> For cluster mode, OpenObserve use PostgreSQL (recommended) or MySQL as the metadata store. + +## Bloom Filter +| Environment Variable | Default Value | Description | +| --------------------------------------- | ------------- | ------------------------------------------------------------------- | +| ZO_BLOOM_FILTER_ENABLED | true | Enable by default, but only enabled for trace_id field. | +| ZO_BLOOM_FILTER_DEFAULT_FIELDS | - | Add more fields support by bloom filter, will add UI setting later. | +| ZO_BLOOM_FILTER_DISABLED_ON_SEARCH | false | Disable bloom filter for search queries. | + +## Usage Reporting +| Environment Variable | Default Value | Description | +| ----------------------------- | -------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| ZO_USAGE_REPORTING_ENABLED | false | Enable usage reporting. This will start capturing how much data has been ingested across each org/stream. You can use this info to enable charge back for internal teams. | +| ZO_USAGE_ORG | meta | To which org the usage data should be sent. | +| ZO_USAGE_BATCH_SIZE | 2000 | How many requests should be batched before flushing the usage data from memory to disk. | +| ZO_USAGE_REPORTING_MODE | local | Local mode means the usage will be reported only in the internal cluster of ZO_USAGE_ORG. remote mode means that the usage reporting will be ingested to the remote target. both ingests the usage reports both to internal and remote target. | +| ZO_USAGE_REPORTING_URL | [http://localhost:5080/api/_meta/usage/_json](http://localhost:5080/api/_meta/usage/_json) | In case of remote or both value of ZO_USAGE_REPORTING_MODE, this URL is used to post the usage reports to remote target. | +| ZO_USAGE_REPORTING_CREDS | - | The credentials required to send along with the post request to the ZO_USAGE_REPORTING_URL. E.g. - Basic cm9vdEBleGFtcGxlLmNvbTpDb21wbGV4UGFzcyMxMjM=. | +| ZO_USAGE_PUBLISH_INTERVAL | 600 | Duration in seconds after the last reporting usage will be published. | + +## SMTP + +| Environment Variable | Default Value| Description | +| -------------------- | --------- | --------------------------------------------------------------------------- | +| ZO_SMTP_ENABLED | false | Indicates if smtp configuration is present. | +| ZO_SMTP_HOST | `localhost` | The SMTP host to connect to.| +| ZO_SMTP_PORT | 25 | The SMTP port to connect to. | +| ZO_SMTP_USER_NAME | | SMTP user name. `Required` when using smtp. | +| ZO_SMTP_PASSWORD | | SMTP user password. `Required` when using smtp. | +| ZO_SMTP_REPLY_TO | | The user email whom people can reply to. | +| ZO_SMTP_FROM_EMAIL | | The user email that is going to send the email. `Required` when using smtp. | +| ZO_SMTP_ENCRYPTION | | SMTP encryption method. Possible values are `ssltls`, `starttls` and "" (in case of localhost smtp). | + + +## Streaming search + +| Environment Variable | Default Value| Description | +| -------------------------------- | --------- | ------------------------------------------------------- | +| ZO_STREAMING_ENABLED | true | Enables streaming search. | +| ZO_STREAMING_RESPONSE_CHUNK_SIZE_MB | 1 | Size in megabytes for each chunk when streaming search responses. | + + +## Rate limiting + +| Environment Variable | Default Value | Description | +| -------------------------------- | --------- | ------------------------------------------------------- | +| O2_RATE_LIMIT_ENABLED | false | Enables rate limiting. | +| O2_RATE_LIMIT_RULE_REFRESH_INTERVAL | 10 | Refresh interval for rate limit rules in seconds. | + + +## Quick mode + +| Environment Variable | Default Value | Description | +| -------------------------------- | --------- | ------------------------------------------------------- | +| ZO_QUICK_MODE_ENABLED | false | Indicates if quick mode is enabled. | +| ZO_QUICK_MODE_NUM_FIELDS | 500 | The number of fields to consider for quick mode. | +| ZO_QUICK_MODE_STRATEGY | | Possible values are `first`, `last`, `both`. | + + +## Miscellaneous +| Environment Variable | Default Value | Description | +|---------------------|---------------|-------------| +| ZO_STARTING_EXPECT_QUERIER_NUM | 0 | The number of queriers expected to be running while caching enrichment tables. | +| ZO_QUERY_THREAD_NUM | - | The number of threads for searching in data files. | +| ZO_QUERY_TIMEOUT | 600 | Default timeout of query, unit: seconds | +| ZO_QUERY_INDEX_THREAD_NUM | 0 | Controls thread count for Tantivy index search. Set to 0 to use default: CPU cores × 4. Set a positive integer to override. 0 does not mean unlimited. | +| ZO_QUERY_OPTIMIZATION_NUM_FIELDS | 1000 | Field count threshold used by query optimizations. | +| ZO_QUERY_PARTITION_BY_SECS | 10 | Query partition size. Unit is seconds. | +| ZO_QUERY_GROUP_BASE_SPEED | 768 | Baseline throughput per core for group operations. Unit is MB per second per core. | +| ZO_MEMORY_CIRCUIT_BREAKER_ENABLED | false | Enables memory circuit breaker. | +| ZO_MEMORY_CIRCUIT_BREAKER_RATIO | 90 | Memory usage threshold percentage for circuit breaker. | +| ZO_RESTRICTED_ROUTES_ON_EMPTY_DATA | false | Redirects users to the ingestion page when no stream is found. | +| ZO_QUERY_ON_STREAM_SELECTION | true | Triggers search based on a button click event. | +| ZO_RESULT_CACHE_ENABLED | true | Enables result cache for query results. | +| ZO_USE_MULTIPLE_RESULT_CACHE | false | Uses multiple result caches for query results. | +| ZO_RESULT_CACHE_SELECTION_STRATEGY | overlap | Strategy for selecting result cache. Allowed values include both, overlap, duration. | +| ZO_ALIGN_PARTITIONS_FOR_INDEX | false | Uses large partitions for index across all streams. | +| ZO_TRACING_SEARCH_ENABLED | false | Enables tracing for search operations. | +| ZO_AGGREGATION_TOPK_ENABLED | true | Enables approx top-k aggregations. | +| ZO_FEATURE_FILELIST_DEDUP_ENABLED | false | Deprecated. Not used by the code. Will be removed. | +| ZO_FEATURE_QUERY_QUEUE_ENABLED | true | Enterprise edition must not enable this. In the open source edition, when enabled, the system processes only one search request at a time. | +| ZO_FEATURE_QUERY_INFER_SCHEMA | false | Deprecated. Not used by the code. Will be removed. | +| ZO_FEATURE_DISTINCT_EXTRA_FIELDS | - | Reserved for future use. Contact the maintainers for guidance. | + + +--- + +## Super-Cluster + +> The following environment variables are available only in the Enterprise edition. + +| Environment Variable | Default Value | Description | +| ---------------------------- | ------------- | ----------------------------------------------- | +| O2_SUPER_CLUSTER_ENABLED | false | Indicates if super cluster is enabled. | +| O2_SUPER_CLUSTER_REGION | default | Region of super cluster. | +| O2_SUPER_CLUSTER_PUBLIC_ADDR | | Public address of super cluster. | +| O2_SUPER_CLUSTER_PUBLIC_PORT | | Public port of super cluster (in case of gRPC). | +| O2_SUPER_CLUSTER_GRPC_TOKEN | | gRPC token. | + +## Search-Group +> The following environment variables are available only in the Enterprise edition. + +| Environment Variable | Default Value | Description | +| --------------------------------------- | ------------- | ------------------- | +| O2_SEARCH_GROUP_LONG_MAX_CPU | 80% | The percentage of CPU allocated to long queries. | +| O2_SEARCH_GROUP_LONG_MAX_MEMORY | 80% |The percentage of memory allocated to long queries. | +| O2_SEARCH_GROUP_LONG_MAX_CONCURRENCY | 2 |Maximum number of concurrent long queries.| +| O2_SEARCH_GROUP_SHORT_MAX_CPU | 20% |Percentage of CPU allocated to short queries.| +| O2_SEARCH_GROUP_SHORT_MAX_CONCURRENCY | 4 |Maximum number of concurrent short queries.| +| O2_SEARCH_GROUP_SHORT_MAX_MEMORY | 20% |Percentage of memory allocated to short queries.| +| O2_SEARCH_GROUP_BASE_SPEED | 1024 | Base speed in MB. | +| O2_SEARCH_GROUP_BASE_SECS | 10 | Base speed in secs. | + +## OpenFGA +> The following environment variables are available only in the Enterprise edition. + +| Environment Variable | Default Value | Description | +| ---------------------------------- | --------- | ---------------------------------------------------------------------------- | +| O2_OPENFGA_ENABLED | false| Indicates if openfga is enabled. | +| O2_OPENFGA_BASE_URL | `http://127.0.0.1:8080/stores` | The base URL of openfga stores server. **Required** when openfga is enabled. | +| O2_OPENFGA_STORE_NAME | `openobserve` | OpenFGA store name. **Required** when openfga is enabled. | +| O2_MAP_GROUP_TO_ROLE | false | If true, the group claims are mapped into roles in the default org. | +| O2_OPENFGA_PAGE_SIZE | `100`| The page size used for openfga queries. | +| O2_OPENFGA_LIST_ONLY_PERMITTED | false | If true, openobserve only lists resources that have `GET` permission. | +| O2_MAP_GROUP_TO_ROLE_SKIP_CREATION | true | Used with `O2_MAP_GROUP_TO_ROLE`. Skips creating the roles mapped from group claims assuming they already exists. | + +## DEX +> The following environment variables are available only in the Enterprise edition. + +| Environment Variable | Default Value |Description | +| --------------------------- | --------------------------- | ------------------------------------------------------------------- | +| O2_DEX_ENABLED | false | Enables SSO in OpenObserve using Dex. | +| O2_DEX_CLIENT_ID | - | Client id of static client. **Required** when dex is enabled. | +| O2_DEX_CLIENT_SECRET | - | Client secret of static client. **Required** when dex is enabled. | +| O2_DEX_BASE_URL | `http://127.0.0.1:5556/dex` | URL of the Dex identity provider. **Required** when dex is enabled. | +| O2_CALLBACK_URL | - | Set this value to `/web/cb`, after successful token received from dex, user will be redirected to this page. **Required** when dex is enabled. | +| O2_DEX_REDIRECT_URL | - | Set this value to `/config/redirect`, Should match to redirect uri specified in dex. **Required** when dex is enabled. | +| O2_DEX_SCOPES | openid profile email groups offline_access | Scopes to be fetched from dex. | +| O2_DEX_GROUP_ATTRIBUTE | ou | Maps user to OpenObserve organization. | +| O2_DEX_ROLE_ATTRIBUTE | cn | User's role in the organization. | +| O2_DEX_DEFAULT_ORG | default | Default organization for users not belonging to any group in ldap. | +| O2_DEX_TOKEN_EP_SUFFIX | `/token` | Suffix for dex token endpoint.| +| O2_DEX_KEYS_EP_SUFFIX | `/keys` | Suffix for dex keys endpoint. | +| O2_DEX_AUTH_EP_SUFFIX | `/auth` | Suffix for dex authentication endpoint. | +| O2_DEX_NATIVE_LOGIN_ENABLED | true | Indicates if native dex login is enabled. | + + +## Other Enterprise Features + +| Environment Variable | Default Value | Description | +| ------------------------- | ------------- | --------------------------------------------------------------------------------------- | +| O2_AUDIT_ENABLED | false | Indicates if audit reporting is enabled. | +| O2_AUDIT_BATCH_SIZE | 500 | How many requests should be batched before flushing the audit data from memory to disk. | +| O2_CUSTOM_LOGO_TEXT | | Custom logo text that will appear along with the openobserve logo. | +| O2_CUSTOM_SLACK_URL | | Custom slack URL that will be used by the `Slack` menu on the openobserve UI. | +| O2_CUSTOM_DOCS_URL | | Custom docs URL that will be used by the `docs` tab on the openobserve UI. | +| O2_CUSTOM_HIDE_MENUS | | Comma-separated menu items that should not be shown in the menu on openobserve UI. For example, `metrics,traces`. | + + + + \ No newline at end of file diff --git a/docs/images/enable-disable-streaming-search.png b/docs/images/enable-disable-streaming-search.png index 454b4d04..f88cf729 100644 Binary files a/docs/images/enable-disable-streaming-search.png and b/docs/images/enable-disable-streaming-search.png differ diff --git a/docs/js/search-close-minimal.js b/docs/js/search-close-minimal.js index d5e44bd1..ac659bba 100644 --- a/docs/js/search-close-minimal.js +++ b/docs/js/search-close-minimal.js @@ -1,9 +1,65 @@ +// Show/hide close icon based on .md-search-result__meta visibility +function isElementInViewport(el) { + if (!el) return false; + const rect = el.getBoundingClientRect(); + return ( + rect.top < window.innerHeight && + rect.bottom > 0 && + rect.left < window.innerWidth && + rect.right > 0 + ); +} + +function toggleCloseIconVisibility() { + const meta = document.querySelector(".md-search-result__meta"); + const closeIcon = document.querySelector(".md-search__close"); + if (closeIcon) { + if (isElementInViewport(meta)) { + closeIcon.style.display = "flex"; + } else { + closeIcon.style.display = "none"; + } + } +} + +window.addEventListener("scroll", toggleCloseIconVisibility); +window.addEventListener("resize", toggleCloseIconVisibility); +document.addEventListener("DOMContentLoaded", toggleCloseIconVisibility); +// Also run after search results update +document.addEventListener("input", function (e) { + if (e.target.classList.contains("md-search__input")) { + setTimeout(toggleCloseIconVisibility, 50); + } +}); /** * Minimal Search Close Functionality * Adds click handler to the close icon in the search input */ document.addEventListener("DOMContentLoaded", function () { + // Inject clear button if not present + const searchInput = document.querySelector(".md-search__input"); + if (searchInput && !document.querySelector(".md-search__clear")) { + const clearBtn = document.createElement("button"); + clearBtn.className = "md-search__clear"; + clearBtn.type = "button"; + clearBtn.textContent = "Clear"; + searchInput.parentNode.insertBefore(clearBtn, searchInput.nextSibling); + + clearBtn.addEventListener("click", function () { + searchInput.value = ""; + searchInput.dispatchEvent(new Event("input", { bubbles: true })); + searchInput.focus(); + clearBtn.style.display = "none"; + }); + + searchInput.addEventListener("input", function () { + clearBtn.style.display = searchInput.value ? "inline" : "none"; + }); + + // Initial state + clearBtn.style.display = searchInput.value ? "inline" : "none"; + } // Add click handler to search input when close icon area is clicked document.addEventListener("click", function (e) { const searchInput = document.querySelector(".md-search__input"); diff --git a/docs/js/toc-highlight.js b/docs/js/toc-highlight.js new file mode 100644 index 00000000..94dbdae0 --- /dev/null +++ b/docs/js/toc-highlight.js @@ -0,0 +1,92 @@ +/** + * Simple TOC scroll-based highlighting + * Highlights current section in purple text + */ + +(function () { + "use strict"; + + let tocLinks = []; + let headings = []; + + function init() { + // Find TOC links + tocLinks = Array.from( + document.querySelectorAll(".md-nav--secondary .md-nav__link") + ); + if (tocLinks.length === 0) return; + + // Find corresponding headings + headings = tocLinks + .map((link) => { + const href = link.getAttribute("href"); + return href && href.startsWith("#") + ? document.getElementById(href.substring(1)) + : null; + }) + .filter((h) => h !== null); + + if (headings.length === 0) return; + + // Listen to scroll + window.addEventListener("scroll", updateHighlight, { passive: true }); + updateHighlight(); + } + + function updateHighlight() { + const scrollTop = window.pageYOffset; + const windowHeight = window.innerHeight; + const documentHeight = document.documentElement.scrollHeight; + + // If near bottom, highlight last item + if (scrollTop + windowHeight >= documentHeight - 50) { + setActive(tocLinks.length - 1); + return; + } + + // Find current section + let activeIndex = -1; + for (let i = headings.length - 1; i >= 0; i--) { + if (headings[i] && headings[i].getBoundingClientRect().top <= 80) { + activeIndex = i; + break; + } + } + + setActive(activeIndex); + } + + function setActive(index) { + // Remove all active classes + tocLinks.forEach((link) => { + link.classList.remove("md-nav__link--active", "is-active"); + }); + + // Add active class to current item and scroll into view if needed + if (index >= 0 && index < tocLinks.length) { + const activeLink = tocLinks[index]; + activeLink.classList.add("md-nav__link--active", "is-active"); + // Scroll the active link into view within the sidebar + // Only if not already fully visible + if (typeof activeLink.scrollIntoView === "function") { + activeLink.scrollIntoView({ block: "nearest", behavior: "smooth" }); + } + } + } + + // Initialize when ready + if (document.readyState === "loading") { + document.addEventListener("DOMContentLoaded", init); + } else { + init(); + } + + // Re-initialize on page changes + let currentUrl = location.href; + new MutationObserver(() => { + if (location.href !== currentUrl) { + currentUrl = location.href; + setTimeout(init, 100); + } + }).observe(document, { childList: true, subtree: true }); +})(); diff --git a/docs/operator-guide/etcd.md b/docs/operator-guide/etcd.md index 8cca3300..f4363177 100644 --- a/docs/operator-guide/etcd.md +++ b/docs/operator-guide/etcd.md @@ -1,12 +1,16 @@ --- -title: Etcd Maintenance +title: Etcd Maintenance (Deprecated) weight: 4450 description: >- Learn how to maintain your etcd cluster with compaction, defragmentation, and space quotas to prevent data loss and ensure reliable performance. --- -# Etcd Maintenance +# Etcd Maintenance (Deprecated) + +!!! warning "Deprecation Notice" + Support for **etcd** has been deprecated in OpenObserve. + ## Overview diff --git a/docs/operator-guide/etcd_restore.md b/docs/operator-guide/etcd_restore.md index 6b1d0fea..a0c30630 100644 --- a/docs/operator-guide/etcd_restore.md +++ b/docs/operator-guide/etcd_restore.md @@ -3,7 +3,7 @@ description: >- Restore a broken etcd cluster in OpenObserve by restarting pods, resetting data, and rejoining members using CLI and updated Helm configs. --- -# Etcd Cluster Restore +# Etcd Cluster Restore (Deprecated) Many users ran into the case only one of the 3 pods of etcd cluster can works. The other 2 pods always restart and can't back to work. diff --git a/docs/stylesheets/extra.css b/docs/stylesheets/extra.css index 2ce80a1b..8d9e5924 100644 --- a/docs/stylesheets/extra.css +++ b/docs/stylesheets/extra.css @@ -1,3 +1,85 @@ +/* Hide the search close icon by default; JS will show it when needed */ +.md-search__close { + display: none !important; +} +/* === FINAL SECONDARY SIDEBAR POSITIONING OVERRIDE === */ +.md-sidebar--secondary, +.md-sidebar--secondary[data-md-component="sidebar"], +.md-sidebar--secondary[data-md-state], +.md-sidebar--secondary[data-md-state="lock"] { + position: sticky !important; + top: 8rem !important; + transform: none !important; + transition: none !important; + will-change: auto !important; + z-index: 200 !important; +} + +/* STRONG FINAL MOBILE SCROLL FIX (highest priority): + Lock the sidebar inner to the viewport and force the scrollwrap to handle + vertical scrolling. This is intentionally placed at the end and uses + !important to win over earlier rules that made nested lists overflow. +*/ +@media (max-width: 76.24em) { + /* Ensure the sidebar occupies the viewport height while drawer is open */ + .md-sidebar--primary, + input[id="__drawer"]:checked ~ .md-container .md-sidebar--primary, + .md-toggle[data-md-toggle="drawer"]:checked + ~ .md-container + .md-sidebar--primary { + position: fixed !important; + top: 0 !important; + left: 0 !important; + height: 100vh !important; + max-height: 100vh !important; + overflow: hidden !important; /* prevent sidebar itself from scrolling */ + will-change: auto !important; + } + + /* Keep the inner wrapper full height but clipped; scrollwrap will scroll */ + .md-sidebar--primary .md-sidebar__inner { + height: 100% !important; + max-height: 100% !important; + overflow: hidden !important; + position: relative !important; + } + + /* Force scrollwrap to fill available space and handle vertical scrolling */ + .md-sidebar--primary .md-sidebar__scrollwrap, + input[id="__drawer"]:checked + ~ .md-container + .md-sidebar--primary + .md-sidebar__scrollwrap, + .md-toggle[data-md-toggle="drawer"]:checked + ~ .md-container + .md-sidebar--primary + .md-sidebar__scrollwrap { + height: 100% !important; + max-height: 100% !important; + overflow-y: auto !important; + overflow-x: hidden !important; + -webkit-overflow-scrolling: touch !important; + position: relative !important; + } + + /* Prevent nested navs from using absolute/transform tricks that remove them + from the scroll context (keep them in normal flow) */ + .md-sidebar--primary .md-nav__list, + .md-sidebar--primary .md-nav__item, + .md-sidebar--primary .md-nav__item > .md-nav__list, + .md-sidebar--primary nav[data-md-level] { + position: static !important; + transform: none !important; + max-height: none !important; + overflow: visible !important; + } + + /* Make sure scrolling works with touch and pointer events */ + .md-sidebar--primary .md-sidebar__scrollwrap { + touch-action: pan-y !important; + } +} + [data-md-color-scheme="openobserve"] { --md-primary-fg-color: #ffffff; --md-primary-fg-color--light: #ecb7b7; @@ -42,15 +124,6 @@ html { 4. Provide stable scrollbar to avoid layout shift. */ @media (min-width: 60em) { - /* Minimal, non-intrusive adjustments */ - .md-sidebar--primary { - position: sticky; /* stay visible */ - top: 0; /* eliminate excess gap */ - z-index: 200; - display: flex; - flex-direction: column; - } - /* Add bottom padding to main content so sidebar never gets overlapped by footer */ .md-main, .md-content { @@ -59,12 +132,19 @@ html { .md-footer { z-index: 0; } - /* Give room so last items can scroll fully into view */ + /* Primary sidebar scroll container - content-based height like secondary sidebar */ .md-sidebar--primary .md-sidebar__scrollwrap { - flex: 1; - overflow-y: auto; - padding: 0.25rem 0 2.25rem; /* trim top, moderate bottom */ - overscroll-behavior: contain; + overflow-y: auto !important; + padding: 0.25rem 0 1rem !important; + overscroll-behavior: contain !important; + width: 100% !important; + padding-right: 0 !important; + margin-right: 0 !important; + border-right: none !important; + box-sizing: border-box !important; + /* Allow content-based height with increased footer clearance */ + height: auto !important; + max-height: calc(100vh - 12rem) !important; } /* Remove bottom fade/overlay that appeared as white block */ .md-sidebar--primary .md-sidebar__scrollwrap:after { @@ -139,20 +219,6 @@ html { background-color: #1a1a2e !important; } -/* Custom search bar styles for MkDocs Material */ - -.md-search__input { - background-color: rgb(245, 243, 254); - border: 2px solid #7c3aed !important; - border-radius: 8px !important; - color: #222 !important; - transition: border-color 0.2s; - box-shadow: none !important; - padding: 0.75em 2.5em 0.75em 1em !important; /* more height and space for icon */ - font-size: 1.5em !important; - min-width: 16em !important; -} - .md-search__input:focus { border-color: #7c3aed !important; outline: none; @@ -171,7 +237,7 @@ html { color: #fff !important; border-radius: 8px !important; box-shadow: none !important; - padding: 0.75em 2.5em 0.75em 3.2em !important; + padding: 8px 3.2em 8px 3.2em !important; font-size: 1.5em !important; min-width: 16em !important; } @@ -196,24 +262,30 @@ html { /* Direct approach: Add close button to search input */ .md-search__input { - background-color: rgb(245, 243, 254); - border: 2px solid #7c3aed !important; + background-color: #ede9fe; + border: 1px solid #7c3aed !important; border-radius: 8px !important; color: #222 !important; transition: border-color 0.2s; box-shadow: none !important; - padding: 0.2em 3.2em 0.2em 3.2em !important; /* Remove extra right padding for desktop */ + padding: 9px 3.2em 9px 3.2em !important; /* Match docs title padding: 5px vertical */ font-size: 1.5em !important; min-width: 20em !important; - height: 3em !important; - /* Remove background image for desktop - will be added for mobile only */ + height: auto !important; /* Let height be determined by padding + content */ + background-image: url("/docs/assets/close-icon.svg") !important; + background-repeat: no-repeat !important; + background-position: calc(100% - 1em) center !important; + background-size: 1.2em !important; } .md-search__input::placeholder { color: #7c3aed !important; opacity: 1 !important; - font-size: 1.25em !important; - font-weight: 500 !important; + font-size: 1.2em !important; + font-weight: 400 !important; letter-spacing: 0.02em; + position: absolute !important; + top: 50% !important; + transform: translateY(-50%) !important; } .md-search__icon { @@ -221,7 +293,7 @@ html { /* transition: color 0.2s; */ position: absolute !important; right: 1.5em !important; - top: 50% !important; + top: 46% !important; transform: translateY(-50%) !important; font-size: 1.25em !important; pointer-events: auto; @@ -241,20 +313,16 @@ html { [data-md_color-scheme="slate"] .md-search__input { background-color: #7c3aed !important; color: #fff !important; - border-radius: 999px !important; + border-radius: 8px !important; box-shadow: none !important; - padding: 0.85em 3.2em 0.85em 3.2em !important; /* Remove extra right padding for desktop */ + padding: 8px 3.2em 8px 3.2em !important; /* Match docs title padding: 5px vertical */ font-size: 1.5em !important; min-width: 20em !important; - height: 3em !important; + height: auto !important; /* Let height be determined by padding + content */ /* Remove close button for desktop - will be added for mobile only */ } [data-md-color-scheme="slate"] .md-search__input::placeholder { color: #fff !important; - opacity: 1 !important; - font-size: 1.25em !important; - font-weight: 500 !important; - letter-spacing: 0.02em; } [data-md-color-scheme="slate"] .md-search__icon { @@ -267,6 +335,20 @@ html { pointer-events: none; } +/* --- NAVBAR HEIGHT CONSISTENCY --- */ +.md-header { + min-height: 4rem !important; + height: auto !important; + position: sticky !important; + top: 0 !important; +} + +.md-header__inner { + min-height: 4rem !important; + height: auto !important; + /* padding: 0.5rem 1rem !important; */ +} + /* --- FINAL: Sidebar Custom Design --- */ .md-sidebar--primary { background: rgb(245, 243, 254) !important; @@ -275,14 +357,24 @@ html { padding: 1em 0.5em !important; /* margin-right: 2em !important; */ box-shadow: none !important; - z-index: 10 !important; - /* allow the active indicator to sit inside the rounded border */ - overflow: visible !important; + z-index: 200 !important; + position: sticky !important; + top: 8rem !important; + /* Content-based height with increased footer clearance */ + height: auto !important; + min-height: auto !important; + max-height: calc(100vh - 9rem) !important; + overflow: hidden !important; + /* Keep it visible when scrolling */ + transform: none !important; + display: block !important; } -@media (min-width: 1024px) { +/* Desktop-only styles */ +@media (min-width: 76.25em) { .md-sidebar--primary { margin-left: 12px; + margin-right: 1em !important; } } [data-md-color-scheme="slate"] .md-sidebar--primary { @@ -290,10 +382,24 @@ html { border: 2px solid #7c3aed !important; border-radius: 8px !important; padding: 1em 0.5em !important; - margin-right: 2em !important; box-shadow: none !important; - z-index: 10 !important; + z-index: 200 !important; + position: sticky !important; + top: 8rem !important; + /* Content-based height with increased footer clearance */ + height: auto !important; + min-height: auto !important; + max-height: calc(100vh - 9rem) !important; overflow: hidden !important; + transform: none !important; + display: block !important; +} + +/* Desktop-only dark theme margin */ +@media (min-width: 76.25em) { + [data-md-color-scheme="slate"] .md-sidebar--primary { + margin-right: 1em !important; + } } .md-sidebar__title, @@ -307,55 +413,31 @@ html { .md-sidebar--primary .md-nav__item--active > .md-nav__link { position: relative !important; background: transparent !important; - border-radius: 5px !important; + border-radius: 3px !important; /* make the active link text bold (applies to the text, not the empty pseudo-element) */ font-weight: 700 !important; /* leave space on the RIGHT for the indicator that sits against the sidebar border */ padding-right: 1.6em !important; /* keep a little left padding for text alignment */ padding-left: 1.1em !important; - overflow: visible !important; + overflow: hidden !important; } .md-sidebar--primary .md-nav__item--active > .md-nav__link::before { content: ""; position: absolute; - /* place the indicator INSIDE the sidebar inner border (right side in this theme) - tweak the `right` value if you want it closer/further from the border */ - right: 8px; /* adjust this number to visually align with your border (2px) */ + right: 8px; left: 0; top: 50%; transform: translateY(-50%); width: 4px; - height: 25px; + height: 30px; background: #4b237a; - /* slightly rounded marker to match sidebar corner curvature */ border-radius: 3px !important; z-index: 3 !important; - /* font-weight on an empty pseudo-element has no effect; kept empty for visual bar */ -} - -/* Thin sidebar scrollbar thumb, flush with border */ -.md-sidebar--primary .md-sidebar__scrollwrap { - scrollbar-width: thin !important; -} -.md-sidebar--primary .md-sidebar__scrollwrap::-webkit-scrollbar { - width: 6px !important; - background: transparent !important; -} -.md-sidebar--primary .md-sidebar__scrollwrap::-webkit-scrollbar-thumb { - background: #7c3aed !important; - border-radius: 6px !important; - margin: 0 !important; - border: none !important; } /* --- Sidebar: Add right margin for full rounded border visibility --- */ -.md-sidebar--primary { - margin-right: 1em !important; -} -[data-md_color-scheme="slate"] .md-sidebar--primary { - margin-right: 1em !important; -} +/* Margins are now handled in the main sidebar rules above */ /* --- Remove white shadow from sidebar title --- */ .md-sidebar__title { @@ -382,16 +464,6 @@ html { border-right: none !important; box-sizing: border-box !important; } -.md-sidebar--primary .md-sidebar__scrollwrap::-webkit-scrollbar { - width: 6px !important; - background: transparent !important; -} -.md-sidebar--primary .md-sidebar__scrollwrap::-webkit-scrollbar-thumb { - background: #7c3aed !important; - border-radius: 6px !important; - border-right: none !important; - margin-right: 0 !important; -} /* --- Final fix: Remove all space between sidebar scrollbar and border --- */ .md-sidebar--primary { @@ -438,43 +510,6 @@ html { } /* Hide native scrollbar inside the sidebar scrollwrap and provide a custom - visual track + thumb that we control via JS so the active marker can be - aligned exactly with the visible thumb. */ -.md-sidebar--primary .md-sidebar__scrollwrap { - scrollbar-width: none !important; /* Firefox */ -} -.md-sidebar--primary .md-sidebar__scrollwrap::-webkit-scrollbar { - display: none !important; /* Chrome/Safari */ -} - -/* custom track & thumb appended as children of the outer sidebar */ -.md-sidebar--primary > .o-scroll-track { - position: absolute; - right: 2px; - width: 12px; /* includes some padding so thumb doesn't touch the border */ - top: 0; - height: 100%; - pointer-events: none; /* visual only */ -} -.md-sidebar--primary > .o-scroll-track .o-scroll-thumb { - position: absolute; - right: 3px; /* place thumb inside track, a few px from border */ - width: 6px; - background: #4b237a; /* purple thumb */ - border-radius: 6px; - box-shadow: 0 0 0 2px rgba(75, 35, 122, 0.06) inset; - transition: top 120ms linear, height 120ms linear; - pointer-events: auto; -} - -/* Keep the active indicator visually matching the custom thumb (same color) - but slightly narrower so it reads as an indicator inside the sidebar. */ -.md-sidebar--primary > .o-active-indicator { - right: 8px; /* move it slightly left so it appears inside the content area */ - width: 4px; - background: #4b237a; -} - /* --- Remove background and shadow from sidebar nav title --- */ .md-sidebar--primary .md-nav__title, .md-sidebar--primary .md-nav__title:before, @@ -484,6 +519,25 @@ html { border: none !important; } +/* Ensure primary sidebar inner container is content-based like secondary */ +.md-sidebar--primary .md-sidebar__inner { + height: auto !important; + min-height: auto !important; + display: block !important; + overflow: hidden !important; +} + +/* Ensure all navigation elements stay within sidebar boundaries */ +.md-sidebar--primary .md-nav, +.md-sidebar--primary .md-nav__list, +.md-sidebar--primary .md-nav__item, +.md-sidebar--primary .md-nav__link { + max-width: 100% !important; + overflow: hidden !important; + text-overflow: ellipsis !important; + word-wrap: break-word !important; +} + .md-nav__title { font-weight: 700 !important; /* Ensure the nav title is not sticky — override any theme "sticky" rules */ @@ -506,6 +560,21 @@ html { display: none !important; } +/* Prevent theme from adding background or shadow to secondary nav titles */ +@media screen and (min-width: 60em) { + .md-nav--secondary .md-nav__title, + .md-nav--secondary .md-nav__title:before, + .md-nav--secondary .md-nav__title:after, + .md-sidebar--secondary .md-nav__title, + .md-sidebar--secondary .md-nav__title:before, + .md-sidebar--secondary .md-nav__title:after { + background: transparent !important; + box-shadow: none !important; + border: none !important; + position: static !important; /* prevent sticky if applied elsewhere */ + z-index: auto !important; + } +} /* Reset any conflicting styles */ /* Reset any conflicting styles */ @@ -515,6 +584,7 @@ html { .md-header .md-search__input { min-width: 14em !important; font-size: 1.5em !important; + height: auto !important; /* Ensure consistent height calculation */ } } @@ -536,7 +606,7 @@ html { width: 100% !important; min-width: auto !important; margin: 0 !important; - padding: 0.75em 4.5em 0.75em 1em !important; /* Extra right padding for close button on mobile */ + padding: 5px 4.5em 5px 1em !important; /* Match docs title padding: 5px vertical, extra right for close button */ font-size: 1.2em !important; border-radius: 8px !important; pointer-events: auto !important; @@ -602,5 +672,835 @@ html { min-width: 20em !important; font-size: 1.5em !important; display: inline-block !important; + height: auto !important; /* Ensure consistent height calculation */ + } +} + +/* Slim scrollbar styling for both sidebars - High specificity override */ +.md-sidebar--primary .md-sidebar__scrollwrap { + scrollbar-width: thin !important; + scrollbar-color: #7c3aed transparent !important; +} + +.md-sidebar--primary .md-sidebar__scrollwrap::-webkit-scrollbar { + width: 3px !important; + height: 3px !important; + background: transparent !important; + background-color: transparent !important; +} + +.md-sidebar--primary .md-sidebar__scrollwrap::-webkit-scrollbar-track { + background: transparent !important; + background-color: transparent !important; +} + +.md-sidebar--primary .md-sidebar__scrollwrap::-webkit-scrollbar-thumb { + background: #7c3aed !important; + background-color: #7c3aed !important; + border-radius: 3px !important; + border: none !important; + min-height: 20px !important; +} + +.md-sidebar--primary .md-sidebar__scrollwrap::-webkit-scrollbar-thumb:hover { + background: #6d28d9 !important; + background-color: #6d28d9 !important; +} + +/* Fix sidebar overflow and ensure proper scrolling */ +.md-sidebar--primary .md-sidebar__scrollwrap { + overflow-y: auto !important; + max-height: inherit !important; +} + +/* Ensure sidebars maintain their position and don't move */ +.md-sidebar--primary { + will-change: auto !important; + transition: none !important; + /* Force sticky positioning and prevent any transforms */ + position: sticky !important; + transform: none !important; +} + +/* Override any MkDocs Material default transforms */ +.md-sidebar--primary[data-md-state] { + transform: none !important; +} + +/* Stronger override for primary sidebar positioning */ +.md-sidebar--primary { + top: 8rem !important; + position: sticky !important; +} + +/* Ensure both sidebars have proper footer clearance */ +@media (min-width: 60em) { + .md-main, + .md-content { + padding-bottom: 3rem; + } + .md-footer { + z-index: 0; + margin-top: 2rem; + } +} + +/* === FINAL SIDEBAR POSITIONING OVERRIDE === */ +/* These rules must be at the end to override all other positioning */ +.md-sidebar--primary, +.md-sidebar--primary[data-md-component="sidebar"], +.md-sidebar--primary[data-md-state], +.md-sidebar--primary[data-md-state="lock"] { + position: sticky !important; + top: 8rem !important; + transform: none !important; + transition: none !important; + will-change: auto !important; + z-index: 200 !important; +} + +/* Override any CSS transforms that might be applied by JavaScript */ +.md-sidebar--primary * { + transform: none !important; +} +/* Force override any inline styles that might be applied by MkDocs Material */ +.md-sidebar--primary[style*="transform"] { + transform: none !important; +} + +/* Additional safety measures to prevent sidebar shifting */ +html .md-sidebar--primary { + position: sticky !important; + top: 8rem !important; +} + +/* Remove any masking pseudo-elements from primary sidebar - like secondary sidebar */ +.md-sidebar--primary .md-sidebar__scrollwrap:after { + display: none !important; +} + +.md-sidebar--primary:before, +.md-sidebar--primary:after, +.md-sidebar--primary .md-sidebar__inner:before, +.md-sidebar--primary .md-sidebar__inner:after { + display: none !important; +} + +.md-header { + position: fixed !important; + top: 70px !important; +} + +.md-main__inner { + margin-top: 70px !important; +} + +nav.md-grid { + max-width: 100%; + margin-left: auto; + margin-right: auto; + padding-left: 1rem; /* default (base) = px-4 */ + padding-right: 1rem; +} + +@media (min-width: 640px) { + nav.md-grid { + padding-left: 1.5rem; /* sm:px-6 */ + padding-right: 1.5rem; + } +} + +@media (min-width: 1024px) { + nav.md-grid { + padding-left: 2rem; /* lg:px-8 */ + padding-right: 2rem; + } +} + +@media (min-width: 1280px) { + nav.md-grid { + padding-left: 2.5rem; /* xl:px-10 */ + padding-right: 2.5rem; + } +} +.md-search__inner { + width: 20rem; +} +@media (max-width: 768px) { + .md-search__inner { + top: 80px !important; + } + + .md-search__input { + pointer-events: auto !important; + color: black !important; + } +} + +.md-header__title { + margin-left: 0.1rem; + width: 100px; +} + +@media (min-width: 1025px) { + .md-header__title { + flex-grow: 0; + flex-basis: auto; + max-width: 400px; + } + .md-header__inner { + display: flex; + align-items: center; + justify-content: space-between; + } +} + +/* === MOBILE SIDEBAR RESPONSIVE FIXES === */ + +/* Mobile breakpoints for sidebar */ +@media (max-width: 76.24em) { + /* Reset sidebar positioning for mobile */ + .md-sidebar--primary, + .md-sidebar--primary[data-md-component="sidebar"], + .md-sidebar--primary[data-md-state], + .md-sidebar--primary[data-md-state="lock"] { + position: fixed !important; + top: 0 !important; + left: 0 !important; + width: 100% !important; + max-width: 280px !important; + height: 100vh !important; + max-height: 100vh !important; + z-index: 300 !important; + transform: translateX(-100%) !important; + transition: transform 0.3s ease-in-out !important; + margin: 0 !important; + padding: 1rem !important; + border-radius: 0 !important; + border: none !important; + border-right: 2px solid #7c3aed !important; + box-shadow: 2px 0 8px rgba(0, 0, 0, 0.1) !important; + will-change: transform !important; + } + + /* Show sidebar when drawer is checked (mobile menu open) */ + .md-toggle[data-md-toggle="drawer"]:checked + ~ .md-container + .md-sidebar--primary, + input[id="__drawer"]:checked ~ .md-container .md-sidebar--primary { + transform: translateX(0) !important; + } + + /* Mobile sidebar scroll container */ + .md-sidebar--primary .md-sidebar__scrollwrap { + height: 100% !important; + max-height: calc(100vh - 2rem) !important; + overflow-y: auto !important; + padding: 0 !important; + margin: 0 !important; + border: none !important; + } + + /* Mobile sidebar inner container */ + .md-sidebar--primary .md-sidebar__inner { + height: 100% !important; + min-height: 100% !important; + padding: 1rem 0 !important; + } + + /* Hide secondary sidebar on mobile */ + .md-sidebar--secondary { + display: none !important; + } + + /* Ensure main content doesn't overlap */ + .md-main { + margin-left: 0 !important; + margin-right: 0 !important; + } + + .md-main__inner { + margin-top: 4rem !important; + margin-left: 0 !important; + margin-right: 0 !important; + padding: 0 1rem !important; + } + + /* Mobile navigation improvements */ + .md-sidebar--primary .md-nav__title { + padding: 1rem 0 0.5rem !important; + font-size: 1.1rem !important; + border-bottom: 1px solid rgba(124, 58, 237, 0.2) !important; + margin-bottom: 0.5rem !important; + } + + .md-sidebar--primary .md-nav__link { + padding: 0.75rem 1rem !important; + font-size: 0.9rem !important; + line-height: 1.4 !important; + } + + /* Mobile nested navigation */ + .md-sidebar--primary .md-nav__item--nested .md-nav__link { + padding-left: 1rem !important; + } + + .md-sidebar--primary .md-nav[data-md-level="1"] .md-nav__link { + padding-left: 1.5rem !important; + } + + .md-sidebar--primary .md-nav[data-md-level="2"] .md-nav__link { + padding-left: 2rem !important; + } + + .md-sidebar--primary .md-nav[data-md-level="3"] .md-nav__link { + padding-left: 2.5rem !important; + } + + /* Mobile active link styling */ + .md-sidebar--primary .md-nav__item--active > .md-nav__link::before { + right: 0 !important; + width: 3px !important; + height: 100% !important; + top: 0 !important; + transform: none !important; + } + + /* Mobile drawer overlay */ + .md-overlay { + position: fixed !important; + top: 0 !important; + left: 0 !important; + width: 100% !important; + height: 100% !important; + background: rgba(0, 0, 0, 0.5) !important; + z-index: 250 !important; + opacity: 0 !important; + pointer-events: none !important; + transition: opacity 0.3s ease !important; + } + + input[id="__drawer"]:checked ~ .md-overlay { + opacity: 1 !important; + pointer-events: auto !important; + } +} + +/* Tablet-specific adjustments */ +@media (max-width: 1024px) and (min-width: 769px) { + .md-sidebar--primary { + max-width: 260px !important; + padding: 0.75rem !important; + } + + .md-sidebar--primary .md-sidebar__scrollwrap { + max-height: calc(100vh - 6rem) !important; + } +} + +/* Extra small mobile devices */ +@media (max-width: 480px) { + .md-sidebar--primary { + max-width: 90vw !important; + padding: 0.75rem !important; + } + + .md-sidebar--primary .md-nav__link { + padding: 0.6rem 0.75rem !important; + font-size: 0.85rem !important; + } + + .md-main__inner { + padding: 0 0.5rem !important; + } +} + +/* Dark theme mobile adjustments */ +@media (max-width: 76.24em) { + [data-md-color-scheme="slate"] .md-sidebar--primary { + background: rgb(23, 20, 29) !important; + border-right: 2px solid #7c3aed !important; + box-shadow: 2px 0 12px rgba(0, 0, 0, 0.3) !important; + } + + [data-md-color-scheme="openobserve"] .md-sidebar--primary { + background: #1a1a2e !important; + border-right: 2px solid #7c3aed !important; + box-shadow: 2px 0 12px rgba(0, 0, 0, 0.4) !important; + } +} + +/* Improve mobile header and navigation button */ +@media (max-width: 76.24em) { + .md-header__button[for="__drawer"] { + margin-right: 0.5rem !important; + color: #7c3aed !important; + } + + .md-header__title { + margin-left: 0.5rem !important; + flex-grow: 1 !important; + } +} + +/* MOBILE FIX: Ensure primary sidebar links are tappable on mobile + - force the sidebar and its inner containers above the overlay + - ensure pointer-events are enabled for sidebar and links + - enable smooth touch scrolling inside the scrollwrap +*/ +@media (max-width: 76.24em) { + /* Make sure the sidebar sits above the overlay and other content */ + .md-sidebar--primary { + z-index: 1000 !important; + pointer-events: auto !important; + -webkit-overflow-scrolling: touch !important; /* smooth scrolling on iOS */ + } + + /* Ensure the scroll container accepts touch and clicks */ + .md-sidebar--primary .md-sidebar__scrollwrap, + .md-sidebar--primary .md-sidebar__inner { + z-index: 1001 !important; + pointer-events: auto !important; + overflow: auto !important; /* allow scrolling and tapping inside */ + } + + /* Make links fully interactive and on top of any small pseudo-elements */ + .md-sidebar--primary .md-nav__link { + position: relative !important; + z-index: 1002 !important; + pointer-events: auto !important; + display: block !important; + } + + /* Prevent any active-indicator pseudo-elements from intercepting taps */ + .md-sidebar--primary .md-nav__item--active > .md-nav__link::before, + .md-sidebar--primary > .o-active-indicator { + pointer-events: none !important; + } + + /* Keep overlay visually behind sidebar and don't intercept taps when drawer is open */ + .md-overlay { + z-index: 900 !important; + } +} + +/* STRONG MOBILE OVERRIDES: fix overlap and non-clickable links */ +@media (max-width: 76.24em) { + /* Make sidebar a narrow drawer (avoid full-width that can cover content) */ + .md-sidebar--primary { + position: fixed !important; + left: 0 !important; + right: auto !important; + width: 280px !important; + max-width: 90vw !important; + transform: translateX(-100%) !important; /* hidden by default */ + z-index: 1200 !important; /* baseline above header */ + top: 0 !important; + height: 100vh !important; + box-shadow: 0 2px 16px rgba(0, 0, 0, 0.25) !important; + background-clip: padding-box !important; + } + + /* When drawer is checked (open), bring sidebar fully into view and above overlay */ + input[id="__drawer"]:checked ~ .md-container .md-sidebar--primary, + .md-toggle[data-md-toggle="drawer"]:checked + ~ .md-container + .md-sidebar--primary { + transform: translateX(0) !important; + z-index: 1400 !important; /* ensure it's above overlay and header */ + pointer-events: auto !important; + } + + /* Ensure overlay remains behind the sidebar when open */ + input[id="__drawer"]:checked ~ .md-overlay, + .md-toggle[data-md-toggle="drawer"]:checked ~ .md-container .md-overlay { + z-index: 1300 !important; /* below the sidebar but above page */ + opacity: 1 !important; + pointer-events: auto !important; + } + + /* Keep header beneath the sidebar so it doesn't capture taps */ + .md-header { + z-index: 1250 !important; + } + + /* Scroll container should allow touch scrolling and not intercept taps */ + .md-sidebar--primary .md-sidebar__scrollwrap, + .md-sidebar--primary .md-sidebar__inner { + overflow-y: auto !important; + -webkit-overflow-scrolling: touch !important; + pointer-events: auto !important; + z-index: 1401 !important; + } + + /* Links: ensure they receive taps and use touch-action for faster response */ + .md-sidebar--primary .md-nav__link { + pointer-events: auto !important; + z-index: 1402 !important; + touch-action: manipulation !important; + } + + /* Deactivate any decorative element from intercepting touches */ + .md-sidebar--primary .md-nav__item--active > .md-nav__link::before, + .md-sidebar--primary > .o-active-indicator, + .md-sidebar--primary:before, + .md-sidebar--primary:after { + pointer-events: none !important; + } + + /* Safety: ensure nothing else is layered above the sidebar when open */ + input[id="__drawer"]:checked ~ .md-container * { + pointer-events: auto !important; + } +} + +/* MOBILE ACCORDION: hide nested navs by default and show only when toggled */ +@media (max-width: 76.24em) { + /* Hide all nested nav blocks by default to prevent them stacking above parents + but keep top-level (data-md-level="0") visible */ + .md-sidebar--primary .md-nav[data-md-level]:not([data-md-level="0"]) { + display: none !important; + visibility: hidden !important; + height: 0 !important; + max-height: 0 !important; + overflow: hidden !important; + position: static !important; + transform: none !important; + } + + /* When the toggle checkbox is checked, show the corresponding nav below the label */ + .md-nav__toggle:checked ~ nav[data-md-level], + .md-nav__toggle:checked + label + nav[data-md-level] { + display: block !important; + visibility: visible !important; + height: auto !important; + max-height: none !important; + overflow: visible !important; + position: static !important; + transform: none !important; + } + + /* Ensure child ul lists are visible when their parent nav is shown */ + .md-nav__toggle:checked ~ nav[data-md-level] .md-nav__list, + .md-nav__toggle:checked + label + nav[data-md-level] .md-nav__list { + display: block !important; + visibility: visible !important; + overflow: visible !important; + max-height: none !important; + } + + /* Make sure labels remain interactive and in normal flow */ + .md-sidebar--primary .md-nav__link { + display: block !important; + position: relative !important; + } +} + +/* MOBILE NESTED-LIST FIX: ensure subitems expand below their parent and are readable */ +@media (max-width: 76.24em) { + /* Allow the sidebar scrolling container and inner container to show expanded content */ + .md-sidebar--primary .md-sidebar__scrollwrap, + .md-sidebar--primary .md-sidebar__inner { + overflow: visible !important; + max-height: none !important; + position: static !important; + } + + /* Ensure nav lists and items flow in document order (not absolutely positioned) */ + .md-sidebar--primary .md-nav__list, + .md-sidebar--primary .md-nav__item, + .md-sidebar--primary .md-nav__item > .md-nav__list { + position: static !important; + overflow: visible !important; + max-height: none !important; + display: block !important; + } + + /* If nested lists were collapsed using transforms or translate, reset them */ + .md-sidebar--primary .md-nav__item .md-nav__list { + transform: none !important; + } + + /* Remove clipping on individual link elements so child lists aren't hidden */ + .md-sidebar--primary .md-nav__link, + .md-sidebar--primary .md-nav__title { + overflow: visible !important; + } + + /* Reduce z-index stacking on nav elements so expanded lists appear in normal flow */ + .md-sidebar--primary .md-nav__list, + .md-sidebar--primary .md-nav__item { + z-index: auto !important; + } +} + +/* Ensure main content is always tall enough so sidebar never shifts above navbar */ +.md-main, +.md-content { + min-height: calc(100vh - 4rem); /* 4rem = navbar height, adjust if needed */ +} + +/* MOBILE: keep label text and arrow on one line; ensure nested navs expand in-flow */ +@media (max-width: 76.24em) { + .md-sidebar--primary .md-nav__link { + display: flex !important; + align-items: center !important; + justify-content: space-between !important; + gap: 0.5rem !important; + white-space: nowrap !important; + width: 100% !important; + box-sizing: border-box !important; + } + + .md-sidebar--primary .md-nav__icon { + margin-left: 0.5rem !important; + flex-shrink: 0 !important; + order: 2 !important; + } + + /* Show nested nav when its toggle checkbox is checked */ + input[type="checkbox"].md-nav__toggle:checked + label + nav[data-md-level], + input[type="checkbox"].md-nav__toggle:checked ~ nav[data-md-level], + .md-nav__toggle:checked + label + nav[data-md-level], + .md-nav__toggle:checked ~ nav[data-md-level] { + display: block !important; + visibility: visible !important; + height: auto !important; + max-height: none !important; + overflow: visible !important; + position: static !important; + transform: none !important; + } + + /* Ensure child lists inside shown nav are visible and flow below */ + input[type="checkbox"].md-nav__toggle:checked + + label + + nav[data-md-level] + .md-nav__list, + input[type="checkbox"].md-nav__toggle:checked + ~ nav[data-md-level] + .md-nav__list, + .md-nav__toggle:checked + label + nav[data-md-level] .md-nav__list, + .md-nav__toggle:checked ~ nav[data-md-level] .md-nav__list { + display: block !important; + visibility: visible !important; + overflow: visible !important; + max-height: none !important; + } + + /* Ensure nested labels stay full-width and don't wrap arrow */ + .md-sidebar--primary .md-nav__item--nested > .md-nav__link { + display: flex !important; + align-items: center !important; + justify-content: space-between !important; + white-space: nowrap !important; + } +} + +/* SHOW ACTUAL SUBITEMS: hide duplicate nav titles and force UL visible when open */ +@media (max-width: 76.24em) { + /* Hide the internal nav title that repeats the parent label inside the nav block */ + .md-sidebar--primary nav[data-md-level] > .md-nav__title { + display: none !important; + visibility: hidden !important; + height: 0 !important; + overflow: hidden !important; + } + + /* Show the direct UL (.md-nav__list) when the toggle checkbox is checked or nav reports expanded */ + input.md-nav__toggle:checked + label + nav[data-md-level] > .md-nav__list, + input.md-nav__toggle:checked ~ nav[data-md-level] > .md-nav__list, + nav[data-md-level][aria-expanded="true"] > .md-nav__list { + display: block !important; + visibility: visible !important; + max-height: none !important; + overflow: visible !important; + height: auto !important; + } + + /* Also ensure the nav container itself is visible when toggled */ + input.md-nav__toggle:checked + label + nav[data-md-level], + input.md-nav__toggle:checked ~ nav[data-md-level], + nav[data-md-level][aria-expanded="true"] { + display: block !important; + visibility: visible !important; + height: auto !important; + max-height: none !important; + overflow: visible !important; + } + + /* Make sure nested items are in normal flow */ + .md-sidebar--primary .md-nav__item--nested { + display: block !important; + } +} + +/* EXTRA: explicitly show/hide the actual