metrics.go 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  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. }, []string{"folder", "operation"})
  21. metricTotalOperationSeconds = promauto.NewCounterVec(prometheus.CounterOpts{
  22. Namespace: "syncthing",
  23. Subsystem: "db",
  24. Name: "operation_seconds_total",
  25. Help: "Total time spent in database operations, per folder and operation",
  26. }, []string{"folder", "operation"})
  27. metricTotalOperationsCount = promauto.NewCounterVec(prometheus.CounterOpts{
  28. Namespace: "syncthing",
  29. Subsystem: "db",
  30. Name: "operations_total",
  31. Help: "Total number of database operations, per folder and operation",
  32. }, []string{"folder", "operation"})
  33. metricTotalFilesUpdatedCount = promauto.NewCounterVec(prometheus.CounterOpts{
  34. Namespace: "syncthing",
  35. Subsystem: "db",
  36. Name: "files_updated_total",
  37. Help: "Total number of files updated",
  38. }, []string{"folder"})
  39. )
  40. func MetricsWrap(db DB) DB {
  41. return metricsDB{db}
  42. }
  43. type metricsDB struct {
  44. DB
  45. }
  46. func (m metricsDB) account(folder, op string) func() {
  47. t0 := time.Now()
  48. metricCurrentOperations.WithLabelValues(folder, op).Inc()
  49. return func() {
  50. if dur := time.Since(t0).Seconds(); dur > 0 {
  51. metricTotalOperationSeconds.WithLabelValues(folder, op).Add(dur)
  52. }
  53. metricTotalOperationsCount.WithLabelValues(folder, op).Inc()
  54. metricCurrentOperations.WithLabelValues(folder, op).Dec()
  55. }
  56. }
  57. func (m metricsDB) AllLocalFilesWithBlocksHash(folder string, h []byte) (iter.Seq[FileMetadata], func() error) {
  58. defer m.account(folder, "AllLocalFilesWithBlocksHash")()
  59. return m.DB.AllLocalFilesWithBlocksHash(folder, h)
  60. }
  61. func (m metricsDB) AllLocalFilesWithBlocksHashAnyFolder(hash []byte) (map[string][]FileMetadata, error) {
  62. defer m.account("-", "AllLocalFilesWithBlocksHashAnyFolder")()
  63. return m.DB.AllLocalFilesWithBlocksHashAnyFolder(hash)
  64. }
  65. func (m metricsDB) AllGlobalFiles(folder string) (iter.Seq[FileMetadata], func() error) {
  66. defer m.account(folder, "AllGlobalFiles")()
  67. return m.DB.AllGlobalFiles(folder)
  68. }
  69. func (m metricsDB) AllGlobalFilesPrefix(folder string, prefix string) (iter.Seq[FileMetadata], func() error) {
  70. defer m.account(folder, "AllGlobalFilesPrefix")()
  71. return m.DB.AllGlobalFilesPrefix(folder, prefix)
  72. }
  73. func (m metricsDB) AllLocalFiles(folder string, device protocol.DeviceID) (iter.Seq[protocol.FileInfo], func() error) {
  74. defer m.account(folder, "AllLocalFiles")()
  75. return m.DB.AllLocalFiles(folder, device)
  76. }
  77. func (m metricsDB) AllLocalFilesWithPrefix(folder string, device protocol.DeviceID, prefix string) (iter.Seq[protocol.FileInfo], func() error) {
  78. defer m.account(folder, "AllLocalFilesPrefix")()
  79. return m.DB.AllLocalFilesWithPrefix(folder, device, prefix)
  80. }
  81. func (m metricsDB) AllLocalFilesBySequence(folder string, device protocol.DeviceID, startSeq int64, limit int) (iter.Seq[protocol.FileInfo], func() error) {
  82. defer m.account(folder, "AllLocalFilesBySequence")()
  83. return m.DB.AllLocalFilesBySequence(folder, device, startSeq, limit)
  84. }
  85. func (m metricsDB) AllNeededGlobalFiles(folder string, device protocol.DeviceID, order config.PullOrder, limit, offset int) (iter.Seq[protocol.FileInfo], func() error) {
  86. defer m.account(folder, "AllNeededGlobalFiles")()
  87. return m.DB.AllNeededGlobalFiles(folder, device, order, limit, offset)
  88. }
  89. func (m metricsDB) GetGlobalAvailability(folder, file string) ([]protocol.DeviceID, error) {
  90. defer m.account(folder, "GetGlobalAvailability")()
  91. return m.DB.GetGlobalAvailability(folder, file)
  92. }
  93. func (m metricsDB) AllLocalBlocksWithHash(hash []byte) ([]BlockMapEntry, error) {
  94. defer m.account("-", "AllLocalBlocksWithHash")()
  95. return m.DB.AllLocalBlocksWithHash(hash)
  96. }
  97. func (m metricsDB) Close() error {
  98. defer m.account("-", "Close")()
  99. return m.DB.Close()
  100. }
  101. func (m metricsDB) ListDevicesForFolder(folder string) ([]protocol.DeviceID, error) {
  102. defer m.account(folder, "ListDevicesForFolder")()
  103. return m.DB.ListDevicesForFolder(folder)
  104. }
  105. func (m metricsDB) RemoteSequences(folder string) (map[protocol.DeviceID]int64, error) {
  106. defer m.account(folder, "RemoteSequences")()
  107. return m.DB.RemoteSequences(folder)
  108. }
  109. func (m metricsDB) DropAllFiles(folder string, device protocol.DeviceID) error {
  110. defer m.account(folder, "DropAllFiles")()
  111. return m.DB.DropAllFiles(folder, device)
  112. }
  113. func (m metricsDB) DropDevice(device protocol.DeviceID) error {
  114. defer m.account("-", "DropDevice")()
  115. return m.DB.DropDevice(device)
  116. }
  117. func (m metricsDB) DropFilesNamed(folder string, device protocol.DeviceID, names []string) error {
  118. defer m.account(folder, "DropFilesNamed")()
  119. return m.DB.DropFilesNamed(folder, device, names)
  120. }
  121. func (m metricsDB) DropFolder(folder string) error {
  122. defer m.account(folder, "DropFolder")()
  123. return m.DB.DropFolder(folder)
  124. }
  125. func (m metricsDB) DropAllIndexIDs() error {
  126. defer m.account("-", "IndexIDDropAll")()
  127. return m.DB.DropAllIndexIDs()
  128. }
  129. func (m metricsDB) ListFolders() ([]string, error) {
  130. defer m.account("-", "ListFolders")()
  131. return m.DB.ListFolders()
  132. }
  133. func (m metricsDB) GetGlobalFile(folder string, file string) (protocol.FileInfo, bool, error) {
  134. defer m.account(folder, "GetGlobalFile")()
  135. return m.DB.GetGlobalFile(folder, file)
  136. }
  137. func (m metricsDB) CountGlobal(folder string) (Counts, error) {
  138. defer m.account(folder, "CountGlobal")()
  139. return m.DB.CountGlobal(folder)
  140. }
  141. func (m metricsDB) GetIndexID(folder string, device protocol.DeviceID) (protocol.IndexID, error) {
  142. defer m.account(folder, "IndexIDGet")()
  143. return m.DB.GetIndexID(folder, device)
  144. }
  145. func (m metricsDB) GetDeviceFile(folder string, device protocol.DeviceID, file string) (protocol.FileInfo, bool, error) {
  146. defer m.account(folder, "GetDeviceFile")()
  147. return m.DB.GetDeviceFile(folder, device, file)
  148. }
  149. func (m metricsDB) CountLocal(folder string, device protocol.DeviceID) (Counts, error) {
  150. defer m.account(folder, "CountLocal")()
  151. return m.DB.CountLocal(folder, device)
  152. }
  153. func (m metricsDB) CountNeed(folder string, device protocol.DeviceID) (Counts, error) {
  154. defer m.account(folder, "CountNeed")()
  155. return m.DB.CountNeed(folder, device)
  156. }
  157. func (m metricsDB) CountReceiveOnlyChanged(folder string) (Counts, error) {
  158. defer m.account(folder, "CountReceiveOnlyChanged")()
  159. return m.DB.CountReceiveOnlyChanged(folder)
  160. }
  161. func (m metricsDB) GetDeviceSequence(folder string, device protocol.DeviceID) (int64, error) {
  162. defer m.account(folder, "GetDeviceSequence")()
  163. return m.DB.GetDeviceSequence(folder, device)
  164. }
  165. func (m metricsDB) SetIndexID(folder string, device protocol.DeviceID, id protocol.IndexID) error {
  166. defer m.account(folder, "IndexIDSet")()
  167. return m.DB.SetIndexID(folder, device, id)
  168. }
  169. func (m metricsDB) Update(folder string, device protocol.DeviceID, fs []protocol.FileInfo) error {
  170. defer m.account(folder, "Update")()
  171. defer metricTotalFilesUpdatedCount.WithLabelValues(folder).Add(float64(len(fs)))
  172. return m.DB.Update(folder, device, fs)
  173. }
  174. func (m metricsDB) GetKV(key string) ([]byte, error) {
  175. defer m.account("-", "GetKV")()
  176. return m.DB.GetKV(key)
  177. }
  178. func (m metricsDB) PutKV(key string, val []byte) error {
  179. defer m.account("-", "PutKV")()
  180. return m.DB.PutKV(key, val)
  181. }
  182. func (m metricsDB) DeleteKV(key string) error {
  183. defer m.account("-", "DeleteKV")()
  184. return m.DB.DeleteKV(key)
  185. }
  186. func (m metricsDB) PrefixKV(prefix string) (iter.Seq[KeyValue], func() error) {
  187. defer m.account("-", "PrefixKV")()
  188. return m.DB.PrefixKV(prefix)
  189. }