-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathmain.go
More file actions
128 lines (113 loc) · 3.71 KB
/
main.go
File metadata and controls
128 lines (113 loc) · 3.71 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
package main
import (
"flag"
"fmt"
"log"
"os"
"os/signal"
"strconv"
"strings"
"syscall"
"time"
"github.com/coreos/go-etcd/etcd"
"github.com/deis/deis/logger/syslogd"
)
var (
logAddr string
logPort int
drainURI string
enablePublish bool
publishHost string
publishPath string
publishPort string
publishInterval int
publishTTL int
)
func init() {
flag.StringVar(&logAddr, "log-addr", "0.0.0.0", "bind address for the logger")
flag.IntVar(&logPort, "log-port", 514, "bind port for the logger")
flag.StringVar(&drainURI, "drain-uri", "", "default drainURI, once set in etcd, this has no effect.")
flag.StringVar(&syslogd.LogRoot, "log-root", "/data/logs", "log path to store logs")
flag.BoolVar(&enablePublish, "enable-publish", false, "enable publishing to service discovery")
flag.StringVar(&publishHost, "publish-host", getopt("HOST", "127.0.0.1"), "service discovery hostname")
flag.IntVar(&publishInterval, "publish-interval", 10, "publish interval in seconds")
flag.StringVar(&publishPath, "publish-path", getopt("ETCD_PATH", "/deis/logs"), "path to publish host/port information")
flag.StringVar(&publishPort, "publish-port", getopt("ETCD_PORT", "4001"), "service discovery port")
flag.IntVar(&publishTTL, "publish-ttl", publishInterval*2, "publish TTL in seconds")
}
func main() {
flag.Parse()
client := etcd.NewClient([]string{"http://" + publishHost + ":" + publishPort})
signalChan := make(chan os.Signal, 1)
drainChan := make(chan string)
stopChan := make(chan bool)
exitChan := make(chan bool)
cleanupChan := make(chan bool)
signal.Notify(signalChan, syscall.SIGTERM, syscall.SIGINT)
// ensure the drain key exists in etcd.
if _, err := client.Get(publishPath+"/drain", false, false); err != nil {
setEtcd(client, publishPath+"/drain", drainURI, 0)
}
go syslogd.Listen(exitChan, cleanupChan, drainChan, fmt.Sprintf("%s:%d", logAddr, logPort))
if enablePublish {
go publishService(exitChan, client, publishHost, publishPath, strconv.Itoa(logPort), uint64(time.Duration(publishTTL)*time.Second))
}
// HACK (bacongobbler): poll etcd for changes in the log drain value
// etcd's .Watch() implementation is broken when you use TTLs
//
// https://github.com/coreos/etcd/issues/2679
go func() {
for {
resp, err := client.Get(publishPath+"/drain", false, false)
if err != nil {
log.Printf("warning: could not retrieve drain URI from etcd: %v\n", err)
continue
}
if resp != nil && resp.Node != nil {
drainChan <- resp.Node.Value
}
time.Sleep(time.Duration(publishInterval) * time.Second)
}
}()
for {
select {
case <-signalChan:
close(exitChan)
stopChan <- true
case <-cleanupChan:
return
}
}
}
// publishKeys sets relevant etcd keys with a time-to-live.
func publishKeys(client *etcd.Client, host, etcdPath, port string, ttl uint64) {
setEtcd(client, etcdPath+"/host", host, ttl)
setEtcd(client, etcdPath+"/port", port, ttl)
}
// publishServices publishes keys immediately, then every publishInterval seconds until it receives
// something on exitChan.
func publishService(exitChan chan bool, client *etcd.Client, host string, etcdPath string, port string, ttl uint64) {
publishKeys(client, host, etcdPath, port, ttl)
t := time.NewTicker(time.Duration(publishInterval) * time.Second)
for {
select {
case <-t.C:
publishKeys(client, host, etcdPath, port, ttl)
case <-exitChan:
return
}
}
}
func setEtcd(client *etcd.Client, key, value string, ttl uint64) {
_, err := client.Set(key, value, ttl)
if err != nil && !strings.Contains(err.Error(), "Key already exists") {
log.Println(err)
}
}
func getopt(name, dfault string) string {
value := os.Getenv(name)
if value == "" {
value = dfault
}
return value
}