Initial Commit
commit
6fc74b7897
|
@ -0,0 +1,19 @@
|
|||
# heartbeet - Health Check utility for hosts
|
||||
|
||||
This utility is mainly for sending "is up" notification to Graphite server.
|
||||
|
||||
## Environment Variables
|
||||
|
||||
* PROJECT_NAME: Name of project which is included in metric name
|
||||
* RUN_MODE: This is usually the environment which it ran in, usually prod/stage/test/dev
|
||||
* GRAPHITE_KEY: This key is used as prefix if needed.
|
||||
* GRAPHITE_ADDRESS: Address of graphite carbon, e.g. `127.0.0.1:2003`
|
||||
|
||||
|
||||
## Run
|
||||
|
||||
Just run with required environment variables
|
||||
|
||||
```bash
|
||||
$ GRAPHITE_ADDRESS=graphitehost.local:2003 RUN_MODE=stage PROJECT_NAME=nginx ./heartbeet
|
||||
```
|
|
@ -0,0 +1,181 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
client = &net.Dialer{
|
||||
Timeout: time.Second * 10,
|
||||
DualStack: false,
|
||||
KeepAlive: time.Second * 60,
|
||||
}
|
||||
// conn net.Conn
|
||||
ticker *time.Ticker
|
||||
quit chan struct{}
|
||||
project = &projecttype{}
|
||||
graphiteAddr string
|
||||
graphiteKey string
|
||||
periodString string
|
||||
period periodValue
|
||||
)
|
||||
|
||||
type projecttype struct {
|
||||
name string
|
||||
mode string
|
||||
}
|
||||
|
||||
type metrictype struct {
|
||||
prefix string
|
||||
metric string
|
||||
value float64
|
||||
timestamp time.Time
|
||||
hostname string
|
||||
network string
|
||||
}
|
||||
|
||||
type periodValue struct {
|
||||
time.Duration
|
||||
}
|
||||
|
||||
func (p *periodValue) Set(value string) error {
|
||||
duration, err := time.ParseDuration(value)
|
||||
p.Duration = duration
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *periodValue) String() string {
|
||||
return p.Duration.String()
|
||||
}
|
||||
|
||||
func init() {
|
||||
flag.Var(&period, "period", "Period ticker runs")
|
||||
// flag.StringVar(&periodString, "period", "30s", "Duration to send metrics")
|
||||
|
||||
quit = make(chan struct{})
|
||||
project.name = os.Getenv("PROJECT_NAME")
|
||||
if project.mode = os.Getenv("RUN_MODE"); project.mode == "" {
|
||||
project.mode = "dev"
|
||||
}
|
||||
graphiteKey = os.Getenv("GRAPHITE_KEY")
|
||||
if graphiteAddr = os.Getenv("GRAPHITE_ADDRESS"); graphiteAddr == "" {
|
||||
graphiteAddr = "127.0.0.1:2003"
|
||||
}
|
||||
flag.Parse()
|
||||
|
||||
if period.Duration > 0 {
|
||||
ticker = time.NewTicker(period.Duration)
|
||||
} else {
|
||||
ticker = time.NewTicker(30 * time.Second)
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
startTicker()
|
||||
// go func(value float64) {
|
||||
// }(value)
|
||||
}
|
||||
|
||||
func startTicker() {
|
||||
for {
|
||||
select {
|
||||
case <-ticker.C:
|
||||
sendMetric()
|
||||
case <-quit:
|
||||
ticker.Stop()
|
||||
return
|
||||
// break loop
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func sendMetric() {
|
||||
m := newMetric("heartbeat", 1)
|
||||
// m.prefix = modePrefixMap[project.mode]
|
||||
err := m.send(graphiteAddr)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
m.network = "udp"
|
||||
err = m.send(graphiteAddr)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (m *metrictype) init() {
|
||||
if m.timestamp.IsZero() {
|
||||
m.timestamp = time.Now()
|
||||
}
|
||||
if m.network == "" {
|
||||
m.network = "tcp"
|
||||
}
|
||||
hostname, err := os.Hostname()
|
||||
if err == nil {
|
||||
m.hostname = hostname
|
||||
}
|
||||
}
|
||||
|
||||
func (m *metrictype) send(addr string) error {
|
||||
conn, err := client.Dial(m.network, addr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer conn.Close()
|
||||
_, err = fmt.Fprintf(conn, "%s %0.2f %d\n", m.metricString(), m.value, m.timestamp.Unix())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func newMetric(metric string, value float64) *metrictype {
|
||||
prefixes := []string{}
|
||||
if project.mode != "" {
|
||||
prefixes = append(prefixes, project.mode)
|
||||
}
|
||||
if project.name != "" {
|
||||
prefixes = append(prefixes, project.name)
|
||||
}
|
||||
prefix := strings.Join(prefixes, ".")
|
||||
|
||||
return newMetricWithPrefix(prefix, metric, value)
|
||||
}
|
||||
|
||||
func newMetricWithPrefix(prefix string, metric string, value float64) *metrictype {
|
||||
m := &metrictype{
|
||||
prefix: prefix,
|
||||
metric: metric,
|
||||
value: value,
|
||||
}
|
||||
m.init()
|
||||
return m
|
||||
}
|
||||
|
||||
func (m *metrictype) metricString() string {
|
||||
metricslice := []string{m.metric}
|
||||
if m.hostname != "" {
|
||||
metricslice = append(metricslice, m.hostname)
|
||||
}
|
||||
if m.prefix != "" {
|
||||
metricslice = append(metricslice, m.prefix)
|
||||
}
|
||||
if graphiteKey != "" {
|
||||
metricslice = append(metricslice, graphiteKey)
|
||||
}
|
||||
// reverse slice
|
||||
for left, right := 0, len(metricslice)-1; left < right; left, right = left+1, right-1 {
|
||||
metricslice[left], metricslice[right] = metricslice[right], metricslice[left]
|
||||
}
|
||||
return strings.Join(metricslice, ".")
|
||||
}
|
Loading…
Reference in New Issue