Initial Commit

pull/1/head
Darshil Chanpura 2019-08-31 21:53:02 +05:30
commit 6fc74b7897
2 changed files with 200 additions and 0 deletions

19
README.md Normal file
View File

@ -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
```

181
main.go Normal file
View File

@ -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, ".")
}