Pull metrics from F5 BIG-IP iControl REST APIs and forward logs from BIG-IP (LTM, ASM, AFM, AVR, and system syslog) to an OpenTelemetry Collector using separate metric and log pipelines.
The React UI is styled similarly to BIG-IP-Telemetry-Streaming-Validator-and-Configurator: connect to one or more BIG-IPs, choose what to export, configure collector exporters, and start export.
- Architecture
- Authentication Security
- User guide
- Installation options
- Install on Ubuntu Linux (without Kubernetes)
- Install on Kubernetes
- Access from other machines
- User guide (detailed)
- API catalog
- Collector exporters (UI)
- Backend environment variables (optional)
- Repository
- License
flowchart LR
UI[React UI] --> API[Python FastAPI]
API --> BIGIP1[BIG-IP 1]
API --> BIGIP2[BIG-IP 2]
API -->|OTLP HTTP metrics| COL[OTEL Collector]
API -->|syslog TCP / HSL| COL
COL --> DEST[Configured log and metric exporters]
| Component | Role |
|---|---|
| Python backend | Sessions to one or more BIG-IPs; polls selected /mgmt/.../stats endpoints; configures remote logging via AS3 and system syslog; pushes OTLP metrics to the collector |
| OTEL Collector | Receives OTLP metrics on :4318; receives BIG-IP logs on syslog :5140 (ASM/AFM) and tcplog :5141 (LTM request logging); forwards via UI-configured exporters |
| React frontend | Multi-BIG-IP connect form, per-device log export toggles (provisioned modules only), API catalog, split metric/log collector exporters, export controls |
The exporter authenticates to each BIG-IP with iControl REST using the credentials you enter in the UI. It does not store tokens in the browser and does not implement its own identity provider for the web UI.
- On Connect, the browser sends host, username, password, and TLS options to the local backend (
POST /api/connect) over the same origin as the UI (typicallyhttp://<host>:8001). - The backend opens HTTPS to the BIG-IP and
POSTs to/mgmt/shared/authn/login` (TMOS login provider). - BIG-IP returns an auth token. The backend stores that token only in the in-memory
BigIPClientsession and sends it on later calls as theX-F5-Auth-Tokenheader. - After login, the backend attempts to extend the token lifetime (default login timeout is ~20 minutes; extension targets ~60 minutes when allowed by the platform).
- Metric polls and AS3 / syslog configuration use that token. On 401, the client clears any stale token header, logs in again with the stored password, and retries the request.
On Remove, the backend deletes the token on the BIG-IP (DELETE /mgmt/shared/authz/tokens/...) and drops the local session.
| Layer | Algorithm / mechanism | What it protects |
|---|---|---|
| BIG-IP transport | TLS (HTTPS). Cipher suite and TLS version are negotiated by the BIG-IP and the Python requests / OpenSSL stack on the host. |
Username/password on login and all subsequent iControl REST traffic (including the auth token). |
| Password at rest | Fernet from the Python cryptography package (cryptography.fernet.Fernet). Fernet is symmetric authenticated encryption: AES-128 in CBC mode with a HMAC-SHA256 integrity check (URL-safe base64 token format). Implemented in backend/session_store.py. |
Only the password field in sessions.json. Host, username, and other session metadata are stored in plaintext JSON. |
| Encryption key | A Fernet key (32 url-safe base64-encoded bytes). Auto-generated with Fernet.generate_key() into sessions.key, or supplied via BIGIP_SESSION_ENCRYPTION_KEY. |
Required to decrypt stored passwords. Losing the key makes encrypted passwords unrecoverable. |
Fernet does not encrypt the entire session file — only each password string. Tokens are not written to disk; they exist only in process memory until logout or restart (restart re-logins with the decrypted password).
| Area | Behavior |
|---|---|
| Transport to BIG-IP | Always HTTPS (https://<host>). Optional Verify TLS certificate in the UI (verify_tls); default is off so lab devices with self-signed certs still work. Enable verification in production when the BIG-IP presents a trusted certificate. |
| Token vs password on the wire | After the initial login, day-to-day API calls use the token, not the password. Token expiry triggers a fresh login. |
| Browser | Passwords are not persisted in localStorage. The UI only holds credentials long enough to POST connect. Device list comes from GET /api/bigips. |
| At-rest session store | When BIGIP_SESSION_PERSIST=true (default), passwords are Fernet-encrypted (AES-128-CBC + HMAC-SHA256) into ~/.config/bigip-telemetry-exporter/sessions.json. The key is sessions.key (mode 0600 when creatable) or BIGIP_SESSION_ENCRYPTION_KEY. The JSON file is also chmod 0600 when possible. |
| Backend process memory | Decrypted passwords and live tokens remain in the Python process for reconnect and export. Anyone who can read that process memory or ptrace the user running the API can recover them. |
| Web UI / API surface | The FastAPI server has no login. Anyone who can reach :8001 can connect BIG-IPs (if they know device credentials) and change export/collector config. Bind and firewall accordingly. |
- Prefer a least-privilege BIG-IP account with iControl REST rights only for the stats and configuration this tool needs — not your personal admin password when avoidable.
- Enable Verify TLS certificate when BIG-IP certificates are valid for the management hostname/IP you configure.
- Treat
sessions.json/sessions.keylike secrets; useBIGIP_SESSION_PERSIST=falseon shared jump hosts if you must not keep passwords on disk. - In containers/Kubernetes, set a stable
BIGIP_SESSION_ENCRYPTION_KEY(or mounted key file) so restarts can decrypt the store, and restrict who can open the UI port. - Do not expose port 8001 on untrusted networks without an external auth proxy or VPN.
Related: Session persistence across restarts.
End-to-end workflow after installation. Expanded copy: docs/user-guide.md. Kubernetes networking: docs/kubernetes.md.
flowchart TD
A[Connect BIG-IP devices] --> B[Enable log types per provisioned module]
B --> C[Select metrics API endpoints]
C --> D[Configure collector metric and log exporters]
D --> E[Apply collector config auto-restart]
E --> F[Start export metrics and logs]
| Step | UI section | Outcome |
|---|---|---|
| 1 | BIG-IP connections | Authenticate; enable per-device log types (LTM, ASM, AFM, AVR, system) based on provisioned modules |
| 2 | API endpoints | Choose which /mgmt/... paths to poll for metrics (stats paths recommended) |
| 2b | tmctl tables | Optional: choose TMCTL TABLES in the API endpoints/tmctl module filter |
| 3 | OpenTelemetry Collector exporters | Configure metric and log exporters separately; Apply collector config restarts the collector |
| 4 | Export to collector | Metrics via OTLP; logs via syslog/tcplog receivers on the collector |
| Area | What it shows |
|---|---|
| Connected status bar (top, when ≥1 device) | Count, chips, export selection summary, Refresh list, auto-refresh every 45 seconds |
| BIG-IP connections | Device list with export checkboxes, per-device log toggles (LTM/ASM/AFM/AVR when provisioned), system syslog, Remove, connect form |
| API endpoints & tmctl tables | iControl REST path catalog plus TMCTL TABLES module for tmctl stats |
| OpenTelemetry Collector exporters | Separate metric and log exporter sections; apply restarts collector |
| Export to collector | OTLP metrics settings and poll interval |
After git pull, rebuild the UI if you serve production assets: cd frontend && npm ci && npm run build, then restart the API.
Open the UI (http://<HOST-IP>:8001 on Ubuntu, or port-forward on Kubernetes).
| Field | Notes |
|---|---|
| Management host | IP or hostname (HTTPS). https:// is added automatically if omitted. |
| Label | Optional friendly name (e.g. prod-dc1). Defaults to the host/IP. |
| Username / Password | Account with iControl REST access (often admin). |
| Verify TLS | Uncheck for default self-signed BIG-IP management certificates. |
- Connect / Add BIG-IP — enabled when host, username, password, and at least one export option (metrics and/or logs) are selected.
- Connect — first device.
- Add BIG-IP — additional devices without disconnecting others.
- Remove — logs out and drops that session (
DELETE /api/session/{id}). - Reconnecting the same host replaces the previous session for that IP.
On the connect form, choose Export metrics and/or Export logs (AS3 remote logging profiles). Use per-device toggles after connect for LTM/ASM/AFM/AVR and System → syslog (:5140).
The BIG-IP connections card shows the count in its title and lists devices when connected. The top status bar appears only after the first device is connected.
Each connected device appears in a list with:
- A checkbox — include or exclude from export (at least one must be checked before Start export).
- Label, management address, and export mode summary.
- Logs row — toggles for LTM, ASM, AFM, AVR (only if that module is provisioned on the device).
- System → syslog (:5140) — toggle system syslog forwarding to the collector (per device, after connect).
- Warning — token extension, AS3, syslog, or provisioning issues.
- Remove — disconnect the session.
On connect (and when you change log toggles), the backend:
- Reads module provisioning (
ltm,asm,afm,avr). - Optionally configures system syslog forwarding (
/mgmt/tm/sys/sysloginclude → TCP:5140). - If any module log profile is enabled, verifies F5 AS3, then POSTs an AS3 declaration with logging/analytics objects for provisioned modules only:
| Profile | Default path | Attach on virtual server | Collector port |
|---|---|---|---|
| LTM request-log | /Common/bigip-telemetry-requestlog |
Request Logging | HSL tcplog 5141 |
| ASM security log | /Common/bigip-telemetry-asm-log |
Security Log Profile (Application Security) | syslog 5140 |
| AFM security log | /Common/bigip-telemetry-afm-log |
Security Log Profile (Network Firewall) | syslog 5140 |
| AVR HTTP analytics | /Common/bigip-telemetry-http-analytics |
HTTP Analytics profile | (analytics events) |
| AVR TCP analytics | /Common/bigip-telemetry-tcp-analytics |
TCP Analytics profile | (analytics events) |
Use PATCH /api/session/{session_id}/log-options to change log types on a connected device without reconnecting.
Log reachability: BIG-IP must reach the collector host on 5140 and 5141. The backend auto-detects a LAN IP for remote log pools; set BIGIP_LOG_SYSLOG_HOST if auto-detection fails. Do not use 127.0.0.1 — BIG-IP rejects loopback destinations.
Connected BIG-IPs and export settings survive backend restarts by default. The UI does not store devices locally — on load it calls GET /api/bigips, which returns whatever the backend restored from disk.
On connect or change, the backend writes an encrypted session file (passwords are Fernet-encrypted, not stored in plain text):
| File | Purpose |
|---|---|
~/.config/bigip-telemetry-exporter/sessions.json |
Device list, encrypted credentials, per-device log/metric options, export config |
~/.config/bigip-telemetry-exporter/sessions.key |
Auto-generated encryption key (when BIGIP_SESSION_ENCRYPTION_KEY is unset) |
On backend startup, the API reloads that file, logs in to each BIG-IP again, and resumes export if it was active when the process stopped.
Restarting only the frontend (browser refresh or Vite) has no effect on persistence — it simply refetches the restored list from the API.
| Environment variable | Default | Purpose |
|---|---|---|
BIGIP_SESSION_PERSIST |
true |
Set false for memory-only sessions (lost on backend restart; 45 min TTL while running) |
BIGIP_SESSION_STORE_PATH |
~/.config/bigip-telemetry-exporter/sessions.json |
Custom path for the session + export state file |
BIGIP_SESSION_ENCRYPTION_KEY |
(auto) | Fixed Fernet key (useful in containers or to reuse one store across hosts) |
BIGIP_SESSION_KEY_FILE |
{store}.key |
Path for the auto-generated key file |
BIGIP_SESSION_TTL_SEC |
2700 |
In-memory session TTL when persistence is disabled |
Adjusting behavior:
- Disable persistence (fresh start every backend restart):
export BIGIP_SESSION_PERSIST=falsebefore startingrun_server.py - Clear saved devices without disabling persistence: stop the backend, delete
sessions.json(and optionally.key), then restart - Disconnect one device in the UI (Remove) — removes that session from the store on the next save
Treat the session store like a secrets file: restrict filesystem permissions. On shared admin hosts, set BIGIP_SESSION_PERSIST=false if you do not want passwords retained on disk.
Log profile environment variables:
| Environment variable | Default | Purpose |
|---|---|---|
BIGIP_REQUEST_LOG_PROFILE_NAME |
bigip-telemetry-requestlog |
LTM request-log profile name |
BIGIP_ASM_LOG_PROFILE_NAME |
bigip-telemetry-asm-log |
ASM security log profile name |
BIGIP_AFM_LOG_PROFILE_NAME |
bigip-telemetry-afm-log |
AFM security log profile name |
BIGIP_LOG_PROFILE_PARTITION |
Common |
Partition for all exporter-managed profiles |
BIGIP_LOG_SYSLOG_HOST |
Auto-detected LAN IP (or browser host); must be reachable from BIG-IP — not 127.0.0.1 |
|
BIGIP_LOG_SYSLOG_PORT |
5140 |
Collector syslog receiver (ASM/AFM security logs, RFC5424) |
BIGIP_LOG_HSL_PORT |
5141 |
Collector tcplog receiver (LTM request/response logs via HSL) |
BIGIP_REQUEST_LOG_AUTO_CREATE |
true |
Set false to skip LTM profile on connect |
BIGIP_ASM_LOG_AUTO_CREATE |
true |
Set false to skip ASM profile on connect |
BIGIP_AFM_LOG_AUTO_CREATE |
true |
Set false to skip AFM profile on connect |
BIGIP_AFM_LOG_PUBLISHER |
/Common/local-db-publisher |
Log publisher for AFM network events |
BIGIP_HTTP_ANALYTICS_PROFILE_NAME |
bigip-telemetry-http-analytics |
AVR HTTP analytics profile name |
BIGIP_TCP_ANALYTICS_PROFILE_NAME |
bigip-telemetry-tcp-analytics |
AVR TCP analytics profile name |
BIGIP_HTTP_ANALYTICS_AUTO_CREATE |
true |
Set false to skip HTTP analytics profile |
BIGIP_TCP_ANALYTICS_AUTO_CREATE |
true |
Set false to skip TCP analytics profile |
BIGIP_AS3_RPM_PATH |
(unset) | Local path to f5-appsvcs-*.noarch.rpm; when unset, the latest RPM is downloaded from F5 AS3 GitHub releases |
BIGIP_AS3_AUTO_INSTALL |
true |
Set false to require AS3 pre-installed |
BIGIP_AS3_GITHUB_DOWNLOAD |
true |
Set false to disable GitHub RPM download when BIGIP_AS3_RPM_PATH is unset |
BIGIP_AS3_RELEASE_VERSION |
latest |
GitHub release tag (e.g. v3.56.0) or latest |
BIGIP_AS3_DOWNLOAD_CACHE_DIR |
~/.cache/bigip-telemetry-exporter/as3-rpms |
Cache directory for downloaded AS3 RPMs |
BIGIP_AS3_GITHUB_REPO |
F5Networks/f5-appsvcs-extension |
GitHub repo for AS3 release downloads |
BIGIP_AS3_INSTALL_TIMEOUT_SEC |
600 |
Max wait for package-management INSTALL task |
BIGIP_AS3_READY_TIMEOUT_SEC |
180 |
Max wait for /mgmt/shared/appsvcs/info after install |
BIGIP_AS3_READY_POLL_SEC |
2 |
Poll interval while waiting for AS3 /info |
BIGIP_AS3_RESTART_RESTNODED_AFTER_SEC |
45 |
Restart restnoded once if /info is still down |
BIGIP_AS3_SCHEMA_VERSION |
3.49.0 |
AS3 declaration schemaVersion when /info is unavailable |
The catalog comes from data/bigip_apis.csv (103 paths; 38 metrics-oriented by default, including ASM event sources and AFM firewall stats).
| Control | Purpose |
|---|---|
| Metrics / stats endpoints only | Filters to rows marked collect_metrics=true |
| Module filter | Filters by the CSV module column (e.g. ASM for /mgmt/tm/asm/*, AFM for /mgmt/tm/security/firewall/*, SECURITY for other /mgmt/tm/security/*) |
| Select all visible / Clear | Bulk selection |
| Per-row checkbox | Individual /mgmt/... paths |
Defaults pre-select stats endpoints. Prefer .../stats paths for time-series style counters and gauges.
In the API endpoints & tmctl tables section, choose the TMCTL TABLES module filter to select tmctl stats tables (see K000151935). Eleven tables are available (e.g. proc_stat, tmm_stat, disk_latency_stat).
Numeric columns become gauges named bigip_tmctl_<table>_<column> with attributes such as tmctl.name / tmctl.slot. The BIG-IP user must be allowed to run bash util commands (/mgmt/tm/util/bash).
You can start export with REST endpoints only, tmctl tables only, or both.
The UI has two sections:
- Metric exporters — sinks for OTLP metrics from the Python backend (remote OTLP, file, etc.).
- Log exporters — sinks for logs received on syslog
:5140and tcplog:5141.
- Add or enable exporters in each section (for metrics, add a Prometheus scrape exporter, OTLP remote write, or other sink as needed).
- For HTTPS destinations with self-signed or untrusted certificates (e.g. Splunk HEC, OTLP, Elasticsearch), check Skip TLS certificate verification — this sets
tls.insecure_skip_verify: trueon the exporter. - Click Apply collector config — writes
otel-collector/generated-config.yamland restarts the OpenTelemetry Collector (Docker Compose orkubectlwhen available). - If restart fails, the UI shows a manual command. Set
COLLECTOR_AUTO_RESTART=falseto only write YAML without restarting.
| Field | Ubuntu (default) | Kubernetes |
|---|---|---|
| OTLP HTTP endpoint | http://127.0.0.1:4318 |
Pre-filled: http://otel-collector.bigip-telemetry.svc.cluster.local:4318 |
| Poll interval | Seconds between full poll cycles (default 30) | Same |
Start export runs when at least one connected device is checked for export:
- Metrics — polls selected
/mgmt/.../statsendpoints and/ortmctltables and sends OTLP metrics to the collector. - Logs — traffic from enabled BIG-IP logging profiles and system syslog reaches the collector on ports 5140 / 5141 (if those features were configured on connect).
Export status (and Refresh status) shows running, device count, last_point_count, last_errors_by_host, and poll_interval_sec.
Stop export ends the background loop.
REST equivalent: POST /api/export/start with body { "session_ids": ["..."], "endpoints": [...], "poll_interval_sec": 30, "otlp_endpoint": "..." }. Empty session_ids exports all connected devices.
| Topic | Behavior |
|---|---|
| Sessions | One session per device; list via GET /api/bigips |
| Metric identity | OTLP instruments keyed per bigip.host so values do not overwrite across devices |
| Metric naming | One OTLP metric name per stat field, e.g. bigip_tm_ltm_virtual_stats_clientside_bitsin; device rollups for CPU (*_device_avg / *_device_max) and memory (`*_host_avg |
| Attributes (dimensions) | bigip_host (device), bigip_object (virtual server, pool slot, CPU core, memory object, etc.); rollups use bigip_host only |
| Excluded objects | Metrics whose bigip_object contains fiveminavg, fivesecavg, or oneminavge / oneminavg are dropped (override: BIGIP_EXCLUDE_OBJECT_PATTERNS) |
| Export scope | Only devices checked in the connections list (unless using API with explicit session_ids) |
| Network | Each device must be reachable from the host/pod running the Python backend |
| Method | Path | Purpose |
|---|---|---|
GET |
/api/health |
Liveness |
GET |
/api/bigips |
List connected devices |
POST |
/api/connect |
Add or replace device session |
DELETE |
/api/session/{session_id} |
Disconnect device |
GET |
/api/apis |
API catalog |
POST |
/api/export/start |
Start multi-device export |
POST |
/api/export/stop |
Stop export |
GET |
/api/export/status |
Loop status + connected devices |
PATCH |
/api/session/{session_id}/log-options |
Update log export toggles on a connected device |
POST |
/api/session/{session_id}/rollback |
Remove exporter log profiles and system syslog on BIG-IP |
GET |
/api/exporters/catalog |
Collector contrib exporter types and form fields |
GET |
/api/collector/control |
Collector restart mode and hints |
GET / POST |
/api/collector/config |
Read/write collector YAML (POST restarts collector when enabled) |
| Symptom | What to do |
|---|---|
| Cannot connect | Ping/curl management IP from the API host/pod; try Verify TLS off |
401 Authentication failed |
Check user/password and REST permissions |
| Token extension warning | Reconnect before long runs, or ignore if export is under ~20 min |
| AS3 / profile errors | Use admin account for AS3 install; allow up to 180s for /info; check BIGIP_AS3_RPM_PATH, provisioning, and BIGIP_LOG_SYSLOG_HOST (not loopback) |
| No metrics at downstream sink | Export running? Devices checked for metrics? Collector up? OTLP URL correct? Metric exporters configured? |
| Only one device in metrics | Confirm multiple devices checked; use bigip_host in PromQL |
| Log options missing | Module not provisioned on BIG-IP (LTM/ASM/AFM/AVR toggles hidden) |
{"detail":"Not Found"} on / |
Build UI: cd frontend && npm ci && npm run build, restart API |
| Method | Best for |
|---|---|
| Ubuntu Linux | Single VM or bare-metal host, Docker for collector, Python for API + UI |
| Kubernetes | Clusters (EKS, GKE, OpenShift, kind, etc.) |
All methods run the same components; only packaging and networking differ.
These steps target Ubuntu 22.04 or 24.04 LTS on a host that can reach your BIG-IP management IP (HTTPS, typically port 443).
Install system packages, Docker, and Node.js (Node is only required to build the UI).
sudo apt-get update
sudo apt-get install -y git curl ca-certificates python3 python3-venv python3-pip
# Docker Engine + Compose plugin (official convenience script)
curl -fsSL https://get.docker.com | sudo sh
sudo usermod -aG docker "$USER"
# Log out and back in so the docker group applies, then:
docker compose version
# Node.js 20.x (for building the React UI)
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt-get install -y nodejs
node --version
npm --versionConfirm the host can reach BIG-IP (replace with your management IP):
curl -sk --connect-timeout 5 https://<BIG-IP-MGMT-IP>/mgmt/shared/ident | head -c 200cd ~
git clone https://github.com/gregcoward/BIG-IP-Telemetry-Exporter.git
cd BIG-IP-Telemetry-Exporter
chmod +x scripts/*.sh./scripts/init-collector-config.sh
docker compose up -d
docker compose psVerify the collector is running:
| Service | Port | Purpose |
|---|---|---|
otel-collector |
4318 | OTLP HTTP (backend sends metrics here) |
otel-collector |
8889 | Prometheus scrape endpoint (default when no metric exporters configured) |
prometheus |
9090 | Prometheus UI (scrapes collector :8889) |
otel-collector |
5140 | Syslog receiver (ASM/AFM security logs, system syslog) |
otel-collector |
5141 | tcplog receiver (LTM request/response logs via HSL) |
otel-collector |
13133 | Health check |
curl -s "http://127.0.0.1:13133/"cd ~/BIG-IP-Telemetry-Exporter
python3 -m venv .venv
source .venv/bin/activate
pip install --upgrade pip
pip install -r requirements.txtRun the API (listens on all interfaces, port 8001 by default — avoids conflict with other services on 8000):
source .venv/bin/activate
python run_server.py
# Default port 8001. Override: PORT=8002 python run_server.pyNote: The Docker/Kubernetes image sets
PORT=8000inside the container (service port 8000). Localrun_server.pydefaults to 8001 unlessPORTis set.
Leave this terminal open, or run in the background:
nohup .venv/bin/python run_server.py > /tmp/bigip-telemetry-api.log 2>&1 &
curl -s http://127.0.0.1:8001/api/healthThe UI is not in git — you must build it once. In a new terminal:
cd ~/BIG-IP-Telemetry-Exporter/frontend
npm ci
npm run build
ls -la dist/index.html # must existThe backend serves files from frontend/dist. Restart run_server.py if it was already running.
If you open the app before building, you will see {"detail":"Not Found"} or a setup hint page instead of the UI.
Open the application:
export HOST_IP="$(./scripts/host-ip.sh)"
echo "UI: http://${HOST_IP}:8001"Follow the User guide. Quick checklist:
- Open
http://<HOST-IP>:8001. - BIG-IP connections — connect with Export metrics and/or Export logs; use per-device toggles for LTM/ASM/AFM/AVR and system syslog.
- API endpoints — select stats paths (defaults are pre-selected).
- Collector exporters (optional) → Apply collector config (auto-restarts collector).
- Export — OTLP
http://127.0.0.1:4318→ Start export.
For log export, ensure BIG-IP can reach this host on 5140 and 5141. Set BIGIP_LOG_SYSLOG_HOST if auto-detection picks the wrong address.
Use this if you are changing the React code (hot reload). Requires the backend from Step 3.
cd ~/BIG-IP-Telemetry-Exporter/frontend
npm run devOpen http://<HOST-IP>:5173 (proxies /api to port 8001).
If UFW is enabled, allow the ports you need:
sudo ufw allow 8001/tcp comment 'BIG-IP Telemetry UI/API'
# Required for BIG-IP remote logging when exporting logs:
sudo ufw allow 5140/tcp comment 'OTEL syslog receiver'
sudo ufw allow 5141/tcp comment 'OTEL HSL tcplog receiver'| Symptom | What to check |
|---|---|
Cannot reach BIG-IP |
Routing/firewall from Ubuntu host to management IP; curl -sk https://<IP>/mgmt/shared/ident |
401 Authentication failed |
Username/password; account not locked; user has iControl REST permission |
Login failed / TLS errors |
Try with Verify TLS unchecked, or install the BIG-IP management CA on Ubuntu |
Token extension failed |
Warning only — connection can still work (~20 min token); fix token PATCH if needed |
| No metrics at downstream sink | Export started? Devices checked for metrics? Metric exporters configured? docker compose logs otel-collector; OTLP http://127.0.0.1:4318 |
| No logs in collector | BIG-IP can reach host on 5140/5141? BIGIP_LOG_SYSLOG_HOST not loopback? Profiles attached on virtual servers? |
| Multiple devices, one host in queries | Use bigip_host label in PromQL; confirm all devices were checked before export |
{"detail":"Not Found"} on / |
Run Step 4: cd frontend && npm ci && npm run build, restart API |
| UI blank after build | frontend/dist exists; restart python run_server.py |
docker compose not found |
Install compose plugin: sudo apt-get install docker-compose-plugin |
Stop the stack:
docker compose down
# stop API: kill the run_server.py process or Ctrl+CDeploy the full application (backend + UI and OpenTelemetry Collector) with manifests under k8s/ and Kustomize.
Detailed guide: docs/kubernetes.md
flowchart TB
subgraph ns [Namespace bigip-telemetry]
ING[Ingress optional]
BE[Deployment bigip-telemetry-backend]
OC[Deployment otel-collector]
BE -->|OTLP HTTP :4318| OC
BE -->|syslog :5140 / tcplog :5141| OC
end
BE --> BIGIP[BIG-IP management API]
ING --> BE
| Workload | Image | Service |
|---|---|---|
| Backend + UI | bigip-telemetry-exporter (built from Dockerfile) |
bigip-telemetry-backend:8000 |
| OTEL Collector | otel/opentelemetry-collector-contrib:0.109.0 |
otel-collector:4317/4318 |
- Kubernetes 1.25+ and
kubectl - Docker on your workstation to build the backend image
- Cluster nodes (or pod network) can reach BIG-IP management IP(s) on HTTPS
- The backend image is not on Docker Hub — you must build and load/push it (see below)
git clone https://github.com/gregcoward/BIG-IP-Telemetry-Exporter.git
cd BIG-IP-Telemetry-Exporter
chmod +x scripts/k8s-*.sh # build, deploy, apply-collector-config, uninstall
./scripts/k8s-build-image.shLocal cluster (kind / minikube / k3d):
./scripts/k8s-load-image.shRemote cluster (registry):
export IMAGE=ghcr.io/<you>/bigip-telemetry-exporter:1.0.0
docker tag bigip-telemetry-exporter:latest "${IMAGE}"
docker push "${IMAGE}"Local image (no registry):
./scripts/k8s-deploy.sh localRegistry image:
IMAGE="${IMAGE}" ./scripts/k8s-deploy.sh minimalWait for pods:
kubectl -n bigip-telemetry get podsBind port-forwards on all interfaces so other machines can use your host IP:
export HOST_IP="$(./scripts/host-ip.sh)"
kubectl -n bigip-telemetry port-forward --address 0.0.0.0 svc/bigip-telemetry-backend 8001:8000
# UI: http://<HOST-IP>:8001Follow the User guide. Kubernetes-specific checklist:
- Open
http://<HOST-IP>:8001(port-forward8001:8000). - Connect with Export metrics and/or log options; use per-device LTM/ASM/AFM/AVR and system syslog toggles.
- Select APIs; configure metric and log collector exporters → Apply collector config (auto-restarts collector, or run
./scripts/k8s-apply-collector-config.sh). - Start export — OTLP endpoint should remain the in-cluster URL (
http://otel-collector.bigip-telemetry.svc.cluster.local:4318). - For log export, ensure BIG-IP can reach collector 5140 / 5141; set
BIGIP_LOG_SYSLOG_HOSTon the backend if needed.
Use the same overlay you deployed with (local, minimal, or example):
./scripts/k8s-uninstall.sh localSkip the confirmation prompt:
./scripts/k8s-uninstall.sh local -yRemove workloads but keep the namespace (for redeploy later):
./scripts/k8s-uninstall.sh local --keep-namespaceManual equivalent (deletes namespace and all resources):
kubectl delete -k k8s/overlays/local --waitAfter uninstall:
- Stop any
kubectl port-forwardsessions still running. - Optionally remove the local Docker image:
docker rmi bigip-telemetry-exporter:latest
| Path | Description |
|---|---|
k8s/base/ |
Namespace, ConfigMaps, Deployments, Services, sample Ingress |
k8s/overlays/local/ |
Local image (imagePullPolicy: Never) |
k8s/overlays/minimal/ |
No Ingress; requires IMAGE=<registry>/... |
k8s/overlays/example/ |
Example registry + Ingress hostnames |
Do not deploy minimal without pushing an image — bigip-telemetry-exporter:latest is not published to docker.io.
| Symptom | What to check |
|---|---|
ErrImagePull / authorization failed |
Image not on Docker Hub — use local overlay or push to your registry |
401 / connect errors in UI |
Pod network → BIG-IP management IP; TLS verify setting |
| No metrics at downstream sink | Export started? Devices checked for metrics? Metric exporters configured? kubectl logs -n bigip-telemetry deploy/otel-collector |
| No logs in collector | BIG-IP → collector on 5140/5141? BIGIP_LOG_SYSLOG_HOST? Log exporters configured? |
| Backend pod not ready | Probes hit port 8000 — image must set PORT=8000 (included in Dockerfile) |
| Port-forward only on localhost | Add --address 0.0.0.0 (see Step 3) |
Services listen on 0.0.0.0. Use the host’s LAN IP instead of 127.0.0.1 when opening the UI from another workstation.
export HOST_IP="$(./scripts/host-ip.sh)" # e.g. 192.168.1.10| Surface | Ubuntu (default) | Kubernetes (port-forward) |
|---|---|---|
| UI + API | http://<HOST-IP>:8001 |
http://<HOST-IP>:8001 (port-forward → pod :8000) |
| Vite dev UI | http://<HOST-IP>:5173 |
— |
Endpoints are defined in data/bigip_apis.csv (103 iControl REST paths; 38 stats/metrics-oriented by default).
The UI configures exporters from the OpenTelemetry Collector Contrib distribution (image: otel/opentelemetry-collector-contrib).
| Category | Examples |
|---|---|
| Core | OTLP HTTP/gRPC, debug, file, OTel Arrow |
| Observability | Datadog, Splunk HEC, SignalFx, Coralogix, Logz.io, Sumo Logic, Mezmo, Sematext, LogicMonitor |
| Cloud | Google Cloud, Google Managed Prometheus, AWS S3, AWS EMF, Azure Monitor |
| Storage | Elasticsearch, InfluxDB, OpenSearch, ClickHouse, Cassandra |
| Messaging | Kafka, Pulsar, RabbitMQ, syslog |
| Advanced | Contrib exporter (custom YAML) — any other contrib component; paste settings from upstream docs |
After Apply collector config, the API restarts the collector when docker or kubectl is available. Set COLLECTOR_AUTO_RESTART=false to disable.
- Ubuntu (manual fallback):
docker compose restart otel-collector - Kubernetes:
./scripts/k8s-apply-collector-config.sh
Generated config file: otel-collector/generated-config.yaml
Catalog API: GET /api/exporters/catalog (categories, field schemas, links to contrib exporter docs).
| Variable | Default | Purpose |
|---|---|---|
BIGIP_EXCLUDE_OBJECT_PATTERNS |
fiveminavg,fivesecavg,oneminavge,oneminavg |
Comma-separated substrings; if bigip_object contains any, the metric is skipped |
PORT |
8001 (local), 8000 (Docker/K8s image) |
API listen port |
OTLP_HTTP_ENDPOINT |
http://127.0.0.1:4318 |
Default OTLP URL in UI (K8s manifest overrides) |
COLLECTOR_AUTO_RESTART |
true |
Set false to write config without restarting the collector |
COLLECTOR_RESTART_CMD |
(unset) | Custom restart command (overrides auto-detect) |
COLLECTOR_RESTART_MODE |
auto | docker, kubernetes, or none |
COLLECTOR_HEALTH_URL |
http://127.0.0.1:13133 |
Health check after restart |
COLLECTOR_CONFIG_PATH |
otel-collector/generated-config.yaml |
Path written by Apply collector config |
https://github.com/gregcoward/BIG-IP-Telemetry-Exporter
Apache 2.0 — see LICENSE.
