metrics.go 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. /*
  2. Copyright 2017 The Kubernetes Authors.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package util
  14. import (
  15. "fmt"
  16. "time"
  17. "github.com/prometheus/client_golang/prometheus"
  18. "k8s.io/kubernetes/pkg/volume"
  19. )
  20. const (
  21. statusSuccess = "success"
  22. statusFailUnknown = "fail-unknown"
  23. )
  24. var storageOperationMetric = prometheus.NewHistogramVec(
  25. prometheus.HistogramOpts{
  26. Name: "storage_operation_duration_seconds",
  27. Help: "Storage operation duration",
  28. Buckets: []float64{.1, .25, .5, 1, 2.5, 5, 10, 15, 25, 50, 120, 300, 600},
  29. },
  30. []string{"volume_plugin", "operation_name"},
  31. )
  32. var storageOperationErrorMetric = prometheus.NewCounterVec(
  33. prometheus.CounterOpts{
  34. Name: "storage_operation_errors_total",
  35. Help: "Storage operation errors",
  36. },
  37. []string{"volume_plugin", "operation_name"},
  38. )
  39. var storageOperationStatusMetric = prometheus.NewCounterVec(
  40. prometheus.CounterOpts{
  41. Name: "storage_operation_status_count",
  42. Help: "Storage operation return statuses count",
  43. },
  44. []string{"volume_plugin", "operation_name", "status"},
  45. )
  46. var storageOperationEndToEndLatencyMetric = prometheus.NewHistogramVec(
  47. prometheus.HistogramOpts{
  48. Name: "volume_operation_total_seconds",
  49. Help: "Storage operation end to end duration in seconds",
  50. Buckets: []float64{.1, .25, .5, 1, 2.5, 5, 10, 15, 25, 50, 120, 300, 600},
  51. },
  52. []string{"plugin_name", "operation_name"},
  53. )
  54. func init() {
  55. registerMetrics()
  56. }
  57. func registerMetrics() {
  58. prometheus.MustRegister(storageOperationMetric)
  59. prometheus.MustRegister(storageOperationErrorMetric)
  60. prometheus.MustRegister(storageOperationStatusMetric)
  61. prometheus.MustRegister(storageOperationEndToEndLatencyMetric)
  62. }
  63. // OperationCompleteHook returns a hook to call when an operation is completed
  64. func OperationCompleteHook(plugin, operationName string) func(*error) {
  65. requestTime := time.Now()
  66. opComplete := func(err *error) {
  67. timeTaken := time.Since(requestTime).Seconds()
  68. // Create metric with operation name and plugin name
  69. status := statusSuccess
  70. if *err != nil {
  71. // TODO: Establish well-known error codes to be able to distinguish
  72. // user configuration errors from system errors.
  73. status = statusFailUnknown
  74. storageOperationErrorMetric.WithLabelValues(plugin, operationName).Inc()
  75. } else {
  76. storageOperationMetric.WithLabelValues(plugin, operationName).Observe(timeTaken)
  77. }
  78. storageOperationStatusMetric.WithLabelValues(plugin, operationName, status).Inc()
  79. }
  80. return opComplete
  81. }
  82. // GetFullQualifiedPluginNameForVolume returns full qualified plugin name for
  83. // given volume. For CSI plugin, it appends plugin driver name at the end of
  84. // plugin name, e.g. kubernetes.io/csi:csi-hostpath. It helps to distinguish
  85. // between metrics emitted for CSI volumes which may be handled by different
  86. // CSI plugin drivers.
  87. func GetFullQualifiedPluginNameForVolume(pluginName string, spec *volume.Spec) string {
  88. if spec != nil && spec.PersistentVolume != nil && spec.PersistentVolume.Spec.CSI != nil {
  89. return fmt.Sprintf("%s:%s", pluginName, spec.PersistentVolume.Spec.CSI.Driver)
  90. }
  91. return pluginName
  92. }
  93. // RecordOperationLatencyMetric records the end to end latency for certain operation
  94. // into metric volume_operation_total_seconds
  95. func RecordOperationLatencyMetric(plugin, operationName string, secondsTaken float64) {
  96. storageOperationEndToEndLatencyMetric.WithLabelValues(plugin, operationName).Observe(secondsTaken)
  97. }