[GH-ISSUE #210] Implement Prometheus /metrics endpoint to ntfy server #166

Closed
opened 2026-05-07 00:20:53 +02:00 by BreizhHardware · 21 comments

Originally created by @rogeliodh on GitHub (Apr 11, 2022).
Original GitHub issue: https://github.com/binwiederhier/ntfy/issues/210

I think it would be very useful to implement a /metrics endpoint to ntfy server so that we could monitor ntfy itself and get some statistics on the service

See https://prometheus.io/docs/guides/go-application/ for details, there is an official library for Go, so it should be relatively easy to integrate

one thing to notice is that "/metrics" is not reserved right now, so if there is a topic named "metrics" it would be a backwards incompatible change. If that is a problem, the endpoint could be moved to another path (ex: "system/metrics", "server/metrics", etc... )

Originally created by @rogeliodh on GitHub (Apr 11, 2022). Original GitHub issue: https://github.com/binwiederhier/ntfy/issues/210 I think it would be very useful to implement a /metrics endpoint to ntfy server so that we could monitor ntfy itself and get some statistics on the service See https://prometheus.io/docs/guides/go-application/ for details, there is an official library for Go, so it should be relatively easy to integrate one thing to notice is that "/metrics" is not reserved right now, so if there is a topic named "metrics" it would be a backwards incompatible change. If that is a problem, the endpoint could be moved to another path (ex: "system/metrics", "server/metrics", etc... )
BreizhHardware 2026-05-07 00:20:53 +02:00
Author
Owner

@binwiederhier commented on GitHub (Apr 12, 2022):

I looked at your link and even briefly implemented it as a test (github.com/binwiederhier/ntfy@3b1852541e). Unfortunately, I don't like it, because it brings in 7 new dependencies and outputs a very Prometheus specific format. I also can't really expose this on the public server because it gives away too much about the system and may be a security risk (maybe?).

If it was easy to implement without a library, maybe. But even then I thought it was gonna be some custom JSON that I output, not the weird Prometheus format.

If people really really really want this I can be convinced otherwise, but I'm trying to protect the (already large) dependency tree.

image

Sample format:

$ curl localhost/metrics
# HELP go_gc_cycles_automatic_gc_cycles_total Count of completed GC cycles generated by the Go runtime.
# TYPE go_gc_cycles_automatic_gc_cycles_total counter
go_gc_cycles_automatic_gc_cycles_total 1
# HELP go_gc_cycles_forced_gc_cycles_total Count of completed GC cycles forced by the application.
# TYPE go_gc_cycles_forced_gc_cycles_total counter
go_gc_cycles_forced_gc_cycles_total 0
# HELP go_gc_cycles_total_gc_cycles_total Count of all completed GC cycles.
# TYPE go_gc_cycles_total_gc_cycles_total counter
go_gc_cycles_total_gc_cycles_total 1
# HELP go_gc_duration_seconds A summary of the pause duration of garbage collection cycles.
# TYPE go_gc_duration_seconds summary
go_gc_duration_seconds{quantile="0"} 2.557e-05
go_gc_duration_seconds{quantile="0.25"} 2.557e-05
go_gc_duration_seconds{quantile="0.5"} 2.557e-05
go_gc_duration_seconds{quantile="0.75"} 2.557e-05
go_gc_duration_seconds{quantile="1"} 2.557e-05
go_gc_duration_seconds_sum 2.557e-05
go_gc_duration_seconds_count 1
# HELP go_gc_heap_allocs_by_size_bytes_total Distribution of heap allocations by approximate size. Note that this does not include tiny objects as defined by /gc/heap/tiny/allocs:objects, only tiny blocks.
# TYPE go_gc_heap_allocs_by_size_bytes_total histogram
go_gc_heap_allocs_by_size_bytes_total_bucket{le="8.999999999999998"} 3187
go_gc_heap_allocs_by_size_bytes_total_bucket{le="24.999999999999996"} 24468
go_gc_heap_allocs_by_size_bytes_total_bucket{le="64.99999999999999"} 33920
go_gc_heap_allocs_by_size_bytes_total_bucket{le="144.99999999999997"} 44153
go_gc_heap_allocs_by_size_bytes_total_bucket{le="320.99999999999994"} 45364
go_gc_heap_allocs_by_size_bytes_total_bucket{le="704.9999999999999"} 45919
go_gc_heap_allocs_by_size_bytes_total_bucket{le="1536.9999999999998"} 46183
go_gc_heap_allocs_by_size_bytes_total_bucket{le="3200.9999999999995"} 46375
go_gc_heap_allocs_by_size_bytes_total_bucket{le="6528.999999999999"} 46533
go_gc_heap_allocs_by_size_bytes_total_bucket{le="13568.999999999998"} 46610
go_gc_heap_allocs_by_size_bytes_total_bucket{le="27264.999999999996"} 46635
go_gc_heap_allocs_by_size_bytes_total_bucket{le="+Inf"} 46652
go_gc_heap_allocs_by_size_bytes_total_sum 6.127456e+06
go_gc_heap_allocs_by_size_bytes_total_count 46652
# HELP go_gc_heap_allocs_bytes_total Cumulative sum of memory allocated to the heap by the application.
# TYPE go_gc_heap_allocs_bytes_total counter
go_gc_heap_allocs_bytes_total 6.127456e+06
# HELP go_gc_heap_allocs_objects_total Cumulative count of heap allocations triggered by the application. Note that this does not include tiny objects as defined by /gc/heap/tiny/allocs:objects, only tiny blocks.
# TYPE go_gc_heap_allocs_objects_total counter
go_gc_heap_allocs_objects_total 46652
# HELP go_gc_heap_frees_by_size_bytes_total Distribution of freed heap allocations by approximate size. Note that this does not include tiny objects as defined by /gc/heap/tiny/allocs:objects, only tiny blocks.
# TYPE go_gc_heap_frees_by_size_bytes_total histogram
go_gc_heap_frees_by_size_bytes_total_bucket{le="8.999999999999998"} 115
go_gc_heap_frees_by_size_bytes_total_bucket{le="24.999999999999996"} 4332
go_gc_heap_frees_by_size_bytes_total_bucket{le="64.99999999999999"} 5493
go_gc_heap_frees_by_size_bytes_total_bucket{le="144.99999999999997"} 11558
go_gc_heap_frees_by_size_bytes_total_bucket{le="320.99999999999994"} 11855
go_gc_heap_frees_by_size_bytes_total_bucket{le="704.9999999999999"} 11997
go_gc_heap_frees_by_size_bytes_total_bucket{le="1536.9999999999998"} 12092
go_gc_heap_frees_by_size_bytes_total_bucket{le="3200.9999999999995"} 12155
go_gc_heap_frees_by_size_bytes_total_bucket{le="6528.999999999999"} 12208
go_gc_heap_frees_by_size_bytes_total_bucket{le="13568.999999999998"} 12217
go_gc_heap_frees_by_size_bytes_total_bucket{le="27264.999999999996"} 12221
go_gc_heap_frees_by_size_bytes_total_bucket{le="+Inf"} 12228
go_gc_heap_frees_by_size_bytes_total_sum 1.9384e+06
go_gc_heap_frees_by_size_bytes_total_count 12228
# HELP go_gc_heap_frees_bytes_total Cumulative sum of heap memory freed by the garbage collector.
# TYPE go_gc_heap_frees_bytes_total counter
go_gc_heap_frees_bytes_total 1.9384e+06
# HELP go_gc_heap_frees_objects_total Cumulative count of heap allocations whose storage was freed by the garbage collector. Note that this does not include tiny objects as defined by /gc/heap/tiny/allocs:objects, only tiny blocks.
# TYPE go_gc_heap_frees_objects_total counter
go_gc_heap_frees_objects_total 12228
# HELP go_gc_heap_goal_bytes Heap size target for the end of the GC cycle.
# TYPE go_gc_heap_goal_bytes gauge
go_gc_heap_goal_bytes 4.268352e+06
# HELP go_gc_heap_objects_objects Number of objects, live or unswept, occupying heap memory.
# TYPE go_gc_heap_objects_objects gauge
go_gc_heap_objects_objects 34424
# HELP go_gc_heap_tiny_allocs_objects_total Count of small allocations that are packed together into blocks. These allocations are counted separately from other allocations because each individual allocation is not tracked by the runtime, only their block. Each block is already accounted for in allocs-by-size and frees-by-size.
# TYPE go_gc_heap_tiny_allocs_objects_total counter
go_gc_heap_tiny_allocs_objects_total 3793
# HELP go_gc_pauses_seconds_total Distribution individual GC-related stop-the-world pause latencies.
# TYPE go_gc_pauses_seconds_total histogram
go_gc_pauses_seconds_total_bucket{le="-5e-324"} 0
go_gc_pauses_seconds_total_bucket{le="9.999999999999999e-10"} 0
go_gc_pauses_seconds_total_bucket{le="9.999999999999999e-09"} 0
go_gc_pauses_seconds_total_bucket{le="9.999999999999998e-08"} 0
go_gc_pauses_seconds_total_bucket{le="1.0239999999999999e-06"} 0
go_gc_pauses_seconds_total_bucket{le="1.0239999999999999e-05"} 1
go_gc_pauses_seconds_total_bucket{le="0.00010239999999999998"} 3
go_gc_pauses_seconds_total_bucket{le="0.0010485759999999998"} 3
go_gc_pauses_seconds_total_bucket{le="0.010485759999999998"} 3
go_gc_pauses_seconds_total_bucket{le="0.10485759999999998"} 3
go_gc_pauses_seconds_total_bucket{le="+Inf"} 3
go_gc_pauses_seconds_total_sum NaN
go_gc_pauses_seconds_total_count 3
# HELP go_goroutines Number of goroutines that currently exist.
# TYPE go_goroutines gauge
go_goroutines 14
# HELP go_info Information about the Go environment.
# TYPE go_info gauge
go_info{version="go1.18"} 1
# HELP go_memory_classes_heap_free_bytes Memory that is completely free and eligible to be returned to the underlying system, but has not been. This metric is the runtime's estimate of free address space that is backed by physical memory.
# TYPE go_memory_classes_heap_free_bytes gauge
go_memory_classes_heap_free_bytes 229376
# HELP go_memory_classes_heap_objects_bytes Memory occupied by live objects and dead objects that have not yet been marked free by the garbage collector.
# TYPE go_memory_classes_heap_objects_bytes gauge
go_memory_classes_heap_objects_bytes 4.189056e+06
# HELP go_memory_classes_heap_released_bytes Memory that is completely free and has been returned to the underlying system. This metric is the runtime's estimate of free address space that is still mapped into the process, but is not backed by physical memory.
# TYPE go_memory_classes_heap_released_bytes gauge
go_memory_classes_heap_released_bytes 2.400256e+06
# HELP go_memory_classes_heap_stacks_bytes Memory allocated from the heap that is reserved for stack space, whether or not it is currently in-use.
# TYPE go_memory_classes_heap_stacks_bytes gauge
go_memory_classes_heap_stacks_bytes 950272
# HELP go_memory_classes_heap_unused_bytes Memory that is reserved for heap objects but is not currently used to hold heap objects.
# TYPE go_memory_classes_heap_unused_bytes gauge
go_memory_classes_heap_unused_bytes 586880
# HELP go_memory_classes_metadata_mcache_free_bytes Memory that is reserved for runtime mcache structures, but not in-use.
# TYPE go_memory_classes_metadata_mcache_free_bytes gauge
go_memory_classes_metadata_mcache_free_bytes 6000
# HELP go_memory_classes_metadata_mcache_inuse_bytes Memory that is occupied by runtime mcache structures that are currently being used.
# TYPE go_memory_classes_metadata_mcache_inuse_bytes gauge
go_memory_classes_metadata_mcache_inuse_bytes 9600
# HELP go_memory_classes_metadata_mspan_free_bytes Memory that is reserved for runtime mspan structures, but not in-use.
# TYPE go_memory_classes_metadata_mspan_free_bytes gauge
go_memory_classes_metadata_mspan_free_bytes 7888
# HELP go_memory_classes_metadata_mspan_inuse_bytes Memory that is occupied by runtime mspan structures that are currently being used.
# TYPE go_memory_classes_metadata_mspan_inuse_bytes gauge
go_memory_classes_metadata_mspan_inuse_bytes 90032
# HELP go_memory_classes_metadata_other_bytes Memory that is reserved for or used to hold runtime metadata.
# TYPE go_memory_classes_metadata_other_bytes gauge
go_memory_classes_metadata_other_bytes 4.590896e+06
# HELP go_memory_classes_os_stacks_bytes Stack memory allocated by the underlying operating system.
# TYPE go_memory_classes_os_stacks_bytes gauge
go_memory_classes_os_stacks_bytes 0
# HELP go_memory_classes_other_bytes Memory used by execution trace buffers, structures for debugging the runtime, finalizer and profiler specials, and more.
# TYPE go_memory_classes_other_bytes gauge
go_memory_classes_other_bytes 978293
# HELP go_memory_classes_profiling_buckets_bytes Memory that is used by the stack trace hash map used for profiling.
# TYPE go_memory_classes_profiling_buckets_bytes gauge
go_memory_classes_profiling_buckets_bytes 5371
# HELP go_memory_classes_total_bytes All memory mapped by the Go runtime into the current process as read-write. Note that this does not include memory mapped by code called via cgo or via the syscall package. Sum of all metrics in /memory/classes.
# TYPE go_memory_classes_total_bytes gauge
go_memory_classes_total_bytes 1.404392e+07
# HELP go_memstats_alloc_bytes Number of bytes allocated and still in use.
# TYPE go_memstats_alloc_bytes gauge
go_memstats_alloc_bytes 4.189056e+06
# HELP go_memstats_alloc_bytes_total Total number of bytes allocated, even if freed.
# TYPE go_memstats_alloc_bytes_total counter
go_memstats_alloc_bytes_total 6.127456e+06
# HELP go_memstats_buck_hash_sys_bytes Number of bytes used by the profiling bucket hash table.
# TYPE go_memstats_buck_hash_sys_bytes gauge
go_memstats_buck_hash_sys_bytes 5371
# HELP go_memstats_frees_total Total number of frees.
# TYPE go_memstats_frees_total counter
go_memstats_frees_total 16021
# HELP go_memstats_gc_cpu_fraction The fraction of this program's available CPU time used by the GC since the program started.
# TYPE go_memstats_gc_cpu_fraction gauge
go_memstats_gc_cpu_fraction 0
# HELP go_memstats_gc_sys_bytes Number of bytes used for garbage collection system metadata.
# TYPE go_memstats_gc_sys_bytes gauge
go_memstats_gc_sys_bytes 4.590896e+06
# HELP go_memstats_heap_alloc_bytes Number of heap bytes allocated and still in use.
# TYPE go_memstats_heap_alloc_bytes gauge
go_memstats_heap_alloc_bytes 4.189056e+06
# HELP go_memstats_heap_idle_bytes Number of heap bytes waiting to be used.
# TYPE go_memstats_heap_idle_bytes gauge
go_memstats_heap_idle_bytes 2.629632e+06
# HELP go_memstats_heap_inuse_bytes Number of heap bytes that are in use.
# TYPE go_memstats_heap_inuse_bytes gauge
go_memstats_heap_inuse_bytes 4.775936e+06
# HELP go_memstats_heap_objects Number of allocated objects.
# TYPE go_memstats_heap_objects gauge
go_memstats_heap_objects 34424
# HELP go_memstats_heap_released_bytes Number of heap bytes released to OS.
# TYPE go_memstats_heap_released_bytes gauge
go_memstats_heap_released_bytes 2.400256e+06
# HELP go_memstats_heap_sys_bytes Number of heap bytes obtained from system.
# TYPE go_memstats_heap_sys_bytes gauge
go_memstats_heap_sys_bytes 7.405568e+06
# HELP go_memstats_last_gc_time_seconds Number of seconds since 1970 of last garbage collection.
# TYPE go_memstats_last_gc_time_seconds gauge
go_memstats_last_gc_time_seconds 1.6497237847950306e+09
# HELP go_memstats_lookups_total Total number of pointer lookups.
# TYPE go_memstats_lookups_total counter
go_memstats_lookups_total 0
# HELP go_memstats_mallocs_total Total number of mallocs.
# TYPE go_memstats_mallocs_total counter
go_memstats_mallocs_total 50445
# HELP go_memstats_mcache_inuse_bytes Number of bytes in use by mcache structures.
# TYPE go_memstats_mcache_inuse_bytes gauge
go_memstats_mcache_inuse_bytes 9600
# HELP go_memstats_mcache_sys_bytes Number of bytes used for mcache structures obtained from system.
# TYPE go_memstats_mcache_sys_bytes gauge
go_memstats_mcache_sys_bytes 15600
# HELP go_memstats_mspan_inuse_bytes Number of bytes in use by mspan structures.
# TYPE go_memstats_mspan_inuse_bytes gauge
go_memstats_mspan_inuse_bytes 90032
# HELP go_memstats_mspan_sys_bytes Number of bytes used for mspan structures obtained from system.
# TYPE go_memstats_mspan_sys_bytes gauge
go_memstats_mspan_sys_bytes 97920
# HELP go_memstats_next_gc_bytes Number of heap bytes when next garbage collection will take place.
# TYPE go_memstats_next_gc_bytes gauge
go_memstats_next_gc_bytes 4.268352e+06
# HELP go_memstats_other_sys_bytes Number of bytes used for other system allocations.
# TYPE go_memstats_other_sys_bytes gauge
go_memstats_other_sys_bytes 978293
# HELP go_memstats_stack_inuse_bytes Number of bytes in use by the stack allocator.
# TYPE go_memstats_stack_inuse_bytes gauge
go_memstats_stack_inuse_bytes 950272
# HELP go_memstats_stack_sys_bytes Number of bytes obtained from system for stack allocator.
# TYPE go_memstats_stack_sys_bytes gauge
go_memstats_stack_sys_bytes 950272
# HELP go_memstats_sys_bytes Number of bytes obtained from system.
# TYPE go_memstats_sys_bytes gauge
go_memstats_sys_bytes 1.404392e+07
# HELP go_sched_goroutines_goroutines Count of live goroutines.
# TYPE go_sched_goroutines_goroutines gauge
go_sched_goroutines_goroutines 13
# HELP go_sched_latencies_seconds Distribution of the time goroutines have spent in the scheduler in a runnable state before actually running.
# TYPE go_sched_latencies_seconds histogram
go_sched_latencies_seconds_bucket{le="-5e-324"} 0
go_sched_latencies_seconds_bucket{le="9.999999999999999e-10"} 34
go_sched_latencies_seconds_bucket{le="9.999999999999999e-09"} 34
go_sched_latencies_seconds_bucket{le="9.999999999999998e-08"} 41
go_sched_latencies_seconds_bucket{le="1.0239999999999999e-06"} 58
go_sched_latencies_seconds_bucket{le="1.0239999999999999e-05"} 62
go_sched_latencies_seconds_bucket{le="0.00010239999999999998"} 66
go_sched_latencies_seconds_bucket{le="0.0010485759999999998"} 66
go_sched_latencies_seconds_bucket{le="0.010485759999999998"} 66
go_sched_latencies_seconds_bucket{le="0.10485759999999998"} 66
go_sched_latencies_seconds_bucket{le="+Inf"} 66
go_sched_latencies_seconds_sum NaN
go_sched_latencies_seconds_count 66
# HELP go_threads Number of OS threads created.
# TYPE go_threads gauge
go_threads 11
# HELP process_cpu_seconds_total Total user and system CPU time spent in seconds.
# TYPE process_cpu_seconds_total counter
process_cpu_seconds_total 0
# HELP process_max_fds Maximum number of open file descriptors.
# TYPE process_max_fds gauge
process_max_fds 1024
# HELP process_open_fds Number of open file descriptors.
# TYPE process_open_fds gauge
process_open_fds 11
# HELP process_resident_memory_bytes Resident memory size in bytes.
# TYPE process_resident_memory_bytes gauge
process_resident_memory_bytes 2.0262912e+07
# HELP process_start_time_seconds Start time of the process since unix epoch in seconds.
# TYPE process_start_time_seconds gauge
process_start_time_seconds 1.64972378424e+09
# HELP process_virtual_memory_bytes Virtual memory size in bytes.
# TYPE process_virtual_memory_bytes gauge
process_virtual_memory_bytes 1.442832384e+09
# HELP process_virtual_memory_max_bytes Maximum amount of virtual memory available in bytes.
# TYPE process_virtual_memory_max_bytes gauge
process_virtual_memory_max_bytes 1.8446744073709552e+19
# HELP promhttp_metric_handler_requests_in_flight Current number of scrapes being served.
# TYPE promhttp_metric_handler_requests_in_flight gauge
promhttp_metric_handler_requests_in_flight 1
# HELP promhttp_metric_handler_requests_total Total number of scrapes by HTTP status code.
# TYPE promhttp_metric_handler_requests_total counter
promhttp_metric_handler_requests_total{code="200"} 0
promhttp_metric_handler_requests_total{code="500"} 0
promhttp_metric_handler_requests_total{code="503"} 0
<!-- gh-comment-id:1095742026 --> @binwiederhier commented on GitHub (Apr 12, 2022): I looked at your link and even briefly implemented it as a test (https://github.com/binwiederhier/ntfy/commit/3b1852541edf66689662d902c0811161b73f3c95). Unfortunately, I don't like it, because it brings in 7 new dependencies and outputs a very Prometheus specific format. I also can't really expose this on the public server because it gives away too much about the system and may be a security risk (maybe?). If it was easy to implement without a library, maybe. But even then I thought it was gonna be some custom JSON that I output, not the weird Prometheus format. If people really really really want this I can be convinced otherwise, but I'm trying to protect the (already large) dependency tree. ![image](https://user-images.githubusercontent.com/664597/162855509-53ff93f1-fbf4-487b-90dd-9c1c1123bae4.png) Sample format: ``` $ curl localhost/metrics # HELP go_gc_cycles_automatic_gc_cycles_total Count of completed GC cycles generated by the Go runtime. # TYPE go_gc_cycles_automatic_gc_cycles_total counter go_gc_cycles_automatic_gc_cycles_total 1 # HELP go_gc_cycles_forced_gc_cycles_total Count of completed GC cycles forced by the application. # TYPE go_gc_cycles_forced_gc_cycles_total counter go_gc_cycles_forced_gc_cycles_total 0 # HELP go_gc_cycles_total_gc_cycles_total Count of all completed GC cycles. # TYPE go_gc_cycles_total_gc_cycles_total counter go_gc_cycles_total_gc_cycles_total 1 # HELP go_gc_duration_seconds A summary of the pause duration of garbage collection cycles. # TYPE go_gc_duration_seconds summary go_gc_duration_seconds{quantile="0"} 2.557e-05 go_gc_duration_seconds{quantile="0.25"} 2.557e-05 go_gc_duration_seconds{quantile="0.5"} 2.557e-05 go_gc_duration_seconds{quantile="0.75"} 2.557e-05 go_gc_duration_seconds{quantile="1"} 2.557e-05 go_gc_duration_seconds_sum 2.557e-05 go_gc_duration_seconds_count 1 # HELP go_gc_heap_allocs_by_size_bytes_total Distribution of heap allocations by approximate size. Note that this does not include tiny objects as defined by /gc/heap/tiny/allocs:objects, only tiny blocks. # TYPE go_gc_heap_allocs_by_size_bytes_total histogram go_gc_heap_allocs_by_size_bytes_total_bucket{le="8.999999999999998"} 3187 go_gc_heap_allocs_by_size_bytes_total_bucket{le="24.999999999999996"} 24468 go_gc_heap_allocs_by_size_bytes_total_bucket{le="64.99999999999999"} 33920 go_gc_heap_allocs_by_size_bytes_total_bucket{le="144.99999999999997"} 44153 go_gc_heap_allocs_by_size_bytes_total_bucket{le="320.99999999999994"} 45364 go_gc_heap_allocs_by_size_bytes_total_bucket{le="704.9999999999999"} 45919 go_gc_heap_allocs_by_size_bytes_total_bucket{le="1536.9999999999998"} 46183 go_gc_heap_allocs_by_size_bytes_total_bucket{le="3200.9999999999995"} 46375 go_gc_heap_allocs_by_size_bytes_total_bucket{le="6528.999999999999"} 46533 go_gc_heap_allocs_by_size_bytes_total_bucket{le="13568.999999999998"} 46610 go_gc_heap_allocs_by_size_bytes_total_bucket{le="27264.999999999996"} 46635 go_gc_heap_allocs_by_size_bytes_total_bucket{le="+Inf"} 46652 go_gc_heap_allocs_by_size_bytes_total_sum 6.127456e+06 go_gc_heap_allocs_by_size_bytes_total_count 46652 # HELP go_gc_heap_allocs_bytes_total Cumulative sum of memory allocated to the heap by the application. # TYPE go_gc_heap_allocs_bytes_total counter go_gc_heap_allocs_bytes_total 6.127456e+06 # HELP go_gc_heap_allocs_objects_total Cumulative count of heap allocations triggered by the application. Note that this does not include tiny objects as defined by /gc/heap/tiny/allocs:objects, only tiny blocks. # TYPE go_gc_heap_allocs_objects_total counter go_gc_heap_allocs_objects_total 46652 # HELP go_gc_heap_frees_by_size_bytes_total Distribution of freed heap allocations by approximate size. Note that this does not include tiny objects as defined by /gc/heap/tiny/allocs:objects, only tiny blocks. # TYPE go_gc_heap_frees_by_size_bytes_total histogram go_gc_heap_frees_by_size_bytes_total_bucket{le="8.999999999999998"} 115 go_gc_heap_frees_by_size_bytes_total_bucket{le="24.999999999999996"} 4332 go_gc_heap_frees_by_size_bytes_total_bucket{le="64.99999999999999"} 5493 go_gc_heap_frees_by_size_bytes_total_bucket{le="144.99999999999997"} 11558 go_gc_heap_frees_by_size_bytes_total_bucket{le="320.99999999999994"} 11855 go_gc_heap_frees_by_size_bytes_total_bucket{le="704.9999999999999"} 11997 go_gc_heap_frees_by_size_bytes_total_bucket{le="1536.9999999999998"} 12092 go_gc_heap_frees_by_size_bytes_total_bucket{le="3200.9999999999995"} 12155 go_gc_heap_frees_by_size_bytes_total_bucket{le="6528.999999999999"} 12208 go_gc_heap_frees_by_size_bytes_total_bucket{le="13568.999999999998"} 12217 go_gc_heap_frees_by_size_bytes_total_bucket{le="27264.999999999996"} 12221 go_gc_heap_frees_by_size_bytes_total_bucket{le="+Inf"} 12228 go_gc_heap_frees_by_size_bytes_total_sum 1.9384e+06 go_gc_heap_frees_by_size_bytes_total_count 12228 # HELP go_gc_heap_frees_bytes_total Cumulative sum of heap memory freed by the garbage collector. # TYPE go_gc_heap_frees_bytes_total counter go_gc_heap_frees_bytes_total 1.9384e+06 # HELP go_gc_heap_frees_objects_total Cumulative count of heap allocations whose storage was freed by the garbage collector. Note that this does not include tiny objects as defined by /gc/heap/tiny/allocs:objects, only tiny blocks. # TYPE go_gc_heap_frees_objects_total counter go_gc_heap_frees_objects_total 12228 # HELP go_gc_heap_goal_bytes Heap size target for the end of the GC cycle. # TYPE go_gc_heap_goal_bytes gauge go_gc_heap_goal_bytes 4.268352e+06 # HELP go_gc_heap_objects_objects Number of objects, live or unswept, occupying heap memory. # TYPE go_gc_heap_objects_objects gauge go_gc_heap_objects_objects 34424 # HELP go_gc_heap_tiny_allocs_objects_total Count of small allocations that are packed together into blocks. These allocations are counted separately from other allocations because each individual allocation is not tracked by the runtime, only their block. Each block is already accounted for in allocs-by-size and frees-by-size. # TYPE go_gc_heap_tiny_allocs_objects_total counter go_gc_heap_tiny_allocs_objects_total 3793 # HELP go_gc_pauses_seconds_total Distribution individual GC-related stop-the-world pause latencies. # TYPE go_gc_pauses_seconds_total histogram go_gc_pauses_seconds_total_bucket{le="-5e-324"} 0 go_gc_pauses_seconds_total_bucket{le="9.999999999999999e-10"} 0 go_gc_pauses_seconds_total_bucket{le="9.999999999999999e-09"} 0 go_gc_pauses_seconds_total_bucket{le="9.999999999999998e-08"} 0 go_gc_pauses_seconds_total_bucket{le="1.0239999999999999e-06"} 0 go_gc_pauses_seconds_total_bucket{le="1.0239999999999999e-05"} 1 go_gc_pauses_seconds_total_bucket{le="0.00010239999999999998"} 3 go_gc_pauses_seconds_total_bucket{le="0.0010485759999999998"} 3 go_gc_pauses_seconds_total_bucket{le="0.010485759999999998"} 3 go_gc_pauses_seconds_total_bucket{le="0.10485759999999998"} 3 go_gc_pauses_seconds_total_bucket{le="+Inf"} 3 go_gc_pauses_seconds_total_sum NaN go_gc_pauses_seconds_total_count 3 # HELP go_goroutines Number of goroutines that currently exist. # TYPE go_goroutines gauge go_goroutines 14 # HELP go_info Information about the Go environment. # TYPE go_info gauge go_info{version="go1.18"} 1 # HELP go_memory_classes_heap_free_bytes Memory that is completely free and eligible to be returned to the underlying system, but has not been. This metric is the runtime's estimate of free address space that is backed by physical memory. # TYPE go_memory_classes_heap_free_bytes gauge go_memory_classes_heap_free_bytes 229376 # HELP go_memory_classes_heap_objects_bytes Memory occupied by live objects and dead objects that have not yet been marked free by the garbage collector. # TYPE go_memory_classes_heap_objects_bytes gauge go_memory_classes_heap_objects_bytes 4.189056e+06 # HELP go_memory_classes_heap_released_bytes Memory that is completely free and has been returned to the underlying system. This metric is the runtime's estimate of free address space that is still mapped into the process, but is not backed by physical memory. # TYPE go_memory_classes_heap_released_bytes gauge go_memory_classes_heap_released_bytes 2.400256e+06 # HELP go_memory_classes_heap_stacks_bytes Memory allocated from the heap that is reserved for stack space, whether or not it is currently in-use. # TYPE go_memory_classes_heap_stacks_bytes gauge go_memory_classes_heap_stacks_bytes 950272 # HELP go_memory_classes_heap_unused_bytes Memory that is reserved for heap objects but is not currently used to hold heap objects. # TYPE go_memory_classes_heap_unused_bytes gauge go_memory_classes_heap_unused_bytes 586880 # HELP go_memory_classes_metadata_mcache_free_bytes Memory that is reserved for runtime mcache structures, but not in-use. # TYPE go_memory_classes_metadata_mcache_free_bytes gauge go_memory_classes_metadata_mcache_free_bytes 6000 # HELP go_memory_classes_metadata_mcache_inuse_bytes Memory that is occupied by runtime mcache structures that are currently being used. # TYPE go_memory_classes_metadata_mcache_inuse_bytes gauge go_memory_classes_metadata_mcache_inuse_bytes 9600 # HELP go_memory_classes_metadata_mspan_free_bytes Memory that is reserved for runtime mspan structures, but not in-use. # TYPE go_memory_classes_metadata_mspan_free_bytes gauge go_memory_classes_metadata_mspan_free_bytes 7888 # HELP go_memory_classes_metadata_mspan_inuse_bytes Memory that is occupied by runtime mspan structures that are currently being used. # TYPE go_memory_classes_metadata_mspan_inuse_bytes gauge go_memory_classes_metadata_mspan_inuse_bytes 90032 # HELP go_memory_classes_metadata_other_bytes Memory that is reserved for or used to hold runtime metadata. # TYPE go_memory_classes_metadata_other_bytes gauge go_memory_classes_metadata_other_bytes 4.590896e+06 # HELP go_memory_classes_os_stacks_bytes Stack memory allocated by the underlying operating system. # TYPE go_memory_classes_os_stacks_bytes gauge go_memory_classes_os_stacks_bytes 0 # HELP go_memory_classes_other_bytes Memory used by execution trace buffers, structures for debugging the runtime, finalizer and profiler specials, and more. # TYPE go_memory_classes_other_bytes gauge go_memory_classes_other_bytes 978293 # HELP go_memory_classes_profiling_buckets_bytes Memory that is used by the stack trace hash map used for profiling. # TYPE go_memory_classes_profiling_buckets_bytes gauge go_memory_classes_profiling_buckets_bytes 5371 # HELP go_memory_classes_total_bytes All memory mapped by the Go runtime into the current process as read-write. Note that this does not include memory mapped by code called via cgo or via the syscall package. Sum of all metrics in /memory/classes. # TYPE go_memory_classes_total_bytes gauge go_memory_classes_total_bytes 1.404392e+07 # HELP go_memstats_alloc_bytes Number of bytes allocated and still in use. # TYPE go_memstats_alloc_bytes gauge go_memstats_alloc_bytes 4.189056e+06 # HELP go_memstats_alloc_bytes_total Total number of bytes allocated, even if freed. # TYPE go_memstats_alloc_bytes_total counter go_memstats_alloc_bytes_total 6.127456e+06 # HELP go_memstats_buck_hash_sys_bytes Number of bytes used by the profiling bucket hash table. # TYPE go_memstats_buck_hash_sys_bytes gauge go_memstats_buck_hash_sys_bytes 5371 # HELP go_memstats_frees_total Total number of frees. # TYPE go_memstats_frees_total counter go_memstats_frees_total 16021 # HELP go_memstats_gc_cpu_fraction The fraction of this program's available CPU time used by the GC since the program started. # TYPE go_memstats_gc_cpu_fraction gauge go_memstats_gc_cpu_fraction 0 # HELP go_memstats_gc_sys_bytes Number of bytes used for garbage collection system metadata. # TYPE go_memstats_gc_sys_bytes gauge go_memstats_gc_sys_bytes 4.590896e+06 # HELP go_memstats_heap_alloc_bytes Number of heap bytes allocated and still in use. # TYPE go_memstats_heap_alloc_bytes gauge go_memstats_heap_alloc_bytes 4.189056e+06 # HELP go_memstats_heap_idle_bytes Number of heap bytes waiting to be used. # TYPE go_memstats_heap_idle_bytes gauge go_memstats_heap_idle_bytes 2.629632e+06 # HELP go_memstats_heap_inuse_bytes Number of heap bytes that are in use. # TYPE go_memstats_heap_inuse_bytes gauge go_memstats_heap_inuse_bytes 4.775936e+06 # HELP go_memstats_heap_objects Number of allocated objects. # TYPE go_memstats_heap_objects gauge go_memstats_heap_objects 34424 # HELP go_memstats_heap_released_bytes Number of heap bytes released to OS. # TYPE go_memstats_heap_released_bytes gauge go_memstats_heap_released_bytes 2.400256e+06 # HELP go_memstats_heap_sys_bytes Number of heap bytes obtained from system. # TYPE go_memstats_heap_sys_bytes gauge go_memstats_heap_sys_bytes 7.405568e+06 # HELP go_memstats_last_gc_time_seconds Number of seconds since 1970 of last garbage collection. # TYPE go_memstats_last_gc_time_seconds gauge go_memstats_last_gc_time_seconds 1.6497237847950306e+09 # HELP go_memstats_lookups_total Total number of pointer lookups. # TYPE go_memstats_lookups_total counter go_memstats_lookups_total 0 # HELP go_memstats_mallocs_total Total number of mallocs. # TYPE go_memstats_mallocs_total counter go_memstats_mallocs_total 50445 # HELP go_memstats_mcache_inuse_bytes Number of bytes in use by mcache structures. # TYPE go_memstats_mcache_inuse_bytes gauge go_memstats_mcache_inuse_bytes 9600 # HELP go_memstats_mcache_sys_bytes Number of bytes used for mcache structures obtained from system. # TYPE go_memstats_mcache_sys_bytes gauge go_memstats_mcache_sys_bytes 15600 # HELP go_memstats_mspan_inuse_bytes Number of bytes in use by mspan structures. # TYPE go_memstats_mspan_inuse_bytes gauge go_memstats_mspan_inuse_bytes 90032 # HELP go_memstats_mspan_sys_bytes Number of bytes used for mspan structures obtained from system. # TYPE go_memstats_mspan_sys_bytes gauge go_memstats_mspan_sys_bytes 97920 # HELP go_memstats_next_gc_bytes Number of heap bytes when next garbage collection will take place. # TYPE go_memstats_next_gc_bytes gauge go_memstats_next_gc_bytes 4.268352e+06 # HELP go_memstats_other_sys_bytes Number of bytes used for other system allocations. # TYPE go_memstats_other_sys_bytes gauge go_memstats_other_sys_bytes 978293 # HELP go_memstats_stack_inuse_bytes Number of bytes in use by the stack allocator. # TYPE go_memstats_stack_inuse_bytes gauge go_memstats_stack_inuse_bytes 950272 # HELP go_memstats_stack_sys_bytes Number of bytes obtained from system for stack allocator. # TYPE go_memstats_stack_sys_bytes gauge go_memstats_stack_sys_bytes 950272 # HELP go_memstats_sys_bytes Number of bytes obtained from system. # TYPE go_memstats_sys_bytes gauge go_memstats_sys_bytes 1.404392e+07 # HELP go_sched_goroutines_goroutines Count of live goroutines. # TYPE go_sched_goroutines_goroutines gauge go_sched_goroutines_goroutines 13 # HELP go_sched_latencies_seconds Distribution of the time goroutines have spent in the scheduler in a runnable state before actually running. # TYPE go_sched_latencies_seconds histogram go_sched_latencies_seconds_bucket{le="-5e-324"} 0 go_sched_latencies_seconds_bucket{le="9.999999999999999e-10"} 34 go_sched_latencies_seconds_bucket{le="9.999999999999999e-09"} 34 go_sched_latencies_seconds_bucket{le="9.999999999999998e-08"} 41 go_sched_latencies_seconds_bucket{le="1.0239999999999999e-06"} 58 go_sched_latencies_seconds_bucket{le="1.0239999999999999e-05"} 62 go_sched_latencies_seconds_bucket{le="0.00010239999999999998"} 66 go_sched_latencies_seconds_bucket{le="0.0010485759999999998"} 66 go_sched_latencies_seconds_bucket{le="0.010485759999999998"} 66 go_sched_latencies_seconds_bucket{le="0.10485759999999998"} 66 go_sched_latencies_seconds_bucket{le="+Inf"} 66 go_sched_latencies_seconds_sum NaN go_sched_latencies_seconds_count 66 # HELP go_threads Number of OS threads created. # TYPE go_threads gauge go_threads 11 # HELP process_cpu_seconds_total Total user and system CPU time spent in seconds. # TYPE process_cpu_seconds_total counter process_cpu_seconds_total 0 # HELP process_max_fds Maximum number of open file descriptors. # TYPE process_max_fds gauge process_max_fds 1024 # HELP process_open_fds Number of open file descriptors. # TYPE process_open_fds gauge process_open_fds 11 # HELP process_resident_memory_bytes Resident memory size in bytes. # TYPE process_resident_memory_bytes gauge process_resident_memory_bytes 2.0262912e+07 # HELP process_start_time_seconds Start time of the process since unix epoch in seconds. # TYPE process_start_time_seconds gauge process_start_time_seconds 1.64972378424e+09 # HELP process_virtual_memory_bytes Virtual memory size in bytes. # TYPE process_virtual_memory_bytes gauge process_virtual_memory_bytes 1.442832384e+09 # HELP process_virtual_memory_max_bytes Maximum amount of virtual memory available in bytes. # TYPE process_virtual_memory_max_bytes gauge process_virtual_memory_max_bytes 1.8446744073709552e+19 # HELP promhttp_metric_handler_requests_in_flight Current number of scrapes being served. # TYPE promhttp_metric_handler_requests_in_flight gauge promhttp_metric_handler_requests_in_flight 1 # HELP promhttp_metric_handler_requests_total Total number of scrapes by HTTP status code. # TYPE promhttp_metric_handler_requests_total counter promhttp_metric_handler_requests_total{code="200"} 0 promhttp_metric_handler_requests_total{code="500"} 0 promhttp_metric_handler_requests_total{code="503"} 0 ```
Author
Owner

@rogeliodh commented on GitHub (Apr 12, 2022):

fair enough!

about dependencies, there is an alternative library which, supposedly as I haven't used it, has less dependencies: https://github.com/VictoriaMetrics/metrics

about the endpoint being public, yes, I think it shoud be protected by some auth, or even published in another port

but let's wait to see if there are more users that want this feature :)

<!-- gh-comment-id:1095783779 --> @rogeliodh commented on GitHub (Apr 12, 2022): fair enough! about dependencies, there is an alternative library which, supposedly as I haven't used it, has less dependencies: https://github.com/VictoriaMetrics/metrics about the endpoint being public, yes, I think it shoud be protected by some auth, or even published in another port but let's wait to see if there are more users that want this feature :)
Author
Owner

@mhameed commented on GitHub (Apr 29, 2022):

Hi,
I would also be interested in seeing ntfy prometheus metrics implemented.
I would also second the idea that the prometheus/victoria/openmetrics information would be served via a diffrent interface/port to the actual ntfy service.
Thanks.

<!-- gh-comment-id:1113178843 --> @mhameed commented on GitHub (Apr 29, 2022): Hi, I would also be interested in seeing ntfy prometheus metrics implemented. I would also second the idea that the prometheus/victoria/[openmetrics](https://github.com/OpenObservability/OpenMetrics/) information would be served via a diffrent interface/port to the actual ntfy service. Thanks.
Author
Owner

@benisai commented on GitHub (Aug 4, 2022):

Interested in this

<!-- gh-comment-id:1204675679 --> @benisai commented on GitHub (Aug 4, 2022): Interested in this
Author
Owner

@genofire commented on GitHub (Aug 12, 2022):

Maybe we should implement /ready and /healthy eigther to run in a k8s.

<!-- gh-comment-id:1213210435 --> @genofire commented on GitHub (Aug 12, 2022): Maybe we should implement /ready and /healthy eigther to run in a k8s.
Author
Owner

@nicois commented on GitHub (Dec 21, 2022):

Victoria metrics looks like a good candidate. Adding a configuration option for the path, defaulting to undefined/off, should be sufficient here I believe. Nginx/Apache can use ACLs to prevent external hosts from reaching whatever endpoint is configured.

<!-- gh-comment-id:1362105015 --> @nicois commented on GitHub (Dec 21, 2022): Victoria metrics looks like a good candidate. Adding a configuration option for the path, defaulting to undefined/off, should be sufficient here I believe. Nginx/Apache can use ACLs to prevent external hosts from reaching whatever endpoint is configured.
Author
Owner

@genofire commented on GitHub (Dec 23, 2022):

https://github.com/binwiederhier/ntfy/issues/210#issuecomment-1095742026

I am missing metric here, like:

  • subscription_total{topic="x"}
  • messages_total {topic="x"}

For getting big topics based on subscription and message rate.
Maybe also a Histogramm of the time get and send to all reciever like: delivery{le="+Inf", topic="x"}

<!-- gh-comment-id:1364050250 --> @genofire commented on GitHub (Dec 23, 2022): > https://github.com/binwiederhier/ntfy/issues/210#issuecomment-1095742026 I am missing metric here, like: - `subscription_total{topic="x"}` - `messages_total {topic="x"}` For getting big topics based on subscription and message rate. Maybe also a Histogramm of the time get and send to all reciever like: `delivery{le="+Inf", topic="x"}`
Author
Owner

@binwiederhier commented on GitHub (Mar 7, 2023):

@rogeliodh @nicois @genofire @benisai @mhameed, and anyone else who is interested, what metrics would you like to see?

Here's my current WIP:

messagesPublishedSuccess: prometheus.NewCounter(prometheus.CounterOpts{
	Name: "ntfy_messages_published_success",
}),
messagesPublishedFailure: prometheus.NewCounter(prometheus.CounterOpts{
	Name: "ntfy_messages_published_failure",
}),
messagesCached: prometheus.NewGauge(prometheus.GaugeOpts{
	Name: "ntfy_messages_cached_total",
}),
firebasePublishedSuccess: prometheus.NewCounter(prometheus.CounterOpts{
	Name: "ntfy_firebase_published_success",
}),
firebasePublishedFailure: prometheus.NewCounter(prometheus.CounterOpts{
	Name: "ntfy_firebase_published_failure",
}),
emailsPublishedSuccess: prometheus.NewCounter(prometheus.CounterOpts{
	Name: "ntfy_emails_sent_success",
}),
emailsPublishedFailure: prometheus.NewCounter(prometheus.CounterOpts{
	Name: "ntfy_emails_sent_failure",
}),
visitors: prometheus.NewGauge(prometheus.GaugeOpts{
	Name: "ntfy_visitors_total",
}),
subscribers: prometheus.NewGauge(prometheus.GaugeOpts{
	Name: "ntfy_subscribers_total",
}),
topics: prometheus.NewGauge(prometheus.GaugeOpts{
	Name: "ntfy_topics_total",
}),
httpRequests: prometheus.NewCounterVec(prometheus.CounterOpts{
	Name: "ntfy_http_requests_total",
}, []string{"http_code", "ntfy_code", "http_method"}),

Here's my dabbling dashboard:

image

<!-- gh-comment-id:1457452943 --> @binwiederhier commented on GitHub (Mar 7, 2023): @rogeliodh @nicois @genofire @benisai @mhameed, and anyone else who is interested, what metrics would you like to see? Here's my current WIP: ``` messagesPublishedSuccess: prometheus.NewCounter(prometheus.CounterOpts{ Name: "ntfy_messages_published_success", }), messagesPublishedFailure: prometheus.NewCounter(prometheus.CounterOpts{ Name: "ntfy_messages_published_failure", }), messagesCached: prometheus.NewGauge(prometheus.GaugeOpts{ Name: "ntfy_messages_cached_total", }), firebasePublishedSuccess: prometheus.NewCounter(prometheus.CounterOpts{ Name: "ntfy_firebase_published_success", }), firebasePublishedFailure: prometheus.NewCounter(prometheus.CounterOpts{ Name: "ntfy_firebase_published_failure", }), emailsPublishedSuccess: prometheus.NewCounter(prometheus.CounterOpts{ Name: "ntfy_emails_sent_success", }), emailsPublishedFailure: prometheus.NewCounter(prometheus.CounterOpts{ Name: "ntfy_emails_sent_failure", }), visitors: prometheus.NewGauge(prometheus.GaugeOpts{ Name: "ntfy_visitors_total", }), subscribers: prometheus.NewGauge(prometheus.GaugeOpts{ Name: "ntfy_subscribers_total", }), topics: prometheus.NewGauge(prometheus.GaugeOpts{ Name: "ntfy_topics_total", }), httpRequests: prometheus.NewCounterVec(prometheus.CounterOpts{ Name: "ntfy_http_requests_total", }, []string{"http_code", "ntfy_code", "http_method"}), ``` Here's my dabbling dashboard: ![image](https://user-images.githubusercontent.com/664597/223312298-9104e347-44b5-46a5-8271-3e11c0be047b.png)
Author
Owner

@genofire commented on GitHub (Mar 7, 2023):

Maybe for find big topics:

subscribers: prometheus.NewGaugeVec(prometheus.GaugeOpts{
	Name: "ntfy_subscribers_total",
}, []string {"topic"),

(Also on other metrics, based on topic).

<!-- gh-comment-id:1457878287 --> @genofire commented on GitHub (Mar 7, 2023): Maybe for find big topics: ``` subscribers: prometheus.NewGaugeVec(prometheus.GaugeOpts{ Name: "ntfy_subscribers_total", }, []string {"topic"), ``` (Also on other metrics, based on `topic`).
Author
Owner

@rogeliodh commented on GitHub (Mar 7, 2023):

I think adding topic label is not a good idea because there could be thousands of topics and adding a high cardinality dimension to prometheus metrics is a bad practice.

So I think original proposal is ok but I was wondering if they are enough to replicate the statistics you generate daily on the stats topic:

IPs: 23000
Clients: 23551
- Google Play: 7905
- F-Droid: 12104
- iOS: 2910
- curl: 5
- other: 627
Messages:
- Successful: 179595
- Failed (rate limited): 49016
- Failed (other): 443320

and I think we would be missing:

  • a label error to ntfy_messages_published_failure (and firebase and emails metrics, too)

for IPs I'm not really sure if ntfy could generate that stat...

for Clients... maybe change it to the "published" metric: add a client_type label to all ntfy_*_published_* metrics so we can get number of published messages per client type.

I'm not sure about the last one. @binwiederhier should know better ;)

<!-- gh-comment-id:1458116521 --> @rogeliodh commented on GitHub (Mar 7, 2023): I think adding `topic` label is not a good idea because there could be thousands of topics and adding a high cardinality dimension to prometheus metrics is a bad practice. So I think original proposal is ok but I was wondering if they are enough to replicate the statistics you generate daily on the `stats` topic: ``` IPs: 23000 Clients: 23551 - Google Play: 7905 - F-Droid: 12104 - iOS: 2910 - curl: 5 - other: 627 Messages: - Successful: 179595 - Failed (rate limited): 49016 - Failed (other): 443320 ``` and I think we would be missing: * a label `error` to ` ntfy_messages_published_failure` (and firebase and emails metrics, too) for IPs I'm not really sure if ntfy could generate that stat... for Clients... maybe change it to the "published" metric: add a `client_type` label to all `ntfy_*_published_*` metrics so we can get number of published messages per client type. I'm not sure about the last one. @binwiederhier should know better ;)
Author
Owner

@xenrox commented on GitHub (Mar 9, 2023):

What about number of user registrations?
That could be useful for abuse prevention/detection.

<!-- gh-comment-id:1462261743 --> @xenrox commented on GitHub (Mar 9, 2023): What about number of user registrations? That could be useful for abuse prevention/detection.
Author
Owner

@binwiederhier commented on GitHub (Mar 14, 2023):

I think I am content the way I have implemented this. I may add a few more metrics and then call it a day for now. We can always add more or change it later. The majority of work for me will be to Anisble-ize the Grafana+Prometheus installation.

image

<!-- gh-comment-id:1467294899 --> @binwiederhier commented on GitHub (Mar 14, 2023): I think I am content the way I have implemented this. I may add a few more metrics and then call it a day for now. We can always add more or change it later. The majority of work for me will be to Anisble-ize the Grafana+Prometheus installation. ![image](https://user-images.githubusercontent.com/664597/224882937-2d043e5c-f587-4613-a177-e2f4289a1045.png)
Author
Owner

@binwiederhier commented on GitHub (Mar 14, 2023):

The funniest thing: Apparently some other dependency had pulled in the prometheus client already, so this won't add any dependencies, whooo.

image

<!-- gh-comment-id:1468189445 --> @binwiederhier commented on GitHub (Mar 14, 2023): The funniest thing: Apparently some other dependency had pulled in the prometheus client already, so this won't add any dependencies, whooo. ![image](https://user-images.githubusercontent.com/664597/225029948-6ad8a1ba-15d1-40dc-ad04-7d334f5992b9.png)
Author
Owner

@binwiederhier commented on GitHub (Mar 15, 2023):

📢 Question around the /metrics endpoint for Prometheus: Right now I have it so that if you configure listen-metrics-http, it'll listen on a different IP/port for the metrics. But I feel like some people may want to just use the same interface potentially.

Are there any best practices around this?

What I have:

listen-http: ":80" # ntfy server, listen on all IPs
listen-metrics-http: "10.0.2.1:9090" # only /metrics endpoint, listen on internal network

I want to keep it simple, but flexible enough to be useful for everyone. Thoughts?

Plus, I don't want 100 different metrics config options...

<!-- gh-comment-id:1470566557 --> @binwiederhier commented on GitHub (Mar 15, 2023): :loudspeaker: Question around the `/metrics` endpoint for Prometheus: Right now I have it so that if you configure `listen-metrics-http`, it'll listen on a different IP/port for the metrics. But I feel like some people may want to just use the same interface potentially. Are there any best practices around this? What I have: ```yaml listen-http: ":80" # ntfy server, listen on all IPs listen-metrics-http: "10.0.2.1:9090" # only /metrics endpoint, listen on internal network ``` I want to keep it simple, but flexible enough to be useful for everyone. Thoughts? Plus, I don't want 100 different metrics config options...
Author
Owner

@xenrox commented on GitHub (Mar 15, 2023):

📢 Question around the /metrics endpoint for Prometheus: Right now I have it so that if you configure listen-metrics-http, it'll listen on a different IP/port for the metrics. But I feel like some people may want to just use the same interface potentially.

Are there any best practices around this?

What I have:

listen-http: ":80" # ntfy server, listen on all IPs
listen-metrics-http: "10.0.2.1:9090" # only /metrics endpoint, listen on internal network

I want to keep it simple, but flexible enough to be useful for everyone. Thoughts?

Plus, I don't want 100 different metrics config options...

Most of the services I scrape with Prometheus, expose their metrics on their default listening port under some variant of "/metrics".
As an example the following services handle it like that: keycloak, sourcehut, gitea, hedgedoc.

synapse is an example that supports both.

I personally prefer a simple "/metrics" on the normal port, but if that somehow does not work with ntfy because of conflicts with topics, a different port seems fine as well and does not really cause any annoyances for setups.

<!-- gh-comment-id:1470822260 --> @xenrox commented on GitHub (Mar 15, 2023): > 📢 Question around the `/metrics` endpoint for Prometheus: Right now I have it so that if you configure `listen-metrics-http`, it'll listen on a different IP/port for the metrics. But I feel like some people may want to just use the same interface potentially. > > Are there any best practices around this? > > What I have: > > ```yaml > listen-http: ":80" # ntfy server, listen on all IPs > listen-metrics-http: "10.0.2.1:9090" # only /metrics endpoint, listen on internal network > ``` > > I want to keep it simple, but flexible enough to be useful for everyone. Thoughts? > > Plus, I don't want 100 different metrics config options... Most of the services I scrape with Prometheus, expose their metrics on their default listening port under some variant of "/metrics". As an example the following services handle it like that: [keycloak], [sourcehut], [gitea], [hedgedoc]. [keycloak]: https://www.keycloak.org/server/configuration-metrics#_querying_metrics [sourcehut]: https://meta.sr.ht/metrics [gitea]: https://docs.gitea.io/en-us/config-cheat-sheet/#metrics-metrics [hedgedoc]: https://docs.hedgedoc.org/dev/api/#hedgedoc-server [synapse] is an example that supports both. [synapse]: https://github.com/matrix-org/synapse/blob/develop/docs/metrics-howto.md I personally prefer a simple "/metrics" on the normal port, but if that somehow does not work with ntfy because of conflicts with topics, a different port seems fine as well and does not really cause any annoyances for setups.
Author
Owner

@binwiederhier commented on GitHub (Mar 15, 2023):

Thanks. I'll check them out tonight. It feels weird to me that these tools allow them to be publicly available. Metrics are sensitive information and can give attackers insight.

<!-- gh-comment-id:1470850419 --> @binwiederhier commented on GitHub (Mar 15, 2023): Thanks. I'll check them out tonight. It feels weird to me that these tools allow them to be publicly available. Metrics are sensitive information and can give attackers insight.
Author
Owner

@xenrox commented on GitHub (Mar 15, 2023):

For sourcehut at least is it a design decision that everything around metrics/alerts is public, so that users can get a better grasp of what is going on.
Besides that, it is easy enough for sysadmins to protect the metrics with e.g. their reverse proxy.
Setting up basic auth, or only internal access (1 2) is pretty straightforward in nginx.

<!-- gh-comment-id:1470865215 --> @xenrox commented on GitHub (Mar 15, 2023): For sourcehut at least is it a design decision that everything around metrics/alerts is public, so that users can get a better grasp of what is going on. Besides that, it is easy enough for sysadmins to protect the metrics with e.g. their reverse proxy. Setting up [basic auth], or only internal access ([1] [2]) is pretty straightforward in nginx. [basic auth]: https://docs.nginx.com/nginx/admin-guide/security-controls/configuring-http-basic-authentication/ [1]: https://git.xenrox.net/~xenrox/ansible/tree/3c279881e01e922bf2bfcef64302017f31739819/item/roles/nginx/templates/internal_access.conf.j2 [2]: https://git.xenrox.net/~xenrox/ansible/tree/3c279881e01e922bf2bfcef64302017f31739819/item/roles/keycloak/files/keycloak.conf#L19
Author
Owner

@binwiederhier commented on GitHub (Mar 16, 2023):

@xenrox Thanks again for the examples. They were great. I did this, and I think I like it:

# ntfy can expose Prometheus-style metrics via a /metrics endpoint, or on a dedicated listen IP/port.
# Metrics may be considered sensitive information, so before you enable them, be sure you know what you are
# 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
#   enables metrics as well, e.g. "10.0.1.1:9090" or ":9090"
#
enable-metrics: false
metrics-listen-http:

The names are a bit weird, but they match the other variables. There is enable-(reservations|login|..). It could be listen-metrics-http to match the other listen- ones, but there's also smtp-listen-addr, so it's already inconsistent...

<!-- gh-comment-id:1472087109 --> @binwiederhier commented on GitHub (Mar 16, 2023): @xenrox Thanks again for the examples. They were great. I did this, and I think I like it: ``` yaml # ntfy can expose Prometheus-style metrics via a /metrics endpoint, or on a dedicated listen IP/port. # Metrics may be considered sensitive information, so before you enable them, be sure you know what you are # 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 # enables metrics as well, e.g. "10.0.1.1:9090" or ":9090" # enable-metrics: false metrics-listen-http: ``` The names are a bit weird, but they match the other variables. There is `enable-(reservations|login|..)`. It could be `listen-metrics-http` to match the other `listen-` ones, but there's also `smtp-listen-addr`, so it's already inconsistent...
Author
Owner

@binwiederhier commented on GitHub (Mar 17, 2023):

This is done and will be in the next release.

<!-- gh-comment-id:1473053259 --> @binwiederhier commented on GitHub (Mar 17, 2023): This is done and will be in the next release.
Author
Owner

@genofire commented on GitHub (Mar 18, 2023):

do you have an grafana dashboard for it? i like to make it part of my helm-chart

<!-- gh-comment-id:1475016158 --> @genofire commented on GitHub (Mar 18, 2023): do you have an grafana dashboard for it? i like to make it part of my helm-chart
Author
Owner

@binwiederhier commented on GitHub (Mar 19, 2023):

Here's one: https://cdn.discordapp.com/attachments/874398661709295629/1086744190312001556/ntfy-1679170350783.json

It's a WIP, and I'll add one to the docs once I think it's good enough.

<!-- gh-comment-id:1475045092 --> @binwiederhier commented on GitHub (Mar 19, 2023): Here's one: https://cdn.discordapp.com/attachments/874398661709295629/1086744190312001556/ntfy-1679170350783.json It's a WIP, and I'll add one to the docs once I think it's good enough.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/ntfy#166
No description provided.