metrics.go 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. // Copyright (C) 2025 The Syncthing Authors.
  2. //
  3. // This Source Code Form is subject to the terms of the Mozilla Public
  4. // License, v. 2.0. If a copy of the MPL was not distributed with this file,
  5. // You can obtain one at https://mozilla.org/MPL/2.0/.
  6. package db
  7. import (
  8. "iter"
  9. "time"
  10. "github.com/prometheus/client_golang/prometheus"
  11. "github.com/prometheus/client_golang/prometheus/promauto"
  12. "github.com/syncthing/syncthing/lib/config"
  13. "github.com/syncthing/syncthing/lib/protocol"
  14. )
  15. var (
  16. metricCurrentOperations = promauto.NewGaugeVec(prometheus.GaugeOpts{
  17. Namespace: "syncthing",
  18. Subsystem: "db",
  19. Name: "operations_current",
  20. Help: "Number of database operations currently ongoing, per folder and operation",
  21. }, []string{"folder", "operation"})
  22. metricTotalOperationSeconds = promauto.NewCounterVec(prometheus.CounterOpts{
  23. Namespace: "syncthing",
  24. Subsystem: "db",
  25. Name: "operation_seconds_total",
  26. Help: "Total time spent in database operations, per folder and operation",
  27. }, []string{"folder", "operation"})
  28. metricTotalOperationsCount = promauto.NewCounterVec(prometheus.CounterOpts{
  29. Namespace: "syncthing",
  30. Subsystem: "db",
  31. Name: "operations_total",
  32. Help: "Total number of database operations, per folder and operation",
  33. }, []string{"folder", "operation"})
  34. metricTotalFilesUpdatedCount = promauto.NewCounterVec(prometheus.CounterOpts{
  35. Namespace: "syncthing",
  36. Subsystem: "db",
  37. Name: "files_updated_total",
  38. Help: "Total number of files updated",
  39. }, []string{"folder"})
  40. )
  41. func MetricsWrap(db DB) DB {
  42. return metricsDB{db}
  43. }
  44. type metricsDB struct {
  45. DB
  46. }
  47. func (m metricsDB) account(folder, op string) func() {
  48. t0 := time.Now()
  49. metricCurrentOperations.WithLabelValues(folder, op).Inc()
  50. return func() {
  51. if dur := time.Since(t0).Seconds(); dur > 0 {
  52. metricTotalOperationSeconds.WithLabelValues(folder, op).Add(dur)
  53. }
  54. metricTotalOperationsCount.WithLabelValues(folder, op).Inc()
  55. metricCurrentOperations.WithLabelValues(folder, op).Dec()
  56. }
  57. }
  58. func (m metricsDB) AllLocalFilesWithBlocksHash(folder string, h []byte) (iter.Seq[FileMetadata], func() error) {
  59. defer m.account(folder, "AllLocalFilesWithBlocksHash")()
  60. return m.DB.AllLocalFilesWithBlocksHash(folder, h)
  61. }
  62. func (m metricsDB) AllGlobalFiles(folder string) (iter.Seq[FileMetadata], func() error) {
  63. defer m.account(folder, "AllGlobalFiles")()
  64. return m.DB.AllGlobalFiles(folder)
  65. }
  66. func (m metricsDB) AllGlobalFilesPrefix(folder string, prefix string) (iter.Seq[FileMetadata], func() error) {
  67. defer m.account(folder, "AllGlobalFilesPrefix")()
  68. return m.DB.AllGlobalFilesPrefix(folder, prefix)
  69. }
  70. func (m metricsDB) AllLocalFiles(folder string, device protocol.DeviceID) (iter.Seq[protocol.FileInfo], func() error) {
  71. defer m.account(folder, "AllLocalFiles")()
  72. return m.DB.AllLocalFiles(folder, device)
  73. }
  74. func (m metricsDB) AllLocalFilesWithPrefix(folder string, device protocol.DeviceID, prefix string) (iter.Seq[protocol.FileInfo], func() error) {
  75. defer m.account(folder, "AllLocalFilesPrefix")()
  76. return m.DB.AllLocalFilesWithPrefix(folder, device, prefix)
  77. }
  78. func (m metricsDB) AllLocalFilesBySequence(folder string, device protocol.DeviceID, startSeq int64, limit int) (iter.Seq[protocol.FileInfo], func() error) {
  79. defer m.account(folder, "AllLocalFilesBySequence")()
  80. return m.DB.AllLocalFilesBySequence(folder, device, startSeq, limit)
  81. }
  82. func (m metricsDB) AllNeededGlobalFiles(folder string, device protocol.DeviceID, order config.PullOrder, limit, offset int) (iter.Seq[protocol.FileInfo], func() error) {
  83. defer m.account(folder, "AllNeededGlobalFiles")()
  84. return m.DB.AllNeededGlobalFiles(folder, device, order, limit, offset)
  85. }
  86. func (m metricsDB) GetGlobalAvailability(folder, file string) ([]protocol.DeviceID, error) {
  87. defer m.account(folder, "GetGlobalAvailability")()
  88. return m.DB.GetGlobalAvailability(folder, file)
  89. }
  90. func (m metricsDB) AllLocalBlocksWithHash(folder string, hash []byte) (iter.Seq[BlockMapEntry], func() error) {
  91. defer m.account("-", "AllLocalBlocksWithHash")()
  92. return m.DB.AllLocalBlocksWithHash(folder, hash)
  93. }
  94. func (m metricsDB) Close() error {
  95. defer m.account("-", "Close")()
  96. return m.DB.Close()
  97. }
  98. func (m metricsDB) ListDevicesForFolder(folder string) ([]protocol.DeviceID, error) {
  99. defer m.account(folder, "ListDevicesForFolder")()
  100. return m.DB.ListDevicesForFolder(folder)
  101. }
  102. func (m metricsDB) RemoteSequences(folder string) (map[protocol.DeviceID]int64, error) {
  103. defer m.account(folder, "RemoteSequences")()
  104. return m.DB.RemoteSequences(folder)
  105. }
  106. func (m metricsDB) DropAllFiles(folder string, device protocol.DeviceID) error {
  107. defer m.account(folder, "DropAllFiles")()
  108. return m.DB.DropAllFiles(folder, device)
  109. }
  110. func (m metricsDB) DropDevice(device protocol.DeviceID) error {
  111. defer m.account("-", "DropDevice")()
  112. return m.DB.DropDevice(device)
  113. }
  114. func (m metricsDB) DropFilesNamed(folder string, device protocol.DeviceID, names []string) error {
  115. defer m.account(folder, "DropFilesNamed")()
  116. return m.DB.DropFilesNamed(folder, device, names)
  117. }
  118. func (m metricsDB) DropFolder(folder string) error {
  119. defer m.account(folder, "DropFolder")()
  120. return m.DB.DropFolder(folder)
  121. }
  122. func (m metricsDB) DropAllIndexIDs() error {
  123. defer m.account("-", "IndexIDDropAll")()
  124. return m.DB.DropAllIndexIDs()
  125. }
  126. func (m metricsDB) ListFolders() ([]string, error) {
  127. defer m.account("-", "ListFolders")()
  128. return m.DB.ListFolders()
  129. }
  130. func (m metricsDB) GetGlobalFile(folder string, file string) (protocol.FileInfo, bool, error) {
  131. defer m.account(folder, "GetGlobalFile")()
  132. return m.DB.GetGlobalFile(folder, file)
  133. }
  134. func (m metricsDB) CountGlobal(folder string) (Counts, error) {
  135. defer m.account(folder, "CountGlobal")()
  136. return m.DB.CountGlobal(folder)
  137. }
  138. func (m metricsDB) GetIndexID(folder string, device protocol.DeviceID) (protocol.IndexID, error) {
  139. defer m.account(folder, "IndexIDGet")()
  140. return m.DB.GetIndexID(folder, device)
  141. }
  142. func (m metricsDB) GetDeviceFile(folder string, device protocol.DeviceID, file string) (protocol.FileInfo, bool, error) {
  143. defer m.account(folder, "GetDeviceFile")()
  144. return m.DB.GetDeviceFile(folder, device, file)
  145. }
  146. func (m metricsDB) CountLocal(folder string, device protocol.DeviceID) (Counts, error) {
  147. defer m.account(folder, "CountLocal")()
  148. return m.DB.CountLocal(folder, device)
  149. }
  150. func (m metricsDB) CountNeed(folder string, device protocol.DeviceID) (Counts, error) {
  151. defer m.account(folder, "CountNeed")()
  152. return m.DB.CountNeed(folder, device)
  153. }
  154. func (m metricsDB) CountReceiveOnlyChanged(folder string) (Counts, error) {
  155. defer m.account(folder, "CountReceiveOnlyChanged")()
  156. return m.DB.CountReceiveOnlyChanged(folder)
  157. }
  158. func (m metricsDB) GetDeviceSequence(folder string, device protocol.DeviceID) (int64, error) {
  159. defer m.account(folder, "GetDeviceSequence")()
  160. return m.DB.GetDeviceSequence(folder, device)
  161. }
  162. func (m metricsDB) SetIndexID(folder string, device protocol.DeviceID, id protocol.IndexID) error {
  163. defer m.account(folder, "IndexIDSet")()
  164. return m.DB.SetIndexID(folder, device, id)
  165. }
  166. func (m metricsDB) Update(folder string, device protocol.DeviceID, fs []protocol.FileInfo) error {
  167. defer m.account(folder, "Update")()
  168. defer metricTotalFilesUpdatedCount.WithLabelValues(folder).Add(float64(len(fs)))
  169. return m.DB.Update(folder, device, fs)
  170. }
  171. func (m metricsDB) GetKV(key string) ([]byte, error) {
  172. defer m.account("-", "GetKV")()
  173. return m.DB.GetKV(key)
  174. }
  175. func (m metricsDB) PutKV(key string, val []byte) error {
  176. defer m.account("-", "PutKV")()
  177. return m.DB.PutKV(key, val)
  178. }
  179. func (m metricsDB) DeleteKV(key string) error {
  180. defer m.account("-", "DeleteKV")()
  181. return m.DB.DeleteKV(key)
  182. }
  183. func (m metricsDB) PrefixKV(prefix string) (iter.Seq[KeyValue], func() error) {
  184. defer m.account("-", "PrefixKV")()
  185. return m.DB.PrefixKV(prefix)
  186. }