Cursor Rules — unpoller/unpoller
Application: Collect ALL UniFi Controller, Site, Device & Client Data - Export to InfluxDB or Prometheus
6/19/2026 · 17 viewsCursor rules
UnPoller - Cursor AI Rules
Project Overview
UnPoller is a Go application that collects metrics from UniFi network controllers and exports them to various backends (InfluxDB, Prometheus, Loki, DataDog). The architecture is plugin-based with input and output plugins.
Architecture
Core Components
- main.go: Entry point, loads plugins via blank imports
- pkg/poller/: Core library providing input/output interfaces and plugin management
- pkg/inputunifi/: Input plugin for UniFi controller data collection
- pkg/influxunifi/: Output plugin for InfluxDB
- pkg/promunifi/: Output plugin for Prometheus
- pkg/lokiunifi/: Output plugin for Loki
- pkg/datadogunifi/: Output plugin for DataDog
- pkg/webserver/: Web server for health checks and metrics
- pkg/mysqlunifi/: MySQL output plugin
Plugin System
- Plugins are loaded via blank imports (
_ "github.com/unpoller/unpoller/pkg/inputunifi") - Input plugins implement the
Inputinterface frompkg/poller/inputs.go - Output plugins implement the
Outputinterface frompkg/poller/outputs.go - The poller core automatically discovers and initializes imported plugins
- Configuration is automatically unmarshaled from config files (TOML/JSON/YAML) and environment variables
Code Style & Conventions
Go Standards
- Use Go 1.25.5+ features
- Follow standard Go formatting (gofmt)
- Use
golangci-lintwith the project's.golangci.yamlconfiguration - Enable linters:
nlreturn,revive,tagalign,testpackage,wsl_v5 - Use
//nolint:gcifor import ordering when needed
Naming Conventions
- Package names should be lowercase, single word
- Exported types/functions use PascalCase
- Unexported types/functions use camelCase
- Constants use PascalCase with descriptive names
- Error variables should be named
errand checked immediately
Error Handling
- Always check errors, don't ignore them
- Use
github.com/pkg/errorsfor error wrapping when appropriate - Return errors from functions, don't log and continue
- Use descriptive error messages
Configuration
- Configuration uses
golift.io/cnfgandgolift.io/cnfgfile - Environment variables use
UP_prefix (defined inENVConfigPrefix) - Support TOML (default), JSON, and YAML formats
- Config structs should have tags:
json,toml,xml,yaml
Testing
- Use
testpackagelinter - tests should be in separate_testpackages - Use
github.com/stretchr/testifyfor assertions - Integration tests use
integration_test_expectations.yamlfiles
Logging
- Use structured logging via logger interfaces
- Log levels: ERROR, WARN, INFO, DEBUG
- Prefix log messages with
[LEVEL]when using standard log package
Dependencies
Key Libraries
github.com/unpoller/unifi/v5- UniFi API client (local replace:/Users/briangates/unifi)golift.io/cnfg- Configuration managementgolift.io/cnfgfile- Config file parsinggithub.com/spf13/pflag- CLI flag parsinggithub.com/gorilla/mux- HTTP routergithub.com/prometheus/client_golang- Prometheus metrics
Output Backends
- InfluxDB:
github.com/influxdata/influxdb1-clientandgithub.com/influxdata/influxdb-client-go/v2 - Prometheus:
github.com/prometheus/client_golang - Loki: Custom HTTP client
- DataDog:
github.com/DataDog/datadog-go/v5
Project Structure
unpoller/
├── main.go # Entry point
├── pkg/
│ ├── poller/ # Core plugin system
│ ├── inputunifi/ # UniFi input plugin
│ ├── influxunifi/ # InfluxDB output
│ ├── promunifi/ # Prometheus output
│ ├── lokiunifi/ # Loki output
│ ├── datadogunifi/ # DataDog output
│ ├── mysqlunifi/ # MySQL output
│ └── webserver/ # Web server
├── examples/ # Configuration examples
├── init/ # Init scripts (systemd, docker, etc.)
└── scripts/ # Build/deployment scripts
Common Patterns
Adding a New Output Plugin
- Create new package in
pkg/(e.g.,pkg/myoutput/) - Implement
Outputinterface frompkg/poller/outputs.go - Register plugin in
init()function - Add blank import to
main.go - Add configuration struct with proper tags
- Create README.md in package directory
Adding a New Input Plugin
- Create new package in
pkg/(e.g.,pkg/myinput/) - Implement
Inputinterface frompkg/poller/inputs.go - Register plugin in
init()function - Add blank import to
main.go - Add configuration struct with proper tags
Device Type Reporting
- Device types: UAP, USG, USW, UDM, UBB, UCI, UXG, PDU
- Each output plugin has device-specific reporting functions (e.g.,
uap.go,usg.go) - Follow existing patterns in
pkg/promunifi/orpkg/influxunifi/
Important Notes
- The
pkg/pollerlibrary is generic and has no knowledge of UniFi, Influx, Prometheus, etc. - It provides interfaces for any type of input/output plugin
- Use
[]anytypes for flexibility in the core library - Configuration is automatically loaded from files and environment variables
- The application supports multiple UniFi controllers via configuration
- Timezone can be set via
TZenvironment variable
Build & Deployment
- Uses GitHub Actions for CI/CD
- Uses
goreleaserfor multi-platform builds - Supports: Linux, macOS, Windows, FreeBSD
- Docker images built automatically
- Homebrew formula for macOS
- Configuration examples in
examples/directory
When Writing Code
- Keep functions focused and single-purpose
- Use interfaces for testability
- Follow the existing plugin patterns
- Document exported functions and types
- Add appropriate error handling
- Consider cross-platform compatibility (Windows, macOS, Linux, BSD)
- Use context.Context for cancellable operations
- Respect timeouts and deadlines
Source: unpoller/unpoller · 2643★ Repo: Application: Collect ALL UniFi Controller, Site, Device & Client Data - Export to InfluxDB or Prometheus