mirror of
https://github.com/unpoller/unpoller.git
synced 2026-03-31 06:33:57 -04:00
Add AI context files for major LLMs
- Add .cursorrules for Cursor AI - Add CLAUDE.md for Claude Code - Add AGENTS.md for universal AI agent context - Add .github/copilot-instructions.md for GitHub Copilot These files provide comprehensive context about the UnPoller project architecture, coding standards, and development patterns to help AI coding assistants understand and work with the codebase effectively.
This commit is contained in:
148
.cursorrules
Normal file
148
.cursorrules
Normal file
@@ -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
|
||||
127
.github/copilot-instructions.md
vendored
Normal file
127
.github/copilot-instructions.md
vendored
Normal file
@@ -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
|
||||
270
AGENTS.md
Normal file
270
AGENTS.md
Normal file
@@ -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)
|
||||
241
CLAUDE.md
Normal file
241
CLAUDE.md
Normal file
@@ -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