From 6de73971a0da45e2d418299342d9f7e6a358281b Mon Sep 17 00:00:00 2001
From: Adam Boguszewski <108867528+aboguszewski-sumo@users.noreply.github.com>
Date: Thu, 3 Nov 2022 14:42:04 +0100
Subject: [PATCH] [receiver/elasticsearch]: add metrics related to GET
operations (#14793)
feat: add metrics related to GET operations
---
.chloggen/elasticsearch-receiver-get-ops.yaml | 5 +
.../elasticsearchreceiver/documentation.md | 3 +
.../internal/metadata/generated_metrics.go | 156 ++++++++++++++++++
.../internal/model/nodestats.go | 8 +-
receiver/elasticsearchreceiver/metadata.yaml | 24 +++
receiver/elasticsearchreceiver/scraper.go | 6 +
.../elasticsearchreceiver/scraper_test.go | 4 +
.../testdata/expected_metrics/full.json | 74 +++++++++
8 files changed, 278 insertions(+), 2 deletions(-)
create mode 100644 .chloggen/elasticsearch-receiver-get-ops.yaml
diff --git a/.chloggen/elasticsearch-receiver-get-ops.yaml b/.chloggen/elasticsearch-receiver-get-ops.yaml
new file mode 100644
index 000000000000..cd18eecd4347
--- /dev/null
+++ b/.chloggen/elasticsearch-receiver-get-ops.yaml
@@ -0,0 +1,5 @@
+change_type: enhancement
+component: elasticsearchreceiver
+note: Add metrics related to GET operations
+issues: [14635]
+
diff --git a/receiver/elasticsearchreceiver/documentation.md b/receiver/elasticsearchreceiver/documentation.md
index f9e5c2dd25f0..44531f17b6a5 100644
--- a/receiver/elasticsearchreceiver/documentation.md
+++ b/receiver/elasticsearchreceiver/documentation.md
@@ -53,6 +53,8 @@ These are the metrics available for this scraper.
| **elasticsearch.node.ingest.operations.failed** | Total number of failed ingest operations during the lifetime of this node. | {operation} | Sum(Int) |
|
| **elasticsearch.node.open_files** | The number of open file descriptors held by the node. | {files} | Sum(Int) | |
| **elasticsearch.node.operations.completed** | The number of operations completed by a node. | {operations} | Sum(Int) | |
+| elasticsearch.node.operations.get.completed | The number of hits and misses resulting from GET operations. | {operations} | Sum(Int) | |
+| elasticsearch.node.operations.get.time | The time spent on hits and misses resulting from GET operations. | ms | Sum(Int) | |
| **elasticsearch.node.operations.time** | Time spent on operations by a node. | ms | Sum(Int) | |
| **elasticsearch.node.pipeline.ingest.documents.current** | Total number of documents currently being ingested by a pipeline. | {documents} | Sum(Int) | |
| **elasticsearch.node.pipeline.ingest.documents.preprocessed** | Number of documents preprocessed by the ingest pipeline. | {documents} | Sum(Int) | |
@@ -117,6 +119,7 @@ metrics:
| direction | The direction of network data. | received, sent |
| document_state (state) | The state of the document. | active, deleted |
| fs_direction (direction) | The direction of filesystem IO. | read, write |
+| get_result (result) | Result of get operation | hit, miss |
| health_status (status) | The health status of the cluster. | green, yellow, red |
| index_aggregation_type (aggregation) | Type of shard aggregation for index statistics | primary_shards, total |
| indexing_memory_state (state) | State of the indexing memory | current, total |
diff --git a/receiver/elasticsearchreceiver/internal/metadata/generated_metrics.go b/receiver/elasticsearchreceiver/internal/metadata/generated_metrics.go
index 06305b8121fb..c56008200be4 100644
--- a/receiver/elasticsearchreceiver/internal/metadata/generated_metrics.go
+++ b/receiver/elasticsearchreceiver/internal/metadata/generated_metrics.go
@@ -82,6 +82,8 @@ type MetricsSettings struct {
ElasticsearchNodeIngestOperationsFailed MetricSettings `mapstructure:"elasticsearch.node.ingest.operations.failed"`
ElasticsearchNodeOpenFiles MetricSettings `mapstructure:"elasticsearch.node.open_files"`
ElasticsearchNodeOperationsCompleted MetricSettings `mapstructure:"elasticsearch.node.operations.completed"`
+ ElasticsearchNodeOperationsGetCompleted MetricSettings `mapstructure:"elasticsearch.node.operations.get.completed"`
+ ElasticsearchNodeOperationsGetTime MetricSettings `mapstructure:"elasticsearch.node.operations.get.time"`
ElasticsearchNodeOperationsTime MetricSettings `mapstructure:"elasticsearch.node.operations.time"`
ElasticsearchNodePipelineIngestDocumentsCurrent MetricSettings `mapstructure:"elasticsearch.node.pipeline.ingest.documents.current"`
ElasticsearchNodePipelineIngestDocumentsPreprocessed MetricSettings `mapstructure:"elasticsearch.node.pipeline.ingest.documents.preprocessed"`
@@ -253,6 +255,12 @@ func DefaultMetricsSettings() MetricsSettings {
ElasticsearchNodeOperationsCompleted: MetricSettings{
Enabled: true,
},
+ ElasticsearchNodeOperationsGetCompleted: MetricSettings{
+ Enabled: false,
+ },
+ ElasticsearchNodeOperationsGetTime: MetricSettings{
+ Enabled: false,
+ },
ElasticsearchNodeOperationsTime: MetricSettings{
Enabled: true,
},
@@ -550,6 +558,32 @@ var MapAttributeFsDirection = map[string]AttributeFsDirection{
"write": AttributeFsDirectionWrite,
}
+// AttributeGetResult specifies the a value get_result attribute.
+type AttributeGetResult int
+
+const (
+ _ AttributeGetResult = iota
+ AttributeGetResultHit
+ AttributeGetResultMiss
+)
+
+// String returns the string representation of the AttributeGetResult.
+func (av AttributeGetResult) String() string {
+ switch av {
+ case AttributeGetResultHit:
+ return "hit"
+ case AttributeGetResultMiss:
+ return "miss"
+ }
+ return ""
+}
+
+// MapAttributeGetResult is a helper map of string to AttributeGetResult attribute value.
+var MapAttributeGetResult = map[string]AttributeGetResult{
+ "hit": AttributeGetResultHit,
+ "miss": AttributeGetResultMiss,
+}
+
// AttributeHealthStatus specifies the a value health_status attribute.
type AttributeHealthStatus int
@@ -3243,6 +3277,112 @@ func newMetricElasticsearchNodeOperationsCompleted(settings MetricSettings) metr
return m
}
+type metricElasticsearchNodeOperationsGetCompleted struct {
+ data pmetric.Metric // data buffer for generated metric.
+ settings MetricSettings // metric settings provided by user.
+ capacity int // max observed number of data points added to the metric.
+}
+
+// init fills elasticsearch.node.operations.get.completed metric with initial data.
+func (m *metricElasticsearchNodeOperationsGetCompleted) init() {
+ m.data.SetName("elasticsearch.node.operations.get.completed")
+ m.data.SetDescription("The number of hits and misses resulting from GET operations.")
+ m.data.SetUnit("{operations}")
+ m.data.SetEmptySum()
+ m.data.Sum().SetIsMonotonic(true)
+ m.data.Sum().SetAggregationTemporality(pmetric.AggregationTemporalityCumulative)
+ m.data.Sum().DataPoints().EnsureCapacity(m.capacity)
+}
+
+func (m *metricElasticsearchNodeOperationsGetCompleted) recordDataPoint(start pcommon.Timestamp, ts pcommon.Timestamp, val int64, getResultAttributeValue string) {
+ if !m.settings.Enabled {
+ return
+ }
+ dp := m.data.Sum().DataPoints().AppendEmpty()
+ dp.SetStartTimestamp(start)
+ dp.SetTimestamp(ts)
+ dp.SetIntValue(val)
+ dp.Attributes().PutStr("result", getResultAttributeValue)
+}
+
+// updateCapacity saves max length of data point slices that will be used for the slice capacity.
+func (m *metricElasticsearchNodeOperationsGetCompleted) updateCapacity() {
+ if m.data.Sum().DataPoints().Len() > m.capacity {
+ m.capacity = m.data.Sum().DataPoints().Len()
+ }
+}
+
+// emit appends recorded metric data to a metrics slice and prepares it for recording another set of data points.
+func (m *metricElasticsearchNodeOperationsGetCompleted) emit(metrics pmetric.MetricSlice) {
+ if m.settings.Enabled && m.data.Sum().DataPoints().Len() > 0 {
+ m.updateCapacity()
+ m.data.MoveTo(metrics.AppendEmpty())
+ m.init()
+ }
+}
+
+func newMetricElasticsearchNodeOperationsGetCompleted(settings MetricSettings) metricElasticsearchNodeOperationsGetCompleted {
+ m := metricElasticsearchNodeOperationsGetCompleted{settings: settings}
+ if settings.Enabled {
+ m.data = pmetric.NewMetric()
+ m.init()
+ }
+ return m
+}
+
+type metricElasticsearchNodeOperationsGetTime struct {
+ data pmetric.Metric // data buffer for generated metric.
+ settings MetricSettings // metric settings provided by user.
+ capacity int // max observed number of data points added to the metric.
+}
+
+// init fills elasticsearch.node.operations.get.time metric with initial data.
+func (m *metricElasticsearchNodeOperationsGetTime) init() {
+ m.data.SetName("elasticsearch.node.operations.get.time")
+ m.data.SetDescription("The time spent on hits and misses resulting from GET operations.")
+ m.data.SetUnit("ms")
+ m.data.SetEmptySum()
+ m.data.Sum().SetIsMonotonic(true)
+ m.data.Sum().SetAggregationTemporality(pmetric.AggregationTemporalityCumulative)
+ m.data.Sum().DataPoints().EnsureCapacity(m.capacity)
+}
+
+func (m *metricElasticsearchNodeOperationsGetTime) recordDataPoint(start pcommon.Timestamp, ts pcommon.Timestamp, val int64, getResultAttributeValue string) {
+ if !m.settings.Enabled {
+ return
+ }
+ dp := m.data.Sum().DataPoints().AppendEmpty()
+ dp.SetStartTimestamp(start)
+ dp.SetTimestamp(ts)
+ dp.SetIntValue(val)
+ dp.Attributes().PutStr("result", getResultAttributeValue)
+}
+
+// updateCapacity saves max length of data point slices that will be used for the slice capacity.
+func (m *metricElasticsearchNodeOperationsGetTime) updateCapacity() {
+ if m.data.Sum().DataPoints().Len() > m.capacity {
+ m.capacity = m.data.Sum().DataPoints().Len()
+ }
+}
+
+// emit appends recorded metric data to a metrics slice and prepares it for recording another set of data points.
+func (m *metricElasticsearchNodeOperationsGetTime) emit(metrics pmetric.MetricSlice) {
+ if m.settings.Enabled && m.data.Sum().DataPoints().Len() > 0 {
+ m.updateCapacity()
+ m.data.MoveTo(metrics.AppendEmpty())
+ m.init()
+ }
+}
+
+func newMetricElasticsearchNodeOperationsGetTime(settings MetricSettings) metricElasticsearchNodeOperationsGetTime {
+ m := metricElasticsearchNodeOperationsGetTime{settings: settings}
+ if settings.Enabled {
+ m.data = pmetric.NewMetric()
+ m.init()
+ }
+ return m
+}
+
type metricElasticsearchNodeOperationsTime struct {
data pmetric.Metric // data buffer for generated metric.
settings MetricSettings // metric settings provided by user.
@@ -4926,6 +5066,8 @@ type MetricsBuilder struct {
metricElasticsearchNodeIngestOperationsFailed metricElasticsearchNodeIngestOperationsFailed
metricElasticsearchNodeOpenFiles metricElasticsearchNodeOpenFiles
metricElasticsearchNodeOperationsCompleted metricElasticsearchNodeOperationsCompleted
+ metricElasticsearchNodeOperationsGetCompleted metricElasticsearchNodeOperationsGetCompleted
+ metricElasticsearchNodeOperationsGetTime metricElasticsearchNodeOperationsGetTime
metricElasticsearchNodeOperationsTime metricElasticsearchNodeOperationsTime
metricElasticsearchNodePipelineIngestDocumentsCurrent metricElasticsearchNodePipelineIngestDocumentsCurrent
metricElasticsearchNodePipelineIngestDocumentsPreprocessed metricElasticsearchNodePipelineIngestDocumentsPreprocessed
@@ -5020,6 +5162,8 @@ func NewMetricsBuilder(settings MetricsSettings, buildInfo component.BuildInfo,
metricElasticsearchNodeIngestOperationsFailed: newMetricElasticsearchNodeIngestOperationsFailed(settings.ElasticsearchNodeIngestOperationsFailed),
metricElasticsearchNodeOpenFiles: newMetricElasticsearchNodeOpenFiles(settings.ElasticsearchNodeOpenFiles),
metricElasticsearchNodeOperationsCompleted: newMetricElasticsearchNodeOperationsCompleted(settings.ElasticsearchNodeOperationsCompleted),
+ metricElasticsearchNodeOperationsGetCompleted: newMetricElasticsearchNodeOperationsGetCompleted(settings.ElasticsearchNodeOperationsGetCompleted),
+ metricElasticsearchNodeOperationsGetTime: newMetricElasticsearchNodeOperationsGetTime(settings.ElasticsearchNodeOperationsGetTime),
metricElasticsearchNodeOperationsTime: newMetricElasticsearchNodeOperationsTime(settings.ElasticsearchNodeOperationsTime),
metricElasticsearchNodePipelineIngestDocumentsCurrent: newMetricElasticsearchNodePipelineIngestDocumentsCurrent(settings.ElasticsearchNodePipelineIngestDocumentsCurrent),
metricElasticsearchNodePipelineIngestDocumentsPreprocessed: newMetricElasticsearchNodePipelineIngestDocumentsPreprocessed(settings.ElasticsearchNodePipelineIngestDocumentsPreprocessed),
@@ -5170,6 +5314,8 @@ func (mb *MetricsBuilder) EmitForResource(rmo ...ResourceMetricsOption) {
mb.metricElasticsearchNodeIngestOperationsFailed.emit(ils.Metrics())
mb.metricElasticsearchNodeOpenFiles.emit(ils.Metrics())
mb.metricElasticsearchNodeOperationsCompleted.emit(ils.Metrics())
+ mb.metricElasticsearchNodeOperationsGetCompleted.emit(ils.Metrics())
+ mb.metricElasticsearchNodeOperationsGetTime.emit(ils.Metrics())
mb.metricElasticsearchNodeOperationsTime.emit(ils.Metrics())
mb.metricElasticsearchNodePipelineIngestDocumentsCurrent.emit(ils.Metrics())
mb.metricElasticsearchNodePipelineIngestDocumentsPreprocessed.emit(ils.Metrics())
@@ -5446,6 +5592,16 @@ func (mb *MetricsBuilder) RecordElasticsearchNodeOperationsCompletedDataPoint(ts
mb.metricElasticsearchNodeOperationsCompleted.recordDataPoint(mb.startTime, ts, val, operationAttributeValue.String())
}
+// RecordElasticsearchNodeOperationsGetCompletedDataPoint adds a data point to elasticsearch.node.operations.get.completed metric.
+func (mb *MetricsBuilder) RecordElasticsearchNodeOperationsGetCompletedDataPoint(ts pcommon.Timestamp, val int64, getResultAttributeValue AttributeGetResult) {
+ mb.metricElasticsearchNodeOperationsGetCompleted.recordDataPoint(mb.startTime, ts, val, getResultAttributeValue.String())
+}
+
+// RecordElasticsearchNodeOperationsGetTimeDataPoint adds a data point to elasticsearch.node.operations.get.time metric.
+func (mb *MetricsBuilder) RecordElasticsearchNodeOperationsGetTimeDataPoint(ts pcommon.Timestamp, val int64, getResultAttributeValue AttributeGetResult) {
+ mb.metricElasticsearchNodeOperationsGetTime.recordDataPoint(mb.startTime, ts, val, getResultAttributeValue.String())
+}
+
// RecordElasticsearchNodeOperationsTimeDataPoint adds a data point to elasticsearch.node.operations.time metric.
func (mb *MetricsBuilder) RecordElasticsearchNodeOperationsTimeDataPoint(ts pcommon.Timestamp, val int64, operationAttributeValue AttributeOperation) {
mb.metricElasticsearchNodeOperationsTime.recordDataPoint(mb.startTime, ts, val, operationAttributeValue.String())
diff --git a/receiver/elasticsearchreceiver/internal/model/nodestats.go b/receiver/elasticsearchreceiver/internal/model/nodestats.go
index 31ad85d2f92a..c2923eaede37 100644
--- a/receiver/elasticsearchreceiver/internal/model/nodestats.go
+++ b/receiver/elasticsearchreceiver/internal/model/nodestats.go
@@ -219,8 +219,12 @@ type IndexingOperations struct {
}
type GetOperation struct {
- Total int64 `json:"total"`
- TotalTimeInMs int64 `json:"time_in_millis"`
+ Total int64 `json:"total"`
+ TotalTimeInMs int64 `json:"time_in_millis"`
+ Exists int64 `json:"exists_total"`
+ ExistsTimeInMs int64 `json:"exists_time_in_millis"`
+ Missing int64 `json:"missing_total"`
+ MissingTimeInMs int64 `json:"missing_time_in_millis"`
}
type SearchOperations struct {
diff --git a/receiver/elasticsearchreceiver/metadata.yaml b/receiver/elasticsearchreceiver/metadata.yaml
index 606f6861d304..7533fb1b0b27 100644
--- a/receiver/elasticsearchreceiver/metadata.yaml
+++ b/receiver/elasticsearchreceiver/metadata.yaml
@@ -154,6 +154,12 @@ attributes:
- doc_value
- index_writer
- fixed_bit_set
+ get_result:
+ value: result
+ description: Result of get operation
+ enum:
+ - hit
+ - miss
metrics:
# these metrics are from /_nodes/stats, and are node level metrics
@@ -309,6 +315,24 @@ metrics:
value_type: int
attributes: [operation]
enabled: true
+ elasticsearch.node.operations.get.completed:
+ description: The number of hits and misses resulting from GET operations.
+ unit: "{operations}"
+ sum:
+ monotonic: true
+ aggregation: cumulative
+ value_type: int
+ attributes: [get_result]
+ enabled: false
+ elasticsearch.node.operations.get.time:
+ description: The time spent on hits and misses resulting from GET operations.
+ unit: ms
+ sum:
+ monotonic: true
+ aggregation: cumulative
+ value_type: int
+ attributes: [get_result]
+ enabled: false
elasticsearch.node.shards.size:
description: The size of the shards assigned to this node.
unit: By
diff --git a/receiver/elasticsearchreceiver/scraper.go b/receiver/elasticsearchreceiver/scraper.go
index 562381c29650..066d0de11326 100644
--- a/receiver/elasticsearchreceiver/scraper.go
+++ b/receiver/elasticsearchreceiver/scraper.go
@@ -160,6 +160,12 @@ func (r *elasticsearchScraper) scrapeNodeMetrics(ctx context.Context, now pcommo
r.mb.RecordElasticsearchNodeOperationsTimeDataPoint(now, info.Indices.FlushOperations.TotalTimeInMs, metadata.AttributeOperationFlush)
r.mb.RecordElasticsearchNodeOperationsTimeDataPoint(now, info.Indices.WarmerOperations.TotalTimeInMs, metadata.AttributeOperationWarmer)
+ r.mb.RecordElasticsearchNodeOperationsGetCompletedDataPoint(now, info.Indices.GetOperation.Exists, metadata.AttributeGetResultHit)
+ r.mb.RecordElasticsearchNodeOperationsGetCompletedDataPoint(now, info.Indices.GetOperation.Missing, metadata.AttributeGetResultMiss)
+
+ r.mb.RecordElasticsearchNodeOperationsGetTimeDataPoint(now, info.Indices.GetOperation.ExistsTimeInMs, metadata.AttributeGetResultHit)
+ r.mb.RecordElasticsearchNodeOperationsGetTimeDataPoint(now, info.Indices.GetOperation.MissingTimeInMs, metadata.AttributeGetResultMiss)
+
r.mb.RecordElasticsearchNodeShardsSizeDataPoint(now, info.Indices.StoreInfo.SizeInBy)
// Elasticsearch version 7.13+ is required to collect `elasticsearch.node.shards.data_set.size`.
diff --git a/receiver/elasticsearchreceiver/scraper_test.go b/receiver/elasticsearchreceiver/scraper_test.go
index b0613c35ac5a..d042911937b4 100644
--- a/receiver/elasticsearchreceiver/scraper_test.go
+++ b/receiver/elasticsearchreceiver/scraper_test.go
@@ -42,6 +42,10 @@ func TestScraper(t *testing.T) {
t.Parallel()
config := createDefaultConfig().(*Config)
+
+ config.Metrics.ElasticsearchNodeOperationsGetCompleted.Enabled = true
+ config.Metrics.ElasticsearchNodeOperationsGetTime.Enabled = true
+
config.Metrics.ElasticsearchIndexOperationsMergeSize.Enabled = true
config.Metrics.ElasticsearchIndexOperationsMergeDocsCount.Enabled = true
config.Metrics.ElasticsearchIndexSegmentsCount.Enabled = true
diff --git a/receiver/elasticsearchreceiver/testdata/expected_metrics/full.json b/receiver/elasticsearchreceiver/testdata/expected_metrics/full.json
index 78dcd37e4253..8bf38acd241c 100644
--- a/receiver/elasticsearchreceiver/testdata/expected_metrics/full.json
+++ b/receiver/elasticsearchreceiver/testdata/expected_metrics/full.json
@@ -1450,6 +1450,80 @@
},
"unit": "ms"
},
+ {
+ "description": "The number of hits and misses resulting from GET operations.",
+ "sum": {
+ "aggregationTemporality": "AGGREGATION_TEMPORALITY_CUMULATIVE",
+ "dataPoints": [
+ {
+ "asInt": "512",
+ "attributes": [
+ {
+ "key": "result",
+ "value": {
+ "stringValue": "hit"
+ }
+ }
+ ],
+ "startTimeUnixNano": "1661811026803971000",
+ "timeUnixNano": "1661811026805343000"
+ },
+ {
+ "asInt": "512",
+ "attributes": [
+ {
+ "key": "result",
+ "value": {
+ "stringValue": "miss"
+ }
+ }
+ ],
+ "startTimeUnixNano": "1661811026803971000",
+ "timeUnixNano": "1661811026805343000"
+ }
+ ],
+ "isMonotonic": true
+ },
+ "name": "elasticsearch.node.operations.get.completed",
+ "unit": "{operations}"
+ },
+ {
+ "description": "The time spent on hits and misses resulting from GET operations.",
+ "sum": {
+ "aggregationTemporality": "AGGREGATION_TEMPORALITY_CUMULATIVE",
+ "dataPoints": [
+ {
+ "asInt": "209",
+ "attributes": [
+ {
+ "key": "result",
+ "value": {
+ "stringValue": "hit"
+ }
+ }
+ ],
+ "startTimeUnixNano": "1661811026803971000",
+ "timeUnixNano": "1661811026805343000"
+ },
+ {
+ "asInt": "124",
+ "attributes": [
+ {
+ "key": "result",
+ "value": {
+ "stringValue": "miss"
+ }
+ }
+ ],
+ "startTimeUnixNano": "1661811026803971000",
+ "timeUnixNano": "1661811026805343000"
+ }
+ ],
+ "isMonotonic": true
+ },
+ "name": "elasticsearch.node.operations.get.time",
+ "unit": "ms"
+ },
{
"description": "Total number of documents currently being ingested by a pipeline.",
"name": "elasticsearch.node.pipeline.ingest.documents.current",