Overview
On-premise Gurubase deployments include Fluent Bit for log collection. By default, logs from all Gurubase services are written to a local file. You can add an OpenSearch output to forward these logs to a centralized OpenSearch cluster for real-time search, dashboards, and alerting. This guide walks you through setting up a dedicated OpenSearch user with minimal permissions, configuring Fluent Bit to ship logs securely, and setting up Slack alerts for error detection.Prerequisites
- A running on-premise Gurubase deployment
- An OpenSearch cluster (self-managed or hosted) accessible from the deployment
- Admin credentials for the OpenSearch cluster (used only during setup)
This guide has been tested with OpenSearch 3.5.0. The APIs used (Security,
ISM, Alerting, Notifications) are available in OpenSearch 2.x and later.
Architecture
Fluent Bit tails Docker container logs from all Gurubase services, enriches them with metadata (container name, version), parses JSON-formatted logs from Python services into structured fields, and forwards them to both a local file and your OpenSearch cluster.Step 1: Create a Dedicated OpenSearch User
It’s recommended to create a dedicated user with write-only permissions
instead of using your OpenSearch admin credentials in Fluent Bit configuration
files.
Create a Write-Only Role
Create the Internal User
Map the Role to the User
These three commands only need to be run once during initial setup.
Step 2: Configure Fluent Bit
Add the following[OUTPUT] block to your Fluent Bit configuration file. The existing file output is preserved. Fluent Bit supports multiple outputs and will send each log record to all matching outputs.
The Fluent Bit configuration file is located at
~/.gurubase/config/fluent-bit.conf on the host machine.Set
Port to your OpenSearch cluster’s port. Common values: 443 for
managed/hosted clusters behind a load balancer, 9200 for self-managed
clusters. Set Host to just the hostname (e.g., opensearch.example.com),
without https://.Step 3: Verify the Setup
Check Fluent Bit Logs
security_exception errors in the output.
Check the Index in OpenSearch
Step 4: Set Up OpenSearch Dashboards
Once logs are flowing, set up OpenSearch Dashboards for browsing and searching.OpenSearch Dashboards is typically available at
http://YOUR_OPENSEARCH_HOST:5601. Open it in your browser and log in with
your OpenSearch admin credentials.Open OpenSearch Dashboards
Navigate to
http://YOUR_OPENSEARCH_HOST:5601 in your browser and log in with your admin credentials.Create an Index Pattern
Go to Management > Dashboards Management > Index patterns and click Create index pattern. Enter
gurubase-onprem-* as the pattern and Click Next step and select @timestamp as the time field and click Create index pattern.Browse Logs in Discover
Go to Discover, select your new index pattern, and adjust the time range. Python service logs (backend, Celery) have structured fields like
level, message, traceback, logger, module, and function. Non-Python services have a plain log field.Filter and Search
Use the search bar with KQL syntax to filter logs:
level: ERROR(all error-level logs from Python services)traceback: *(all logs with a stack trace)container_name: *postgres*(PostgreSQL logs only)log: *error*(plain-text logs containing “error”)container_name: *celery* and level: ERROR(Celery errors)
Step 5: Configure Log Retention
OpenSearch’s Index State Management (ISM) can automatically delete old log indices to control disk usage. The following policy deletes indices older than 14 days.This command only needs to be run once. The ISM template automatically
attaches the policy to all future daily indices.
Step 6: Set Up Error Alerting with Slack
OpenSearch’s Alerting plugin can automatically detect error logs and send notifications to Slack. This section sets up a monitor that checks for error-level logs every 5 minutes and sends a Slack message when errors are detected.6a. Create a Slack Incoming Webhook
Go to the Slack API portal
Open https://api.slack.com/apps and click
Create New App → From scratch. Name it Gurubase Onprem Alerts.
Enable Incoming Webhooks
In the app settings, navigate to Features → Incoming Webhooks and
toggle it On.
Add a new webhook
Click Add New Webhook to Workspace, select the channel you want alerts
sent to (e.g.,
#gurubase-alerts), and click Allow.6b. Create a Notification Channel in OpenSearch
Use the OpenSearch Notifications API to register your Slack webhook as a notification channel.config_id that you need for the next step:
Save the
config_id from the response. You will use it as the channel_id
when creating the monitor.6c. Create an Error Log Monitor
This monitor runs every 5 minutes. It queries allgurubase-onprem-* indices for error-level structured logs from Python services (using the level and traceback fields) as well as plain-text error patterns from non-Python services (using the log field) within the last 5-minute window. If any matches are found, it sends a summary to Slack.
Throttling is enabled at 15 minutes. Even if the monitor fires every 5
minutes, Slack will receive at most one notification per 15 minutes. Adjust
the
throttle.value to control notification frequency.6d. Test the Monitor
You can trigger a dry run to verify the monitor works without sending an actual notification:Replace
MONITOR_ID with the _id returned when you created the monitor. The
dry run response shows whether the trigger condition would fire based on
current data.Monitor: Gurubase Error Log Monitor Period: 2026-02-16T12:30:00Z - 2026-02-16T12:35:00Z Total errors: 15 Recent error logs:
gurubase-backend: Internal Server Error: /api/v1/…gurubase-celery-worker: Connection refused
6e. Manage the Monitor
List all monitors:Replace
MONITOR_ID with the _id returned when you created the monitor.
This command fetches the current monitor definition, sets enabled to
false, and updates it in place, preserving all existing configuration
including Slack actions. These commands require
jq to be installed.Customization Tips
Change error keywords
Change error keywords
The default query matches structured For non-Python service logs, modify the Plain-text patterns must be lowercase because OpenSearch’s default analyzer lowercases indexed text.
level fields (ERROR, FATAL), the traceback field, and plain-text patterns in the log field. To also match warnings from Python services, add a term clause for WARNING:query_string in the monitor’s input query. For example, to also match warnings:Filter by specific service
Filter by specific service
To alert only on errors from a specific Gurubase service, add a
term filter to the bool.filter array:Change monitoring interval
Change monitoring interval
Adjust the Remember to also adjust the time range in the query (
schedule.period.interval value. For example, to check every minute:gte value) to match the interval (e.g., {{period_end}}||-1m).Alert on high error volume only
Alert on high error volume only
To avoid alerts for occasional errors, raise the trigger threshold. For example, to alert only when there are more than 50 errors in the window:
Use OpenSearch Dashboards UI instead
Use OpenSearch Dashboards UI instead
You can also create monitors visually through OpenSearch Dashboards → Alerting → Monitors → Create monitor. The Dashboards UI provides a form-based editor that is equivalent to the REST API approach documented above.
Log Record Fields
Gurubase uses JSON structured logging for Python services (backend, Celery workers, Celery beat). Each log entry, including full stack traces, is emitted as a single JSON line. Fluent Bit automatically parses these JSON logs into structured OpenSearch fields. Non-Python services (PostgreSQL, Redis, Milvus) continue to emit plain-text logs.You can pretty-print JSON logs in the terminal with
jq:| Field | Description |
|---|---|
@timestamp | When the log was indexed |
timestamp | When the log was produced |
level | Log level (ERROR, WARNING, INFO, DEBUG) |
message | The log message |
traceback | Full stack trace (only present for exceptions) |
logger | Python logger name |
module | Python module name |
function | Function name |
line | Source line number |
container_name | Which Gurubase service produced the log |
version | The Gurubase deployment version |
stream | Output stream (stdout or stderr) |
| Field | Description |
|---|---|
@timestamp | When the log was indexed |
log | The plain-text log line |
container_name | Which Gurubase service produced the log |
version | The Gurubase deployment version |
stream | Output stream (stdout or stderr) |
Troubleshooting
Permission denied errors (security_exception)
Permission denied errors (security_exception)
If Fluent Bit logs show
no permissions for [indices:data/write/bulk[s]], the role may be missing wildcard write permissions. Update the role to use indices:data/write/* instead of individual write actions:TLS certificate errors
TLS certificate errors
If your OpenSearch cluster uses a self-signed certificate, set
tls.verify Off in the Fluent Bit output configuration. For production, it is recommended
to use a valid certificate and keep verification enabled.Connection refused or timeout
Connection refused or timeout
Ensure the Fluent Bit container can reach your OpenSearch cluster. Check that
the hostname resolves correctly and the port is accessible. If OpenSearch is
behind a firewall or VPN, the Gurubase host must have network access.
No data appearing in OpenSearch
No data appearing in OpenSearch
- Check Fluent Bit logs:
docker logs gurubase-fluent-bit --tail 1002. Verify the container name grep filter matches your deployment prefix 3. Ensure the Fluent Bit flush interval (default 5 seconds) has elapsed 4. Confirm the index pattern in OpenSearch Dashboards matches the index name
Slack alerts not being sent
Slack alerts not being sent
- Verify the notification channel exists:
curl -u 'admin:YOUR_ADMIN_PASSWORD' 'https://YOUR_OPENSEARCH_HOST/_plugins/_notifications/configs/NOTIFICATION_CHANNEL_ID' - Send a test notification:
curl -u 'admin:YOUR_ADMIN_PASSWORD' 'https://YOUR_OPENSEARCH_HOST/_plugins/_notifications/feature/test/NOTIFICATION_CHANNEL_ID' - Check if throttling is suppressing notifications. The default throttle is
15 minutes 4. Verify the Slack webhook URL is still valid in your Slack app
settings 5. Check monitor execution status:
curl -u 'admin:YOUR_ADMIN_PASSWORD' 'https://YOUR_OPENSEARCH_HOST/_plugins/_alerting/monitors/alerts'
Monitor error: no mapping found for message.keyword
Monitor error: no mapping found for message.keyword
If the monitor alert shows
IllegalArgumentException[no mapping found for message.keyword in order to collapse on], the monitor query is using a collapse clause on the message.keyword field. Non-Python services (PostgreSQL, Redis, Milvus) don’t have a message field — they use log instead. When an index contains only non-Python service logs, the message field mapping doesn’t exist, causing the collapse (and the entire query) to fail.Fix: Remove the collapse clause from the monitor’s input query. The size: 10 limit already restricts the number of results returned. Update the monitor via the REST API or through OpenSearch Dashboards → Alerting → Monitors → edit the monitor → remove the collapse from the extraction query.Using Elasticsearch Instead of OpenSearch
If you are using Elasticsearch instead of OpenSearch, the same Fluent Bit setup works with minimal changes.Fluent Bit Configuration
Change the plugin name fromopensearch to es. All other parameters remain the same:
Suppress_Type_Name On is required for Elasticsearch 8.x+ (just like
OpenSearch 2.x+). For Elasticsearch 7.x, you can omit it.User and Role Setup
Elasticsearch uses X-Pack Security instead of the OpenSearch Security plugin. The API paths are different:Log Retention with ILM
Elasticsearch uses Index Lifecycle Management (ILM) instead of ISM. Create a policy that deletes indices after 14 days:Key Differences Summary
| OpenSearch | Elasticsearch | |
|---|---|---|
| Fluent Bit plugin name | opensearch | es |
| Security API path | /_plugins/_security/api/ | /_security/ |
| Retention system | ISM (Index State Management) | ILM (Index Lifecycle Management) |
Suppress_Type_Name | Required for 2.x+ | Required for 8.x+ |
| Dashboards port | :5601 (OpenSearch Dashboards) | :5601 (Kibana) |
Security Considerations
- The
gurubase_fluentbit_writeruser has write-only access togurubase-onprem-*indices - No read, delete, or cluster administration permissions are granted
- If the credentials are compromised, an attacker can only append log data. They cannot read existing data or access other indices
- Admin credentials are only used during the one-time setup and are not stored in any configuration file
- For additional security, consider rotating the
gurubase_fluentbit_writerpassword periodically