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)
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
Create a Write-Only Role
Create the Internal User
Map the Role to the User
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.
~/.gurubase/config/fluent-bit.conf on the host machine.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.http://YOUR_OPENSEARCH_HOST:5601. Open it in your browser and log in with
your OpenSearch admin credentials.Open OpenSearch Dashboards
http://YOUR_OPENSEARCH_HOST:5601 in your browser and log in with your admin credentials.Create an Index Pattern
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
level, message, traceback, logger, module, and function. Non-Python services have a plain log field.Filter and Search
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)
Save Searches (Optional)
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.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
Enable Incoming Webhooks
Add a new webhook
#gurubase-alerts), and click Allow.Copy the webhook URL
https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX.
You will need this in the next step.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:
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.
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: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: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
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
term filter to the bool.filter array:Change monitoring interval
Change monitoring interval
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
Use OpenSearch Dashboards UI instead
Use OpenSearch Dashboards UI instead
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.jq:Troubleshooting
Permission denied errors (security_exception)
Permission denied errors (security_exception)
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
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
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
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
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