diff --git a/receiver/zookeeperreceiver/README.md b/receiver/zookeeperreceiver/README.md
index 399382f44c9f..a7ef25837d94 100644
--- a/receiver/zookeeperreceiver/README.md
+++ b/receiver/zookeeperreceiver/README.md
@@ -23,5 +23,48 @@ receivers:
collection_interval: 20s
```
+## Metrics
+
+Details about the metrics produced by this receiver can be found in [metadata.yaml](./metadata.yaml) with further documentation in [documentation.md](./documentation.md)
+
+### Feature gate configurations
+
+#### Transition from metrics with "direction" attribute
+
+Some zookeeper metrics reported are transitioning from being reported with
+ a `direction` attribute to being reported with the
+direction included in the metric name to adhere to the OpenTelemetry specification
+(https://github.com/open-telemetry/opentelemetry-specification/pull/2617):
+
+- `zookeeper.packet.count` will become:
+ - `zookeeper.packet.received.count`
+ - `zookeeper.packet.sent.count`
+
+The following feature gates control the transition process:
+
+- **receiver.zookeeperreceiver.emitMetricsWithoutDirectionAttribute**: controls if the new metrics without `direction` attribute are emitted by the receiver.
+- **receiver.zookeeperreceiver.emitMetricsWithDirectionAttribute**: controls if the deprecated metrics with `direction` attribute are emitted by the receiver.
+
+##### Transition schedule:
+
+1. v0.57.0, July 2022:
+
+- The new metrics are available for all scrapers, but disabled by default, they can be enabled with the feature gates.
+- The old metrics with `direction` attribute are deprecated with a warning.
+- `receiver.zookeeperreceiver.emitMetricsWithDirectionAttribute` is enabled by default.
+- `receiver.zookeeperreceiver.emitMetricsWithoutDirectionAttribute` is disabled by default.
+
+2. v0.58.0, August 2022:
+
+- The new metrics are enabled by default, deprecated metrics disabled, they can be enabled with the feature gates.
+- `receiver.zookeeperreceiver.emitMetricsWithDirectionAttribute` is disabled by default.
+- `receiver.zookeeperreceiver.emitMetricsWithoutDirectionAttribute` is enabled by default.
+
+3. v0.60.0, September 2022:
+
+- The feature gates are removed.
+- The new metrics without `direction` attribute are always emitted.
+- The deprecated metrics with `direction` attribute are no longer available.
+
[in development]: https://github.com/open-telemetry/opentelemetry-collector#in-development
-[contrib]: https://github.com/open-telemetry/opentelemetry-collector-releases/tree/main/distributions/otelcol-contrib
\ No newline at end of file
+[contrib]: https://github.com/open-telemetry/opentelemetry-collector-releases/tree/main/distributions/otelcol-contrib
diff --git a/receiver/zookeeperreceiver/documentation.md b/receiver/zookeeperreceiver/documentation.md
index 9a70a8c9c12f..a1ccf19b0198 100644
--- a/receiver/zookeeperreceiver/documentation.md
+++ b/receiver/zookeeperreceiver/documentation.md
@@ -19,6 +19,8 @@ These are the metrics available for this scraper.
| **zookeeper.latency.max** | Maximum time in milliseconds for requests to be processed. | ms | Gauge(Int) |
|
| **zookeeper.latency.min** | Minimum time in milliseconds for requests to be processed. | ms | Gauge(Int) | |
| **zookeeper.packet.count** | The number of ZooKeeper packets received or sent by a server. | {packets} | Sum(Int) | |
+| **zookeeper.packet.received.count** | The number of ZooKeeper packets received by a server. | {packets} | Sum(Int) | |
+| **zookeeper.packet.sent.count** | The number of ZooKeeper packets sent by a server. | {packets} | Sum(Int) | |
| **zookeeper.request.active** | Number of currently executing requests. | {requests} | Sum(Int) | |
| **zookeeper.sync.pending** | The number of pending syncs from the followers. Only exposed by the leader. | {syncs} | Sum(Int) | |
| **zookeeper.watch.count** | Number of watches placed on Z-Nodes on a ZooKeeper server. | {watches} | Sum(Int) | |
diff --git a/receiver/zookeeperreceiver/internal/metadata/generated_metrics_v2.go b/receiver/zookeeperreceiver/internal/metadata/generated_metrics_v2.go
index 89cf0d643e9b..95299c835c24 100644
--- a/receiver/zookeeperreceiver/internal/metadata/generated_metrics_v2.go
+++ b/receiver/zookeeperreceiver/internal/metadata/generated_metrics_v2.go
@@ -28,6 +28,8 @@ type MetricsSettings struct {
ZookeeperLatencyMax MetricSettings `mapstructure:"zookeeper.latency.max"`
ZookeeperLatencyMin MetricSettings `mapstructure:"zookeeper.latency.min"`
ZookeeperPacketCount MetricSettings `mapstructure:"zookeeper.packet.count"`
+ ZookeeperPacketReceivedCount MetricSettings `mapstructure:"zookeeper.packet.received.count"`
+ ZookeeperPacketSentCount MetricSettings `mapstructure:"zookeeper.packet.sent.count"`
ZookeeperRequestActive MetricSettings `mapstructure:"zookeeper.request.active"`
ZookeeperSyncPending MetricSettings `mapstructure:"zookeeper.sync.pending"`
ZookeeperWatchCount MetricSettings `mapstructure:"zookeeper.watch.count"`
@@ -69,6 +71,12 @@ func DefaultMetricsSettings() MetricsSettings {
ZookeeperPacketCount: MetricSettings{
Enabled: true,
},
+ ZookeeperPacketReceivedCount: MetricSettings{
+ Enabled: true,
+ },
+ ZookeeperPacketSentCount: MetricSettings{
+ Enabled: true,
+ },
ZookeeperRequestActive: MetricSettings{
Enabled: true,
},
@@ -693,6 +701,108 @@ func newMetricZookeeperPacketCount(settings MetricSettings) metricZookeeperPacke
return m
}
+type metricZookeeperPacketReceivedCount 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 zookeeper.packet.received.count metric with initial data.
+func (m *metricZookeeperPacketReceivedCount) init() {
+ m.data.SetName("zookeeper.packet.received.count")
+ m.data.SetDescription("The number of ZooKeeper packets received by a server.")
+ m.data.SetUnit("{packets}")
+ m.data.SetDataType(pmetric.MetricDataTypeSum)
+ m.data.Sum().SetIsMonotonic(true)
+ m.data.Sum().SetAggregationTemporality(pmetric.MetricAggregationTemporalityCumulative)
+}
+
+func (m *metricZookeeperPacketReceivedCount) recordDataPoint(start pcommon.Timestamp, ts pcommon.Timestamp, val int64) {
+ if !m.settings.Enabled {
+ return
+ }
+ dp := m.data.Sum().DataPoints().AppendEmpty()
+ dp.SetStartTimestamp(start)
+ dp.SetTimestamp(ts)
+ dp.SetIntVal(val)
+}
+
+// updateCapacity saves max length of data point slices that will be used for the slice capacity.
+func (m *metricZookeeperPacketReceivedCount) 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 *metricZookeeperPacketReceivedCount) emit(metrics pmetric.MetricSlice) {
+ if m.settings.Enabled && m.data.Sum().DataPoints().Len() > 0 {
+ m.updateCapacity()
+ m.data.MoveTo(metrics.AppendEmpty())
+ m.init()
+ }
+}
+
+func newMetricZookeeperPacketReceivedCount(settings MetricSettings) metricZookeeperPacketReceivedCount {
+ m := metricZookeeperPacketReceivedCount{settings: settings}
+ if settings.Enabled {
+ m.data = pmetric.NewMetric()
+ m.init()
+ }
+ return m
+}
+
+type metricZookeeperPacketSentCount 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 zookeeper.packet.sent.count metric with initial data.
+func (m *metricZookeeperPacketSentCount) init() {
+ m.data.SetName("zookeeper.packet.sent.count")
+ m.data.SetDescription("The number of ZooKeeper packets sent by a server.")
+ m.data.SetUnit("{packets}")
+ m.data.SetDataType(pmetric.MetricDataTypeSum)
+ m.data.Sum().SetIsMonotonic(true)
+ m.data.Sum().SetAggregationTemporality(pmetric.MetricAggregationTemporalityCumulative)
+}
+
+func (m *metricZookeeperPacketSentCount) recordDataPoint(start pcommon.Timestamp, ts pcommon.Timestamp, val int64) {
+ if !m.settings.Enabled {
+ return
+ }
+ dp := m.data.Sum().DataPoints().AppendEmpty()
+ dp.SetStartTimestamp(start)
+ dp.SetTimestamp(ts)
+ dp.SetIntVal(val)
+}
+
+// updateCapacity saves max length of data point slices that will be used for the slice capacity.
+func (m *metricZookeeperPacketSentCount) 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 *metricZookeeperPacketSentCount) emit(metrics pmetric.MetricSlice) {
+ if m.settings.Enabled && m.data.Sum().DataPoints().Len() > 0 {
+ m.updateCapacity()
+ m.data.MoveTo(metrics.AppendEmpty())
+ m.init()
+ }
+}
+
+func newMetricZookeeperPacketSentCount(settings MetricSettings) metricZookeeperPacketSentCount {
+ m := metricZookeeperPacketSentCount{settings: settings}
+ if settings.Enabled {
+ m.data = pmetric.NewMetric()
+ m.init()
+ }
+ return m
+}
+
type metricZookeeperRequestActive struct {
data pmetric.Metric // data buffer for generated metric.
settings MetricSettings // metric settings provided by user.
@@ -916,6 +1026,8 @@ type MetricsBuilder struct {
metricZookeeperLatencyMax metricZookeeperLatencyMax
metricZookeeperLatencyMin metricZookeeperLatencyMin
metricZookeeperPacketCount metricZookeeperPacketCount
+ metricZookeeperPacketReceivedCount metricZookeeperPacketReceivedCount
+ metricZookeeperPacketSentCount metricZookeeperPacketSentCount
metricZookeeperRequestActive metricZookeeperRequestActive
metricZookeeperSyncPending metricZookeeperSyncPending
metricZookeeperWatchCount metricZookeeperWatchCount
@@ -948,6 +1060,8 @@ func NewMetricsBuilder(settings MetricsSettings, buildInfo component.BuildInfo,
metricZookeeperLatencyMax: newMetricZookeeperLatencyMax(settings.ZookeeperLatencyMax),
metricZookeeperLatencyMin: newMetricZookeeperLatencyMin(settings.ZookeeperLatencyMin),
metricZookeeperPacketCount: newMetricZookeeperPacketCount(settings.ZookeeperPacketCount),
+ metricZookeeperPacketReceivedCount: newMetricZookeeperPacketReceivedCount(settings.ZookeeperPacketReceivedCount),
+ metricZookeeperPacketSentCount: newMetricZookeeperPacketSentCount(settings.ZookeeperPacketSentCount),
metricZookeeperRequestActive: newMetricZookeeperRequestActive(settings.ZookeeperRequestActive),
metricZookeeperSyncPending: newMetricZookeeperSyncPending(settings.ZookeeperSyncPending),
metricZookeeperWatchCount: newMetricZookeeperWatchCount(settings.ZookeeperWatchCount),
@@ -1029,6 +1143,8 @@ func (mb *MetricsBuilder) EmitForResource(rmo ...ResourceMetricsOption) {
mb.metricZookeeperLatencyMax.emit(ils.Metrics())
mb.metricZookeeperLatencyMin.emit(ils.Metrics())
mb.metricZookeeperPacketCount.emit(ils.Metrics())
+ mb.metricZookeeperPacketReceivedCount.emit(ils.Metrics())
+ mb.metricZookeeperPacketSentCount.emit(ils.Metrics())
mb.metricZookeeperRequestActive.emit(ils.Metrics())
mb.metricZookeeperSyncPending.emit(ils.Metrics())
mb.metricZookeeperWatchCount.emit(ils.Metrics())
@@ -1107,6 +1223,16 @@ func (mb *MetricsBuilder) RecordZookeeperPacketCountDataPoint(ts pcommon.Timesta
mb.metricZookeeperPacketCount.recordDataPoint(mb.startTime, ts, val, directionAttributeValue.String())
}
+// RecordZookeeperPacketReceivedCountDataPoint adds a data point to zookeeper.packet.received.count metric.
+func (mb *MetricsBuilder) RecordZookeeperPacketReceivedCountDataPoint(ts pcommon.Timestamp, val int64) {
+ mb.metricZookeeperPacketReceivedCount.recordDataPoint(mb.startTime, ts, val)
+}
+
+// RecordZookeeperPacketSentCountDataPoint adds a data point to zookeeper.packet.sent.count metric.
+func (mb *MetricsBuilder) RecordZookeeperPacketSentCountDataPoint(ts pcommon.Timestamp, val int64) {
+ mb.metricZookeeperPacketSentCount.recordDataPoint(mb.startTime, ts, val)
+}
+
// RecordZookeeperRequestActiveDataPoint adds a data point to zookeeper.request.active metric.
func (mb *MetricsBuilder) RecordZookeeperRequestActiveDataPoint(ts pcommon.Timestamp, val int64) {
mb.metricZookeeperRequestActive.recordDataPoint(mb.startTime, ts, val)
diff --git a/receiver/zookeeperreceiver/metadata.yaml b/receiver/zookeeperreceiver/metadata.yaml
index 3778c6614287..e343c51240d0 100644
--- a/receiver/zookeeperreceiver/metadata.yaml
+++ b/receiver/zookeeperreceiver/metadata.yaml
@@ -118,6 +118,7 @@ metrics:
unit: "{file_descriptors}"
gauge:
value_type: int
+ # produced when receiver.zookeeperreceiver.emitMetricsWithDirectionAttribute feature gate is enabled
zookeeper.packet.count:
enabled: true
description: The number of ZooKeeper packets received or sent by a server.
@@ -127,6 +128,24 @@ metrics:
value_type: int
monotonic: true
aggregation: cumulative
+ # produced when receiver.zookeeperreceiver.emitMetricsWithoutDirectionAttribute feature gate is enabled
+ zookeeper.packet.sent.count:
+ enabled: true
+ description: The number of ZooKeeper packets sent by a server.
+ unit: "{packets}"
+ sum:
+ value_type: int
+ monotonic: true
+ aggregation: cumulative
+ # produced when receiver.zookeeperreceiver.emitMetricsWithoutDirectionAttribute feature gate is enabled
+ zookeeper.packet.received.count:
+ enabled: true
+ description: The number of ZooKeeper packets received by a server.
+ unit: "{packets}"
+ sum:
+ value_type: int
+ monotonic: true
+ aggregation: cumulative
zookeeper.fsync.exceeded_threshold.count:
enabled: true
description: Number of times fsync duration has exceeded warning threshold.
diff --git a/receiver/zookeeperreceiver/metrics.go b/receiver/zookeeperreceiver/metrics.go
index 0aeb045a5ea9..4759f990ebe1 100644
--- a/receiver/zookeeperreceiver/metrics.go
+++ b/receiver/zookeeperreceiver/metrics.go
@@ -53,12 +53,17 @@ const (
type metricCreator struct {
computedMetricStore map[string]int64
mb *metadata.MetricsBuilder
+ // Temporary feature gates while transitioning to metrics without a direction attribute
+ emitMetricsWithDirectionAttribute bool
+ emitMetricsWithoutDirectionAttribute bool
}
-func newMetricCreator(mb *metadata.MetricsBuilder) *metricCreator {
+func newMetricCreator(mb *metadata.MetricsBuilder, emitMetricsWithDirectionAttribute, emitMetricsWithoutDirectionAttribute bool) *metricCreator {
return &metricCreator{
- computedMetricStore: make(map[string]int64),
- mb: mb,
+ computedMetricStore: make(map[string]int64),
+ mb: mb,
+ emitMetricsWithDirectionAttribute: emitMetricsWithDirectionAttribute,
+ emitMetricsWithoutDirectionAttribute: emitMetricsWithoutDirectionAttribute,
}
}
@@ -101,11 +106,21 @@ func (m *metricCreator) recordDataPointsFunc(metric string) func(ts pcommon.Time
return m.mb.RecordZookeeperFsyncExceededThresholdCountDataPoint
case packetsReceivedMetricKey:
return func(ts pcommon.Timestamp, val int64) {
- m.mb.RecordZookeeperPacketCountDataPoint(ts, val, metadata.AttributeDirectionReceived)
+ if m.emitMetricsWithDirectionAttribute {
+ m.mb.RecordZookeeperPacketCountDataPoint(ts, val, metadata.AttributeDirectionReceived)
+ }
+ if m.emitMetricsWithoutDirectionAttribute {
+ m.mb.RecordZookeeperPacketReceivedCountDataPoint(ts, val)
+ }
}
case packetsSentMetricKey:
return func(ts pcommon.Timestamp, val int64) {
- m.mb.RecordZookeeperPacketCountDataPoint(ts, val, metadata.AttributeDirectionSent)
+ if m.emitMetricsWithDirectionAttribute {
+ m.mb.RecordZookeeperPacketCountDataPoint(ts, val, metadata.AttributeDirectionSent)
+ }
+ if m.emitMetricsWithoutDirectionAttribute {
+ m.mb.RecordZookeeperPacketSentCountDataPoint(ts, val)
+ }
}
}
diff --git a/receiver/zookeeperreceiver/scraper.go b/receiver/zookeeperreceiver/scraper.go
index 69e18d1dfd28..83c72d1aa334 100644
--- a/receiver/zookeeperreceiver/scraper.go
+++ b/receiver/zookeeperreceiver/scraper.go
@@ -27,6 +27,7 @@ import (
"go.opentelemetry.io/collector/component"
"go.opentelemetry.io/collector/pdata/pcommon"
"go.opentelemetry.io/collector/pdata/pmetric"
+ "go.opentelemetry.io/collector/service/featuregate"
"go.uber.org/zap"
"github.com/open-telemetry/opentelemetry-collector-contrib/receiver/zookeeperreceiver/internal/metadata"
@@ -35,9 +36,38 @@ import (
var zookeeperFormatRE = regexp.MustCompile(`(^zk_\w+)\s+([\w\.\-]+)`)
const (
- mntrCommand = "mntr"
+ mntrCommand = "mntr"
+ emitMetricsWithDirectionAttributeFeatureGateID = "receiver.zookeeperreceiver.emitMetricsWithDirectionAttribute"
+ emitMetricsWithoutDirectionAttributeFeatureGateID = "receiver.zookeeperreceiver.emitMetricsWithoutDirectionAttribute"
)
+var (
+ emitMetricsWithDirectionAttributeFeatureGate = featuregate.Gate{
+ ID: emitMetricsWithDirectionAttributeFeatureGateID,
+ Enabled: true,
+ Description: "Some zookeeper metrics reported are transitioning from being reported with a direction " +
+ "attribute to being reported with the direction included in the metric name to adhere to the " +
+ "OpenTelemetry specification. This feature gate controls emitting the old metrics with the direction " +
+ "attribute. For more details, see: " +
+ "https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/main/receiver/zookeeperreceiver/README.md#feature-gate-configurations",
+ }
+
+ emitMetricsWithoutDirectionAttributeFeatureGate = featuregate.Gate{
+ ID: emitMetricsWithoutDirectionAttributeFeatureGateID,
+ Enabled: false,
+ Description: "Some zookeeper metrics reported are transitioning from being reported with a direction " +
+ "attribute to being reported with the direction included in the metric name to adhere to the " +
+ "OpenTelemetry specification. This feature gate controls emitting the new metrics without the direction " +
+ "attribute. For more details, see: " +
+ "https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/main/receiver/zookeeperreceiver/README.md#feature-gate-configurations",
+ }
+)
+
+func init() {
+ featuregate.GetRegistry().MustRegister(emitMetricsWithDirectionAttributeFeatureGate)
+ featuregate.GetRegistry().MustRegister(emitMetricsWithoutDirectionAttributeFeatureGate)
+}
+
type zookeeperMetricsScraper struct {
logger *zap.Logger
config *Config
@@ -48,6 +78,10 @@ type zookeeperMetricsScraper struct {
closeConnection func(net.Conn) error
setConnectionDeadline func(net.Conn, time.Time) error
sendCmd func(net.Conn, string) (*bufio.Scanner, error)
+
+ // Feature gates while transitioning to metrics without a direction attribute
+ emitMetricsWithDirectionAttribute bool
+ emitMetricsWithoutDirectionAttribute bool
}
func (z *zookeeperMetricsScraper) Name() string {
@@ -64,14 +98,29 @@ func newZookeeperMetricsScraper(settings component.ReceiverCreateSettings, confi
return nil, errors.New("timeout must be a positive duration")
}
- return &zookeeperMetricsScraper{
- logger: settings.Logger,
- config: config,
- mb: metadata.NewMetricsBuilder(config.Metrics, settings.BuildInfo),
- closeConnection: closeConnection,
- setConnectionDeadline: setConnectionDeadline,
- sendCmd: sendCmd,
- }, nil
+ z := &zookeeperMetricsScraper{
+ logger: settings.Logger,
+ config: config,
+ mb: metadata.NewMetricsBuilder(config.Metrics, settings.BuildInfo),
+ closeConnection: closeConnection,
+ setConnectionDeadline: setConnectionDeadline,
+ sendCmd: sendCmd,
+ emitMetricsWithDirectionAttribute: featuregate.GetRegistry().IsEnabled(emitMetricsWithDirectionAttributeFeatureGateID),
+ emitMetricsWithoutDirectionAttribute: featuregate.GetRegistry().IsEnabled(emitMetricsWithoutDirectionAttributeFeatureGateID),
+ }
+
+ if z.emitMetricsWithDirectionAttribute {
+ z.logger.Info("WARNING - Breaking Change: " + emitMetricsWithDirectionAttributeFeatureGate.Description)
+ z.logger.Info("The feature gate " + emitMetricsWithDirectionAttributeFeatureGate.ID + " is enabled. This " +
+ "otel collector will report metrics with a direction attribute, be aware this will not be supported in the future")
+ }
+
+ if z.emitMetricsWithoutDirectionAttribute {
+ z.logger.Info("The " + emitMetricsWithoutDirectionAttributeFeatureGate.ID + " feature gate is enabled. This " +
+ "otel collector will report metrics without a direction attribute, which is good for future support")
+ }
+
+ return z, nil
}
func (z *zookeeperMetricsScraper) shutdown(_ context.Context) error {
@@ -120,7 +169,7 @@ func (z *zookeeperMetricsScraper) getResourceMetrics(conn net.Conn) (pmetric.Met
return pmetric.NewMetrics(), err
}
- creator := newMetricCreator(z.mb)
+ creator := newMetricCreator(z.mb, z.emitMetricsWithDirectionAttribute, z.emitMetricsWithoutDirectionAttribute)
now := pcommon.NewTimestampFromTime(time.Now())
resourceOpts := make([]metadata.ResourceMetricsOption, 0, 2)
for scanner.Scan() {
diff --git a/receiver/zookeeperreceiver/scraper_test.go b/receiver/zookeeperreceiver/scraper_test.go
index 2039942470a4..a5d28f10d231 100644
--- a/receiver/zookeeperreceiver/scraper_test.go
+++ b/receiver/zookeeperreceiver/scraper_test.go
@@ -29,6 +29,7 @@ import (
"github.com/stretchr/testify/require"
"go.opentelemetry.io/collector/component/componenttest"
"go.opentelemetry.io/collector/pdata/pmetric"
+ "go.opentelemetry.io/collector/service/featuregate"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
"go.uber.org/zap/zaptest/observer"
@@ -49,19 +50,42 @@ func TestZookeeperMetricsScraperScrape(t *testing.T) {
t.Skip("skipping flaky test on windows, see https://github.com/open-telemetry/opentelemetry-collector-contrib/issues/10171")
}
+ // additional temporary log messages expected while transitioning to metrics without a direction attribute
+ expectedLogsWithDirectionAttribute := []logMsg{
+ {
+ msg: "WARNING - Breaking Change: " + emitMetricsWithDirectionAttributeFeatureGate.Description,
+ level: zapcore.InfoLevel,
+ },
+ {
+ msg: "The feature gate " + emitMetricsWithDirectionAttributeFeatureGate.ID + " is enabled. This " +
+ "otel collector will report metrics with a direction attribute, be aware this will not be supported in the future",
+ level: zapcore.InfoLevel,
+ },
+ }
+
+ expectedLogsWithoutDirectionAttribute := []logMsg{
+ {
+ msg: "The " + emitMetricsWithoutDirectionAttributeFeatureGate.ID + " feature gate is enabled. This " +
+ "otel collector will report metrics without a direction attribute, which is good for future support",
+ level: zapcore.InfoLevel,
+ },
+ }
+
tests := []struct {
- name string
- expectedMetricsFilename string
- expectedResourceAttributes map[string]string
- metricsSettings func() metadata.MetricsSettings
- mockedZKOutputSourceFilename string
- mockZKConnectionErr bool
- expectedLogs []logMsg
- expectedNumResourceMetrics int
- setConnectionDeadline func(net.Conn, time.Time) error
- closeConnection func(net.Conn) error
- sendCmd func(net.Conn, string) (*bufio.Scanner, error)
- wantErr bool
+ name string
+ expectedMetricsFilename string
+ expectedResourceAttributes map[string]string
+ metricsSettings func() metadata.MetricsSettings
+ mockedZKOutputSourceFilename string
+ mockZKConnectionErr bool
+ expectedLogs []logMsg
+ expectedNumResourceMetrics int
+ setConnectionDeadline func(net.Conn, time.Time) error
+ closeConnection func(net.Conn) error
+ sendCmd func(net.Conn, string) (*bufio.Scanner, error)
+ wantErr bool
+ emitMetricsWithDirectionAttribute bool
+ emitMetricsWithoutDirectionAttribute bool
}{
{
name: "Test correctness with v3.4.14",
@@ -77,7 +101,27 @@ func TestZookeeperMetricsScraperScrape(t *testing.T) {
level: zapcore.DebugLevel,
},
},
- expectedNumResourceMetrics: 1,
+ expectedNumResourceMetrics: 1,
+ emitMetricsWithDirectionAttribute: true,
+ emitMetricsWithoutDirectionAttribute: false,
+ },
+ {
+ name: "Test correctness with v3.4.14 without direction attribute",
+ mockedZKOutputSourceFilename: "mntr-3.4.14",
+ expectedMetricsFilename: "correctness-v3.4.14-without-direction",
+ expectedResourceAttributes: map[string]string{
+ "server.state": "standalone",
+ "zk.version": "3.4.14-4c25d480e66aadd371de8bd2fd8da255ac140bcf",
+ },
+ expectedLogs: []logMsg{
+ {
+ msg: "metric computation failed",
+ level: zapcore.DebugLevel,
+ },
+ },
+ expectedNumResourceMetrics: 1,
+ emitMetricsWithDirectionAttribute: false,
+ emitMetricsWithoutDirectionAttribute: true,
},
{
name: "Test correctness with v3.5.5",
@@ -87,7 +131,21 @@ func TestZookeeperMetricsScraperScrape(t *testing.T) {
"server.state": "leader",
"zk.version": "3.5.5-390fe37ea45dee01bf87dc1c042b5e3dcce88653",
},
- expectedNumResourceMetrics: 1,
+ expectedNumResourceMetrics: 1,
+ emitMetricsWithDirectionAttribute: true,
+ emitMetricsWithoutDirectionAttribute: false,
+ },
+ {
+ name: "Test correctness with v3.5.5 without direction attribute",
+ mockedZKOutputSourceFilename: "mntr-3.5.5",
+ expectedMetricsFilename: "correctness-v3.5.5-without-direction",
+ expectedResourceAttributes: map[string]string{
+ "server.state": "leader",
+ "zk.version": "3.5.5-390fe37ea45dee01bf87dc1c042b5e3dcce88653",
+ },
+ expectedNumResourceMetrics: 1,
+ emitMetricsWithDirectionAttribute: false,
+ emitMetricsWithoutDirectionAttribute: true,
},
{
name: "Arbitrary connection error",
@@ -152,6 +210,8 @@ func TestZookeeperMetricsScraperScrape(t *testing.T) {
setConnectionDeadline: func(conn net.Conn, t time.Time) error {
return errors.New("")
},
+ emitMetricsWithDirectionAttribute: true,
+ emitMetricsWithoutDirectionAttribute: false,
},
{
name: "Error closing connection",
@@ -175,6 +235,8 @@ func TestZookeeperMetricsScraperScrape(t *testing.T) {
closeConnection: func(conn net.Conn) error {
return errors.New("")
},
+ emitMetricsWithDirectionAttribute: true,
+ emitMetricsWithoutDirectionAttribute: false,
},
{
name: "Failed to send command",
@@ -208,7 +270,9 @@ func TestZookeeperMetricsScraperScrape(t *testing.T) {
level: zapcore.DebugLevel,
},
},
- expectedNumResourceMetrics: 1,
+ expectedNumResourceMetrics: 1,
+ emitMetricsWithDirectionAttribute: true,
+ emitMetricsWithoutDirectionAttribute: false,
},
}
for _, tt := range tests {
@@ -226,6 +290,8 @@ func TestZookeeperMetricsScraperScrape(t *testing.T) {
cfg.Metrics = tt.metricsSettings()
}
+ featuregate.GetRegistry().MustApply(map[string]bool{emitMetricsWithDirectionAttributeFeatureGate.ID: tt.emitMetricsWithDirectionAttribute})
+ featuregate.GetRegistry().MustApply(map[string]bool{emitMetricsWithoutDirectionAttributeFeatureGate.ID: tt.emitMetricsWithoutDirectionAttribute})
core, observedLogs := observer.New(zap.DebugLevel)
settings := componenttest.NewNopReceiverCreateSettings()
settings.Logger = zap.New(core)
@@ -250,8 +316,20 @@ func TestZookeeperMetricsScraperScrape(t *testing.T) {
actualMetrics, err := z.scrape(ctx)
require.NoError(t, z.shutdown(ctx))
- require.Equal(t, len(tt.expectedLogs), observedLogs.Len())
- for i, log := range tt.expectedLogs {
+ var expectedLogs []logMsg
+
+ if tt.emitMetricsWithoutDirectionAttribute {
+ expectedLogs = append(expectedLogs, expectedLogsWithoutDirectionAttribute...)
+ }
+
+ if tt.emitMetricsWithDirectionAttribute {
+ expectedLogs = append(expectedLogs, expectedLogsWithDirectionAttribute...)
+ }
+
+ expectedLogs = append(expectedLogs, tt.expectedLogs...)
+
+ require.Equal(t, len(expectedLogs), observedLogs.Len())
+ for i, log := range expectedLogs {
require.Equal(t, log.msg, observedLogs.All()[i].Message)
require.Equal(t, log.level, observedLogs.All()[i].Level)
}
diff --git a/receiver/zookeeperreceiver/testdata/scraper/correctness-v3.4.14-without-direction.json b/receiver/zookeeperreceiver/testdata/scraper/correctness-v3.4.14-without-direction.json
new file mode 100644
index 000000000000..6774cdf4a347
--- /dev/null
+++ b/receiver/zookeeperreceiver/testdata/scraper/correctness-v3.4.14-without-direction.json
@@ -0,0 +1,242 @@
+{
+ "resourceMetrics": [
+ {
+ "scopeMetrics": [
+ {
+ "scope": {
+ "name": "otelcol/zookeeperreceiver",
+ "version": "latest"
+ },
+ "metrics": [
+ {
+ "description": "Number of active clients connected to a ZooKeeper server.",
+ "name": "zookeeper.connection.active",
+ "sum": {
+ "aggregationTemporality": "AGGREGATION_TEMPORALITY_CUMULATIVE",
+ "dataPoints": [
+ {
+ "asInt": "1",
+ "startTimeUnixNano": "1642685966444471000",
+ "timeUnixNano": "1642685966444739000"
+ }
+ ]
+ },
+ "unit": "{connections}"
+ },
+ {
+ "description": "Number of ephemeral nodes that a ZooKeeper server has in its data tree.",
+ "name": "zookeeper.data_tree.ephemeral_node.count",
+ "sum": {
+ "aggregationTemporality": "AGGREGATION_TEMPORALITY_CUMULATIVE",
+ "dataPoints": [
+ {
+ "asInt": "0",
+ "startTimeUnixNano": "1642685966444471000",
+ "timeUnixNano": "1642685966444739000"
+ }
+ ]
+ },
+ "unit": "{nodes}"
+ },
+ {
+ "description": "Size of data in bytes that a ZooKeeper server has in its data tree.",
+ "name": "zookeeper.data_tree.size",
+ "sum": {
+ "aggregationTemporality": "AGGREGATION_TEMPORALITY_CUMULATIVE",
+ "dataPoints": [
+ {
+ "asInt": "27",
+ "startTimeUnixNano": "1642685966444471000",
+ "timeUnixNano": "1642685966444739000"
+ }
+ ]
+ },
+ "unit": "By"
+ },
+ {
+ "description": "Maximum number of file descriptors that a ZooKeeper server can open.",
+ "gauge": {
+ "dataPoints": [
+ {
+ "asInt": "1048576",
+ "startTimeUnixNano": "1642685966444471000",
+ "timeUnixNano": "1642685966444739000"
+ }
+ ]
+ },
+ "name": "zookeeper.file_descriptor.limit",
+ "unit": "{file_descriptors}"
+ },
+ {
+ "description": "Number of file descriptors that a ZooKeeper server has open.",
+ "name": "zookeeper.file_descriptor.open",
+ "sum": {
+ "aggregationTemporality": "AGGREGATION_TEMPORALITY_CUMULATIVE",
+ "dataPoints": [
+ {
+ "asInt": "26",
+ "startTimeUnixNano": "1642685966444471000",
+ "timeUnixNano": "1642685966444739000"
+ }
+ ]
+ },
+ "unit": "{file_descriptors}"
+ },
+ {
+ "description": "Number of times fsync duration has exceeded warning threshold.",
+ "name": "zookeeper.fsync.exceeded_threshold.count",
+ "sum": {
+ "aggregationTemporality": "AGGREGATION_TEMPORALITY_CUMULATIVE",
+ "dataPoints": [
+ {
+ "asInt": "0",
+ "startTimeUnixNano": "1642685966444471000",
+ "timeUnixNano": "1642685966444739000"
+ }
+ ],
+ "isMonotonic": true
+ },
+ "unit": "{events}"
+ },
+ {
+ "description": "Average time in milliseconds for requests to be processed.",
+ "gauge": {
+ "dataPoints": [
+ {
+ "asInt": "0",
+ "startTimeUnixNano": "1642685966444471000",
+ "timeUnixNano": "1642685966444739000"
+ }
+ ]
+ },
+ "name": "zookeeper.latency.avg",
+ "unit": "ms"
+ },
+ {
+ "description": "Maximum time in milliseconds for requests to be processed.",
+ "gauge": {
+ "dataPoints": [
+ {
+ "asInt": "0",
+ "startTimeUnixNano": "1642685966444471000",
+ "timeUnixNano": "1642685966444739000"
+ }
+ ]
+ },
+ "name": "zookeeper.latency.max",
+ "unit": "ms"
+ },
+ {
+ "description": "Minimum time in milliseconds for requests to be processed.",
+ "gauge": {
+ "dataPoints": [
+ {
+ "asInt": "0",
+ "startTimeUnixNano": "1642685966444471000",
+ "timeUnixNano": "1642685966444739000"
+ }
+ ]
+ },
+ "name": "zookeeper.latency.min",
+ "unit": "ms"
+ },
+ {
+ "description": "The number of ZooKeeper packets received by a server.",
+ "name": "zookeeper.packet.received.count",
+ "sum": {
+ "aggregationTemporality": "AGGREGATION_TEMPORALITY_CUMULATIVE",
+ "dataPoints": [
+ {
+ "asInt": "1",
+
+ "startTimeUnixNano": "1642685966444471000",
+ "timeUnixNano": "1642685966444739000"
+ }
+ ],
+ "isMonotonic": true
+ },
+ "unit": "{packets}"
+ },
+ {
+ "description": "The number of ZooKeeper packets sent by a server.",
+ "name": "zookeeper.packet.sent.count",
+ "sum": {
+ "aggregationTemporality": "AGGREGATION_TEMPORALITY_CUMULATIVE",
+ "dataPoints": [
+ {
+ "asInt": "0",
+ "startTimeUnixNano": "1642685966444471000",
+ "timeUnixNano": "1642685966444739000"
+ }
+ ],
+ "isMonotonic": true
+ },
+ "unit": "{packets}"
+ },
+ {
+ "description": "Number of currently executing requests.",
+ "name": "zookeeper.request.active",
+ "sum": {
+ "aggregationTemporality": "AGGREGATION_TEMPORALITY_CUMULATIVE",
+ "dataPoints": [
+ {
+ "asInt": "0",
+ "startTimeUnixNano": "1642685966444471000",
+ "timeUnixNano": "1642685966444739000"
+ }
+ ]
+ },
+ "unit": "{requests}"
+ },
+ {
+ "description": "Number of watches placed on Z-Nodes on a ZooKeeper server.",
+ "name": "zookeeper.watch.count",
+ "sum": {
+ "aggregationTemporality": "AGGREGATION_TEMPORALITY_CUMULATIVE",
+ "dataPoints": [
+ {
+ "asInt": "0",
+ "startTimeUnixNano": "1642685966444471000",
+ "timeUnixNano": "1642685966444739000"
+ }
+ ]
+ },
+ "unit": "{watches}"
+ },
+ {
+ "description": "Number of z-nodes that a ZooKeeper server has in its data tree.",
+ "name": "zookeeper.znode.count",
+ "sum": {
+ "aggregationTemporality": "AGGREGATION_TEMPORALITY_CUMULATIVE",
+ "dataPoints": [
+ {
+ "asInt": "4",
+ "startTimeUnixNano": "1642685966444471000",
+ "timeUnixNano": "1642685966444739000"
+ }
+ ]
+ },
+ "unit": "{znodes}"
+ }
+ ]
+ }
+ ],
+ "resource": {
+ "attributes": [
+ {
+ "key": "zk.version",
+ "value": {
+ "stringValue": "3.4.14-4c25d480e66aadd371de8bd2fd8da255ac140bcf"
+ }
+ },
+ {
+ "key": "server.state",
+ "value": {
+ "stringValue": "standalone"
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/receiver/zookeeperreceiver/testdata/scraper/correctness-v3.5.5-without-direction.json b/receiver/zookeeperreceiver/testdata/scraper/correctness-v3.5.5-without-direction.json
new file mode 100644
index 000000000000..3a8b0f927d5d
--- /dev/null
+++ b/receiver/zookeeperreceiver/testdata/scraper/correctness-v3.5.5-without-direction.json
@@ -0,0 +1,276 @@
+{
+ "resourceMetrics": [
+ {
+ "scopeMetrics": [
+ {
+ "scope": {
+ "name": "otelcol/zookeeperreceiver",
+ "version": "latest"
+ },
+ "metrics": [
+ {
+ "description": "Number of active clients connected to a ZooKeeper server.",
+ "name": "zookeeper.connection.active",
+ "sum": {
+ "aggregationTemporality": "AGGREGATION_TEMPORALITY_CUMULATIVE",
+ "dataPoints": [
+ {
+ "asInt": "1",
+ "startTimeUnixNano": "1642685966447704000",
+ "timeUnixNano": "1642685966447860000"
+ }
+ ]
+ },
+ "unit": "{connections}"
+ },
+ {
+ "description": "Number of ephemeral nodes that a ZooKeeper server has in its data tree.",
+ "name": "zookeeper.data_tree.ephemeral_node.count",
+ "sum": {
+ "aggregationTemporality": "AGGREGATION_TEMPORALITY_CUMULATIVE",
+ "dataPoints": [
+ {
+ "asInt": "0",
+ "startTimeUnixNano": "1642685966447704000",
+ "timeUnixNano": "1642685966447860000"
+ }
+ ]
+ },
+ "unit": "{nodes}"
+ },
+ {
+ "description": "Size of data in bytes that a ZooKeeper server has in its data tree.",
+ "name": "zookeeper.data_tree.size",
+ "sum": {
+ "aggregationTemporality": "AGGREGATION_TEMPORALITY_CUMULATIVE",
+ "dataPoints": [
+ {
+ "asInt": "107",
+ "startTimeUnixNano": "1642685966447704000",
+ "timeUnixNano": "1642685966447860000"
+ }
+ ]
+ },
+ "unit": "By"
+ },
+ {
+ "description": "Maximum number of file descriptors that a ZooKeeper server can open.",
+ "gauge": {
+ "dataPoints": [
+ {
+ "asInt": "1048576",
+ "startTimeUnixNano": "1642685966447704000",
+ "timeUnixNano": "1642685966447860000"
+ }
+ ]
+ },
+ "name": "zookeeper.file_descriptor.limit",
+ "unit": "{file_descriptors}"
+ },
+ {
+ "description": "Number of file descriptors that a ZooKeeper server has open.",
+ "name": "zookeeper.file_descriptor.open",
+ "sum": {
+ "aggregationTemporality": "AGGREGATION_TEMPORALITY_CUMULATIVE",
+ "dataPoints": [
+ {
+ "asInt": "54",
+ "startTimeUnixNano": "1642685966447704000",
+ "timeUnixNano": "1642685966447860000"
+ }
+ ]
+ },
+ "unit": "{file_descriptors}"
+ },
+ {
+ "description": "The number of followers. Only exposed by the leader.",
+ "name": "zookeeper.follower.count",
+ "sum": {
+ "aggregationTemporality": "AGGREGATION_TEMPORALITY_CUMULATIVE",
+ "dataPoints": [
+ {
+ "asInt": "1",
+ "attributes": [
+ {
+ "key": "state",
+ "value": {
+ "stringValue": "synced"
+ }
+ }
+ ],
+ "startTimeUnixNano": "1642685966447704000",
+ "timeUnixNano": "1642685966447860000"
+ },
+ {
+ "asInt": "1",
+ "attributes": [
+ {
+ "key": "state",
+ "value": {
+ "stringValue": "unsynced"
+ }
+ }
+ ],
+ "startTimeUnixNano": "1642685966447704000",
+ "timeUnixNano": "1642685966447860000"
+ }
+ ]
+ },
+ "unit": "{followers}"
+ },
+ {
+ "description": "Average time in milliseconds for requests to be processed.",
+ "gauge": {
+ "dataPoints": [
+ {
+ "asInt": "0",
+ "startTimeUnixNano": "1642685966447704000",
+ "timeUnixNano": "1642685966447860000"
+ }
+ ]
+ },
+ "name": "zookeeper.latency.avg",
+ "unit": "ms"
+ },
+ {
+ "description": "Maximum time in milliseconds for requests to be processed.",
+ "gauge": {
+ "dataPoints": [
+ {
+ "asInt": "0",
+ "startTimeUnixNano": "1642685966447704000",
+ "timeUnixNano": "1642685966447860000"
+ }
+ ]
+ },
+ "name": "zookeeper.latency.max",
+ "unit": "ms"
+ },
+ {
+ "description": "Minimum time in milliseconds for requests to be processed.",
+ "gauge": {
+ "dataPoints": [
+ {
+ "asInt": "0",
+ "startTimeUnixNano": "1642685966447704000",
+ "timeUnixNano": "1642685966447860000"
+ }
+ ]
+ },
+ "name": "zookeeper.latency.min",
+ "unit": "ms"
+ },
+ {
+ "description": "The number of ZooKeeper packets received by a server.",
+ "name": "zookeeper.packet.received.count",
+ "sum": {
+ "aggregationTemporality": "AGGREGATION_TEMPORALITY_CUMULATIVE",
+ "dataPoints": [
+ {
+ "asInt": "1",
+ "startTimeUnixNano": "1642685966447704000",
+ "timeUnixNano": "1642685966447860000"
+ }
+ ],
+ "isMonotonic": true
+ },
+ "unit": "{packets}"
+ },
+ {
+ "description": "The number of ZooKeeper packets sent by a server.",
+ "name": "zookeeper.packet.sent.count",
+ "sum": {
+ "aggregationTemporality": "AGGREGATION_TEMPORALITY_CUMULATIVE",
+ "dataPoints": [
+ {
+ "asInt": "0",
+ "startTimeUnixNano": "1642685966447704000",
+ "timeUnixNano": "1642685966447860000"
+ }
+ ],
+ "isMonotonic": true
+ },
+ "unit": "{packets}"
+ },
+ {
+ "description": "Number of currently executing requests.",
+ "name": "zookeeper.request.active",
+ "sum": {
+ "aggregationTemporality": "AGGREGATION_TEMPORALITY_CUMULATIVE",
+ "dataPoints": [
+ {
+ "asInt": "0",
+ "startTimeUnixNano": "1642685966447704000",
+ "timeUnixNano": "1642685966447860000"
+ }
+ ]
+ },
+ "unit": "{requests}"
+ },
+ {
+ "description": "The number of pending syncs from the followers. Only exposed by the leader.",
+ "name": "zookeeper.sync.pending",
+ "sum": {
+ "aggregationTemporality": "AGGREGATION_TEMPORALITY_CUMULATIVE",
+ "dataPoints": [
+ {
+ "asInt": "0",
+ "startTimeUnixNano": "1642685966447704000",
+ "timeUnixNano": "1642685966447860000"
+ }
+ ]
+ },
+ "unit": "{syncs}"
+ },
+ {
+ "description": "Number of watches placed on Z-Nodes on a ZooKeeper server.",
+ "name": "zookeeper.watch.count",
+ "sum": {
+ "aggregationTemporality": "AGGREGATION_TEMPORALITY_CUMULATIVE",
+ "dataPoints": [
+ {
+ "asInt": "0",
+ "startTimeUnixNano": "1642685966447704000",
+ "timeUnixNano": "1642685966447860000"
+ }
+ ]
+ },
+ "unit": "{watches}"
+ },
+ {
+ "description": "Number of z-nodes that a ZooKeeper server has in its data tree.",
+ "name": "zookeeper.znode.count",
+ "sum": {
+ "aggregationTemporality": "AGGREGATION_TEMPORALITY_CUMULATIVE",
+ "dataPoints": [
+ {
+ "asInt": "5",
+ "startTimeUnixNano": "1642685966447704000",
+ "timeUnixNano": "1642685966447860000"
+ }
+ ]
+ },
+ "unit": "{znodes}"
+ }
+ ]
+ }
+ ],
+ "resource": {
+ "attributes": [
+ {
+ "key": "zk.version",
+ "value": {
+ "stringValue": "3.5.5-390fe37ea45dee01bf87dc1c042b5e3dcce88653"
+ }
+ },
+ {
+ "key": "server.state",
+ "value": {
+ "stringValue": "leader"
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/unreleased/zk_direction.yaml b/unreleased/zk_direction.yaml
new file mode 100755
index 000000000000..0f77d5dd69b2
--- /dev/null
+++ b/unreleased/zk_direction.yaml
@@ -0,0 +1,20 @@
+# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
+change_type: breaking
+
+# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver)
+component: zookeeperreceiver
+
+# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
+note: "Remove direction for metrics. The feature gate: receiver.zookeeperreceiver.emitMetricsWithoutDirectionAttribute can be set to apply the following (#12772)"
+
+# One or more tracking issues related to the change
+issues: [12184]
+
+# (Optional) One or more lines of additional information to render under the primary note.
+# These lines will be padded with 2 spaces and then inserted directly into the document.
+# Use pipe (|) for multiline entries.
+subtext: |-
+ - `zookeeper` metrics:
+ - `zookeeper.packet.count` will become:
+ - `zookeeper.packet.received.count`
+ - `zookeeper.packet.sent.count`