diff --git a/cmd/circologctl/main.go b/cmd/circologctl/main.go new file mode 100644 index 0000000..ea87c38 --- /dev/null +++ b/cmd/circologctl/main.go @@ -0,0 +1,90 @@ +package main + +import ( + "flag" + "fmt" + "io" + "os" +) + +var globalOpts struct { + ctlSock string + verbose bool +} + +type commandFunc func([]string) error + +var cmdMap map[string]commandFunc + +func init() { + cmdMap = map[string]commandFunc{ + // TODO: implement set and get of config at runtime + //"set": setCmd, + //"get": getCmd, + "pause": pauseCmd, + "reload": reloadCmd, + "restart": restartCmd, + "help": helpCmd, + } +} + +//func setCmd(ctlSock string, args []string) error {} + +//func getCmd(ctlSock string, args []string) error {} + +func pauseCmd(args []string) error { + return nil +} + +func reloadCmd(args []string) error { + return nil +} + +func restartCmd(args []string) error { + return nil +} + +func helpCmd(args []string) error { + usage(os.Stdout) + os.Exit(0) + return nil +} + +func usage(w io.Writer) { + fmt.Fprintf(w, "USAGE: %s [globalOpts] [SUBCOMMAND] [opts]\n", os.Args[0]) + fmt.Fprintf(w, "\nSUBCOMMANDS:\n\n") + for command := range cmdMap { + fmt.Fprintf(w, "\t%s\n", command) + } +} + +func parseAndRun(args []string) { + cmdName := args[0] + cmdToRun, ok := cmdMap[cmdName] + if !ok { + fmt.Fprintf(os.Stderr, "Unknown subcommand: %s\n", cmdName) + usage(os.Stderr) + os.Exit(2) + } + err := cmdToRun(args) + if err != nil { + fmt.Fprintf(os.Stderr, "Error:\n%s\n", err) + os.Exit(1) + } +} + +func main() { + flag.StringVar(&globalOpts.ctlSock, "ctl-socket", "/tmp/circologd-ctl.sock", + "Path to a unix domain socket for the control server; leave empty to disable") + flag.BoolVar(&globalOpts.verbose, "verbose", false, "Print more output") + flag.Parse() + args := flag.Args() + if globalOpts.verbose { + fmt.Fprintf(os.Stdout, "Args: %v", args) + } + if len(args) == 0 { + usage(os.Stderr) + os.Exit(-1) + } + parseAndRun(args) +} diff --git a/cmd/circologd/http_ctl.go b/cmd/circologd/http_ctl.go index cde8538..f35a0bc 100644 --- a/cmd/circologd/http_ctl.go +++ b/cmd/circologd/http_ctl.go @@ -2,21 +2,30 @@ package main import ( "encoding/json" + "fmt" + "log" "net/http" + "os" + fractal "git.lattuga.net/blallo/gotools/formatting" "git.lattuga.net/boyska/circolog" "github.com/gorilla/mux" ) -func setupHTTPCtl(hub circolog.Hub) *mux.Router { - mux := mux.NewRouter() - mux.HandleFunc("/pause/toggle", togglePause(hub)).Methods("POST") - mux.HandleFunc("/logs/clear", clearQueue(hub)).Methods("POST") - return mux +func setupHTTPCtl(hub circolog.Hub, verbose bool) *mux.Router { + m := mux.NewRouter() + m.HandleFunc("/pause/toggle", togglePause(hub, verbose)).Methods("POST") + m.HandleFunc("/logs/clear", clearQueue(hub, verbose)).Methods("POST") + m.HandleFunc("/help", printHelp(verbose)).Methods("GET") + m.HandleFunc("/echo", echo(verbose)).Methods("GET") + return m } -func togglePause(hub circolog.Hub) http.HandlerFunc { +func togglePause(hub circolog.Hub, verbose bool) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { + if verbose { + log.Printf("[%s] %s - toggled pause", r.Method, r.RemoteAddr) + } hub.Commands <- circolog.HubFullCommand{Command: circolog.CommandPauseToggle} resp := <-hub.Responses active := resp.Value.(bool) @@ -26,8 +35,11 @@ func togglePause(hub circolog.Hub) http.HandlerFunc { } } -func clearQueue(hub circolog.Hub) http.HandlerFunc { +func clearQueue(hub circolog.Hub, verbose bool) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { + if verbose { + log.Printf("[%s] %s - cleared queue", r.Method, r.RemoteAddr) + } hub.Commands <- circolog.HubFullCommand{Command: circolog.CommandClear} resp := <-hub.Responses success := resp.Value.(bool) @@ -36,3 +48,35 @@ func clearQueue(hub circolog.Hub) http.HandlerFunc { enc.Encode(map[string]interface{}{"success": success}) } } + +func printHelp(verbose bool) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + if verbose { + log.Printf("[%s] %s - asked for help", r.Method, r.RemoteAddr) + } + w.Header().Set("content-type", "application/json") + enc := json.NewEncoder(w) + var pathsWithDocs = map[string]string{ + "/pause/toggle": "Toggle the server from pause state (not listening)", + "/logs/clear": "Wipe the buffer from all the messages", + "/help": "This help", + "/echo": "Answers to heartbeat", + } + fractal.EncodeJSON(pathsWithDocs, enc) + if verbose { + errEnc := json.NewEncoder(os.Stderr) + fractal.EncodeJSON(pathsWithDocs, errEnc) + } + } +} + +func echo(verbose bool) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + log.Println("Echo") + if verbose { + log.Printf("[%s] %s - asked for echo", r.Method, r.RemoteAddr) + } + w.Header().Set("content-type", "text/plain") + fmt.Fprintln(w, "I am on!") + } +} diff --git a/cmd/circologd/main.go b/cmd/circologd/main.go index b40641c..6f269c7 100644 --- a/cmd/circologd/main.go +++ b/cmd/circologd/main.go @@ -29,10 +29,11 @@ func main() { queryAddr := flag.String("query-addr", "127.0.0.1:9080", "Address:port where to bind the query service") 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") + verbose := flag.Bool("verbose", false, "Print more output executing the daemon") flag.Parse() interrupt := make(chan os.Signal, 1) - signal.Notify(interrupt, syscall.SIGINT, syscall.SIGUSR1, syscall.SIGTERM) + signal.Notify(interrupt, syscall.SIGINT, syscall.SIGUSR1, syscall.SIGUSR2, syscall.SIGTERM) hub := circolog.NewHub(*bufsize) handler := syslog.NewChannelHandler(hub.LogMessages) @@ -85,7 +86,7 @@ func main() { }() } - httpCtlServer := http.Server{Handler: setupHTTPCtl(hub)} + httpCtlServer := http.Server{Handler: setupHTTPCtl(hub, *verbose)} if *ctlSocket != "" { fmt.Printf("Binding address `%s` [http]\n", *ctlSocket) unixListener, err := net.Listen("unix", *ctlSocket) @@ -115,6 +116,15 @@ func main() { log.Println("paused") } } + if sig == syscall.SIGUSR2 { + hub.Commands <- circolog.HubFullCommand{Command: circolog.CommandClear} + resp := <-hub.Responses + if resp.Value.(bool) { + log.Println("buffer cleaned") + } else { + log.Println("buffer NOT cleaned") + } + } if sig == syscall.SIGTERM || sig == syscall.SIGINT { log.Println("Quitting because of signal", sig) server.Kill() diff --git a/hub.go b/hub.go index 639612f..be530e4 100644 --- a/hub.go +++ b/hub.go @@ -135,7 +135,7 @@ func (h *Hub) Run() { } } -// Clear removes every all elements from the buffer +// Clear removes all elements from the buffer func (h *Hub) clear() { buf := h.circbuf for i := 0; i < buf.Len(); i++ {