Lightweight, concurrent HTTP health checker built with Go. Keep your services alive with configurable intervals, retry logic, and structured logging.
- Overview
- Features
- Quick Start
- Configuration
- Usage
- Architecture
- Deployment
- Development
- Troubleshooting
- License
- Contact
Pinger is a production-ready HTTP health monitoring service written in Go. It periodically sends GET requests to configured endpoints to ensure they remain responsive. Perfect for keeping free-tier services (Render, Heroku, Railway) awake or monitoring critical APIs.
- Lightweight: Single binary, minimal resource usage (~5MB memory)
- Concurrent: Parallel health checks with goroutines
- Resilient: Configurable retry logic with exponential backoff
- Observable: Structured logging with zap (JSON or console)
- Production-Ready: Graceful shutdown, signal handling, error recovery
- Easy Deploy: Docker support, systemd service, cloud-ready
- Multi-Target Monitoring: Check unlimited URLs concurrently
- Configurable Intervals: Set custom ping frequencies (seconds/minutes/hours)
- Smart Retries: Automatic retry with exponential backoff
- Request Timeout: Prevent hanging requests with configurable timeout
- Response Logging: Optional body logging for debugging
- Structured Logs: JSON or console output with zap
- Log Levels: Debug, Info, Warn, Error
- Rich Context: Status codes, response times, error details
- Color Output: Terminal-friendly colored logs
- Graceful Shutdown: SIGTERM/SIGINT handling
- Context Cancellation: Clean goroutine cleanup
- Error Recovery: Continues on individual failures
- Concurrent-Safe: Thread-safe operations
- Environment Variables: 12-factor app compliant
- .env File Support: Easy local development
- Validation: Config validation at startup
- Flexible: Override defaults per environment
- Go 1.21+ (for building from source)
- Or Docker (for containerized deployment)
# Download latest release (replace VERSION)
wget https://github.com/KhanhRomVN/Pinger/releases/download/v1.0.0/pinger-linux-amd64
# Make executable
chmod +x pinger-linux-amd64
mv pinger-linux-amd64 /usr/local/bin/pinger# Clone repository
git clone https://github.com/KhanhRomVN/Pinger.git
cd Pinger
# Install dependencies
go mod download
# Build binary
go build -o pinger cmd/pinger/main.go# Pull image
docker pull khanhromvn/pinger:latest
# Run container
docker run -d \
-e PING_URLS="https://api.example.com/health" \
-e PING_INTERVAL=60 \
khanhromvn/pinger:latest# Create .env file
cp .env.example .env
# Edit configuration
nano .env
# Run pinger
./pingerOutput:
2024-01-15T10:30:00.123Z INFO Starting Pinger service target_count=3 interval=1m0s
2024-01-15T10:30:00.456Z INFO Pinger started url_count=3 interval=1m0s timeout=10s
2024-01-15T10:30:01.234Z INFO Ping successful url=https://api.example.com/health success=true status_code=200 response_time=778ms
Create a .env file or set environment variables:
# Required: Comma-separated list of URLs
PING_URLS=https://api.example.com/health,https://service2.com/ping
# Optional: Ping interval in seconds (default: 60)
PING_INTERVAL=60
# Optional: Request timeout in seconds (default: 10)
REQUEST_TIMEOUT=10
# Optional: Max retry attempts (default: 3)
MAX_RETRIES=3
# Optional: Log level: debug|info|warn|error (default: info)
LOG_LEVEL=info
# Optional: Log response body (default: false)
LOG_RESPONSE_BODY=false| Variable | Type | Default | Description |
|---|---|---|---|
PING_URLS |
string | required | Comma-separated URLs to monitor |
PING_INTERVAL |
int | 60 | Seconds between each ping cycle |
REQUEST_TIMEOUT |
int | 10 | HTTP request timeout in seconds |
MAX_RETRIES |
int | 3 | Retry attempts before marking as failed |
LOG_LEVEL |
string | info | Logging verbosity level |
LOG_RESPONSE_BODY |
bool | false | Include response body in logs |
Keep Free Services Alive:
# Ping every 5 minutes to prevent sleep
PING_URLS=https://myapp.onrender.com/health
PING_INTERVAL=300
REQUEST_TIMEOUT=30
MAX_RETRIES=5API Monitoring:
# Monitor multiple APIs with detailed logging
PING_URLS=https://api1.com/v1/health,https://api2.com/status,https://api3.com/ping
PING_INTERVAL=30
LOG_LEVEL=debug
LOG_RESPONSE_BODY=trueProduction Setup:
# Production monitoring with quick failure detection
PING_URLS=https://prod-api.com/health
PING_INTERVAL=10
REQUEST_TIMEOUT=5
MAX_RETRIES=2
LOG_LEVEL=error# Simple run
./pinger
# With environment variables
PING_URLS=https://example.com LOG_LEVEL=debug ./pinger
# Run in background
nohup ./pinger > pinger.log 2>&1 &Create /etc/systemd/system/pinger.service:
[Unit]
Description=Pinger Health Monitoring Service
After=network.target
[Service]
Type=simple
User=pinger
WorkingDirectory=/opt/pinger
EnvironmentFile=/opt/pinger/.env
ExecStart=/opt/pinger/pinger
Restart=on-failure
RestartSec=10
[Install]
WantedBy=multi-user.targetManage service:
# Enable and start
sudo systemctl enable pinger
sudo systemctl start pinger
# Check status
sudo systemctl status pinger
# View logs
sudo journalctl -u pinger -fCreate docker-compose.yml:
version: '3.8'
services:
pinger:
image: khanhromvn/pinger:latest
container_name: pinger
environment:
- PING_URLS=https://api.example.com/health,https://service2.com/ping
- PING_INTERVAL=60
- REQUEST_TIMEOUT=10
- MAX_RETRIES=3
- LOG_LEVEL=info
restart: unless-stoppedRun:
docker-compose up -dPinger/
βββ cmd/
β βββ pinger/
β βββ main.go # Application entry point
βββ internal/
β βββ config/
β β βββ config.go # Configuration loader
β βββ logger/
β β βββ logger.go # Zap logger setup
β βββ pinger/
β βββ pinger.go # Core ping logic
βββ .env.example # Example configuration
βββ go.mod # Go module definition
βββ go.sum # Dependency checksums
βββ Dockerfile # Container build
βββ README.md
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Pinger Service β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β ββββββββββββββββ ββββββββββββββββ ββββββββββ β
β β Main βββββββΊβ Config βββββββΊβ Logger β β
β β (cmd/main) β β Loader β β (zap) β β
β ββββββββββββββββ ββββββββββββββββ ββββββββββ β
β β β
β β creates β
β βΌ β
β ββββββββββββββββββββββββββββββββββββββββββββββββ β
β β Pinger Core β β
β β - Start(ctx) : goroutine per URL β β
β β - pingAll() : concurrent execution β β
β β - pingURL() : retry logic + timeout β β
β β - logResult(): structured logging β β
β ββββββββββββββββββββββββββββββββββββββββββββββββ β
β β β
β β HTTP GET β
β βΌ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
β Requests
βΌ
ββββββββββββββββββββ
β Target Services β
β (URLs to ping) β
ββββββββββββββββββββ
Start
β
ββ Load Config (.env)
β ββ Validate PING_URLS
β
ββ Initialize Logger (zap)
β ββ Set log level
β
ββ Create Pinger Instance
β ββ HTTP Client (with timeout)
β ββ Ticker (interval)
β
ββ Setup Context + Signal Handler
β ββ Listen for SIGTERM/SIGINT
β
ββ Start Pinger
β ββ Immediate ping (t=0)
β ββ Ticker loop
β ββ Every PING_INTERVAL
β β ββ pingAll()
β β ββ Spawn goroutine per URL
β β ββ Retry loop (MAX_RETRIES)
β β β ββ HTTP GET
β β β ββ Check status code
β β β ββ Measure response time
β β ββ Log result
β β
β ββ Wait for signal
β ββ Graceful shutdown
β
ββ Exit
render.yaml:
services:
- type: web
name: pinger
env: docker
dockerfilePath: ./Dockerfile
envVars:
- key: PING_URLS
value: https://myapp.onrender.com/health
- key: PING_INTERVAL
value: 300
- key: LOG_LEVEL
value: info# Install Railway CLI
npm install -g @railway/cli
# Login
railway login
# Deploy
railway up# Create app
heroku create my-pinger
# Set config
heroku config:set PING_URLS=https://example.com/health
# Deploy
git push heroku main# Upload binary
scp pinger user@server:/opt/pinger/
# Upload .env
scp .env user@server:/opt/pinger/
# Setup systemd service (see Usage section)
sudo systemctl enable pinger
sudo systemctl start pingerdeployment.yaml:
apiVersion: apps/v1
kind: Deployment
metadata:
name: pinger
spec:
replicas: 1
selector:
matchLabels:
app: pinger
template:
metadata:
labels:
app: pinger
spec:
containers:
- name: pinger
image: khanhromvn/pinger:latest
env:
- name: PING_URLS
value: "https://api.example.com/health"
- name: PING_INTERVAL
value: "60"
resources:
limits:
memory: "32Mi"
cpu: "50m"# Build for current platform
go build -o pinger cmd/pinger/main.go
# Build for Linux
GOOS=linux GOARCH=amd64 go build -o pinger-linux-amd64 cmd/pinger/main.go
# Build for Windows
GOOS=windows GOARCH=amd64 go build -o pinger-windows-amd64.exe cmd/pinger/main.go
# Build for macOS
GOOS=darwin GOARCH=amd64 go build -o pinger-darwin-amd64 cmd/pinger/main.go# Build image
docker build -t khanhromvn/pinger:latest .
# Run locally
docker run --rm \
-e PING_URLS=https://example.com \
khanhromvn/pinger:latest
# Push to registry
docker push khanhromvn/pinger:latest# Run tests
go test ./...
# Run with coverage
go test -cover ./...
# Benchmark
go test -bench=. ./internal/pinger# Format code
go fmt ./...
# Lint
golangci-lint run
# Vet
go vet ./...Problem: .env file not found error
Solution:
# Create .env from example
cp .env.example .env
# Or set environment variables directly
export PING_URLS=https://example.com
./pingerProblem: request failed: context deadline exceeded
Solution:
# Increase timeout
REQUEST_TIMEOUT=30
MAX_RETRIES=5Problem: Memory usage increasing over time
Solution:
# Disable response body logging
LOG_RESPONSE_BODY=false
# Reduce log level
LOG_LEVEL=errorProblem: Permission denied when accessing logs
Solution:
# Create dedicated user
sudo useradd -r -s /bin/false pinger
# Fix permissions
sudo chown -R pinger:pinger /opt/pinger
sudo chmod 755 /opt/pinger/pingerProblem: Ping reports failure but manual curl works
Solution:
# Check User-Agent blocking
# Pinger uses "Pinger/1.0" by default
# Test with curl
curl -H "User-Agent: Pinger/1.0" https://example.com
# If blocked, modify user agent in code (pinger.go:85)# Prevent Render/Heroku free tier sleep
PING_URLS=https://myapp.onrender.com/health
PING_INTERVAL=300 # Every 5 minutes# Monitor critical APIs
PING_URLS=https://api1.com/v1/health,https://api2.com/status
PING_INTERVAL=30
LOG_LEVEL=info# Warm up services before load test
PING_URLS=https://staging.example.com/api/warmup
PING_INTERVAL=5
REQUEST_TIMEOUT=60# Simple uptime check
PING_URLS=https://example.com
PING_INTERVAL=60
LOG_RESPONSE_BODY=falseThis project is licensed under the MIT License - see the LICENSE file for details.
MIT License
Copyright (c) 2024 KhanhRomVN
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
KhΓ‘nh Rom
- GitHub: @KhanhRomVN
- Email: khanhromvn@gmail.com
Project Link: https://github.com/KhanhRomVN/Pinger
- Uber Zap - Blazing fast structured logging
- godotenv - .env file support
- Go Standard Library - Built on solid foundations
- Prometheus metrics export
- Webhook notifications on failure
- HTTP POST support with custom payloads
- Response validation (status code, body pattern)
- Dashboard for visualization
- Multi-region pinging
- Slack/Discord integration
Made with β€οΈ by KhanhRomVN
β Star this repo if you find it helpful!
Keep your services alive, one ping at a time! π