diff --git a/cmd/access.go b/cmd/access.go index e70a68b7..b36dc38b 100644 --- a/cmd/access.go +++ b/cmd/access.go @@ -19,7 +19,7 @@ const ( ) var flagsAccess = append( - userCommandFlags(), + flagsUser, &cli.BoolFlag{Name: "reset", Aliases: []string{"r"}, Usage: "reset access for user (and topic)"}, ) @@ -28,7 +28,7 @@ var cmdAccess = &cli.Command{ Usage: "Grant/revoke access to a topic, or show access", UsageText: "ntfy access [USERNAME [TOPIC [PERMISSION]]]", Flags: flagsAccess, - Before: initConfigFileInputSourceFunc("config", flagsAccess), + Before: initLogFunc(initConfigFileInputSourceFunc("config", flagsAccess)), Action: execUserAccess, Category: categoryServer, Description: `Manage the access control list for the ntfy server. diff --git a/cmd/app.go b/cmd/app.go index 5a0b426f..89634a8b 100644 --- a/cmd/app.go +++ b/cmd/app.go @@ -3,6 +3,7 @@ package cmd import ( "github.com/urfave/cli/v2" + "heckel.io/ntfy/log" "os" ) @@ -13,6 +14,11 @@ const ( var commands = make([]*cli.Command, 0) +var flagsDefault = []cli.Flag{ + &cli.BoolFlag{Name: "debug", Aliases: []string{"d"}, EnvVars: []string{"NTFY_DEBUG"}, Usage: "enable debug logging"}, + &cli.StringFlag{Name: "log-level", Aliases: []string{"log_level"}, Value: log.InfoLevel.String(), EnvVars: []string{"NTFY_LOG_LEVEL"}, Usage: "set log level"}, +} + // New creates a new CLI application func New() *cli.App { return &cli.App{ @@ -25,5 +31,23 @@ func New() *cli.App { Writer: os.Stdout, ErrWriter: os.Stderr, Commands: commands, + Flags: flagsDefault, + Before: initLogFunc(nil), + } +} + +func initLogFunc(next cli.BeforeFunc) cli.BeforeFunc { + return func(c *cli.Context) error { + if c.Bool("debug") { + log.SetLevel(log.DebugLevel) + } else { + log.SetLevel(log.ToLevel(c.String("log-level"))) + } + if next != nil { + if err := next(c); err != nil { + return err + } + } + return nil } } diff --git a/cmd/publish.go b/cmd/publish.go index 06f8d962..51d30b6a 100644 --- a/cmd/publish.go +++ b/cmd/publish.go @@ -16,31 +16,35 @@ func init() { commands = append(commands, cmdPublish) } +var flagsPublish = append( + flagsDefault, + &cli.StringFlag{Name: "config", Aliases: []string{"c"}, EnvVars: []string{"NTFY_CONFIG"}, Usage: "client config file"}, + &cli.StringFlag{Name: "title", Aliases: []string{"t"}, EnvVars: []string{"NTFY_TITLE"}, Usage: "message title"}, + &cli.StringFlag{Name: "priority", Aliases: []string{"p"}, EnvVars: []string{"NTFY_PRIORITY"}, Usage: "priority of the message (1=min, 2=low, 3=default, 4=high, 5=max)"}, + &cli.StringFlag{Name: "tags", Aliases: []string{"tag", "T"}, EnvVars: []string{"NTFY_TAGS"}, Usage: "comma separated list of tags and emojis"}, + &cli.StringFlag{Name: "delay", Aliases: []string{"at", "in", "D"}, EnvVars: []string{"NTFY_DELAY"}, Usage: "delay/schedule message"}, + &cli.StringFlag{Name: "click", Aliases: []string{"U"}, EnvVars: []string{"NTFY_CLICK"}, Usage: "URL to open when notification is clicked"}, + &cli.StringFlag{Name: "actions", Aliases: []string{"A"}, EnvVars: []string{"NTFY_ACTIONS"}, Usage: "actions JSON array or simple definition"}, + &cli.StringFlag{Name: "attach", Aliases: []string{"a"}, EnvVars: []string{"NTFY_ATTACH"}, Usage: "URL to send as an external attachment"}, + &cli.StringFlag{Name: "filename", Aliases: []string{"name", "n"}, EnvVars: []string{"NTFY_FILENAME"}, Usage: "filename for the attachment"}, + &cli.StringFlag{Name: "file", Aliases: []string{"f"}, EnvVars: []string{"NTFY_FILE"}, Usage: "file to upload as an attachment"}, + &cli.StringFlag{Name: "email", Aliases: []string{"mail", "e"}, EnvVars: []string{"NTFY_EMAIL"}, Usage: "also send to e-mail address"}, + &cli.StringFlag{Name: "user", Aliases: []string{"u"}, EnvVars: []string{"NTFY_USER"}, Usage: "username[:password] used to auth against the server"}, + &cli.BoolFlag{Name: "no-cache", Aliases: []string{"C"}, EnvVars: []string{"NTFY_NO_CACHE"}, Usage: "do not cache message server-side"}, + &cli.BoolFlag{Name: "no-firebase", Aliases: []string{"F"}, EnvVars: []string{"NTFY_NO_FIREBASE"}, Usage: "do not forward message to Firebase"}, + &cli.BoolFlag{Name: "env-topic", Aliases: []string{"P"}, EnvVars: []string{"NTFY_ENV_TOPIC"}, Usage: "use topic from NTFY_TOPIC env variable"}, + &cli.BoolFlag{Name: "quiet", Aliases: []string{"q"}, EnvVars: []string{"NTFY_QUIET"}, Usage: "do not print message"}, +) + var cmdPublish = &cli.Command{ Name: "publish", Aliases: []string{"pub", "send", "trigger"}, Usage: "Send message via a ntfy server", - UsageText: "ntfy send [OPTIONS..] TOPIC [MESSAGE]\n NTFY_TOPIC=.. ntfy send [OPTIONS..] -P [MESSAGE]", + UsageText: "ntfy publish [OPTIONS..] TOPIC [MESSAGE]\nNTFY_TOPIC=.. ntfy publish [OPTIONS..] -P [MESSAGE]", Action: execPublish, Category: categoryClient, - Flags: []cli.Flag{ - &cli.StringFlag{Name: "config", Aliases: []string{"c"}, EnvVars: []string{"NTFY_CONFIG"}, Usage: "client config file"}, - &cli.StringFlag{Name: "title", Aliases: []string{"t"}, EnvVars: []string{"NTFY_TITLE"}, Usage: "message title"}, - &cli.StringFlag{Name: "priority", Aliases: []string{"p"}, EnvVars: []string{"NTFY_PRIORITY"}, Usage: "priority of the message (1=min, 2=low, 3=default, 4=high, 5=max)"}, - &cli.StringFlag{Name: "tags", Aliases: []string{"tag", "T"}, EnvVars: []string{"NTFY_TAGS"}, Usage: "comma separated list of tags and emojis"}, - &cli.StringFlag{Name: "delay", Aliases: []string{"at", "in", "D"}, EnvVars: []string{"NTFY_DELAY"}, Usage: "delay/schedule message"}, - &cli.StringFlag{Name: "click", Aliases: []string{"U"}, EnvVars: []string{"NTFY_CLICK"}, Usage: "URL to open when notification is clicked"}, - &cli.StringFlag{Name: "actions", Aliases: []string{"A"}, EnvVars: []string{"NTFY_ACTIONS"}, Usage: "actions JSON array or simple definition"}, - &cli.StringFlag{Name: "attach", Aliases: []string{"a"}, EnvVars: []string{"NTFY_ATTACH"}, Usage: "URL to send as an external attachment"}, - &cli.StringFlag{Name: "filename", Aliases: []string{"name", "n"}, EnvVars: []string{"NTFY_FILENAME"}, Usage: "filename for the attachment"}, - &cli.StringFlag{Name: "file", Aliases: []string{"f"}, EnvVars: []string{"NTFY_FILE"}, Usage: "file to upload as an attachment"}, - &cli.StringFlag{Name: "email", Aliases: []string{"mail", "e"}, EnvVars: []string{"NTFY_EMAIL"}, Usage: "also send to e-mail address"}, - &cli.StringFlag{Name: "user", Aliases: []string{"u"}, EnvVars: []string{"NTFY_USER"}, Usage: "username[:password] used to auth against the server"}, - &cli.BoolFlag{Name: "no-cache", Aliases: []string{"C"}, EnvVars: []string{"NTFY_NO_CACHE"}, Usage: "do not cache message server-side"}, - &cli.BoolFlag{Name: "no-firebase", Aliases: []string{"F"}, EnvVars: []string{"NTFY_NO_FIREBASE"}, Usage: "do not forward message to Firebase"}, - &cli.BoolFlag{Name: "env-topic", Aliases: []string{"P"}, EnvVars: []string{"NTFY_ENV_TOPIC"}, Usage: "use topic from NTFY_TOPIC env variable"}, - &cli.BoolFlag{Name: "quiet", Aliases: []string{"q"}, EnvVars: []string{"NTFY_QUIET"}, Usage: "do print message"}, - }, + Flags: flagsPublish, + Before: initLogFunc(nil), Description: `Publish a message to a ntfy server. Examples: diff --git a/cmd/serve.go b/cmd/serve.go index 630889d0..df1f5798 100644 --- a/cmd/serve.go +++ b/cmd/serve.go @@ -5,7 +5,7 @@ package cmd import ( "errors" "fmt" - "log" + "heckel.io/ntfy/log" "math" "net" "strings" @@ -21,7 +21,8 @@ func init() { commands = append(commands, cmdServe) } -var flagsServe = []cli.Flag{ +var flagsServe = append( + flagsDefault, &cli.StringFlag{Name: "config", Aliases: []string{"c"}, EnvVars: []string{"NTFY_CONFIG_FILE"}, Value: "/etc/ntfy/server.yml", DefaultText: "/etc/ntfy/server.yml", Usage: "config file"}, altsrc.NewStringFlag(&cli.StringFlag{Name: "base-url", Aliases: []string{"base_url", "B"}, EnvVars: []string{"NTFY_BASE_URL"}, Usage: "externally visible base URL for this host (e.g. https://ntfy.sh)"}), altsrc.NewStringFlag(&cli.StringFlag{Name: "listen-http", Aliases: []string{"listen_http", "l"}, EnvVars: []string{"NTFY_LISTEN_HTTP"}, Value: server.DefaultListenHTTP, Usage: "ip:port used to as HTTP listen address"}), @@ -59,7 +60,7 @@ var flagsServe = []cli.Flag{ altsrc.NewIntFlag(&cli.IntFlag{Name: "visitor-email-limit-burst", Aliases: []string{"visitor_email_limit_burst"}, EnvVars: []string{"NTFY_VISITOR_EMAIL_LIMIT_BURST"}, Value: server.DefaultVisitorEmailLimitBurst, Usage: "initial limit of e-mails per visitor"}), altsrc.NewDurationFlag(&cli.DurationFlag{Name: "visitor-email-limit-replenish", Aliases: []string{"visitor_email_limit_replenish"}, EnvVars: []string{"NTFY_VISITOR_EMAIL_LIMIT_REPLENISH"}, Value: server.DefaultVisitorEmailLimitReplenish, Usage: "interval at which burst limit is replenished (one per x)"}), altsrc.NewBoolFlag(&cli.BoolFlag{Name: "behind-proxy", Aliases: []string{"behind_proxy", "P"}, EnvVars: []string{"NTFY_BEHIND_PROXY"}, Value: false, Usage: "if set, use X-Forwarded-For header to determine visitor IP address (for rate limiting)"}), -} +) var cmdServe = &cli.Command{ Name: "serve", @@ -68,7 +69,7 @@ var cmdServe = &cli.Command{ Action: execServe, Category: categoryServer, Flags: flagsServe, - Before: initConfigFileInputSourceFunc("config", flagsServe), + Before: initLogFunc(initConfigFileInputSourceFunc("config", flagsServe)), Description: `Run the ntfy server and listen for incoming requests The command will load the configuration from /etc/ntfy/server.yml. Config options can @@ -192,7 +193,7 @@ func execServe(c *cli.Context) error { for _, host := range visitorRequestLimitExemptHosts { ips, err := net.LookupIP(host) if err != nil { - log.Printf("cannot resolve host %s: %s, ignoring visitor request exemption", host, err.Error()) + log.Warn("cannot resolve host %s: %s, ignoring visitor request exemption", host, err.Error()) continue } for _, ip := range ips { @@ -242,12 +243,12 @@ func execServe(c *cli.Context) error { conf.EnableWeb = enableWeb s, err := server.New(conf) if err != nil { - log.Fatalln(err) + log.Fatal(err) } if err := s.Run(); err != nil { - log.Fatalln(err) + log.Fatal(err) } - log.Printf("Exiting.") + log.Info("Exiting.") return nil } diff --git a/cmd/subscribe.go b/cmd/subscribe.go index 97f7e410..618cdb9b 100644 --- a/cmd/subscribe.go +++ b/cmd/subscribe.go @@ -24,6 +24,17 @@ const ( clientUserConfigFileWindowsRelative = "ntfy\\client.yml" ) +var flagsSubscribe = append( + flagsDefault, + &cli.StringFlag{Name: "config", Aliases: []string{"c"}, Usage: "client config file"}, + &cli.StringFlag{Name: "since", Aliases: []string{"s"}, Usage: "return events since `SINCE` (Unix timestamp, or all)"}, + &cli.StringFlag{Name: "user", Aliases: []string{"u"}, Usage: "username[:password] used to auth against the server"}, + &cli.BoolFlag{Name: "from-config", Aliases: []string{"C"}, Usage: "read subscriptions from config file (service mode)"}, + &cli.BoolFlag{Name: "poll", Aliases: []string{"p"}, Usage: "return events and exit, do not listen for new events"}, + &cli.BoolFlag{Name: "scheduled", Aliases: []string{"sched", "S"}, Usage: "also return scheduled/delayed events"}, + &cli.BoolFlag{Name: "verbose", Aliases: []string{"v"}, Usage: "print verbose output"}, +) + var cmdSubscribe = &cli.Command{ Name: "subscribe", Aliases: []string{"sub"}, @@ -31,15 +42,8 @@ var cmdSubscribe = &cli.Command{ UsageText: "ntfy subscribe [OPTIONS..] [TOPIC]", Action: execSubscribe, Category: categoryClient, - Flags: []cli.Flag{ - &cli.StringFlag{Name: "config", Aliases: []string{"c"}, Usage: "client config file"}, - &cli.StringFlag{Name: "since", Aliases: []string{"s"}, Usage: "return events since `SINCE` (Unix timestamp, or all)"}, - &cli.StringFlag{Name: "user", Aliases: []string{"u"}, Usage: "username[:password] used to auth against the server"}, - &cli.BoolFlag{Name: "from-config", Aliases: []string{"C"}, Usage: "read subscriptions from config file (service mode)"}, - &cli.BoolFlag{Name: "poll", Aliases: []string{"p"}, Usage: "return events and exit, do not listen for new events"}, - &cli.BoolFlag{Name: "scheduled", Aliases: []string{"sched", "S"}, Usage: "also return scheduled/delayed events"}, - &cli.BoolFlag{Name: "verbose", Aliases: []string{"v"}, Usage: "print verbose output"}, - }, + Flags: flagsSubscribe, + Before: initLogFunc(nil), Description: `Subscribe to a topic from a ntfy server, and either print or execute a command for every arriving message. There are 3 modes in which the command can be run: diff --git a/cmd/user.go b/cmd/user.go index 5ccc5b15..921aeda1 100644 --- a/cmd/user.go +++ b/cmd/user.go @@ -17,14 +17,19 @@ func init() { commands = append(commands, cmdUser) } -var flagsUser = userCommandFlags() +var flagsUser = append( + flagsDefault, + &cli.StringFlag{Name: "config", Aliases: []string{"c"}, EnvVars: []string{"NTFY_CONFIG_FILE"}, Value: "/etc/ntfy/server.yml", DefaultText: "/etc/ntfy/server.yml", Usage: "config file"}, + altsrc.NewStringFlag(&cli.StringFlag{Name: "auth-file", Aliases: []string{"H"}, EnvVars: []string{"NTFY_AUTH_FILE"}, Usage: "auth database file used for access control"}), + altsrc.NewStringFlag(&cli.StringFlag{Name: "auth-default-access", Aliases: []string{"p"}, EnvVars: []string{"NTFY_AUTH_DEFAULT_ACCESS"}, Value: "read-write", Usage: "default permissions if no matching entries in the auth database are found"}), +) var cmdUser = &cli.Command{ Name: "user", Usage: "Manage/show users", UsageText: "ntfy user [list|add|remove|change-pass|change-role] ...", Flags: flagsUser, - Before: initConfigFileInputSourceFunc("config", flagsUser), + Before: initLogFunc(initConfigFileInputSourceFunc("config", flagsUser)), Category: categoryServer, Subcommands: []*cli.Command{ { @@ -269,11 +274,3 @@ func readPasswordAndConfirm(c *cli.Context) (string, error) { } return string(password), nil } - -func userCommandFlags() []cli.Flag { - return []cli.Flag{ - &cli.StringFlag{Name: "config", Aliases: []string{"c"}, EnvVars: []string{"NTFY_CONFIG_FILE"}, Value: "/etc/ntfy/server.yml", DefaultText: "/etc/ntfy/server.yml", Usage: "config file"}, - altsrc.NewStringFlag(&cli.StringFlag{Name: "auth-file", Aliases: []string{"H"}, EnvVars: []string{"NTFY_AUTH_FILE"}, Usage: "auth database file used for access control"}), - altsrc.NewStringFlag(&cli.StringFlag{Name: "auth-default-access", Aliases: []string{"p"}, EnvVars: []string{"NTFY_AUTH_DEFAULT_ACCESS"}, Value: "read-write", Usage: "default permissions if no matching entries in the auth database are found"}), - } -} diff --git a/log/log.go b/log/log.go new file mode 100644 index 00000000..8c134508 --- /dev/null +++ b/log/log.go @@ -0,0 +1,79 @@ +package log + +import ( + "log" + "strings" +) + +type Level int + +const ( + DebugLevel Level = iota + InfoLevel + WarnLevel + ErrorLevel +) + +func (l Level) String() string { + switch l { + case DebugLevel: + return "DEBUG" + case InfoLevel: + return "INFO" + case WarnLevel: + return "WARN" + case ErrorLevel: + return "ERROR" + } + return "unknown" +} + +var ( + level = InfoLevel +) + +func Debug(message string, v ...interface{}) { + logIf(DebugLevel, message, v...) +} + +func Info(message string, v ...interface{}) { + logIf(InfoLevel, message, v...) +} + +func Warn(message string, v ...interface{}) { + logIf(WarnLevel, message, v...) +} + +func Error(message string, v ...interface{}) { + logIf(ErrorLevel, message, v...) +} + +func Fatal(v ...interface{}) { + log.Fatalln(v...) +} + +func SetLevel(newLevel Level) { + level = newLevel +} + +func ToLevel(s string) Level { + switch strings.ToLower(s) { + case "debug": + return DebugLevel + case "info": + return InfoLevel + case "warn", "warning": + return WarnLevel + case "error": + return ErrorLevel + default: + log.Fatalf("unknown log level: %s", s) + return 0 + } +} + +func logIf(l Level, message string, v ...interface{}) { + if level <= l { + log.Printf(l.String()+" "+message, v...) + } +} diff --git a/server/server.go b/server/server.go index 86ed7539..fe5a661c 100644 --- a/server/server.go +++ b/server/server.go @@ -9,8 +9,8 @@ import ( "encoding/json" "errors" "fmt" + "heckel.io/ntfy/log" "io" - "log" "net" "net/http" "net/http/httptest" @@ -181,7 +181,7 @@ func (s *Server) Run() error { if s.config.SMTPServerListen != "" { listenStr += fmt.Sprintf(" %s[smtp]", s.config.SMTPServerListen) } - log.Printf("Listening on%s", listenStr) + log.Info("Listening on%s", listenStr) mux := http.NewServeMux() mux.HandleFunc("/", s.handle) errChan := make(chan error) @@ -221,7 +221,7 @@ func (s *Server) Run() error { } s.mu.Unlock() go s.runManager() - go s.runAtSender() + go s.runDelaySender() go s.runFirebaseKeepaliver() return <-errChan @@ -248,16 +248,18 @@ func (s *Server) Stop() { func (s *Server) handle(w http.ResponseWriter, r *http.Request) { v := s.visitor(r) + log.Debug("[%s] %s %s", v.ip, r.Method, r.URL.Path) + if err := s.handleInternal(w, r, v); err != nil { if websocket.IsWebSocketUpgrade(r) { - log.Printf("[%s] WS %s %s - %s", v.ip, r.Method, r.URL.Path, err.Error()) + log.Info("[%s] WS %s %s - %s", v.ip, r.Method, r.URL.Path, err.Error()) return // Do not attempt to write to upgraded connection } httpErr, ok := err.(*errHTTP) if !ok { httpErr = errHTTPInternalError } - log.Printf("[%s] HTTP %s %s - %d - %d - %s", v.ip, r.Method, r.URL.Path, httpErr.HTTPCode, httpErr.Code, err.Error()) + log.Info("[%s] HTTP %s %s - %d - %d - %s", v.ip, r.Method, r.URL.Path, httpErr.HTTPCode, httpErr.Code, err.Error()) w.Header().Set("Content-Type", "application/json") w.Header().Set("Access-Control-Allow-Origin", "*") // CORS, allow cross-origin requests w.WriteHeader(httpErr.HTTPCode) @@ -434,6 +436,8 @@ func (s *Server) handlePublish(w http.ResponseWriter, r *http.Request, v *visito m.Message = emptyMessageBody } delayed := m.Time > time.Now().Unix() + log.Debug("[%s] %s %s: ev=%s, body=%d bytes, delayed=%t, fb=%t, cache=%t, up=%t, email=%s", + v.ip, r.Method, r.URL.Path, m.Event, len(body.PeekedBytes), delayed, firebase, cache, unifiedpush, email) if !delayed { if err := t.Publish(m); err != nil { return err @@ -466,13 +470,13 @@ func (s *Server) handlePublish(w http.ResponseWriter, r *http.Request, v *visito func (s *Server) sendToFirebase(v *visitor, m *message) { if err := s.firebase(m); err != nil { - log.Printf("[%s] FB - Unable to publish to Firebase: %v", v.ip, err.Error()) + log.Warn("[%s] FB - Unable to publish to Firebase: %v", v.ip, err.Error()) } } func (s *Server) sendEmail(v *visitor, m *message, email string) { if err := s.mailer.Send(v.ip, email, m); err != nil { - log.Printf("[%s] MAIL - Unable to send email: %v", v.ip, err.Error()) + log.Warn("[%s] MAIL - Unable to send email: %v", v.ip, err.Error()) } } @@ -482,16 +486,16 @@ func (s *Server) forwardPollRequest(v *visitor, m *message) { forwardURL := fmt.Sprintf("%s/%s", s.config.UpstreamBaseURL, topicHash) req, err := http.NewRequest("POST", forwardURL, strings.NewReader("")) if err != nil { - log.Printf("[%s] FWD - Unable to forward poll request: %v", v.ip, err.Error()) + log.Warn("[%s] FWD - Unable to forward poll request: %v", v.ip, err.Error()) return } req.Header.Set("X-Poll-ID", m.ID) response, err := http.DefaultClient.Do(req) if err != nil { - log.Printf("[%s] FWD - Unable to forward poll request: %v", v.ip, err.Error()) + log.Warn("[%s] FWD - Unable to forward poll request: %v", v.ip, err.Error()) return } else if response.StatusCode != http.StatusOK { - log.Printf("[%s] FWD - Unable to forward poll request, unexpected status: %d", v.ip, response.StatusCode) + log.Warn("[%s] FWD - Unable to forward poll request, unexpected status: %d", v.ip, response.StatusCode) return } } @@ -1015,17 +1019,17 @@ func (s *Server) updateStatsAndPrune() { ids, err := s.messageCache.AttachmentsExpired() if err == nil { if err := s.fileCache.Remove(ids...); err != nil { - log.Printf("error while deleting attachments: %s", err.Error()) + log.Warn("Error deleting attachments: %s", err.Error()) } } else { - log.Printf("error retrieving expired attachments: %s", err.Error()) + log.Warn("Error retrieving expired attachments: %s", err.Error()) } } // Prune message cache olderThan := time.Now().Add(-1 * s.config.CacheDuration) if err := s.messageCache.Prune(olderThan); err != nil { - log.Printf("error pruning cache: %s", err.Error()) + log.Warn("Error pruning cache: %s", err.Error()) } // Prune old topics, remove subscriptions without subscribers @@ -1034,7 +1038,7 @@ func (s *Server) updateStatsAndPrune() { subs := t.Subscribers() msgs, err := s.messageCache.MessageCount(t.ID) if err != nil { - log.Printf("cannot get stats for topic %s: %s", t.ID, err.Error()) + log.Warn("Cannot get stats for topic %s: %s", t.ID, err.Error()) continue } if msgs == 0 && subs == 0 { @@ -1052,7 +1056,7 @@ func (s *Server) updateStatsAndPrune() { } // Print stats - log.Printf("Stats: %d message(s) published, %d in cache, %d successful mails, %d failed, %d topic(s) active, %d subscriber(s), %d visitor(s)", + log.Info("Stats: %d message(s) published, %d in cache, %d successful mails, %d failed, %d topic(s) active, %d subscriber(s), %d visitor(s)", s.messages, messages, mailSuccess, mailFailure, len(s.topics), subscribers, len(s.visitors)) } @@ -1096,12 +1100,12 @@ func (s *Server) runManager() { } } -func (s *Server) runAtSender() { +func (s *Server) runDelaySender() { for { select { case <-time.After(s.config.AtSenderInterval): if err := s.sendDelayedMessages(); err != nil { - log.Printf("error sending scheduled messages: %s", err.Error()) + log.Warn("error sending scheduled messages: %s", err.Error()) } case <-s.closeChan: return @@ -1117,11 +1121,11 @@ func (s *Server) runFirebaseKeepaliver() { select { case <-time.After(s.config.FirebaseKeepaliveInterval): if err := s.firebase(newKeepaliveMessage(firebaseControlTopic)); err != nil { - log.Printf("error sending Firebase keepalive message to %s: %s", firebaseControlTopic, err.Error()) + log.Info("error sending Firebase keepalive message to %s: %s", firebaseControlTopic, err.Error()) } case <-time.After(s.config.FirebasePollInterval): if err := s.firebase(newKeepaliveMessage(firebasePollTopic)); err != nil { - log.Printf("error sending Firebase keepalive message to %s: %s", firebasePollTopic, err.Error()) + log.Info("error sending Firebase keepalive message to %s: %s", firebasePollTopic, err.Error()) } case <-s.closeChan: return @@ -1140,12 +1144,12 @@ func (s *Server) sendDelayedMessages() error { t, ok := s.topics[m.Topic] // If no subscribers, just mark message as published if ok { if err := t.Publish(m); err != nil { - log.Printf("unable to publish message %s to topic %s: %v", m.ID, m.Topic, err.Error()) + log.Info("unable to publish message %s to topic %s: %v", m.ID, m.Topic, err.Error()) } } if s.firebase != nil { // Firebase subscribers may not show up in topics map if err := s.firebase(m); err != nil { - log.Printf("unable to publish to Firebase: %v", err.Error()) + log.Info("unable to publish to Firebase: %v", err.Error()) } } if err := s.messageCache.MarkPublished(m); err != nil { @@ -1252,13 +1256,13 @@ func (s *Server) withAuth(next handleFunc, perm auth.Permission) handleFunc { username, password, ok := extractUserPass(r) if ok { if user, err = s.auth.Authenticate(username, password); err != nil { - log.Printf("authentication failed: %s", err.Error()) + log.Info("authentication failed: %s", err.Error()) return errHTTPUnauthorized } } for _, t := range topics { if err := s.auth.Authorize(user, t.ID, perm); err != nil { - log.Printf("unauthorized: %s", err.Error()) + log.Info("unauthorized: %s", err.Error()) return errHTTPForbidden } }