binwiederhier před 2 roky
rodič
revize
ca9fed7b67
5 změnil soubory, kde provedl 60 přidání a 19 odebrání
  1. 2 2
      docs/config.md
  2. 2 0
      server/server.go
  3. 11 0
      server/server_manager.go
  4. 27 17
      server/server_metrics.go
  5. 18 0
      user/manager.go

+ 2 - 2
docs/config.md

@@ -1099,7 +1099,7 @@ If a non-200 HTTP status code is returned or if the returned `health` field is `
 
 See [Installation for Docker](install.md#docker) for an example of how this could be used in a `docker-compose` environment.
 
-## Metrics
+## Monitoring
 If configured, ntfy can expose a `/metrics` endpoint for [Prometheus](https://prometheus.io/), which can then be used to
 create dashboards and alerts (e.g. via [Grafana](https://grafana.com/)).
 
@@ -1108,7 +1108,7 @@ listen address. Metrics may be considered sensitive information, so before you e
 doing, and/or secure access to the endpoint in your reverse proxy.
 
 - `enable-metrics` enables the /metrics endpoint for the default ntfy server (i.e. HTTP, HTTPS and/or Unix socket)
-- `metrics-listen-http` exposes the metrics endpoint via a dedicated [IP]:port. If set, this option implicitly
+- `metrics-listen-http` exposes the metrics endpoint via a dedicated `[IP]:port`. If set, this option implicitly
   enables metrics as well, e.g. "10.0.1.1:9090" or ":9090"
 
 === Using default port

+ 2 - 0
server/server.go

@@ -618,6 +618,7 @@ func (s *Server) handleMatrixDiscovery(w http.ResponseWriter) error {
 }
 
 func (s *Server) handlePublishInternal(r *http.Request, v *visitor) (*message, error) {
+	start := time.Now()
 	t, err := fromContext[*topic](r, contextTopic)
 	if err != nil {
 		return nil, err
@@ -707,6 +708,7 @@ func (s *Server) handlePublishInternal(r *http.Request, v *visitor) (*message, e
 	if unifiedpush {
 		minc(metricUnifiedPushPublishedSuccess)
 	}
+	mset(metricMessagePublishDurationMillis, time.Since(start).Milliseconds())
 	return m, nil
 }
 

+ 11 - 0
server/server_manager.go

@@ -63,6 +63,15 @@ func (s *Server) execManager() {
 		sentMailTotal, sentMailSuccess, sentMailFailure = s.smtpSender.Counts()
 	}
 
+	// Users
+	var usersCount int64
+	if s.userManager != nil {
+		usersCount, err = s.userManager.UsersCount()
+		if err != nil {
+			log.Tag(tagManager).Err(err).Warn("Error counting users")
+		}
+	}
+
 	// Print stats
 	s.mu.Lock()
 	messagesCount, topicsCount, visitorsCount := s.messages, len(s.topics), len(s.visitors)
@@ -75,6 +84,7 @@ func (s *Server) execManager() {
 			"topics_active":           topicsCount,
 			"subscribers":             subscribers,
 			"visitors":                visitorsCount,
+			"users":                   usersCount,
 			"emails_received":         receivedMailTotal,
 			"emails_received_success": receivedMailSuccess,
 			"emails_received_failure": receivedMailFailure,
@@ -85,6 +95,7 @@ func (s *Server) execManager() {
 		Info("Server stats")
 	mset(metricMessagesCached, messagesCached)
 	mset(metricVisitors, visitorsCount)
+	mset(metricUsers, usersCount)
 	mset(metricSubscribers, subscribers)
 	mset(metricTopics, topicsCount)
 }

+ 27 - 17
server/server_metrics.go

@@ -5,23 +5,25 @@ import (
 )
 
 var (
-	metricMessagesPublishedSuccess    prometheus.Counter
-	metricMessagesPublishedFailure    prometheus.Counter
-	metricMessagesCached              prometheus.Gauge
-	metricFirebasePublishedSuccess    prometheus.Counter
-	metricFirebasePublishedFailure    prometheus.Counter
-	metricEmailsPublishedSuccess      prometheus.Counter
-	metricEmailsPublishedFailure      prometheus.Counter
-	metricEmailsReceivedSuccess       prometheus.Counter
-	metricEmailsReceivedFailure       prometheus.Counter
-	metricUnifiedPushPublishedSuccess prometheus.Counter
-	metricMatrixPublishedSuccess      prometheus.Counter
-	metricMatrixPublishedFailure      prometheus.Counter
-	metricAttachmentsTotalSize        prometheus.Gauge
-	metricVisitors                    prometheus.Gauge
-	metricSubscribers                 prometheus.Gauge
-	metricTopics                      prometheus.Gauge
-	metricHTTPRequests                *prometheus.CounterVec
+	metricMessagesPublishedSuccess     prometheus.Counter
+	metricMessagesPublishedFailure     prometheus.Counter
+	metricMessagesCached               prometheus.Gauge
+	metricMessagePublishDurationMillis prometheus.Gauge
+	metricFirebasePublishedSuccess     prometheus.Counter
+	metricFirebasePublishedFailure     prometheus.Counter
+	metricEmailsPublishedSuccess       prometheus.Counter
+	metricEmailsPublishedFailure       prometheus.Counter
+	metricEmailsReceivedSuccess        prometheus.Counter
+	metricEmailsReceivedFailure        prometheus.Counter
+	metricUnifiedPushPublishedSuccess  prometheus.Counter
+	metricMatrixPublishedSuccess       prometheus.Counter
+	metricMatrixPublishedFailure       prometheus.Counter
+	metricAttachmentsTotalSize         prometheus.Gauge
+	metricVisitors                     prometheus.Gauge
+	metricSubscribers                  prometheus.Gauge
+	metricTopics                       prometheus.Gauge
+	metricUsers                        prometheus.Gauge
+	metricHTTPRequests                 *prometheus.CounterVec
 )
 
 func initMetrics() {
@@ -34,6 +36,9 @@ func initMetrics() {
 	metricMessagesCached = prometheus.NewGauge(prometheus.GaugeOpts{
 		Name: "ntfy_messages_cached_total",
 	})
+	metricMessagePublishDurationMillis = prometheus.NewGauge(prometheus.GaugeOpts{
+		Name: "ntfy_message_publish_duration_ms",
+	})
 	metricFirebasePublishedSuccess = prometheus.NewCounter(prometheus.CounterOpts{
 		Name: "ntfy_firebase_published_success",
 	})
@@ -67,6 +72,9 @@ func initMetrics() {
 	metricVisitors = prometheus.NewGauge(prometheus.GaugeOpts{
 		Name: "ntfy_visitors_total",
 	})
+	metricUsers = prometheus.NewGauge(prometheus.GaugeOpts{
+		Name: "ntfy_users_total",
+	})
 	metricSubscribers = prometheus.NewGauge(prometheus.GaugeOpts{
 		Name: "ntfy_subscribers_total",
 	})
@@ -80,6 +88,7 @@ func initMetrics() {
 		metricMessagesPublishedSuccess,
 		metricMessagesPublishedFailure,
 		metricMessagesCached,
+		metricMessagePublishDurationMillis,
 		metricFirebasePublishedSuccess,
 		metricFirebasePublishedFailure,
 		metricEmailsPublishedSuccess,
@@ -91,6 +100,7 @@ func initMetrics() {
 		metricMatrixPublishedFailure,
 		metricAttachmentsTotalSize,
 		metricVisitors,
+		metricUsers,
 		metricSubscribers,
 		metricTopics,
 		metricHTTPRequests,

+ 18 - 0
user/manager.go

@@ -169,6 +169,7 @@ const (
 				ELSE 2
 			END, user
 	`
+	selectUserCountQuery         = `SELECT COUNT(*) FROM user`
 	updateUserPassQuery          = `UPDATE user SET pass = ? WHERE user = ?`
 	updateUserRoleQuery          = `UPDATE user SET role = ? WHERE user = ?`
 	updateUserPrefsQuery         = `UPDATE user SET prefs = ? WHERE id = ?`
@@ -853,6 +854,23 @@ func (a *Manager) Users() ([]*User, error) {
 	return users, nil
 }
 
+// UsersCount returns the number of users in the databsae
+func (a *Manager) UsersCount() (int64, error) {
+	rows, err := a.db.Query(selectUserCountQuery)
+	if err != nil {
+		return 0, err
+	}
+	defer rows.Close()
+	if !rows.Next() {
+		return 0, errNoRows
+	}
+	var count int64
+	if err := rows.Scan(&count); err != nil {
+		return 0, err
+	}
+	return count, nil
+}
+
 // User returns the user with the given username if it exists, or ErrUserNotFound otherwise.
 // You may also pass Everyone to retrieve the anonymous user and its Grant list.
 func (a *Manager) User(username string) (*User, error) {