More metrics

This commit is contained in:
binwiederhier 2023-03-16 22:19:20 -04:00
parent 358b344916
commit ca9fed7b67
5 changed files with 60 additions and 19 deletions

View file

@ -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. 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 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/)). 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. 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) - `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" enables metrics as well, e.g. "10.0.1.1:9090" or ":9090"
=== Using default port === Using default port

View file

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

View file

@ -63,6 +63,15 @@ func (s *Server) execManager() {
sentMailTotal, sentMailSuccess, sentMailFailure = s.smtpSender.Counts() 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 // Print stats
s.mu.Lock() s.mu.Lock()
messagesCount, topicsCount, visitorsCount := s.messages, len(s.topics), len(s.visitors) messagesCount, topicsCount, visitorsCount := s.messages, len(s.topics), len(s.visitors)
@ -75,6 +84,7 @@ func (s *Server) execManager() {
"topics_active": topicsCount, "topics_active": topicsCount,
"subscribers": subscribers, "subscribers": subscribers,
"visitors": visitorsCount, "visitors": visitorsCount,
"users": usersCount,
"emails_received": receivedMailTotal, "emails_received": receivedMailTotal,
"emails_received_success": receivedMailSuccess, "emails_received_success": receivedMailSuccess,
"emails_received_failure": receivedMailFailure, "emails_received_failure": receivedMailFailure,
@ -85,6 +95,7 @@ func (s *Server) execManager() {
Info("Server stats") Info("Server stats")
mset(metricMessagesCached, messagesCached) mset(metricMessagesCached, messagesCached)
mset(metricVisitors, visitorsCount) mset(metricVisitors, visitorsCount)
mset(metricUsers, usersCount)
mset(metricSubscribers, subscribers) mset(metricSubscribers, subscribers)
mset(metricTopics, topicsCount) mset(metricTopics, topicsCount)
} }

View file

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

View file

@ -169,6 +169,7 @@ const (
ELSE 2 ELSE 2
END, user END, user
` `
selectUserCountQuery = `SELECT COUNT(*) FROM user`
updateUserPassQuery = `UPDATE user SET pass = ? WHERE user = ?` updateUserPassQuery = `UPDATE user SET pass = ? WHERE user = ?`
updateUserRoleQuery = `UPDATE user SET role = ? WHERE user = ?` updateUserRoleQuery = `UPDATE user SET role = ? WHERE user = ?`
updateUserPrefsQuery = `UPDATE user SET prefs = ? WHERE id = ?` updateUserPrefsQuery = `UPDATE user SET prefs = ? WHERE id = ?`
@ -853,6 +854,23 @@ func (a *Manager) Users() ([]*User, error) {
return users, nil 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. // 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. // You may also pass Everyone to retrieve the anonymous user and its Grant list.
func (a *Manager) User(username string) (*User, error) { func (a *Manager) User(username string) (*User, error) {