metrics.go 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  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. "k8s.io/component-base/metrics"
  18. "k8s.io/component-base/metrics/legacyregistry"
  19. "k8s.io/kubernetes/pkg/volume"
  20. )
  21. const (
  22. statusSuccess = "success"
  23. statusFailUnknown = "fail-unknown"
  24. )
  25. /*
  26. * By default, all the following metrics are defined as falling under
  27. * ALPHA stability level https://github.com/kubernetes/enhancements/blob/master/keps/sig-instrumentation/20190404-kubernetes-control-plane-metrics-stability.md#stability-classes)
  28. *
  29. * Promoting the stability level of the metric is a responsibility of the component owner, since it
  30. * involves explicitly acknowledging support for the metric across multiple releases, in accordance with
  31. * the metric stability policy.
  32. */
  33. var storageOperationMetric = metrics.NewHistogramVec(
  34. &metrics.HistogramOpts{
  35. Name: "storage_operation_duration_seconds",
  36. Help: "Storage operation duration",
  37. Buckets: []float64{.1, .25, .5, 1, 2.5, 5, 10, 15, 25, 50, 120, 300, 600},
  38. StabilityLevel: metrics.ALPHA,
  39. },
  40. []string{"volume_plugin", "operation_name"},
  41. )
  42. var storageOperationErrorMetric = metrics.NewCounterVec(
  43. &metrics.CounterOpts{
  44. Name: "storage_operation_errors_total",
  45. Help: "Storage operation errors",
  46. StabilityLevel: metrics.ALPHA,
  47. },
  48. []string{"volume_plugin", "operation_name"},
  49. )
  50. var storageOperationStatusMetric = metrics.NewCounterVec(
  51. &metrics.CounterOpts{
  52. Name: "storage_operation_status_count",
  53. Help: "Storage operation return statuses count",
  54. StabilityLevel: metrics.ALPHA,
  55. },
  56. []string{"volume_plugin", "operation_name", "status"},
  57. )
  58. var storageOperationEndToEndLatencyMetric = metrics.NewHistogramVec(
  59. &metrics.HistogramOpts{
  60. Name: "volume_operation_total_seconds",
  61. Help: "Storage operation end to end duration in seconds",
  62. Buckets: []float64{.1, .25, .5, 1, 2.5, 5, 10, 15, 25, 50, 120, 300, 600},
  63. StabilityLevel: metrics.ALPHA,
  64. },
  65. []string{"plugin_name", "operation_name"},
  66. )
  67. func init() {
  68. registerMetrics()
  69. }
  70. func registerMetrics() {
  71. // legacyregistry is the internal k8s wrapper around the prometheus
  72. // global registry, used specifically for metric stability enforcement
  73. legacyregistry.MustRegister(storageOperationMetric)
  74. legacyregistry.MustRegister(storageOperationErrorMetric)
  75. legacyregistry.MustRegister(storageOperationStatusMetric)
  76. legacyregistry.MustRegister(storageOperationEndToEndLatencyMetric)
  77. }
  78. // OperationCompleteHook returns a hook to call when an operation is completed
  79. func OperationCompleteHook(plugin, operationName string) func(*error) {
  80. requestTime := time.Now()
  81. opComplete := func(err *error) {
  82. timeTaken := time.Since(requestTime).Seconds()
  83. // Create metric with operation name and plugin name
  84. status := statusSuccess
  85. if *err != nil {
  86. // TODO: Establish well-known error codes to be able to distinguish
  87. // user configuration errors from system errors.
  88. status = statusFailUnknown
  89. storageOperationErrorMetric.WithLabelValues(plugin, operationName).Inc()
  90. } else {
  91. storageOperationMetric.WithLabelValues(plugin, operationName).Observe(timeTaken)
  92. }
  93. storageOperationStatusMetric.WithLabelValues(plugin, operationName, status).Inc()
  94. }
  95. return opComplete
  96. }
  97. // GetFullQualifiedPluginNameForVolume returns full qualified plugin name for
  98. // given volume. For CSI plugin, it appends plugin driver name at the end of
  99. // plugin name, e.g. kubernetes.io/csi:csi-hostpath. It helps to distinguish
  100. // between metrics emitted for CSI volumes which may be handled by different
  101. // CSI plugin drivers.
  102. func GetFullQualifiedPluginNameForVolume(pluginName string, spec *volume.Spec) string {
  103. if spec != nil && spec.PersistentVolume != nil && spec.PersistentVolume.Spec.CSI != nil {
  104. return fmt.Sprintf("%s:%s", pluginName, spec.PersistentVolume.Spec.CSI.Driver)
  105. }
  106. return pluginName
  107. }
  108. // RecordOperationLatencyMetric records the end to end latency for certain operation
  109. // into metric volume_operation_total_seconds
  110. func RecordOperationLatencyMetric(plugin, operationName string, secondsTaken float64) {
  111. storageOperationEndToEndLatencyMetric.WithLabelValues(plugin, operationName).Observe(secondsTaken)
  112. }