Thank you for your interest in contributing to TelemetryFlow Agent! This document provides guidelines and instructions for contributing to this project.
- Code of Conduct
- Getting Started
- Development Setup
- Project Structure
- Making Changes
- Testing
- Submitting Changes
- Coding Standards
- Documentation
- Community
This project adheres to the Contributor Covenant Code of Conduct. By participating, you are expected to uphold this code. Please report unacceptable behavior to support@devopscorner.id.
- Go 1.25 or later
- Git
- Make
- Docker (optional, for container builds)
- golangci-lint (for linting)
- Fork the repository on GitHub
- Clone your fork locally:
git clone https://github.com/YOUR_USERNAME/telemetryflow-agent.git
cd telemetryflow-agent- Add the upstream remote:
git remote add upstream https://github.com/telemetryflow/telemetryflow-agent.git# Download Go dependencies
make deps
# Or manually
go mod download
go mod tidy# Build for current platform
make build
# Build for all platforms
make build-all
# Build for specific platforms
make build-linux
make build-darwin# Install golangci-lint (macOS)
brew install golangci-lint
# Install golangci-lint (Linux)
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bintelemetryflow-agent/
├── cmd/tfo-agent/ # CLI entry point
├── internal/
│ ├── agent/ # Core agent lifecycle
│ ├── buffer/ # Disk-backed retry buffer
│ ├── collector/ # Metric collectors
│ │ └── system/ # System metrics collector
│ ├── config/ # Configuration management
│ ├── exporter/ # OTLP data exporters
│ └── version/ # Version and banner info
├── pkg/ # LEGO Building Blocks (reusable)
│ ├── api/ # HTTP API client
│ ├── banner/ # Startup banner
│ ├── config/ # Config loader utilities
│ └── plugin/ # Plugin registry system
├── configs/ # Configuration templates
├── tests/
│ ├── unit/ # Unit tests
│ ├── integration/ # Integration tests
│ └── e2e/ # End-to-end tests
├── scripts/ # Build/install scripts
├── build/ # Build output
├── docs/ # Documentation
├── Makefile
├── Dockerfile
└── docker-compose.yml
| Package | Description |
|---|---|
cmd/tfo-agent |
Main entry point with Cobra CLI |
internal/agent |
Core agent lifecycle management |
internal/collector |
Telemetry collectors |
internal/config |
Configuration parsing and validation |
internal/exporter |
OTLP exporters |
pkg/plugin |
Plugin registry for extensibility |
Use descriptive branch names:
feature/add-kubernetes-collectorfix/memory-leak-in-bufferdocs/update-configuration-guiderefactor/simplify-exporter-logic
# Sync with upstream
git fetch upstream
git checkout main
git merge upstream/main
# Create your branch
git checkout -b feature/your-feature-nameFollow Conventional Commits:
<type>(<scope>): <description>
[optional body]
[optional footer]
Types:
feat: New featurefix: Bug fixdocs: Documentation changesstyle: Code style changes (formatting, etc.)refactor: Code refactoringtest: Adding or updating testschore: Maintenance tasks
Examples:
feat(collector): add network metrics collector
fix(buffer): resolve memory leak in retry logic
docs(readme): update installation instructions
# Run unit and integration tests
make test
# Run all tests including E2E
make test-all# Unit tests only
make test-unit
# Integration tests only
make test-integration
# E2E tests only
make test-e2e
# Run short tests (skip E2E)
make test-short# Generate coverage report
make test-coverage
# View coverage in browser
go tool cover -html=coverage-unit.out- Place unit tests in
tests/unit/mirroring the package structure - Place integration tests in
tests/integration/ - Place E2E tests in
tests/e2e/ - Use table-driven tests where appropriate
- Mock external dependencies
Example test:
func TestCollector_CollectMetrics(t *testing.T) {
tests := []struct {
name string
config Config
want []Metric
wantErr bool
}{
{
name: "collect CPU metrics",
config: Config{EnableCPU: true},
want: []Metric{{Name: "system.cpu.usage"}},
},
// Add more test cases...
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
c := NewCollector(tt.config)
got, err := c.CollectMetrics()
if (err != nil) != tt.wantErr {
t.Errorf("CollectMetrics() error = %v, wantErr %v", err, tt.wantErr)
return
}
// Assert results...
})
}
}Before submitting, ensure your code passes all checks:
# Format code
make fmt
# Run linter
make lint
# Run go vet
make vet
# Run all tests
make test-all- Update documentation if needed
- Add tests for new functionality
- Ensure all tests pass
- Update CHANGELOG.md if applicable
- Submit a pull request to
mainbranch
## Description
Brief description of changes
## Type of Change
- [ ] Bug fix
- [ ] New feature
- [ ] Breaking change
- [ ] Documentation update
## Testing
- [ ] Unit tests added/updated
- [ ] Integration tests added/updated
- [ ] E2E tests added/updated
## Checklist
- [ ] Code follows project style guidelines
- [ ] Self-review completed
- [ ] Documentation updated
- [ ] Tests pass locally- Follow Effective Go
- Follow Go Code Review Comments
- Use
gofmtfor formatting - Keep functions focused and small
- Use meaningful variable names
// Good: Handle errors explicitly
result, err := doSomething()
if err != nil {
return fmt.Errorf("failed to do something: %w", err)
}
// Good: Use error wrapping for context
if err := validateConfig(cfg); err != nil {
return fmt.Errorf("config validation: %w", err)
}Use structured logging with zap:
logger.Info("starting collector",
zap.String("collector", "system"),
zap.Duration("interval", interval),
)
logger.Error("failed to export metrics",
zap.Error(err),
zap.Int("count", len(metrics)),
)- Use YAML for configuration files
- Provide sensible defaults
- Document all configuration options
- Validate configuration on load
- Add package-level documentation
- Document exported functions, types, and constants
- Use examples where helpful
// Package collector provides telemetry collection functionality.
//
// It supports collecting system metrics including CPU, memory,
// disk, and network statistics.
package collector
// Collector collects system telemetry data.
// It implements the plugin.Plugin interface for extensibility.
type Collector struct {
// ...
}
// NewCollector creates a new Collector with the given configuration.
// If config is nil, default values are used.
func NewCollector(config *Config) *Collector {
// ...
}- Update README.md for user-facing changes
- Add/update docs in the
docs/directory - Include examples for new features
- GitHub Issues: Report bugs or request features
- Discussions: Ask questions and share ideas
- Email: support@devopscorner.id
Contributors are recognized in:
- Release notes
- CONTRIBUTORS.md file
- GitHub contributors page
By contributing to TelemetryFlow Agent, you agree that your contributions will be licensed under the Apache License 2.0.
Thank you for contributing to TelemetryFlow Agent!
Copyright (c) 2024-2026 DevOpsCorner Indonesia. All rights reserved.