circolog/cmd/circologd/main.go

182 lines
5.9 KiB
Go
Raw Normal View History

2018-08-22 18:47:00 +02:00
package main
import (
"flag"
"fmt"
2018-11-10 17:41:45 +01:00
"log"
2018-08-23 02:08:53 +02:00
"net"
2018-08-22 18:47:00 +02:00
"net/http"
2018-08-22 23:51:59 +02:00
"os"
"os/signal"
2018-11-10 17:41:45 +01:00
"syscall"
"time"
2018-08-22 18:47:00 +02:00
2018-08-23 01:21:53 +02:00
"git.lattuga.net/boyska/circolog"
2019-05-01 15:55:41 +02:00
"git.lattuga.net/boyska/circolog/formatter"
"github.com/coreos/go-systemd/daemon"
2018-08-22 18:47:00 +02:00
syslog "gopkg.in/mcuadros/go-syslog.v2"
)
2019-05-03 10:32:18 +02:00
var socketsToRemove []string
func cleanSocket(socket string) {
if err := os.Remove(socket); err != nil {
fmt.Fprintln(os.Stderr, "Error cleaning", socket, ":", err)
}
}
2019-05-03 10:32:18 +02:00
func removeAtExit(socket string) {
socketsToRemove = append(socketsToRemove, socket)
}
2018-08-22 18:47:00 +02:00
func main() {
2018-08-22 23:51:59 +02:00
var err error
2019-05-03 10:45:35 +02:00
var syslogSocket SyslogSocket
2019-05-01 15:55:41 +02:00
var logFmt formatter.SyslogRFC
logFmt.Format = syslog.Automatic
2019-05-03 10:45:35 +02:00
flag.Var(&syslogSocket, "syslogd-socket", "The socket to listen to syslog addresses")
2018-08-22 18:47:00 +02:00
// dumpSocketPath := flag.String("dump-socket", "/run/buffer.sock", "The socket that user will connect to in order to receive logs")
bufsize := flag.Int("buffer-size", 1000, "Number of messages to keep")
syslogAddr := flag.String("syslog-addr", "127.0.0.1:9514", "Address:port where to listen for syslog messages")
queryAddr := flag.String("query-addr", "127.0.0.1:9080", "Address:port where to bind the query service")
2018-08-23 02:08:53 +02:00
querySocket := flag.String("query-socket", "", "Path to a unix domain socket for the HTTP server; recommended for security reasons!")
ctlSocket := flag.String("ctl-socket", "/tmp/circologd-ctl.sock", "Path to a unix domain socket for the control server; leave empty to disable")
2019-05-01 15:55:41 +02:00
flag.Var(&logFmt, "log-fmt", "Log messages format. If not set, defaults to automatic choice. Allowed values: rfc3164, rfc5424, auto.")
2018-12-20 09:45:05 +01:00
verbose := flag.Bool("verbose", false, "Print more output executing the daemon")
2018-12-24 18:41:06 +01:00
debug := flag.Bool("debug", false, "Print debugging info executing the daemon")
2018-08-22 18:47:00 +02:00
flag.Parse()
interrupt := make(chan os.Signal, 1)
signal.Notify(interrupt, syscall.SIGINT, syscall.SIGUSR1, syscall.SIGUSR2, syscall.SIGTERM)
2018-08-23 01:21:53 +02:00
hub := circolog.NewHub(*bufsize)
handler := syslog.NewChannelHandler(hub.LogMessages)
2018-11-10 17:50:51 +01:00
go hub.Run()
2018-08-22 18:47:00 +02:00
server := syslog.NewServer()
2019-05-01 15:55:41 +02:00
server.SetFormat(logFmt.Format)
fmt.Printf("Syslog format set to: %s\n", logFmt.String())
2018-08-22 18:47:00 +02:00
server.SetHandler(handler)
2019-05-03 10:45:35 +02:00
if syslogSocket.isSocketActivated {
fmt.Printf("Binding to socket `%s` [syslog]\n", syslogSocket.String())
2019-05-03 12:04:04 +02:00
if syslogSocket.Listener != nil {
fmt.Println("(stream)")
server.Listen(syslogSocket.Listener)
} else {
fmt.Println("(datagram)", syslogSocket.Conn)
server.ListenDgram(syslogSocket.Conn)
}
2018-08-22 20:56:43 +02:00
} else {
2019-05-03 10:45:35 +02:00
syslogSocketPath := syslogSocket.Path
if syslogSocketPath != "" {
if err = server.ListenUnixgram(syslogSocketPath); err != nil {
fmt.Fprintln(os.Stderr, "argh", err)
os.Exit(1)
}
fmt.Printf("Binding socket `%s` [syslog]\n", syslogSocketPath)
removeAtExit(syslogSocketPath)
} else {
fmt.Printf("Binding address `%s` [syslog]\n", *syslogAddr)
if err = server.ListenUDP(*syslogAddr); err != nil {
fmt.Fprintln(os.Stderr, "argh", err)
os.Exit(1)
}
2018-08-22 23:51:59 +02:00
}
2018-08-22 18:47:00 +02:00
}
2018-08-22 23:51:59 +02:00
if err = server.Boot(); err != nil {
fmt.Fprintln(os.Stderr, "argh", err)
os.Exit(1)
}
2018-08-22 18:47:00 +02:00
httpQueryServer := http.Server{Handler: setupHTTP(hub)}
2018-08-23 02:08:53 +02:00
if *querySocket != "" {
fmt.Printf("Binding address `%s` [http]\n", *querySocket)
unixListener, err := net.Listen("unix", *querySocket)
if err != nil {
fmt.Fprintln(os.Stderr, "Error binding HTTP unix domain socket", err)
2018-11-10 17:28:02 +01:00
return
2018-08-23 02:08:53 +02:00
}
2019-05-03 10:32:18 +02:00
removeAtExit(*querySocket)
2018-11-10 17:28:02 +01:00
go func() {
if err := httpQueryServer.Serve(unixListener); err != nil && err != http.ErrServerClosed {
fmt.Fprintln(os.Stderr, "error binding", *querySocket, ":", err)
2018-11-10 17:28:02 +01:00
}
}()
2018-08-23 02:08:53 +02:00
} else {
httpQueryServer.Addr = *queryAddr
2018-08-23 02:08:53 +02:00
fmt.Printf("Binding address `%s` [http]\n", *queryAddr)
2018-11-10 17:28:02 +01:00
go func() {
err := httpQueryServer.ListenAndServe()
if err != nil && err != http.ErrServerClosed {
fmt.Fprintln(os.Stderr, "error binding", *queryAddr, ":", err)
}
}()
}
2018-12-24 18:41:06 +01:00
httpCtlServer := http.Server{Handler: setupHTTPCtl(hub, *verbose, *debug)}
if *ctlSocket != "" {
fmt.Printf("Binding address `%s` [http]\n", *ctlSocket)
unixListener, err := net.Listen("unix", *ctlSocket)
if err != nil {
fmt.Fprintln(os.Stderr, "Error binding HTTP unix domain socket", err)
return
}
2019-05-03 10:32:18 +02:00
removeAtExit(*ctlSocket)
go func() {
if err := httpCtlServer.Serve(unixListener); err != nil && err != http.ErrServerClosed {
2018-11-10 17:28:02 +01:00
fmt.Fprintln(os.Stderr, "error binding:", err)
}
}()
}
daemon.SdNotify(false, daemon.SdNotifyReady)
var wdTick <-chan time.Time
if watchdogTime, err := daemon.SdWatchdogEnabled(false); err == nil && watchdogTime != 0 {
fmt.Println("systemd watchdog enabled")
wdTick = time.Tick(watchdogTime / 2) // much less than systemd default of 30s; TODO: make it configurable
}
for {
select {
case <-wdTick:
daemon.SdNotify(false, daemon.SdNotifyWatchdog)
2018-11-10 17:41:45 +01:00
case sig := <-interrupt:
2018-11-10 18:21:42 +01:00
if sig == syscall.SIGUSR1 {
2018-12-24 15:54:22 +01:00
response := make(chan circolog.CommandResponse)
hub.Commands <- circolog.HubFullCommand{Command: circolog.CommandPauseToggle, Response: response}
resp := <-response
2018-11-11 19:10:53 +01:00
if resp.Value.(bool) {
log.Println("resumed")
} else {
log.Println("paused")
}
2018-11-10 18:00:35 +01:00
}
if sig == syscall.SIGUSR2 {
2018-12-24 15:54:22 +01:00
response := make(chan circolog.CommandResponse)
hub.Commands <- circolog.HubFullCommand{Command: circolog.CommandClear, Response: response}
resp := <-response
if resp.Value.(bool) {
log.Println("buffer cleaned")
} else {
log.Println("buffer NOT cleaned")
}
}
2018-11-10 18:00:35 +01:00
if sig == syscall.SIGTERM || sig == syscall.SIGINT {
log.Println("Quitting because of signal", sig)
daemon.SdNotify(false, daemon.SdNotifyStopping)
2018-11-10 18:00:35 +01:00
server.Kill()
if err := httpQueryServer.Shutdown(nil); err != nil {
2018-11-10 18:00:35 +01:00
fmt.Fprintln(os.Stderr, "Error closing http server:", err)
}
if err := httpCtlServer.Shutdown(nil); err != nil {
fmt.Fprintln(os.Stderr, "Error closing control server:", err)
}
2019-05-03 10:32:18 +02:00
for _, socket := range socketsToRemove {
cleanSocket(socket)
}
2018-11-10 18:00:35 +01:00
return
2018-11-10 17:36:17 +01:00
}
}
2018-08-23 02:08:53 +02:00
}
2018-08-22 18:47:00 +02:00
}