7.8 KiB
UnPoller - AI Agent Context
This file provides comprehensive context for AI coding assistants working on the UnPoller project.
Project Identity
Name: UnPoller (UniFi Poller)
Language: Go 1.25.5+
Purpose: Collect metrics and events from UniFi network controllers and export to monitoring backends
Repository: https://github.com/unpoller/unpoller
Documentation: https://unpoller.com
Architecture Overview
UnPoller uses a plugin-based architecture with a generic core that provides input/output interfaces. The core library (pkg/poller) has no knowledge of UniFi or specific backends - it's a generic plugin system.
Core Components
-
Plugin System (
pkg/poller/):- Generic input/output interfaces
- Automatic plugin discovery via blank imports
- Configuration management (TOML/JSON/YAML + env vars)
- Metrics and events aggregation
-
Input Plugins:
pkg/inputunifi/- Collects data from UniFi controllers
-
Output Plugins:
pkg/influxunifi/- InfluxDB (v1 and v2)pkg/promunifi/- Prometheuspkg/lokiunifi/- Lokipkg/datadogunifi/- DataDogpkg/mysqlunifi/- MySQL
-
Web Server (
pkg/webserver/):- Health checks
- Metrics endpoint
- Plugin information
Code Organization
Directory Structure
unpoller/
├── main.go # Entry point, loads plugins
├── pkg/
│ ├── poller/ # Core plugin system (generic)
│ │ ├── config.go # Configuration structures
│ │ ├── inputs.go # Input plugin interface
│ │ ├── outputs.go # Output plugin interface
│ │ ├── start.go # Application startup
│ │ └── commands.go # CLI commands
│ ├── 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 scripts
Plugin Interface Pattern
Input Plugin:
type Input interface {
GetMetrics() (*Metrics, error)
GetEvents() (*Events, error)
}
Output Plugin:
type Output interface {
WriteMetrics(*Metrics) error
WriteEvents(*Events) error
}
Registration:
func init() {
poller.RegisterInput(&MyInput{})
// or
poller.RegisterOutput(&MyOutput{})
}
Coding Standards
Go Style
- Formatting: Standard
gofmt - Linting:
.golangci.yamlconfiguration- Enabled:
nlreturn,revive,tagalign,testpackage,wsl_v5
- Enabled:
- Imports: Use
//nolint:gciwhen import ordering needs exception
Naming Conventions
- Packages:
lowercase, single word - Exported:
PascalCase - Unexported:
camelCase - Constants:
PascalCasewith descriptive names - Errors: Always
err, checked immediately
Error Handling
// ✅ Good
if err != nil {
return fmt.Errorf("context: %w", err)
}
// ❌ Bad
_ = functionThatReturnsError()
Configuration Pattern
All configuration structs must include:
type Config struct {
Field string `json:"field" toml:"field" xml:"field" yaml:"field"`
}
- Environment variables use
UP_prefix (defined inENVConfigPrefix) - Automatic unmarshaling via
golift.io/cnfgandgolift.io/cnfgfile
Testing
- Tests in
_testpackages (enforced bytestpackagelinter) - Use
github.com/stretchr/testifyfor assertions - Integration tests:
integration_test.gowithintegration_test_expectations.yaml
Key Dependencies
Core Libraries
github.com/unpoller/unifi/v5- UniFi API client (local:/Users/briangates/unifi)golift.io/cnfg- Configuration managementgolift.io/cnfgfile- Config file parsinggithub.com/spf13/pflag- CLI flagsgithub.com/gorilla/mux- HTTP router
Output Backends
- InfluxDB:
github.com/influxdata/influxdb1-client(v1),github.com/influxdata/influxdb-client-go/v2(v2) - Prometheus:
github.com/prometheus/client_golang - DataDog:
github.com/DataDog/datadog-go/v5 - Loki: Custom HTTP implementation
Data Structures
Metrics
type Metrics struct {
TS time.Time
Sites []any
Clients []any
SitesDPI []any
ClientsDPI []any
Devices []any
RogueAPs []any
SpeedTests []any
CountryTraffic []any
}
Events
type Events struct {
Logs []any
}
Device Types
UniFi devices supported:
- UAP - Access Points (
uap.go) - USG - Security Gateways (
usg.go) - USW - Switches (
usw.go) - UDM - Dream Machines (
udm.go) - UXG - Next-Gen Gateways (
uxg.go) - UBB - Building Bridges (
ubb.go) - UCI - Industrial devices (
uci.go) - PDU - Power Distribution Units (
pdu.go)
Each output plugin has device-specific reporting functions following the pattern:
func (r *Report) UAP(uaps []*unifi.UAP) {
// Convert and export UAP data
}
Common Development Tasks
Adding a New Output Plugin
- Create package in
pkg/myoutput/ - Implement
Outputinterface - Register in
init()function - Add blank import to
main.go:_ "github.com/unpoller/unpoller/pkg/myoutput" - Add configuration struct with tags
- Create
README.mdwith usage examples
Adding Device Type Support
- Add device-specific file (e.g.,
mydevice.go) - Follow pattern from existing device files
- Convert UniFi device struct to output format
- Handle errors appropriately
Modifying Configuration
- Add fields to appropriate config struct
- Include all format tags:
json,toml,xml,yaml - Update example configs in
examples/ - Document in package
README.md
Build & Deployment
- CI/CD: GitHub Actions (
.github/workflows/) - Build:
goreleaser(.goreleaser.yaml) - Platforms: Linux, macOS, Windows, FreeBSD
- Docker: Auto-built to
ghcr.io - Packages: Debian, RedHat via goreleaser
- Homebrew: Formula for macOS
Important Constraints
- Generic Core:
pkg/pollermust remain generic - no UniFi/backend knowledge - Cross-Platform: Support Windows, macOS, Linux, BSD
- Configuration: Support TOML (default), JSON, YAML, and environment variables
- Error Handling: Always check and return errors
- Context: Use
context.Contextfor cancellable operations - Timeouts: Respect timeouts and deadlines
- Logging: Use structured logging via logger interfaces
Configuration Examples
File Formats: See examples/up.conf.example, examples/up.json.example, examples/up.yaml.example
Environment Variables:
UP_INFLUX_URL=http://localhost:8086
UP_UNIFI_DEFAULT_USER=admin
UP_UNIFI_DEFAULT_PASS=password
UP_POLLER_DEBUG=true
UP_POLLER_INTERVAL=30s
When Writing Code
- Follow Existing Patterns: Look at similar plugins for examples
- Keep Core Generic: Don't add UniFi/backend-specific code to
pkg/poller - Error Handling: Check all errors, return descriptive messages
- Documentation: Document exported functions and types
- Testing: Write tests in
_testpackages - Cross-Platform: Test on multiple platforms when possible
- Performance: Consider polling intervals and data volume
- Security: Don't log passwords or sensitive data
Resources
- Documentation: https://unpoller.com
- UniFi Library: https://github.com/unpoller/unifi
- Grafana Dashboards: https://grafana.com/dashboards?search=unifi-poller
- Discord: https://golift.io/discord (#unpoller channel)