util.go 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. // Copyright The OpenTelemetry Authors
  2. // SPDX-License-Identifier: Apache-2.0
  3. package internal // import "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/prometheusreceiver/internal"
  4. import (
  5. "errors"
  6. "sort"
  7. "strconv"
  8. "strings"
  9. "github.com/prometheus/common/model"
  10. "github.com/prometheus/prometheus/model/labels"
  11. "github.com/prometheus/prometheus/model/textparse"
  12. "go.opentelemetry.io/collector/pdata/pcommon"
  13. "go.opentelemetry.io/collector/pdata/pmetric"
  14. )
  15. const (
  16. metricsSuffixCount = "_count"
  17. metricsSuffixBucket = "_bucket"
  18. metricsSuffixSum = "_sum"
  19. metricSuffixTotal = "_total"
  20. metricSuffixInfo = "_info"
  21. metricSuffixCreated = "_created"
  22. startTimeMetricName = "process_start_time_seconds"
  23. scrapeUpMetricName = "up"
  24. transport = "http"
  25. dataformat = "prometheus"
  26. )
  27. var (
  28. trimmableSuffixes = []string{metricsSuffixBucket, metricsSuffixCount, metricsSuffixSum, metricSuffixTotal, metricSuffixInfo, metricSuffixCreated}
  29. errNoDataToBuild = errors.New("there's no data to build")
  30. errNoBoundaryLabel = errors.New("given metricType has no 'le' or 'quantile' label")
  31. errEmptyQuantileLabel = errors.New("'quantile' label on summary metric is missing or empty")
  32. errEmptyLeLabel = errors.New("'le' label on histogram metric is missing or empty")
  33. errMetricNameNotFound = errors.New("metricName not found from labels")
  34. errTransactionAborted = errors.New("transaction aborted")
  35. errNoJobInstance = errors.New("job or instance cannot be found from labels")
  36. notUsefulLabelsHistogram = sortString([]string{model.MetricNameLabel, model.InstanceLabel, model.SchemeLabel, model.MetricsPathLabel, model.JobLabel, model.BucketLabel})
  37. notUsefulLabelsSummary = sortString([]string{model.MetricNameLabel, model.InstanceLabel, model.SchemeLabel, model.MetricsPathLabel, model.JobLabel, model.QuantileLabel})
  38. notUsefulLabelsOther = sortString([]string{model.MetricNameLabel, model.InstanceLabel, model.SchemeLabel, model.MetricsPathLabel, model.JobLabel})
  39. )
  40. func sortString(strs []string) []string {
  41. sort.Strings(strs)
  42. return strs
  43. }
  44. func getSortedNotUsefulLabels(mType pmetric.MetricType) []string {
  45. switch mType {
  46. case pmetric.MetricTypeHistogram:
  47. return notUsefulLabelsHistogram
  48. case pmetric.MetricTypeSummary:
  49. return notUsefulLabelsSummary
  50. case pmetric.MetricTypeEmpty, pmetric.MetricTypeGauge, pmetric.MetricTypeSum, pmetric.MetricTypeExponentialHistogram:
  51. fallthrough
  52. default:
  53. return notUsefulLabelsOther
  54. }
  55. }
  56. func timestampFromFloat64(ts float64) pcommon.Timestamp {
  57. secs := int64(ts)
  58. nanos := int64((ts - float64(secs)) * 1e9)
  59. return pcommon.Timestamp(secs*1e9 + nanos)
  60. }
  61. func timestampFromMs(timeAtMs int64) pcommon.Timestamp {
  62. return pcommon.Timestamp(timeAtMs * 1e6)
  63. }
  64. func getBoundary(metricType pmetric.MetricType, labels labels.Labels) (float64, error) {
  65. var val string
  66. switch metricType {
  67. case pmetric.MetricTypeHistogram:
  68. val = labels.Get(model.BucketLabel)
  69. if val == "" {
  70. return 0, errEmptyLeLabel
  71. }
  72. case pmetric.MetricTypeSummary:
  73. val = labels.Get(model.QuantileLabel)
  74. if val == "" {
  75. return 0, errEmptyQuantileLabel
  76. }
  77. case pmetric.MetricTypeEmpty, pmetric.MetricTypeGauge, pmetric.MetricTypeSum, pmetric.MetricTypeExponentialHistogram:
  78. fallthrough
  79. default:
  80. return 0, errNoBoundaryLabel
  81. }
  82. return strconv.ParseFloat(val, 64)
  83. }
  84. // convToMetricType returns the data type and if it is monotonic
  85. func convToMetricType(metricType textparse.MetricType) (pmetric.MetricType, bool) {
  86. switch metricType {
  87. case textparse.MetricTypeCounter:
  88. // always use float64, as it's the internal data type used in prometheus
  89. return pmetric.MetricTypeSum, true
  90. // textparse.MetricTypeUnknown is converted to gauge by default to prevent Prometheus untyped metrics from being dropped
  91. case textparse.MetricTypeGauge, textparse.MetricTypeUnknown:
  92. return pmetric.MetricTypeGauge, false
  93. case textparse.MetricTypeHistogram:
  94. return pmetric.MetricTypeHistogram, true
  95. // dropping support for gaugehistogram for now until we have an official spec of its implementation
  96. // a draft can be found in: https://docs.google.com/document/d/1KwV0mAXwwbvvifBvDKH_LU1YjyXE_wxCkHNoCGq1GX0/edit#heading=h.1cvzqd4ksd23
  97. // case textparse.MetricTypeGaugeHistogram:
  98. // return <pdata gauge histogram type>
  99. case textparse.MetricTypeSummary:
  100. return pmetric.MetricTypeSummary, true
  101. case textparse.MetricTypeInfo, textparse.MetricTypeStateset:
  102. return pmetric.MetricTypeSum, false
  103. case textparse.MetricTypeGaugeHistogram:
  104. fallthrough
  105. default:
  106. // including: textparse.MetricTypeGaugeHistogram
  107. return pmetric.MetricTypeEmpty, false
  108. }
  109. }
  110. func normalizeMetricName(name string) string {
  111. for _, s := range trimmableSuffixes {
  112. if strings.HasSuffix(name, s) && name != s {
  113. return strings.TrimSuffix(name, s)
  114. }
  115. }
  116. return name
  117. }