mirror of
https://github.com/unpoller/unpoller.git
synced 2026-09-30 03:21:28 +02:00
Merge pull request #922 from brngates98/add-ai-context-files
Add AI context files for major LLMs
This commit is contained in:
+148
@@ -0,0 +1,148 @@
|
||||
# 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 `Input` interface from `pkg/poller/inputs.go`
|
||||
- Output plugins implement the `Output` interface from `pkg/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-lint` with the project's `.golangci.yaml` configuration
|
||||
- Enable linters: `nlreturn`, `revive`, `tagalign`, `testpackage`, `wsl_v5`
|
||||
- Use `//nolint:gci` for 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 `err` and checked immediately
|
||||
|
||||
### Error Handling
|
||||
- Always check errors, don't ignore them
|
||||
- Use `github.com/pkg/errors` for error wrapping when appropriate
|
||||
- Return errors from functions, don't log and continue
|
||||
- Use descriptive error messages
|
||||
|
||||
### Configuration
|
||||
- Configuration uses `golift.io/cnfg` and `golift.io/cnfgfile`
|
||||
- Environment variables use `UP_` prefix (defined in `ENVConfigPrefix`)
|
||||
- Support TOML (default), JSON, and YAML formats
|
||||
- Config structs should have tags: `json`, `toml`, `xml`, `yaml`
|
||||
|
||||
### Testing
|
||||
- Use `testpackage` linter - tests should be in separate `_test` packages
|
||||
- Use `github.com/stretchr/testify` for assertions
|
||||
- Integration tests use `integration_test_expectations.yaml` files
|
||||
|
||||
### 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 management
|
||||
- `golift.io/cnfgfile` - Config file parsing
|
||||
- `github.com/spf13/pflag` - CLI flag parsing
|
||||
- `github.com/gorilla/mux` - HTTP router
|
||||
- `github.com/prometheus/client_golang` - Prometheus metrics
|
||||
|
||||
### Output Backends
|
||||
- InfluxDB: `github.com/influxdata/influxdb1-client` and `github.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
|
||||
1. Create new package in `pkg/` (e.g., `pkg/myoutput/`)
|
||||
2. Implement `Output` interface from `pkg/poller/outputs.go`
|
||||
3. Register plugin in `init()` function
|
||||
4. Add blank import to `main.go`
|
||||
5. Add configuration struct with proper tags
|
||||
6. Create README.md in package directory
|
||||
|
||||
### Adding a New Input Plugin
|
||||
1. Create new package in `pkg/` (e.g., `pkg/myinput/`)
|
||||
2. Implement `Input` interface from `pkg/poller/inputs.go`
|
||||
3. Register plugin in `init()` function
|
||||
4. Add blank import to `main.go`
|
||||
5. 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/` or `pkg/influxunifi/`
|
||||
|
||||
## Important Notes
|
||||
|
||||
- The `pkg/poller` library is generic and has no knowledge of UniFi, Influx, Prometheus, etc.
|
||||
- It provides interfaces for any type of input/output plugin
|
||||
- Use `[]any` types 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 `TZ` environment variable
|
||||
|
||||
## Build & Deployment
|
||||
|
||||
- Uses GitHub Actions for CI/CD
|
||||
- Uses `goreleaser` for 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
|
||||
@@ -0,0 +1,127 @@
|
||||
# UnPoller - GitHub Copilot Instructions
|
||||
|
||||
## Project Overview
|
||||
|
||||
UnPoller is a Go application that collects metrics and events from UniFi network controllers and exports them to monitoring backends (InfluxDB, Prometheus, Loki, DataDog, MySQL). The application uses a plugin-based architecture with a generic core.
|
||||
|
||||
## Architecture
|
||||
|
||||
### Plugin System
|
||||
- **Core Library** (`pkg/poller/`): Generic plugin system with input/output interfaces
|
||||
- **Input Plugins**: Collect data (e.g., `pkg/inputunifi/`)
|
||||
- **Output Plugins**: Export data to backends (e.g., `pkg/influxunifi/`, `pkg/promunifi/`)
|
||||
- **Plugin Discovery**: Automatic via blank imports in `main.go`
|
||||
|
||||
### Key Interfaces
|
||||
|
||||
**Input Interface**:
|
||||
```go
|
||||
type Input interface {
|
||||
GetMetrics() (*Metrics, error)
|
||||
GetEvents() (*Events, error)
|
||||
}
|
||||
```
|
||||
|
||||
**Output Interface**:
|
||||
```go
|
||||
type Output interface {
|
||||
WriteMetrics(*Metrics) error
|
||||
WriteEvents(*Events) error
|
||||
}
|
||||
```
|
||||
|
||||
## Code Style
|
||||
|
||||
### Go Conventions
|
||||
- Go 1.25.5+
|
||||
- Use `gofmt` formatting
|
||||
- Follow `.golangci.yaml` linting rules
|
||||
- Enabled linters: `nlreturn`, `revive`, `tagalign`, `testpackage`, `wsl_v5`
|
||||
|
||||
### Naming
|
||||
- Packages: `lowercase`
|
||||
- Exported: `PascalCase`
|
||||
- Unexported: `camelCase`
|
||||
- Errors: Always `err`, check immediately
|
||||
|
||||
### Error Handling
|
||||
```go
|
||||
if err != nil {
|
||||
return fmt.Errorf("context: %w", err)
|
||||
}
|
||||
```
|
||||
|
||||
### Configuration
|
||||
All config structs must include format tags:
|
||||
```go
|
||||
type Config struct {
|
||||
Field string `json:"field" toml:"field" xml:"field" yaml:"field"`
|
||||
}
|
||||
```
|
||||
|
||||
Environment variables use `UP_` prefix.
|
||||
|
||||
## Common Patterns
|
||||
|
||||
### Plugin Registration
|
||||
```go
|
||||
func init() {
|
||||
poller.RegisterInput(&Input{})
|
||||
// or
|
||||
poller.RegisterOutput(&Output{})
|
||||
}
|
||||
```
|
||||
|
||||
### Device Type Reporting
|
||||
Each output plugin has device-specific functions:
|
||||
- `UAP()` - Access Points
|
||||
- `USG()` - Security Gateways
|
||||
- `USW()` - Switches
|
||||
- `UDM()` - Dream Machines
|
||||
- `UXG()` - Next-Gen Gateways
|
||||
- `UBB()` - Building Bridges
|
||||
- `UCI()` - Industrial devices
|
||||
- `PDU()` - Power Distribution Units
|
||||
|
||||
### Adding New Plugin
|
||||
1. Create package in `pkg/`
|
||||
2. Implement `Input` or `Output` interface
|
||||
3. Register in `init()`
|
||||
4. Add blank import to `main.go`
|
||||
5. Add config struct with tags
|
||||
6. Create `README.md`
|
||||
|
||||
## Dependencies
|
||||
|
||||
### Core
|
||||
- `github.com/unpoller/unifi/v5` - UniFi API (local: `/Users/briangates/unifi`)
|
||||
- `golift.io/cnfg` - Configuration
|
||||
- `golift.io/cnfgfile` - Config parsing
|
||||
- `github.com/spf13/pflag` - CLI flags
|
||||
|
||||
### Outputs
|
||||
- InfluxDB: `github.com/influxdata/influxdb1-client`, `github.com/influxdata/influxdb-client-go/v2`
|
||||
- Prometheus: `github.com/prometheus/client_golang`
|
||||
- DataDog: `github.com/DataDog/datadog-go/v5`
|
||||
- Loki: Custom HTTP client
|
||||
|
||||
## Important Notes
|
||||
|
||||
- `pkg/poller` core is generic - no UniFi/backend knowledge
|
||||
- Support Windows, macOS, Linux, BSD
|
||||
- Configuration: TOML (default), JSON, YAML, env vars
|
||||
- Always check and return errors
|
||||
- Use `context.Context` for cancellable operations
|
||||
- Tests in `_test` packages
|
||||
- Use `github.com/stretchr/testify` for assertions
|
||||
|
||||
## When Writing Code
|
||||
|
||||
1. Follow existing plugin patterns
|
||||
2. Keep core library generic
|
||||
3. Check all errors
|
||||
4. Document exported functions
|
||||
5. Write tests in `_test` packages
|
||||
6. Consider cross-platform compatibility
|
||||
7. Use structured logging
|
||||
8. Respect timeouts and deadlines
|
||||
@@ -0,0 +1,270 @@
|
||||
# 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
|
||||
|
||||
1. **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
|
||||
|
||||
2. **Input Plugins**:
|
||||
- `pkg/inputunifi/` - Collects data from UniFi controllers
|
||||
|
||||
3. **Output Plugins**:
|
||||
- `pkg/influxunifi/` - InfluxDB (v1 and v2)
|
||||
- `pkg/promunifi/` - Prometheus
|
||||
- `pkg/lokiunifi/` - Loki
|
||||
- `pkg/datadogunifi/` - DataDog
|
||||
- `pkg/mysqlunifi/` - MySQL
|
||||
|
||||
4. **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**:
|
||||
```go
|
||||
type Input interface {
|
||||
GetMetrics() (*Metrics, error)
|
||||
GetEvents() (*Events, error)
|
||||
}
|
||||
```
|
||||
|
||||
**Output Plugin**:
|
||||
```go
|
||||
type Output interface {
|
||||
WriteMetrics(*Metrics) error
|
||||
WriteEvents(*Events) error
|
||||
}
|
||||
```
|
||||
|
||||
**Registration**:
|
||||
```go
|
||||
func init() {
|
||||
poller.RegisterInput(&MyInput{})
|
||||
// or
|
||||
poller.RegisterOutput(&MyOutput{})
|
||||
}
|
||||
```
|
||||
|
||||
## Coding Standards
|
||||
|
||||
### Go Style
|
||||
|
||||
- **Formatting**: Standard `gofmt`
|
||||
- **Linting**: `.golangci.yaml` configuration
|
||||
- Enabled: `nlreturn`, `revive`, `tagalign`, `testpackage`, `wsl_v5`
|
||||
- **Imports**: Use `//nolint:gci` when import ordering needs exception
|
||||
|
||||
### Naming Conventions
|
||||
|
||||
- Packages: `lowercase`, single word
|
||||
- Exported: `PascalCase`
|
||||
- Unexported: `camelCase`
|
||||
- Constants: `PascalCase` with descriptive names
|
||||
- Errors: Always `err`, checked immediately
|
||||
|
||||
### Error Handling
|
||||
|
||||
```go
|
||||
// ✅ Good
|
||||
if err != nil {
|
||||
return fmt.Errorf("context: %w", err)
|
||||
}
|
||||
|
||||
// ❌ Bad
|
||||
_ = functionThatReturnsError()
|
||||
```
|
||||
|
||||
### Configuration Pattern
|
||||
|
||||
All configuration structs must include:
|
||||
```go
|
||||
type Config struct {
|
||||
Field string `json:"field" toml:"field" xml:"field" yaml:"field"`
|
||||
}
|
||||
```
|
||||
|
||||
- Environment variables use `UP_` prefix (defined in `ENVConfigPrefix`)
|
||||
- Automatic unmarshaling via `golift.io/cnfg` and `golift.io/cnfgfile`
|
||||
|
||||
### Testing
|
||||
|
||||
- Tests in `_test` packages (enforced by `testpackage` linter)
|
||||
- Use `github.com/stretchr/testify` for assertions
|
||||
- Integration tests: `integration_test.go` with `integration_test_expectations.yaml`
|
||||
|
||||
## Key Dependencies
|
||||
|
||||
### Core Libraries
|
||||
- `github.com/unpoller/unifi/v5` - UniFi API client (local: `/Users/briangates/unifi`)
|
||||
- `golift.io/cnfg` - Configuration management
|
||||
- `golift.io/cnfgfile` - Config file parsing
|
||||
- `github.com/spf13/pflag` - CLI flags
|
||||
- `github.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
|
||||
```go
|
||||
type Metrics struct {
|
||||
TS time.Time
|
||||
Sites []any
|
||||
Clients []any
|
||||
SitesDPI []any
|
||||
ClientsDPI []any
|
||||
Devices []any
|
||||
RogueAPs []any
|
||||
SpeedTests []any
|
||||
CountryTraffic []any
|
||||
}
|
||||
```
|
||||
|
||||
### Events
|
||||
```go
|
||||
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:
|
||||
```go
|
||||
func (r *Report) UAP(uaps []*unifi.UAP) {
|
||||
// Convert and export UAP data
|
||||
}
|
||||
```
|
||||
|
||||
## Common Development Tasks
|
||||
|
||||
### Adding a New Output Plugin
|
||||
|
||||
1. Create package in `pkg/myoutput/`
|
||||
2. Implement `Output` interface
|
||||
3. Register in `init()` function
|
||||
4. Add blank import to `main.go`: `_ "github.com/unpoller/unpoller/pkg/myoutput"`
|
||||
5. Add configuration struct with tags
|
||||
6. Create `README.md` with usage examples
|
||||
|
||||
### Adding Device Type Support
|
||||
|
||||
1. Add device-specific file (e.g., `mydevice.go`)
|
||||
2. Follow pattern from existing device files
|
||||
3. Convert UniFi device struct to output format
|
||||
4. Handle errors appropriately
|
||||
|
||||
### Modifying Configuration
|
||||
|
||||
1. Add fields to appropriate config struct
|
||||
2. Include all format tags: `json`, `toml`, `xml`, `yaml`
|
||||
3. Update example configs in `examples/`
|
||||
4. 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
|
||||
|
||||
1. **Generic Core**: `pkg/poller` must remain generic - no UniFi/backend knowledge
|
||||
2. **Cross-Platform**: Support Windows, macOS, Linux, BSD
|
||||
3. **Configuration**: Support TOML (default), JSON, YAML, and environment variables
|
||||
4. **Error Handling**: Always check and return errors
|
||||
5. **Context**: Use `context.Context` for cancellable operations
|
||||
6. **Timeouts**: Respect timeouts and deadlines
|
||||
7. **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**:
|
||||
```bash
|
||||
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
|
||||
|
||||
1. **Follow Existing Patterns**: Look at similar plugins for examples
|
||||
2. **Keep Core Generic**: Don't add UniFi/backend-specific code to `pkg/poller`
|
||||
3. **Error Handling**: Check all errors, return descriptive messages
|
||||
4. **Documentation**: Document exported functions and types
|
||||
5. **Testing**: Write tests in `_test` packages
|
||||
6. **Cross-Platform**: Test on multiple platforms when possible
|
||||
7. **Performance**: Consider polling intervals and data volume
|
||||
8. **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)
|
||||
@@ -0,0 +1,241 @@
|
||||
# UnPoller - Claude Code Context
|
||||
|
||||
## Project Overview
|
||||
|
||||
UnPoller is a Go application that collects metrics and events from UniFi network controllers and exports them to various time-series databases and monitoring systems. The application uses a plugin-based architecture where input plugins collect data and output plugins export it to different backends.
|
||||
|
||||
## Architecture
|
||||
|
||||
### Core Design Principles
|
||||
|
||||
1. **Plugin-Based Architecture**: The core `pkg/poller` library is generic and provides interfaces for input and output plugins. It has no knowledge of UniFi, InfluxDB, Prometheus, etc.
|
||||
|
||||
2. **Automatic Plugin Discovery**: Plugins are loaded via blank imports in `main.go`. The poller automatically discovers and initializes all imported plugins.
|
||||
|
||||
3. **Flexible Configuration**: Supports TOML (default), JSON, and YAML configuration files, plus environment variables with `UP_` prefix.
|
||||
|
||||
4. **Multiple Backends**: Supports InfluxDB, Prometheus, Loki, DataDog, and MySQL as output backends.
|
||||
|
||||
### Package Structure
|
||||
|
||||
```
|
||||
pkg/
|
||||
├── poller/ # Core plugin system - generic, no UniFi/backend knowledge
|
||||
├── inputunifi/ # UniFi controller input plugin
|
||||
├── influxunifi/ # InfluxDB output plugin
|
||||
├── promunifi/ # Prometheus output plugin
|
||||
├── lokiunifi/ # Loki output plugin
|
||||
├── datadogunifi/ # DataDog output plugin
|
||||
├── mysqlunifi/ # MySQL output plugin
|
||||
└── webserver/ # Web server for health checks and metrics
|
||||
```
|
||||
|
||||
### Key Interfaces
|
||||
|
||||
**Input Interface** (`pkg/poller/inputs.go`):
|
||||
- `GetMetrics()` - Returns aggregated metrics
|
||||
- `GetEvents()` - Returns events/logs
|
||||
- Plugins must implement this to provide data
|
||||
|
||||
**Output Interface** (`pkg/poller/outputs.go`):
|
||||
- `WriteMetrics()` - Writes metrics to backend
|
||||
- `WriteEvents()` - Writes events to backend
|
||||
- Plugins must implement this to export data
|
||||
|
||||
## Code Style Guidelines
|
||||
|
||||
### Go Conventions
|
||||
|
||||
- **Go Version**: 1.25.5+
|
||||
- **Formatting**: Use `gofmt` standard formatting
|
||||
- **Linting**: Follow `.golangci.yaml` configuration
|
||||
- Enabled: `nlreturn`, `revive`, `tagalign`, `testpackage`, `wsl_v5`
|
||||
- Use `//nolint:gci` for import ordering exceptions
|
||||
|
||||
### Naming
|
||||
|
||||
- **Packages**: Lowercase, single word
|
||||
- **Exported**: PascalCase (types, functions, constants)
|
||||
- **Unexported**: camelCase
|
||||
- **Errors**: Always named `err`, checked immediately
|
||||
|
||||
### Error Handling
|
||||
|
||||
```go
|
||||
// Good: Check and return errors
|
||||
if err != nil {
|
||||
return fmt.Errorf("operation failed: %w", err)
|
||||
}
|
||||
|
||||
// Bad: Ignoring errors
|
||||
_ = someFunction()
|
||||
```
|
||||
|
||||
### Configuration Pattern
|
||||
|
||||
```go
|
||||
type Config struct {
|
||||
URL string `json:"url" toml:"url" yaml:"url"`
|
||||
Interval string `json:"interval" toml:"interval" yaml:"interval"`
|
||||
Timeout string `json:"timeout" toml:"timeout" yaml:"timeout"`
|
||||
}
|
||||
```
|
||||
|
||||
- Always include `json`, `toml`, `xml`, `yaml` tags
|
||||
- Environment variables use `UP_` prefix automatically
|
||||
- Use `golift.io/cnfg` for configuration management
|
||||
|
||||
### Testing
|
||||
|
||||
- Tests in separate `_test` packages (enforced by `testpackage` linter)
|
||||
- Use `github.com/stretchr/testify` for assertions
|
||||
- Integration tests use `integration_test_expectations.yaml`
|
||||
|
||||
## Common Tasks
|
||||
|
||||
### Adding a New Output Plugin
|
||||
|
||||
1. **Create Package Structure**:
|
||||
```go
|
||||
package myoutput
|
||||
|
||||
import (
|
||||
"github.com/unpoller/unpoller/pkg/poller"
|
||||
)
|
||||
|
||||
type Output struct {
|
||||
// Configuration fields
|
||||
}
|
||||
|
||||
func (o *Output) WriteMetrics(m *poller.Metrics) error {
|
||||
// Implementation
|
||||
}
|
||||
|
||||
func (o *Output) WriteEvents(e *poller.Events) error {
|
||||
// Implementation
|
||||
}
|
||||
|
||||
func init() {
|
||||
poller.RegisterOutput(&Output{})
|
||||
}
|
||||
```
|
||||
|
||||
2. **Add Blank Import** to `main.go`:
|
||||
```go
|
||||
_ "github.com/unpoller/unpoller/pkg/myoutput"
|
||||
```
|
||||
|
||||
3. **Add Configuration** to config structs with proper tags
|
||||
|
||||
4. **Create README.md** documenting usage
|
||||
|
||||
### Adding Device Type Support
|
||||
|
||||
Each output plugin has device-specific files:
|
||||
- `uap.go` - Access Points
|
||||
- `usg.go` - Security Gateways
|
||||
- `usw.go` - Switches
|
||||
- `udm.go` - Dream Machines
|
||||
- `uxg.go` - Next-Gen Gateways
|
||||
- `ubb.go` - Building Bridges
|
||||
- `uci.go` - Industrial devices
|
||||
- `pdu.go` - Power Distribution Units
|
||||
|
||||
Follow the pattern in existing files:
|
||||
```go
|
||||
func (r *Report) UAP(uaps []*unifi.UAP) {
|
||||
// Convert UniFi device data to output format
|
||||
}
|
||||
```
|
||||
|
||||
### Working with UniFi Data
|
||||
|
||||
- UniFi library: `github.com/unpoller/unifi/v5` (local replace at `/Users/briangates/unifi`)
|
||||
- Device types come from the UniFi controller API
|
||||
- Data includes: sites, clients, devices, DPI data, speed tests, country traffic
|
||||
- Events include: system logs, alarms, IDS events, anomalies
|
||||
|
||||
## Dependencies
|
||||
|
||||
### Core
|
||||
- `github.com/unpoller/unifi/v5` - UniFi API client
|
||||
- `golift.io/cnfg` - Configuration management
|
||||
- `golift.io/cnfgfile` - Config file parsing
|
||||
- `github.com/spf13/pflag` - CLI flags
|
||||
|
||||
### Output Backends
|
||||
- InfluxDB: `github.com/influxdata/influxdb1-client` (v1) and `github.com/influxdata/influxdb-client-go/v2` (v2)
|
||||
- Prometheus: `github.com/prometheus/client_golang`
|
||||
- DataDog: `github.com/DataDog/datadog-go/v5`
|
||||
- Loki: Custom HTTP client implementation
|
||||
|
||||
## Important Patterns
|
||||
|
||||
### Plugin Registration
|
||||
```go
|
||||
func init() {
|
||||
poller.RegisterInput(&Input{})
|
||||
// or
|
||||
poller.RegisterOutput(&Output{})
|
||||
}
|
||||
```
|
||||
|
||||
### Configuration Loading
|
||||
Configuration is automatically loaded from:
|
||||
1. Config file (TOML/JSON/YAML) - path specified via `--config` flag or defaults
|
||||
2. Environment variables with `UP_` prefix
|
||||
3. CLI flags
|
||||
|
||||
### Metrics Structure
|
||||
```go
|
||||
type Metrics struct {
|
||||
TS time.Time
|
||||
Sites []any
|
||||
Clients []any
|
||||
SitesDPI []any
|
||||
ClientsDPI []any
|
||||
Devices []any
|
||||
RogueAPs []any
|
||||
SpeedTests []any
|
||||
CountryTraffic []any
|
||||
}
|
||||
```
|
||||
|
||||
### Events Structure
|
||||
```go
|
||||
type Events struct {
|
||||
Logs []any
|
||||
}
|
||||
```
|
||||
|
||||
## Build & Deployment
|
||||
|
||||
- **CI/CD**: GitHub Actions
|
||||
- **Build Tool**: `goreleaser` for multi-platform builds
|
||||
- **Platforms**: Linux, macOS, Windows, FreeBSD
|
||||
- **Docker**: Images built automatically to `ghcr.io`
|
||||
- **Homebrew**: Formula for macOS users
|
||||
- **Packages**: Debian, RedHat packages via goreleaser
|
||||
|
||||
## When Writing Code
|
||||
|
||||
1. **Keep it Generic**: The `pkg/poller` core should remain generic
|
||||
2. **Follow Patterns**: Look at existing plugins for examples
|
||||
3. **Error Handling**: Always check and return errors
|
||||
4. **Cross-Platform**: Consider Windows, macOS, Linux, BSD differences
|
||||
5. **Context Usage**: Use `context.Context` for cancellable operations
|
||||
6. **Timeouts**: Respect timeouts and deadlines
|
||||
7. **Documentation**: Document exported functions and types
|
||||
8. **Testing**: Write tests in separate `_test` packages
|
||||
|
||||
## Configuration Examples
|
||||
|
||||
Configuration files support multiple formats. See `examples/` directory:
|
||||
- `up.conf.example` - TOML format
|
||||
- `up.json.example` - JSON format
|
||||
- `up.yaml.example` - YAML format
|
||||
|
||||
Environment variables use `UP_` prefix:
|
||||
- `UP_INFLUX_URL=http://localhost:8086`
|
||||
- `UP_UNIFI_DEFAULT_USER=admin`
|
||||
- `UP_POLLER_DEBUG=true`
|
||||
Reference in New Issue
Block a user