chore(otel/netdataexporter): poc version (#20199)
Ilya Mashchenko committed
May 2, 2025 at 11:57 UTC
c6d0e417a3e5438e9ad981d2248d503faf230fbb
11 files changed
+1892
-171
src/go/otel-collector/builder-config.yaml
+5
-5
@@ -8,13 +8,13 @@ dist:
8
9
10
receivers:
11
- - gomod: go.opentelemetry.io/collector/receiver/otlpreceiver v0.124.0
12
- - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/receiver/filelogreceiver v0.124.0
11
+ - gomod: go.opentelemetry.io/collector/receiver/otlpreceiver v0.125.0
12
+ - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/receiver/filelogreceiver v0.125.0
13
14
exporters:
15
- - gomod: go.opentelemetry.io/collector/exporter/debugexporter v0.124.0
16
- - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/exporter/fileexporter v0.124.0
17
- - gomod: go.opentelemetry.io/collector/exporter/otlpexporter v0.124.0
15
+ - gomod: go.opentelemetry.io/collector/exporter/debugexporter v0.125.0
16
+ - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/exporter/fileexporter v0.125.0
17
+ - gomod: go.opentelemetry.io/collector/exporter/otlpexporter v0.125.0
18
- gomod: github.com/netdata/netdata/otel-collector/exporter/journaldexporter v0.0.0
19
- gomod: github.com/netdata/netdata/otel-collector/exporter/netdataexporter v0.0.0
20
src/go/otel-collector/exporter/journaldexporter/go.mod
+24
-23
@@ -5,14 +5,14 @@ go 1.24.0
5
require (
6
github.com/google/uuid v1.6.0
7
github.com/stretchr/testify v1.10.0
8
- go.opentelemetry.io/collector/component v1.30.0
9
- go.opentelemetry.io/collector/component/componenttest v0.124.0
10
- go.opentelemetry.io/collector/confmap v1.30.0
11
- go.opentelemetry.io/collector/consumer v1.30.0
12
- go.opentelemetry.io/collector/exporter v0.124.0
13
- go.opentelemetry.io/collector/exporter/exportertest v0.124.0
14
- go.opentelemetry.io/collector/exporter/xexporter v0.124.0
15
- go.opentelemetry.io/collector/pdata v1.30.0
8
+ go.opentelemetry.io/collector/component v1.31.0
9
+ go.opentelemetry.io/collector/component/componenttest v0.125.0
10
+ go.opentelemetry.io/collector/confmap v1.31.0
11
+ go.opentelemetry.io/collector/consumer v1.31.0
12
+ go.opentelemetry.io/collector/exporter v0.125.0
13
+ go.opentelemetry.io/collector/exporter/exportertest v0.125.0
14
+ go.opentelemetry.io/collector/exporter/xexporter v0.125.0
15
+ go.opentelemetry.io/collector/pdata v1.31.0
16
go.uber.org/goleak v1.3.0
17
go.uber.org/zap v1.27.0
18
)
@@ -35,19 +35,19 @@ require (
35
github.com/modern-go/reflect2 v1.0.2 // indirect
36
github.com/pmezard/go-difflib v1.0.0 // indirect
37
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
38
- go.opentelemetry.io/collector/config/configretry v1.30.0 // indirect
39
- go.opentelemetry.io/collector/consumer/consumererror v0.124.0 // indirect
40
- go.opentelemetry.io/collector/consumer/consumertest v0.124.0 // indirect
41
- go.opentelemetry.io/collector/consumer/xconsumer v0.124.0 // indirect
42
- go.opentelemetry.io/collector/extension v1.30.0 // indirect
43
- go.opentelemetry.io/collector/extension/xextension v0.124.0 // indirect
44
- go.opentelemetry.io/collector/featuregate v1.30.0 // indirect
45
- go.opentelemetry.io/collector/internal/telemetry v0.124.0 // indirect
46
- go.opentelemetry.io/collector/pdata/pprofile v0.124.0 // indirect
47
- go.opentelemetry.io/collector/pipeline v0.124.0 // indirect
48
- go.opentelemetry.io/collector/receiver v1.30.0 // indirect
49
- go.opentelemetry.io/collector/receiver/receivertest v0.124.0 // indirect
50
- go.opentelemetry.io/collector/receiver/xreceiver v0.124.0 // indirect
38
+ go.opentelemetry.io/collector/config/configretry v1.31.0 // indirect
39
+ go.opentelemetry.io/collector/consumer/consumererror v0.125.0 // indirect
40
+ go.opentelemetry.io/collector/consumer/consumertest v0.125.0 // indirect
41
+ go.opentelemetry.io/collector/consumer/xconsumer v0.125.0 // indirect
42
+ go.opentelemetry.io/collector/extension v1.31.0 // indirect
43
+ go.opentelemetry.io/collector/extension/xextension v0.125.0 // indirect
44
+ go.opentelemetry.io/collector/featuregate v1.31.0 // indirect
45
+ go.opentelemetry.io/collector/internal/telemetry v0.125.0 // indirect
46
+ go.opentelemetry.io/collector/pdata/pprofile v0.125.0 // indirect
47
+ go.opentelemetry.io/collector/pipeline v0.125.0 // indirect
48
+ go.opentelemetry.io/collector/receiver v1.31.0 // indirect
49
+ go.opentelemetry.io/collector/receiver/receivertest v0.125.0 // indirect
50
+ go.opentelemetry.io/collector/receiver/xreceiver v0.125.0 // indirect
51
go.opentelemetry.io/contrib/bridges/otelzap v0.10.0 // indirect
52
go.opentelemetry.io/otel v1.35.0 // indirect
53
go.opentelemetry.io/otel/log v0.11.0 // indirect
@@ -59,8 +59,9 @@ require (
59
golang.org/x/net v0.39.0 // indirect
60
golang.org/x/sys v0.32.0 // indirect
61
golang.org/x/text v0.24.0 // indirect
62
- google.golang.org/genproto/googleapis/rpc v0.0.0-20250414145226-207652e42e2e // indirect
63
- google.golang.org/grpc v1.71.1 // indirect
62
+ google.golang.org/genproto/googleapis/rpc v0.0.0-20250428153025-10db94c68c34 // indirect
63
+ google.golang.org/grpc v1.72.0 // indirect
64
google.golang.org/protobuf v1.36.6 // indirect
65
gopkg.in/yaml.v3 v3.0.1 // indirect
66
+ sigs.k8s.io/yaml v1.4.0 // indirect
67
)
src/go/otel-collector/exporter/journaldexporter/go.sum
+55
-50
@@ -14,6 +14,7 @@ github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
14
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
15
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
16
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
17
+github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
18
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
19
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
20
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
@@ -56,52 +57,54 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
57
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
58
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
59
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
59
-go.opentelemetry.io/collector/component v1.30.0 h1:HXjqBHaQ47/EEuWdnkjr4Y3kRWvmyWIDvqa1Q262Fls=
60
-go.opentelemetry.io/collector/component v1.30.0/go.mod h1:vfM9kN+BM6oHBXWibquiprz8CVawxd4/aYy3nbhme3E=
61
-go.opentelemetry.io/collector/component/componenttest v0.124.0 h1:Wsc+DmDrWTFs/aEyjDA3slNwV+h/0NOyIR5Aywvr6Zw=
62
-go.opentelemetry.io/collector/component/componenttest v0.124.0/go.mod h1:NQ4ATOzMFc7QA06B993tq8o27DR0cu/JR/zK7slGJ3E=
63
-go.opentelemetry.io/collector/config/configretry v1.30.0 h1:sapni1tymwNiuI0PjqlRR5CvYxIQYT8tyjQGVJDkVPM=
64
-go.opentelemetry.io/collector/config/configretry v1.30.0/go.mod h1:QNnb+MCk7aS1k2EuGJMtlNCltzD7b8uC7Xel0Dxm1wQ=
65
-go.opentelemetry.io/collector/confmap v1.30.0 h1:Y0MXhjQCdMyJN9xZMWWdNPWs6ncMVf7YVnyAEN2dAcM=
66
-go.opentelemetry.io/collector/confmap v1.30.0/go.mod h1:9DdThVDIC3VsdtTb7DgT+HwusWOocoqDkd/TErEtQgA=
67
-go.opentelemetry.io/collector/consumer v1.30.0 h1:Nn6kFTH+EJbv13E0W+sNvWrTgbiFCRv8f6DaA2F1DQs=
68
-go.opentelemetry.io/collector/consumer v1.30.0/go.mod h1:edRyfk61ugdhCQ93PBLRZfYMVWjdMPpKP8z5QLyESf0=
69
-go.opentelemetry.io/collector/consumer/consumererror v0.124.0 h1:OmeJex0C8jcwyILG+eJIGDe6rGaR15fip+Rj3XyMTRY=
70
-go.opentelemetry.io/collector/consumer/consumererror v0.124.0/go.mod h1:A6WL/E70dUh9oFdQsL+aVYGL+d6UqiAhi7rIW/6gvDM=
71
-go.opentelemetry.io/collector/consumer/consumertest v0.124.0 h1:2arChG4RPrHW3lfVWlK/KDF7Y7qkUm/YAiBXh8oTue0=
72
-go.opentelemetry.io/collector/consumer/consumertest v0.124.0/go.mod h1:Hlu+EXbINHxVAyIT1baKO2d0j5odR3fLlLAiaP+JqQg=
73
-go.opentelemetry.io/collector/consumer/xconsumer v0.124.0 h1:/cut96EWVNoz6lIeGI9+EzS6UClMtnZkx5YIpkD0Xe0=
74
-go.opentelemetry.io/collector/consumer/xconsumer v0.124.0/go.mod h1:fHH/MpzFCRNk/4foiYE6BoXQCAMf5sJTO35uvzVrrd4=
75
-go.opentelemetry.io/collector/exporter v0.124.0 h1:ii+9tU/iSrPl4+YDvqFVflksA9hUYEzwMIpmvP4JZ8w=
76
-go.opentelemetry.io/collector/exporter v0.124.0/go.mod h1:Q8tOEwFu3CN8VGjE4H2yZcCRG9Q60foQIyZGKPD/jig=
77
-go.opentelemetry.io/collector/exporter/exportertest v0.124.0 h1:IOxA/4CiVWGPlmA0JofK6W4DzvwW1YJes09r6osluIE=
78
-go.opentelemetry.io/collector/exporter/exportertest v0.124.0/go.mod h1:2EmU8IwVJV79MmFBFFW1LCN0Ob2UZsEkX/mSUB06lbI=
79
-go.opentelemetry.io/collector/exporter/xexporter v0.124.0 h1:Itfn2+F4ki8hObOtPCecWBwGpuxakUYSsTwwkB5iUns=
80
-go.opentelemetry.io/collector/exporter/xexporter v0.124.0/go.mod h1:dNK/PPY02gA9BawIKHyVk8kIFdYvqVZ2A+LlMZucIPY=
81
-go.opentelemetry.io/collector/extension v1.30.0 h1:AJqntAp1p40Q1az2Vze3OHiMURq56KWnUxaLzs1ghaA=
82
-go.opentelemetry.io/collector/extension v1.30.0/go.mod h1:a21WpypFQp9x0Go7yMOknYmIKvdIoWGzjz+h1WMjzLk=
83
-go.opentelemetry.io/collector/extension/extensiontest v0.124.0 h1:pWfKxEqvq5vVdQy+UIerw5j7ZrXezxsfQfuUe8g/xVo=
84
-go.opentelemetry.io/collector/extension/extensiontest v0.124.0/go.mod h1:DLVRyW7tJt8TtYq0Wr5BUsM494YqDiIjN8YCmbVKqjs=
85
-go.opentelemetry.io/collector/extension/xextension v0.124.0 h1:Yzf11HXaiMHfS50Zy/CYKfJjoi+/w/tgRZdDQ2VIdW0=
86
-go.opentelemetry.io/collector/extension/xextension v0.124.0/go.mod h1:GeM0aSgwVSba3Bvvspuy1E+1aa/Q1CDxoK+e/xcJFVg=
87
-go.opentelemetry.io/collector/featuregate v1.30.0 h1:mx7+iP/FQnY7KO8qw/xE3Qd1MQkWcU8VgcqLNrJ8EU8=
88
-go.opentelemetry.io/collector/featuregate v1.30.0/go.mod h1:Y/KsHbvREENKvvN9RlpiWk/IGBK+CATBYzIIpU7nccc=
89
-go.opentelemetry.io/collector/internal/telemetry v0.124.0 h1:kzd1/ZYhLj4bt2pDB529mL4rIRrRacemXodFNxfhdWk=
90
-go.opentelemetry.io/collector/internal/telemetry v0.124.0/go.mod h1:ZjXjqV0dJ+6D4XGhTOxg/WHjnhdmXsmwmUSgALea66Y=
91
-go.opentelemetry.io/collector/pdata v1.30.0 h1:j3jyq9um436r6WzWySzexP2nLnFdmL5uVBYAlyr9nDM=
92
-go.opentelemetry.io/collector/pdata v1.30.0/go.mod h1:0Bxu1ktuj4wE7PIASNSvd0SdBscQ1PLtYasymJ13/Cs=
93
-go.opentelemetry.io/collector/pdata/pprofile v0.124.0 h1:ZjL9wKqzP4BHj0/F1jfGxs1Va8B7xmYayipZeNVoWJE=
94
-go.opentelemetry.io/collector/pdata/pprofile v0.124.0/go.mod h1:1EN3Gw5LSI4fSVma/Yfv/6nqeuYgRTm1/kmG5nE5Oyo=
95
-go.opentelemetry.io/collector/pdata/testdata v0.124.0 h1:vY+pWG7CQfzzGSB5+zGYHQOltRQr59Ek9QiPe+rI+NY=
96
-go.opentelemetry.io/collector/pdata/testdata v0.124.0/go.mod h1:lNH48lGhGv4CYk27fJecpsR1zYHmZjKgNrAprwjym0o=
97
-go.opentelemetry.io/collector/pipeline v0.124.0 h1:hKvhDyH2GPnNO8LGL34ugf36sY7EOXPjBvlrvBhsOdw=
98
-go.opentelemetry.io/collector/pipeline v0.124.0/go.mod h1:TO02zju/K6E+oFIOdi372Wk0MXd+Szy72zcTsFQwXl4=
99
-go.opentelemetry.io/collector/receiver v1.30.0 h1:XbgU4yT3Ld+hL9+jHcD/Kctcr3gXjpiFxKO+50pSayg=
100
-go.opentelemetry.io/collector/receiver v1.30.0/go.mod h1:U3cApz9PHiRMgN0WkZaz4o8mvj1+cVQYsyj2Nl1v3FQ=
101
-go.opentelemetry.io/collector/receiver/receivertest v0.124.0 h1:mx0290aXAo+wfjm4NgbKUodjT5SbS306zmk+AeqeVxE=
102
-go.opentelemetry.io/collector/receiver/receivertest v0.124.0/go.mod h1:3RpopRmIzx5T4zTStHJC0HHfd8YFWm8e9bia1HiuDtY=
103
-go.opentelemetry.io/collector/receiver/xreceiver v0.124.0 h1:YigTUKk8p/aIfqaT0ST7teT9KbLThWD5n2km83byftw=
104
-go.opentelemetry.io/collector/receiver/xreceiver v0.124.0/go.mod h1:NkTpmpAEDT17Dko4gpHUnRztrSkdSd6B0+Y4gfuCWIA=
60
+go.opentelemetry.io/collector/client v1.31.0 h1:PdmUJSx8FgFcrqm12pMwvdVp98aYSdaKjMqJandFIgE=
61
+go.opentelemetry.io/collector/client v1.31.0/go.mod h1:pSyJ1+XhsLP6nqJDP7uj3AFTw26z9mqCnRGyMw0Im8o=
62
+go.opentelemetry.io/collector/component v1.31.0 h1:9LzU8X1RhV3h8/QsAoTX23aFUfoJ3EUc9O/vK+hFpSI=
63
+go.opentelemetry.io/collector/component v1.31.0/go.mod h1:JbZl/KywXJxpUXPbt96qlEXJSym1zQ2hauMxYMuvlxM=
64
+go.opentelemetry.io/collector/component/componenttest v0.125.0 h1:E2mpnMQbkMpYoZ3Q8pHx4kod7kedjwRs1xqDpzCe/84=
65
+go.opentelemetry.io/collector/component/componenttest v0.125.0/go.mod h1:pQtsE1u/SPZdTphP5BZP64XbjXSq6wc+mDut5Ws/JDI=
66
+go.opentelemetry.io/collector/config/configretry v1.31.0 h1:GWl/UM7+xNCmXBz5lvaMxBIQTcNn1EcCvMjVvUwgOLg=
67
+go.opentelemetry.io/collector/config/configretry v1.31.0/go.mod h1:QNnb+MCk7aS1k2EuGJMtlNCltzD7b8uC7Xel0Dxm1wQ=
68
+go.opentelemetry.io/collector/confmap v1.31.0 h1:+AW5VJc1rCtgEyGd+1J5uSNw/kVZ98+lKO/pqXEwVvU=
69
+go.opentelemetry.io/collector/confmap v1.31.0/go.mod h1:TdutQlIoHDPXcZ2xZ0QWGRkSFC8oTKO61zTx569dvrY=
70
+go.opentelemetry.io/collector/consumer v1.31.0 h1:L+y66ywxLHnAxnUxv0JDwUf5bFj53kMxCCyEfRKlM7s=
71
+go.opentelemetry.io/collector/consumer v1.31.0/go.mod h1:rPsqy5ni+c6xNMUkOChleZYO/nInVY6eaBNZ1FmWJVk=
72
+go.opentelemetry.io/collector/consumer/consumererror v0.125.0 h1:Qq9SgbxlJoRn0952dj4lPJhcuBiqKzD1aNxCfa+Bz00=
73
+go.opentelemetry.io/collector/consumer/consumererror v0.125.0/go.mod h1:t/YDU7G2TxG27LbcUvgKo/l75TI5VApnnqC7FgKZds0=
74
+go.opentelemetry.io/collector/consumer/consumertest v0.125.0 h1:TUkxomGS4DAtjBvcWQd2UY4FDLLEKMQD6iOIDUr/5dM=
75
+go.opentelemetry.io/collector/consumer/consumertest v0.125.0/go.mod h1:vkHf3y85cFLDHARO/cTREVjLjOPAV+cQg7lkC44DWOY=
76
+go.opentelemetry.io/collector/consumer/xconsumer v0.125.0 h1:oTreUlk1KpMSWwuHFnstW+orrjGTyvs2xd3o/Dpy+hI=
77
+go.opentelemetry.io/collector/consumer/xconsumer v0.125.0/go.mod h1:FX0G37r0W+wXRgxxFtwEJ4rlsCB+p0cIaxtU3C4hskw=
78
+go.opentelemetry.io/collector/exporter v0.125.0 h1:GJxeCuOQVPndQzvzpZUFEv5njHuVnzBEuXgddRShiCM=
79
+go.opentelemetry.io/collector/exporter v0.125.0/go.mod h1:x+FFBRxWGk+GGaP7u+Bi+OcZoG5qK5vZmgFwI/t4ZwM=
80
+go.opentelemetry.io/collector/exporter/exportertest v0.125.0 h1:FFCEHKlTct0vl/657E1papmL3NicdcxY4ChZbHI3nWk=
81
+go.opentelemetry.io/collector/exporter/exportertest v0.125.0/go.mod h1:UQ6ETigK5yTASXGvjSlE7RcM8C6Ro+TcR8iqDHpXa2U=
82
+go.opentelemetry.io/collector/exporter/xexporter v0.125.0 h1:be5oK6+QOXvyXiCxfiTKxdo/TmjewvciCbC8iMKi/1s=
83
+go.opentelemetry.io/collector/exporter/xexporter v0.125.0/go.mod h1:ebfTFVtKR2eUiAQQc/cS1aBTV2OoFDvFjLiX+thE23s=
84
+go.opentelemetry.io/collector/extension v1.31.0 h1:DaqSl50jOA3BGtqPfPtSGJy4XwyXtQwvemVl/L9fDb4=
85
+go.opentelemetry.io/collector/extension v1.31.0/go.mod h1:SiRNOZIJ6R0JbHEvs3g84hPEmiys5CZyIlMOE1RQ85s=
86
+go.opentelemetry.io/collector/extension/extensiontest v0.125.0 h1:NYtQ42HBjfS5lnfmZdT8+ucq+i70JGLdvDN8V/drvIw=
87
+go.opentelemetry.io/collector/extension/extensiontest v0.125.0/go.mod h1:HABANc94xQmUtOSZokG5E6Z02GrHfKYSkQqOz+oCpPQ=
88
+go.opentelemetry.io/collector/extension/xextension v0.125.0 h1:4BOzKuI5jtNP74X7LMeezFidSYdg8ny3Epv4GzV7LO4=
89
+go.opentelemetry.io/collector/extension/xextension v0.125.0/go.mod h1:JNx5t/UnzxJiH2piNtko7Nj3E4x6YNkWxrVlpvpbm6w=
90
+go.opentelemetry.io/collector/featuregate v1.31.0 h1:20q7plPQZwmAiaYAa6l1m/i2qDITZuWlhjr4EkmeQls=
91
+go.opentelemetry.io/collector/featuregate v1.31.0/go.mod h1:Y/KsHbvREENKvvN9RlpiWk/IGBK+CATBYzIIpU7nccc=
92
+go.opentelemetry.io/collector/internal/telemetry v0.125.0 h1:6lcGOxw3dAg7LfXTKdN8ZjR+l7KvzLdEiPMhhLwG4r4=
93
+go.opentelemetry.io/collector/internal/telemetry v0.125.0/go.mod h1:5GyFslLqjZgq1DZTtFiluxYhhXrCofHgOOOybodDPGE=
94
+go.opentelemetry.io/collector/pdata v1.31.0 h1:P5WuLr1l2JcIvr6Dw2hl01ltp2ZafPnC4Isv+BLTBqU=
95
+go.opentelemetry.io/collector/pdata v1.31.0/go.mod h1:m41io9nWpy7aCm/uD1L9QcKiZwOP0ldj83JEA34dmlk=
96
+go.opentelemetry.io/collector/pdata/pprofile v0.125.0 h1:Qqlx8w1HpiYZ9RQqjmMQIysI0cHNO1nh3E/fCTeFysA=
97
+go.opentelemetry.io/collector/pdata/pprofile v0.125.0/go.mod h1:p/yK023VxAp8hm27/1G5DPTcMIpnJy3cHGAFUQZGyaQ=
98
+go.opentelemetry.io/collector/pdata/testdata v0.125.0 h1:due1Hl0EEVRVwfCkiamRy5E8lS6yalv0lo8Zl/SJtGw=
99
+go.opentelemetry.io/collector/pdata/testdata v0.125.0/go.mod h1:1GpEWlgdMrd+fWsBk37ZC2YmOP5YU3gFQ4rWuCu9g24=
100
+go.opentelemetry.io/collector/pipeline v0.125.0 h1:oitBgcAFqntDB4ihQJUHJSQ8IHqKFpPkaTVbTYdIUzM=
101
+go.opentelemetry.io/collector/pipeline v0.125.0/go.mod h1:TO02zju/K6E+oFIOdi372Wk0MXd+Szy72zcTsFQwXl4=
102
+go.opentelemetry.io/collector/receiver v1.31.0 h1:OSRrCWclb1QmGPnxFMxQsdegua4vlKpZESOtDKSzKeQ=
103
+go.opentelemetry.io/collector/receiver v1.31.0/go.mod h1:zPUiv3jgJGQSY01nx500cYJiEz6JfaR53BAvCW2tgGs=
104
+go.opentelemetry.io/collector/receiver/receivertest v0.125.0 h1:xV3Jm3OT7SfDpJ5mXhNmK/Nch7f41whA8k0q4XkaWT8=
105
+go.opentelemetry.io/collector/receiver/receivertest v0.125.0/go.mod h1:CoSPPn3kwVcAhdLOK5NVjMCVVjmCsFpBXU9h9I6Kdh8=
106
+go.opentelemetry.io/collector/receiver/xreceiver v0.125.0 h1:wQ1ZgCA0Y3EFWWZ6gZDGDXT7qV5IrqkisccUWhvmmTg=
107
+go.opentelemetry.io/collector/receiver/xreceiver v0.125.0/go.mod h1:5Kl/mtf6oIy+rizFcElkUpp3LEVTJnjAyos6z+FVsGc=
108
go.opentelemetry.io/contrib/bridges/otelzap v0.10.0 h1:ojdSRDvjrnm30beHOmwsSvLpoRF40MlwNCA+Oo93kXU=
109
go.opentelemetry.io/contrib/bridges/otelzap v0.10.0/go.mod h1:oTTm4g7NEtHSV2i/0FeVdPaPgUIZPfQkFbq0vbzqnv0=
110
go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ=
@@ -153,10 +156,10 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T
156
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
157
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
158
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
156
-google.golang.org/genproto/googleapis/rpc v0.0.0-20250414145226-207652e42e2e h1:ztQaXfzEXTmCBvbtWYRhJxW+0iJcz2qXfd38/e9l7bA=
157
-google.golang.org/genproto/googleapis/rpc v0.0.0-20250414145226-207652e42e2e/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
158
-google.golang.org/grpc v1.71.1 h1:ffsFWr7ygTUscGPI0KKK6TLrGz0476KUvvsbqWK0rPI=
159
-google.golang.org/grpc v1.71.1/go.mod h1:H0GRtasmQOh9LkFoCPDu3ZrwUtD1YGE+b2vYBYd/8Ec=
159
+google.golang.org/genproto/googleapis/rpc v0.0.0-20250428153025-10db94c68c34 h1:h6p3mQqrmT1XkHVTfzLdNz1u7IhINeZkz67/xTbOuWs=
160
+google.golang.org/genproto/googleapis/rpc v0.0.0-20250428153025-10db94c68c34/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
161
+google.golang.org/grpc v1.72.0 h1:S7UkcVa60b5AAQTaO6ZKamFp1zMZSU0fGDK2WZLbBnM=
162
+google.golang.org/grpc v1.72.0/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM=
163
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
164
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
165
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
@@ -164,3 +167,5 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntN
167
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
168
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
169
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
170
+sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=
171
+sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=
src/go/otel-collector/exporter/netdataexporter/convert.go
new
+821
@@ -0,0 +1,821 @@
1
+package netdataexporter
2
+
3
+import (
4
+ "fmt"
5
+ "hash/fnv"
6
+ "sort"
7
+ "strconv"
8
+ "strings"
9
+ "unicode"
10
+
11
+ "go.opentelemetry.io/collector/pdata/pcommon"
12
+ "go.opentelemetry.io/collector/pdata/pmetric"
13
+)
14
+
15
+type ChartDefinition struct {
16
+ ID string // must be globally unique
17
+ Title string
18
+ Units string
19
+ Family string
20
+ Context string // metric name
21
+ Type string // line, area, stacked
22
+ Options string // set to "obsolete" to delete the chart, otherwise empty string
23
+ Labels []LabelDefinition
24
+ Dimensions []DimensionDefinition
25
+ IsNew bool // Indicates if this chart is new and needs to be sent to Netdata
26
+}
27
+
28
+// LabelDefinition represents a Netdata chart label
29
+type LabelDefinition struct {
30
+ Name string
31
+ Value string
32
+}
33
+
34
+// DimensionDefinition represents a Netdata chart dimension
35
+type DimensionDefinition struct {
36
+ ID string // must be unique within the chart
37
+ Name string // replaces ID in UI
38
+ Algo string // absolute (Gauge), incremental (Counter)
39
+ Value float64
40
+}
41
+
42
+// Maximum length for chart IDs to prevent excessively long IDs
43
+const maxChartIDLength = 1000
44
+
45
+// Convert transforms OTLP metrics into Netdata charts
46
+func (e *netdataExporter) Convert(pms pmetric.Metrics) map[string]*ChartDefinition {
47
+ // Track new and updated charts in this batch
48
+ currentCharts := make(map[string]bool, len(e.charts))
49
+
50
+ for _, rm := range pms.ResourceMetrics().All() {
51
+ resAttrs := rm.Resource().Attributes()
52
+
53
+ for _, sm := range rm.ScopeMetrics().All() {
54
+ for _, metric := range sm.Metrics().All() {
55
+ switch metric.Type() {
56
+ case pmetric.MetricTypeGauge:
57
+ e.processGauge(metric, resAttrs, currentCharts)
58
+ case pmetric.MetricTypeSum:
59
+ e.processSum(metric, resAttrs, currentCharts)
60
+ case pmetric.MetricTypeHistogram:
61
+ e.processHistogram(metric, resAttrs, currentCharts)
62
+ case pmetric.MetricTypeExponentialHistogram:
63
+ e.processExponentialHistogram(metric, resAttrs, currentCharts)
64
+ case pmetric.MetricTypeSummary:
65
+ e.processSummary(metric, resAttrs, currentCharts)
66
+ default:
67
+ }
68
+ }
69
+ }
70
+ }
71
+
72
+ for id, chart := range e.charts {
73
+ if !currentCharts[id] {
74
+ chart.IsNew = false
75
+ }
76
+ }
77
+
78
+ return e.charts
79
+}
80
+
81
+// processGauge handles gauge metric types
82
+func (e *netdataExporter) processGauge(metric pmetric.Metric, resourceAttrs pcommon.Map, currentCharts map[string]bool) {
83
+ gauge := metric.Gauge()
84
+ metricName := metric.Name()
85
+
86
+ // Group data points by their attributes to create separate charts
87
+ attributeGroups := groupDataPointsByAttributes(gauge.DataPoints())
88
+
89
+ for attrHash, points := range attributeGroups {
90
+ // Generate a unique chart ID
91
+ chartID := generateChartID(metricName, attrHash)
92
+ currentCharts[chartID] = true
93
+
94
+ // Get or create chart
95
+ chart, exists := e.charts[chartID]
96
+ if !exists {
97
+ chart = &ChartDefinition{
98
+ ID: chartID,
99
+ Title: getTitle(metric),
100
+ Units: getUnits(metric),
101
+ Family: getFamily(metricName, resourceAttrs),
102
+ Context: metricName,
103
+ Type: "line", // Default to line chart
104
+ Labels: make([]LabelDefinition, 0, resourceAttrs.Len()),
105
+ IsNew: true,
106
+ }
107
+ e.charts[chartID] = chart
108
+ }
109
+
110
+ // Update chart with resource attributes as labels
111
+ updateChartLabels(chart, resourceAttrs)
112
+
113
+ // Process data points
114
+ dimensions := make([]DimensionDefinition, 0, len(points))
115
+
116
+ for _, dp := range points {
117
+ if dp.Flags().NoRecordedValue() {
118
+ continue
119
+ }
120
+
121
+ dimID := generateDimensionID(dp.Attributes())
122
+ dimName := getDimensionName(dp.Attributes())
123
+
124
+ value := 0.0
125
+ if dp.ValueType() == pmetric.NumberDataPointValueTypeDouble {
126
+ value = dp.DoubleValue()
127
+ } else {
128
+ value = float64(dp.IntValue())
129
+ }
130
+
131
+ dimensions = append(dimensions, DimensionDefinition{
132
+ ID: dimID,
133
+ Name: dimName,
134
+ Algo: "absolute", // Gauge uses absolute algorithm
135
+ Value: value,
136
+ })
137
+
138
+ // Add data point attributes as labels
139
+ addDataPointAttributesAsLabels(chart, dp.Attributes())
140
+ }
141
+
142
+ chart.Dimensions = append(chart.Dimensions[:0], dimensions...)
143
+ }
144
+}
145
+
146
+// processSum handles sum metric types
147
+func (e *netdataExporter) processSum(metric pmetric.Metric, resourceAttrs pcommon.Map, currentCharts map[string]bool) {
148
+ sum := metric.Sum()
149
+ metricName := metric.Name()
150
+
151
+ // Determine algorithm based on aggregation temporality
152
+ algo := "absolute" // Default for CUMULATIVE and UNSPECIFIED
153
+ if sum.AggregationTemporality() == pmetric.AggregationTemporalityDelta {
154
+ algo = "incremental"
155
+ }
156
+
157
+ // Group data points by their attributes to create separate charts
158
+ attributeGroups := groupDataPointsByAttributes(sum.DataPoints())
159
+
160
+ for attrHash, points := range attributeGroups {
161
+ // Generate a unique chart ID
162
+ chartID := generateChartID(metricName, attrHash)
163
+ currentCharts[chartID] = true
164
+
165
+ // Get or create chart
166
+ chart, exists := e.charts[chartID]
167
+ if !exists {
168
+ chart = &ChartDefinition{
169
+ ID: chartID,
170
+ Title: getTitle(metric),
171
+ Units: getUnits(metric),
172
+ Family: getFamily(metricName, resourceAttrs),
173
+ Context: metricName,
174
+ Type: "line", // Default to line chart
175
+ Labels: make([]LabelDefinition, 0, resourceAttrs.Len()),
176
+ IsNew: true,
177
+ }
178
+ e.charts[chartID] = chart
179
+ }
180
+
181
+ // Update chart with resource attributes as labels
182
+ updateChartLabels(chart, resourceAttrs)
183
+
184
+ // Process data points
185
+ dimensions := make([]DimensionDefinition, 0, len(points))
186
+
187
+ for _, dp := range points {
188
+ if dp.Flags().NoRecordedValue() {
189
+ continue
190
+ }
191
+
192
+ dimID := generateDimensionID(dp.Attributes())
193
+ dimName := getDimensionName(dp.Attributes())
194
+
195
+ value := 0.0
196
+ if dp.ValueType() == pmetric.NumberDataPointValueTypeDouble {
197
+ value = dp.DoubleValue()
198
+ } else {
199
+ value = float64(dp.IntValue())
200
+ }
201
+
202
+ dimensions = append(dimensions, DimensionDefinition{
203
+ ID: dimID,
204
+ Name: dimName,
205
+ Algo: algo,
206
+ Value: value,
207
+ })
208
+
209
+ // Add data point attributes as labels
210
+ addDataPointAttributesAsLabels(chart, dp.Attributes())
211
+ }
212
+
213
+ chart.Dimensions = dimensions
214
+ }
215
+}
216
+
217
+// processHistogram handles histogram metric types
218
+func (e *netdataExporter) processHistogram(metric pmetric.Metric, resourceAttrs pcommon.Map, currentCharts map[string]bool) {
219
+ histogram := metric.Histogram()
220
+ metricName := metric.Name()
221
+
222
+ // Determine algorithm based on aggregation temporality
223
+ algo := "absolute" // Default for CUMULATIVE and UNSPECIFIED
224
+ if histogram.AggregationTemporality() == pmetric.AggregationTemporalityDelta {
225
+ algo = "incremental"
226
+ }
227
+
228
+ for _, dp := range histogram.DataPoints().All() {
229
+ if dp.Flags().NoRecordedValue() {
230
+ continue
231
+ }
232
+
233
+ attrHash := attributesHash(dp.Attributes())
234
+ dimID := generateDimensionID(dp.Attributes())
235
+ dimName := getDimensionName(dp.Attributes())
236
+
237
+ // 1. Count chart
238
+ countChartID := generateChartID(metricName+".count", attrHash)
239
+ currentCharts[countChartID] = true
240
+
241
+ countChart, exists := e.charts[countChartID]
242
+ if !exists {
243
+ countChart = &ChartDefinition{
244
+ ID: countChartID,
245
+ Title: getTitle(metric) + " (Count)",
246
+ Units: "count",
247
+ Family: getFamily(metricName, resourceAttrs),
248
+ Context: metricName + ".count",
249
+ Type: "line",
250
+ Labels: make([]LabelDefinition, 0, resourceAttrs.Len()),
251
+ IsNew: true,
252
+ }
253
+ e.charts[countChartID] = countChart
254
+ }
255
+
256
+ updateChartLabels(countChart, resourceAttrs)
257
+ addDataPointAttributesAsLabels(countChart, dp.Attributes())
258
+
259
+ countChart.Dimensions = []DimensionDefinition{
260
+ {
261
+ ID: dimID,
262
+ Name: dimName,
263
+ Algo: algo,
264
+ Value: float64(dp.Count()),
265
+ },
266
+ }
267
+
268
+ // 2. Sum chart (if sum exists)
269
+ if dp.HasSum() {
270
+ sumChartID := generateChartID(metricName+".sum", attrHash)
271
+ currentCharts[sumChartID] = true
272
+
273
+ sumChart, exists := e.charts[sumChartID]
274
+ if !exists {
275
+ sumChart = &ChartDefinition{
276
+ ID: sumChartID,
277
+ Title: getTitle(metric) + " (Sum)",
278
+ Units: getUnits(metric),
279
+ Family: getFamily(metricName, resourceAttrs),
280
+ Context: metricName + ".sum",
281
+ Type: "line",
282
+ Labels: make([]LabelDefinition, 0, resourceAttrs.Len()),
283
+ IsNew: true,
284
+ }
285
+ e.charts[sumChartID] = sumChart
286
+ }
287
+
288
+ updateChartLabels(sumChart, resourceAttrs)
289
+ addDataPointAttributesAsLabels(sumChart, dp.Attributes())
290
+
291
+ sumChart.Dimensions = []DimensionDefinition{
292
+ {
293
+ ID: dimID,
294
+ Name: dimName,
295
+ Algo: algo,
296
+ Value: dp.Sum(),
297
+ },
298
+ }
299
+ }
300
+
301
+ // 3. Buckets chart (if buckets exist)
302
+ bucketCounts := dp.BucketCounts()
303
+ explicitBounds := dp.ExplicitBounds()
304
+
305
+ if bucketCounts.Len() > 0 && explicitBounds.Len() > 0 {
306
+ bucketsChartID := generateChartID(metricName+".buckets", attrHash)
307
+ currentCharts[bucketsChartID] = true
308
+
309
+ bucketsChart, exists := e.charts[bucketsChartID]
310
+ if !exists {
311
+ bucketsChart = &ChartDefinition{
312
+ ID: bucketsChartID,
313
+ Title: getTitle(metric) + " (Buckets)",
314
+ Units: "count",
315
+ Family: getFamily(metricName, resourceAttrs),
316
+ Context: metricName + ".buckets",
317
+ Type: "stacked", // Histogram buckets should be stacked
318
+ Labels: make([]LabelDefinition, 0, resourceAttrs.Len()),
319
+ IsNew: true,
320
+ }
321
+ e.charts[bucketsChartID] = bucketsChart
322
+ }
323
+
324
+ updateChartLabels(bucketsChart, resourceAttrs)
325
+ addDataPointAttributesAsLabels(bucketsChart, dp.Attributes())
326
+
327
+ dimensions := make([]DimensionDefinition, 0, bucketCounts.Len())
328
+
329
+ // Add dimensions for each bucket
330
+ for j := 0; j < bucketCounts.Len(); j++ {
331
+ var upperBound string
332
+ if j < explicitBounds.Len() {
333
+ upperBound = fmt.Sprintf("%.2f", explicitBounds.At(j))
334
+ } else {
335
+ upperBound = "inf"
336
+ }
337
+
338
+ bucketDimID := dimID + "_bucket_" + strconv.Itoa(j)
339
+ bucketDimName := "≤ " + upperBound
340
+
341
+ dimensions = append(dimensions, DimensionDefinition{
342
+ ID: bucketDimID,
343
+ Name: bucketDimName,
344
+ Algo: algo,
345
+ Value: float64(bucketCounts.At(j)),
346
+ })
347
+ }
348
+
349
+ bucketsChart.Dimensions = dimensions
350
+ }
351
+ }
352
+}
353
+
354
+// processExponentialHistogram handles exponential histogram metric types
355
+func (e *netdataExporter) processExponentialHistogram(metric pmetric.Metric, resourceAttrs pcommon.Map, currentCharts map[string]bool) {
356
+ expHistogram := metric.ExponentialHistogram()
357
+ metricName := metric.Name()
358
+
359
+ // Determine algorithm based on aggregation temporality
360
+ algo := "absolute" // Default for CUMULATIVE and UNSPECIFIED
361
+ if expHistogram.AggregationTemporality() == pmetric.AggregationTemporalityDelta {
362
+ algo = "incremental"
363
+ }
364
+
365
+ for _, dp := range expHistogram.DataPoints().All() {
366
+ if dp.Flags().NoRecordedValue() {
367
+ continue
368
+ }
369
+
370
+ attrHash := attributesHash(dp.Attributes())
371
+ dimID := generateDimensionID(dp.Attributes())
372
+ dimName := getDimensionName(dp.Attributes())
373
+
374
+ // 1. Count chart
375
+ countChartID := generateChartID(metricName+".count", attrHash)
376
+ currentCharts[countChartID] = true
377
+
378
+ countChart, exists := e.charts[countChartID]
379
+ if !exists {
380
+ countChart = &ChartDefinition{
381
+ ID: countChartID,
382
+ Title: getTitle(metric) + " (Count)",
383
+ Units: "count",
384
+ Family: getFamily(metricName, resourceAttrs),
385
+ Context: metricName + ".count",
386
+ Type: "line",
387
+ Labels: make([]LabelDefinition, 0, resourceAttrs.Len()),
388
+ IsNew: true,
389
+ }
390
+ e.charts[countChartID] = countChart
391
+ }
392
+
393
+ updateChartLabels(countChart, resourceAttrs)
394
+ addDataPointAttributesAsLabels(countChart, dp.Attributes())
395
+
396
+ countChart.Dimensions = []DimensionDefinition{
397
+ {
398
+ ID: dimID,
399
+ Name: dimName,
400
+ Algo: algo,
401
+ Value: float64(dp.Count()),
402
+ },
403
+ }
404
+
405
+ // 2. Sum chart (if sum exists)
406
+ if dp.HasSum() {
407
+ sumChartID := generateChartID(metricName+".sum", attrHash)
408
+ currentCharts[sumChartID] = true
409
+
410
+ sumChart, exists := e.charts[sumChartID]
411
+ if !exists {
412
+ sumChart = &ChartDefinition{
413
+ ID: sumChartID,
414
+ Title: getTitle(metric) + " (Sum)",
415
+ Units: getUnits(metric),
416
+ Family: getFamily(metricName, resourceAttrs),
417
+ Context: metricName + ".sum",
418
+ Type: "line",
419
+ Labels: make([]LabelDefinition, 0, resourceAttrs.Len()),
420
+ IsNew: true,
421
+ }
422
+ e.charts[sumChartID] = sumChart
423
+ }
424
+
425
+ updateChartLabels(sumChart, resourceAttrs)
426
+ addDataPointAttributesAsLabels(sumChart, dp.Attributes())
427
+
428
+ sumChart.Dimensions = []DimensionDefinition{
429
+ {
430
+ ID: dimID,
431
+ Name: dimName,
432
+ Algo: algo,
433
+ Value: dp.Sum(),
434
+ },
435
+ }
436
+ }
437
+
438
+ // 3. Simplified histogram buckets chart
439
+ // For exponential histograms, we'll create a simplified view with positive, zero, and negative counts
440
+ bucketsChartID := generateChartID(metricName+".exp_buckets", attrHash)
441
+ currentCharts[bucketsChartID] = true
442
+
443
+ bucketsChart, exists := e.charts[bucketsChartID]
444
+ if !exists {
445
+ bucketsChart = &ChartDefinition{
446
+ ID: bucketsChartID,
447
+ Title: getTitle(metric) + " (Distribution)",
448
+ Units: "count",
449
+ Family: getFamily(metricName, resourceAttrs),
450
+ Context: metricName + ".distribution",
451
+ Type: "stacked",
452
+ Labels: make([]LabelDefinition, 0, resourceAttrs.Len()),
453
+ IsNew: true,
454
+ }
455
+ e.charts[bucketsChartID] = bucketsChart
456
+ }
457
+
458
+ updateChartLabels(bucketsChart, resourceAttrs)
459
+ addDataPointAttributesAsLabels(bucketsChart, dp.Attributes())
460
+
461
+ // Add dimensions for positive, negative, and zero buckets
462
+ bucketsChart.Dimensions = []DimensionDefinition{
463
+ {
464
+ ID: dimID + "_positive",
465
+ Name: "Positive Values",
466
+ Algo: algo,
467
+ Value: getTotalCountFromBuckets(dp.Positive()),
468
+ },
469
+ {
470
+ ID: dimID + "_zero",
471
+ Name: "Zero Values",
472
+ Algo: algo,
473
+ Value: float64(dp.ZeroCount()),
474
+ },
475
+ {
476
+ ID: dimID + "_negative",
477
+ Name: "Negative Values",
478
+ Algo: algo,
479
+ Value: getTotalCountFromBuckets(dp.Negative()),
480
+ },
481
+ }
482
+ }
483
+}
484
+
485
+// processSummary handles summary metric types
486
+func (e *netdataExporter) processSummary(metric pmetric.Metric, resourceAttrs pcommon.Map, currentCharts map[string]bool) {
487
+ summary := metric.Summary()
488
+ metricName := metric.Name()
489
+
490
+ for _, dp := range summary.DataPoints().All() {
491
+ if dp.Flags().NoRecordedValue() {
492
+ continue
493
+ }
494
+
495
+ attrHash := attributesHash(dp.Attributes())
496
+ dimID := generateDimensionID(dp.Attributes())
497
+ dimName := getDimensionName(dp.Attributes())
498
+
499
+ // 1. Count chart
500
+ countChartID := generateChartID(metricName+".count", attrHash)
501
+ currentCharts[countChartID] = true
502
+
503
+ countChart, exists := e.charts[countChartID]
504
+ if !exists {
505
+ countChart = &ChartDefinition{
506
+ ID: countChartID,
507
+ Title: getTitle(metric) + " (Count)",
508
+ Units: "count",
509
+ Family: getFamily(metricName, resourceAttrs),
510
+ Context: metricName + ".count",
511
+ Type: "line",
512
+ Labels: make([]LabelDefinition, 0, resourceAttrs.Len()),
513
+ IsNew: true,
514
+ }
515
+ e.charts[countChartID] = countChart
516
+ }
517
+
518
+ updateChartLabels(countChart, resourceAttrs)
519
+ addDataPointAttributesAsLabels(countChart, dp.Attributes())
520
+
521
+ countChart.Dimensions = []DimensionDefinition{
522
+ {
523
+ ID: dimID,
524
+ Name: dimName,
525
+ Algo: "absolute", // Summary count should be absolute
526
+ Value: float64(dp.Count()),
527
+ },
528
+ }
529
+
530
+ // 2. Sum chart
531
+ sumChartID := generateChartID(metricName+".sum", attrHash)
532
+ currentCharts[sumChartID] = true
533
+
534
+ sumChart, exists := e.charts[sumChartID]
535
+ if !exists {
536
+ sumChart = &ChartDefinition{
537
+ ID: sumChartID,
538
+ Title: getTitle(metric) + " (Sum)",
539
+ Units: getUnits(metric),
540
+ Family: getFamily(metricName, resourceAttrs),
541
+ Context: metricName + ".sum",
542
+ Type: "line",
543
+ Labels: make([]LabelDefinition, 0, resourceAttrs.Len()),
544
+ IsNew: true,
545
+ }
546
+ e.charts[sumChartID] = sumChart
547
+ }
548
+
549
+ updateChartLabels(sumChart, resourceAttrs)
550
+ addDataPointAttributesAsLabels(sumChart, dp.Attributes())
551
+
552
+ sumChart.Dimensions = []DimensionDefinition{
553
+ {
554
+ ID: dimID,
555
+ Name: dimName,
556
+ Algo: "absolute", // Summary sum should be absolute
557
+ Value: dp.Sum(),
558
+ },
559
+ }
560
+
561
+ // 3. Quantiles chart
562
+ qvs := dp.QuantileValues()
563
+ if qvs.Len() > 0 {
564
+ quantilesChartID := generateChartID(metricName+".quantiles", attrHash)
565
+ currentCharts[quantilesChartID] = true
566
+
567
+ quantilesChart, exists := e.charts[quantilesChartID]
568
+ if !exists {
569
+ quantilesChart = &ChartDefinition{
570
+ ID: quantilesChartID,
571
+ Title: getTitle(metric) + " (Quantiles)",
572
+ Units: getUnits(metric),
573
+ Family: getFamily(metricName, resourceAttrs),
574
+ Context: metricName + ".quantiles",
575
+ Type: "line",
576
+ Labels: make([]LabelDefinition, 0, resourceAttrs.Len()),
577
+ IsNew: true,
578
+ }
579
+ e.charts[quantilesChartID] = quantilesChart
580
+ }
581
+
582
+ updateChartLabels(quantilesChart, resourceAttrs)
583
+ addDataPointAttributesAsLabels(quantilesChart, dp.Attributes())
584
+
585
+ dimensions := make([]DimensionDefinition, 0, qvs.Len())
586
+
587
+ // Add dimensions for each quantile
588
+ for _, qv := range qvs.All() {
589
+ quantileStr := fmt.Sprintf("%.2f", qv.Quantile())
590
+
591
+ // Special names for min/max
592
+ var quantileName string
593
+ if qv.Quantile() == 0 {
594
+ quantileName = "min"
595
+ } else if qv.Quantile() == 1 {
596
+ quantileName = "max"
597
+ } else {
598
+ quantileName = "p" + strings.ReplaceAll(quantileStr, "0.", "")
599
+ }
600
+
601
+ dimensions = append(dimensions, DimensionDefinition{
602
+ ID: dimID + "_q" + strings.ReplaceAll(quantileStr, ".", "_"),
603
+ Name: quantileName,
604
+ Algo: "absolute", // Quantiles are absolute values
605
+ Value: qv.Value(),
606
+ })
607
+ }
608
+
609
+ quantilesChart.Dimensions = dimensions
610
+ }
611
+ }
612
+}
613
+
614
+// groupDataPointsByAttributes groups data points by attributes to create separate charts
615
+func groupDataPointsByAttributes(dataPoints pmetric.NumberDataPointSlice) map[string][]pmetric.NumberDataPoint {
616
+ groups := make(map[string][]pmetric.NumberDataPoint)
617
+
618
+ for _, dp := range dataPoints.All() {
619
+ hash := attributesHash(dp.Attributes())
620
+ groups[hash] = append(groups[hash], dp)
621
+ }
622
+
623
+ return groups
624
+}
625
+
626
+func generateChartID(metricName, attrHash string) string {
627
+ // Sanitize and limit the length of the metric name to prevent overly long IDs
628
+ sanitizedName := sanitizeID(metricName)
629
+ if len(sanitizedName) > maxChartIDLength-1-len(attrHash) {
630
+ sanitizedName = sanitizedName[:maxChartIDLength-1-len(attrHash)]
631
+ }
632
+ return sanitizedName + "_" + attrHash
633
+}
634
+
635
+func generateDimensionID(attrs pcommon.Map) string {
636
+ if attrs.Len() == 0 {
637
+ return "value"
638
+ }
639
+
640
+ return "value_" + attributesHash(attrs)
641
+}
642
+
643
+func getDimensionName(attrs pcommon.Map) string {
644
+ if attrs.Len() == 0 {
645
+ return "value"
646
+ }
647
+
648
+ // Try to find a good name from the attributes
649
+ nameAttrs := []string{"name", "id", "key"}
650
+ for _, nameAttr := range nameAttrs {
651
+ if val, ok := attrs.Get(nameAttr); ok {
652
+ return val.AsString()
653
+ }
654
+ }
655
+
656
+ return "value"
657
+}
658
+
659
+func getTitle(metric pmetric.Metric) string {
660
+ if metric.Description() != "" {
661
+ return metric.Description()
662
+ }
663
+ return metric.Name()
664
+}
665
+
666
+func getUnits(metric pmetric.Metric) string {
667
+ if metric.Unit() != "" {
668
+ return metric.Unit()
669
+ }
670
+ return "count" // Default unit
671
+}
672
+
673
+func getFamily(metricName string, resourceAttrs pcommon.Map) string {
674
+ var sb strings.Builder
675
+
676
+ if val, ok := resourceAttrs.Get("service.name"); ok {
677
+ sb.WriteString(sanitizeID(val.AsString()))
678
+ } else if val, ok := resourceAttrs.Get("service.namespace"); ok {
679
+ sb.WriteString(sanitizeID(val.AsString()))
680
+ }
681
+
682
+ // Split the metric name
683
+ parts := strings.Split(metricName, ".")
684
+ prefix := metricName
685
+ if len(parts) > 1 {
686
+ prefix = parts[0]
687
+ }
688
+
689
+ if sb.Len() > 0 {
690
+ sb.WriteString("_")
691
+ }
692
+ sb.WriteString(sanitizeID(prefix))
693
+
694
+ return sb.String()
695
+}
696
+
697
+func updateChartLabels(chart *ChartDefinition, resourceAttrs pcommon.Map) {
698
+ if len(chart.Labels) == resourceAttrs.Len() {
699
+ same := true
700
+ resourceAttrs.Range(func(key string, value pcommon.Value) bool {
701
+ found := false
702
+ for _, label := range chart.Labels {
703
+ if label.Name == key && label.Value == value.AsString() {
704
+ found = true
705
+ break
706
+ }
707
+ }
708
+ if !found {
709
+ same = false
710
+ return false
711
+ }
712
+ return true
713
+ })
714
+ if same {
715
+ return
716
+ }
717
+ }
718
+
719
+ chart.Labels = make([]LabelDefinition, 0, resourceAttrs.Len())
720
+
721
+ resourceAttrs.Range(func(key string, value pcommon.Value) bool {
722
+ chart.Labels = append(chart.Labels, LabelDefinition{
723
+ Name: key,
724
+ Value: value.AsString(),
725
+ })
726
+ return true
727
+ })
728
+
729
+ sort.Slice(chart.Labels, func(i, j int) bool {
730
+ return chart.Labels[i].Name < chart.Labels[j].Name
731
+ })
732
+}
733
+
734
+func addDataPointAttributesAsLabels(chart *ChartDefinition, attrs pcommon.Map) {
735
+ // Use a map to track existing labels by name for O(1) lookup
736
+ existingLabels := make(map[string]bool, len(chart.Labels))
737
+ for _, label := range chart.Labels {
738
+ existingLabels[label.Name] = true
739
+ }
740
+
741
+ var newLabels []LabelDefinition
742
+ attrs.Range(func(key string, value pcommon.Value) bool {
743
+ if !existingLabels[key] {
744
+ newLabels = append(newLabels, LabelDefinition{
745
+ Name: key,
746
+ Value: value.AsString(),
747
+ })
748
+ existingLabels[key] = true
749
+ }
750
+ return true
751
+ })
752
+
753
+ if len(newLabels) > 0 {
754
+ chart.Labels = append(chart.Labels, newLabels...)
755
+
756
+ // Sort labels by name for consistent output
757
+ sort.Slice(chart.Labels, func(i, j int) bool {
758
+ return chart.Labels[i].Name < chart.Labels[j].Name
759
+ })
760
+ }
761
+}
762
+
763
+func attributesHash(attrs pcommon.Map) string {
764
+ if attrs.Len() == 0 {
765
+ return "default"
766
+ }
767
+
768
+ hash := fnv.New64a()
769
+
770
+ // Sort keys for consistent hashing
771
+ keys := make([]string, 0, attrs.Len())
772
+ attrs.Range(func(k string, v pcommon.Value) bool {
773
+ keys = append(keys, k)
774
+ return true
775
+ })
776
+ sort.Strings(keys)
777
+
778
+ for _, k := range keys {
779
+ v, _ := attrs.Get(k)
780
+ _, _ = hash.Write([]byte(k))
781
+ _, _ = hash.Write([]byte(":"))
782
+ _, _ = hash.Write([]byte(v.AsString()))
783
+ _, _ = hash.Write([]byte(";"))
784
+ }
785
+
786
+ return strconv.FormatUint(hash.Sum64(), 16)
787
+}
788
+
789
+func sanitizeID(name string) string {
790
+ if name == "" {
791
+ return "unknown"
792
+ }
793
+
794
+ var sb strings.Builder
795
+ sb.Grow(len(name))
796
+
797
+ // Ensure the ID doesn't start with a number
798
+ if unicode.IsDigit(rune(name[0])) {
799
+ sb.WriteString("n_")
800
+ }
801
+
802
+ for _, r := range name {
803
+ switch {
804
+ case unicode.IsLetter(r), unicode.IsDigit(r), r == '_', r == '.', r == '-':
805
+ sb.WriteRune(r)
806
+ default:
807
+ sb.WriteRune('_')
808
+ }
809
+ }
810
+
811
+ return sb.String()
812
+}
813
+
814
+func getTotalCountFromBuckets(buckets pmetric.ExponentialHistogramDataPointBuckets) float64 {
815
+ counts := buckets.BucketCounts()
816
+ var sum uint64
817
+ for i := 0; i < counts.Len(); i++ {
818
+ sum += counts.At(i)
819
+ }
820
+ return float64(sum)
821
+}
src/go/otel-collector/exporter/netdataexporter/convert_test.go
new
+657
@@ -0,0 +1,657 @@
1
+package netdataexporter
2
+
3
+import (
4
+ "strings"
5
+ "testing"
6
+
7
+ "github.com/stretchr/testify/assert"
8
+ "github.com/stretchr/testify/require"
9
+ "go.opentelemetry.io/collector/pdata/pcommon"
10
+ "go.opentelemetry.io/collector/pdata/pmetric"
11
+)
12
+
13
+func TestNetdataExporter_Convert(t *testing.T) {
14
+ tests := map[string]struct {
15
+ inputMetrics func() pmetric.Metrics
16
+ expectedChartCount int
17
+ expectedCharts map[string]ChartDefinition
18
+ }{
19
+ "gauge_metric": {
20
+ inputMetrics: func() pmetric.Metrics {
21
+ metrics := pmetric.NewMetrics()
22
+ rm := metrics.ResourceMetrics().AppendEmpty()
23
+
24
+ // Add resource attributes
25
+ rm.Resource().Attributes().PutStr("service.name", "test-service")
26
+
27
+ sm := rm.ScopeMetrics().AppendEmpty()
28
+ metric := sm.Metrics().AppendEmpty()
29
+ metric.SetName("test.gauge")
30
+ metric.SetDescription("Test Gauge")
31
+ metric.SetUnit("bytes")
32
+
33
+ gauge := metric.SetEmptyGauge()
34
+ dp := gauge.DataPoints().AppendEmpty()
35
+ dp.SetDoubleValue(42.0)
36
+ dp.Attributes().PutStr("host", "test-host")
37
+
38
+ return metrics
39
+ },
40
+ expectedChartCount: 1,
41
+ expectedCharts: map[string]ChartDefinition{},
42
+ },
43
+ "sum_metric_delta": {
44
+ inputMetrics: func() pmetric.Metrics {
45
+ metrics := pmetric.NewMetrics()
46
+ rm := metrics.ResourceMetrics().AppendEmpty()
47
+
48
+ sm := rm.ScopeMetrics().AppendEmpty()
49
+ metric := sm.Metrics().AppendEmpty()
50
+ metric.SetName("test.sum")
51
+ metric.SetDescription("Test Sum")
52
+ metric.SetUnit("count")
53
+
54
+ sum := metric.SetEmptySum()
55
+ sum.SetAggregationTemporality(pmetric.AggregationTemporalityDelta)
56
+ sum.SetIsMonotonic(true)
57
+
58
+ dp := sum.DataPoints().AppendEmpty()
59
+ dp.SetIntValue(100)
60
+
61
+ return metrics
62
+ },
63
+ expectedChartCount: 1,
64
+ expectedCharts: map[string]ChartDefinition{},
65
+ },
66
+ "sum_metric_cumulative": {
67
+ inputMetrics: func() pmetric.Metrics {
68
+ metrics := pmetric.NewMetrics()
69
+ rm := metrics.ResourceMetrics().AppendEmpty()
70
+
71
+ sm := rm.ScopeMetrics().AppendEmpty()
72
+ metric := sm.Metrics().AppendEmpty()
73
+ metric.SetName("test.sum")
74
+ metric.SetDescription("Test Sum")
75
+ metric.SetUnit("count")
76
+
77
+ sum := metric.SetEmptySum()
78
+ sum.SetAggregationTemporality(pmetric.AggregationTemporalityCumulative)
79
+ sum.SetIsMonotonic(true)
80
+
81
+ dp := sum.DataPoints().AppendEmpty()
82
+ dp.SetIntValue(100)
83
+
84
+ return metrics
85
+ },
86
+ expectedChartCount: 1,
87
+ expectedCharts: map[string]ChartDefinition{},
88
+ },
89
+ "histogram_metric": {
90
+ inputMetrics: func() pmetric.Metrics {
91
+ metrics := pmetric.NewMetrics()
92
+ rm := metrics.ResourceMetrics().AppendEmpty()
93
+
94
+ sm := rm.ScopeMetrics().AppendEmpty()
95
+ metric := sm.Metrics().AppendEmpty()
96
+ metric.SetName("test.histogram")
97
+ metric.SetDescription("Test Histogram")
98
+ metric.SetUnit("ms")
99
+
100
+ histogram := metric.SetEmptyHistogram()
101
+ histogram.SetAggregationTemporality(pmetric.AggregationTemporalityCumulative)
102
+
103
+ dp := histogram.DataPoints().AppendEmpty()
104
+ dp.SetCount(30)
105
+ dp.SetSum(200.0)
106
+ dp.BucketCounts().FromRaw([]uint64{10, 15, 5})
107
+ dp.ExplicitBounds().FromRaw([]float64{10.0, 20.0})
108
+
109
+ return metrics
110
+ },
111
+ expectedChartCount: 3, // Count, Sum, and Buckets charts
112
+ expectedCharts: map[string]ChartDefinition{},
113
+ },
114
+ "exponential_histogram_metric": {
115
+ inputMetrics: func() pmetric.Metrics {
116
+ metrics := pmetric.NewMetrics()
117
+ rm := metrics.ResourceMetrics().AppendEmpty()
118
+
119
+ sm := rm.ScopeMetrics().AppendEmpty()
120
+ metric := sm.Metrics().AppendEmpty()
121
+ metric.SetName("test.exponential_histogram")
122
+ metric.SetDescription("Test Exponential Histogram")
123
+ metric.SetUnit("ms")
124
+
125
+ expHistogram := metric.SetEmptyExponentialHistogram()
126
+ expHistogram.SetAggregationTemporality(pmetric.AggregationTemporalityDelta)
127
+
128
+ dp := expHistogram.DataPoints().AppendEmpty()
129
+ dp.SetCount(30)
130
+ dp.SetSum(200.0)
131
+ dp.SetZeroCount(5)
132
+
133
+ // Set up positive buckets
134
+ dp.Positive().SetOffset(0)
135
+ dp.Positive().BucketCounts().FromRaw([]uint64{10, 5})
136
+
137
+ // Set up negative buckets
138
+ dp.Negative().SetOffset(0)
139
+ dp.Negative().BucketCounts().FromRaw([]uint64{7, 3})
140
+
141
+ return metrics
142
+ },
143
+ expectedChartCount: 3, // Count, Sum, and Distribution charts
144
+ expectedCharts: map[string]ChartDefinition{},
145
+ },
146
+ "summary_metric": {
147
+ inputMetrics: func() pmetric.Metrics {
148
+ metrics := pmetric.NewMetrics()
149
+ rm := metrics.ResourceMetrics().AppendEmpty()
150
+
151
+ sm := rm.ScopeMetrics().AppendEmpty()
152
+ metric := sm.Metrics().AppendEmpty()
153
+ metric.SetName("test.summary")
154
+ metric.SetDescription("Test Summary")
155
+ metric.SetUnit("ms")
156
+
157
+ summary := metric.SetEmptySummary()
158
+
159
+ dp := summary.DataPoints().AppendEmpty()
160
+ dp.SetCount(100)
161
+ dp.SetSum(5000.0)
162
+
163
+ // Add quantiles (0%, 50%, 95%, 99%, 100%)
164
+ qv := dp.QuantileValues().AppendEmpty()
165
+ qv.SetQuantile(0.0)
166
+ qv.SetValue(1.0)
167
+
168
+ qv = dp.QuantileValues().AppendEmpty()
169
+ qv.SetQuantile(0.5)
170
+ qv.SetValue(5.0)
171
+
172
+ qv = dp.QuantileValues().AppendEmpty()
173
+ qv.SetQuantile(0.95)
174
+ qv.SetValue(9.5)
175
+
176
+ qv = dp.QuantileValues().AppendEmpty()
177
+ qv.SetQuantile(0.99)
178
+ qv.SetValue(10.0)
179
+
180
+ qv = dp.QuantileValues().AppendEmpty()
181
+ qv.SetQuantile(1.0)
182
+ qv.SetValue(100.0)
183
+
184
+ return metrics
185
+ },
186
+ expectedChartCount: 3, // Count, Sum, and Quantiles charts
187
+ expectedCharts: map[string]ChartDefinition{},
188
+ },
189
+ "multiple_data_points_by_attribute": {
190
+ inputMetrics: func() pmetric.Metrics {
191
+ metrics := pmetric.NewMetrics()
192
+ rm := metrics.ResourceMetrics().AppendEmpty()
193
+
194
+ sm := rm.ScopeMetrics().AppendEmpty()
195
+ metric := sm.Metrics().AppendEmpty()
196
+ metric.SetName("test.gauge.multi")
197
+ metric.SetDescription("Test Gauge with Multiple Points")
198
+ metric.SetUnit("bytes")
199
+
200
+ gauge := metric.SetEmptyGauge()
201
+
202
+ // First data point with host=server1
203
+ dp1 := gauge.DataPoints().AppendEmpty()
204
+ dp1.SetDoubleValue(100.0)
205
+ dp1.Attributes().PutStr("host", "server1")
206
+
207
+ // Second data point with host=server2
208
+ dp2 := gauge.DataPoints().AppendEmpty()
209
+ dp2.SetDoubleValue(200.0)
210
+ dp2.Attributes().PutStr("host", "server2")
211
+
212
+ return metrics
213
+ },
214
+ expectedChartCount: 2, // One chart per unique attribute set
215
+ expectedCharts: map[string]ChartDefinition{},
216
+ },
217
+ "staleness_marker": {
218
+ inputMetrics: func() pmetric.Metrics {
219
+ metrics := pmetric.NewMetrics()
220
+ rm := metrics.ResourceMetrics().AppendEmpty()
221
+
222
+ sm := rm.ScopeMetrics().AppendEmpty()
223
+ metric := sm.Metrics().AppendEmpty()
224
+ metric.SetName("test.gauge.stale")
225
+ metric.SetDescription("Test Gauge with Staleness Marker")
226
+
227
+ gauge := metric.SetEmptyGauge()
228
+
229
+ // Normal data point
230
+ dp1 := gauge.DataPoints().AppendEmpty()
231
+ dp1.SetDoubleValue(100.0)
232
+
233
+ // Stale data point (with staleness flag set)
234
+ dp2 := gauge.DataPoints().AppendEmpty()
235
+ dp2.SetDoubleValue(0.0)
236
+ dp2.SetFlags(1) // Set staleness marker flag
237
+
238
+ return metrics
239
+ },
240
+ expectedChartCount: 1,
241
+ expectedCharts: map[string]ChartDefinition{},
242
+ },
243
+ "resource_and_datapoint_attributes_as_labels": {
244
+ inputMetrics: func() pmetric.Metrics {
245
+ metrics := pmetric.NewMetrics()
246
+ rm := metrics.ResourceMetrics().AppendEmpty()
247
+
248
+ // Add resource attributes
249
+ rm.Resource().Attributes().PutStr("service.name", "test-service")
250
+ rm.Resource().Attributes().PutStr("deployment.environment", "production")
251
+
252
+ sm := rm.ScopeMetrics().AppendEmpty()
253
+ metric := sm.Metrics().AppendEmpty()
254
+ metric.SetName("test.labels")
255
+
256
+ gauge := metric.SetEmptyGauge()
257
+ dp := gauge.DataPoints().AppendEmpty()
258
+ dp.SetDoubleValue(42.0)
259
+
260
+ // Add data point attributes
261
+ dp.Attributes().PutStr("host", "host1")
262
+ dp.Attributes().PutStr("region", "us-west")
263
+
264
+ return metrics
265
+ },
266
+ expectedChartCount: 1,
267
+ expectedCharts: map[string]ChartDefinition{},
268
+ },
269
+ }
270
+
271
+ for name, tt := range tests {
272
+ t.Run(name, func(t *testing.T) {
273
+ // Create a new exporter for each test to avoid state between tests
274
+ exporter := &netdataExporter{
275
+ charts: make(map[string]*ChartDefinition),
276
+ }
277
+
278
+ // Convert the metrics
279
+ inputMetrics := tt.inputMetrics()
280
+ charts := exporter.Convert(inputMetrics)
281
+
282
+ // Verify the chart count
283
+ assert.Equal(t, tt.expectedChartCount, len(charts), "Wrong number of charts created")
284
+
285
+ switch name {
286
+ case "gauge_metric":
287
+ // Find the chart for the gauge metric
288
+ var gaugeChart *ChartDefinition
289
+ for _, chart := range charts {
290
+ if chart.Context == "test.gauge" {
291
+ gaugeChart = chart
292
+ break
293
+ }
294
+ }
295
+ require.NotNil(t, gaugeChart, "Gauge chart should exist")
296
+ assert.Equal(t, "Test Gauge", gaugeChart.Title)
297
+ assert.Equal(t, "bytes", gaugeChart.Units)
298
+ assert.Equal(t, "test-service_test", gaugeChart.Family)
299
+ assert.Equal(t, "line", gaugeChart.Type)
300
+ assert.Len(t, gaugeChart.Dimensions, 1)
301
+ assert.Equal(t, 42.0, gaugeChart.Dimensions[0].Value)
302
+ assert.Equal(t, "absolute", gaugeChart.Dimensions[0].Algo)
303
+
304
+ case "sum_metric_delta":
305
+ // Find the chart for the delta sum metric
306
+ var sumChart *ChartDefinition
307
+ for _, chart := range charts {
308
+ if chart.Context == "test.sum" {
309
+ sumChart = chart
310
+ break
311
+ }
312
+ }
313
+ require.NotNil(t, sumChart, "Sum chart should exist")
314
+ assert.Equal(t, "Test Sum", sumChart.Title)
315
+ assert.Equal(t, "count", sumChart.Units)
316
+ assert.Equal(t, "test", sumChart.Family)
317
+ assert.Equal(t, "line", sumChart.Type)
318
+ assert.Len(t, sumChart.Dimensions, 1)
319
+ assert.Equal(t, 100.0, sumChart.Dimensions[0].Value)
320
+ assert.Equal(t, "incremental", sumChart.Dimensions[0].Algo, "Delta temporality should use incremental algorithm")
321
+
322
+ case "sum_metric_cumulative":
323
+ // Find the chart for the cumulative sum metric
324
+ var sumChart *ChartDefinition
325
+ for _, chart := range charts {
326
+ if chart.Context == "test.sum" {
327
+ sumChart = chart
328
+ break
329
+ }
330
+ }
331
+ require.NotNil(t, sumChart, "Sum chart should exist")
332
+ assert.Equal(t, "Test Sum", sumChart.Title)
333
+ assert.Equal(t, "count", sumChart.Units)
334
+ assert.Equal(t, "test", sumChart.Family)
335
+ assert.Equal(t, "line", sumChart.Type)
336
+ assert.Len(t, sumChart.Dimensions, 1)
337
+ assert.Equal(t, 100.0, sumChart.Dimensions[0].Value)
338
+ assert.Equal(t, "absolute", sumChart.Dimensions[0].Algo, "Cumulative temporality should use absolute algorithm")
339
+
340
+ case "histogram_metric":
341
+ // Check count chart
342
+ var countChart *ChartDefinition
343
+ for _, chart := range charts {
344
+ if chart.Context == "test.histogram.count" {
345
+ countChart = chart
346
+ break
347
+ }
348
+ }
349
+ require.NotNil(t, countChart, "Histogram count chart should exist")
350
+ assert.Equal(t, "Test Histogram (Count)", countChart.Title)
351
+ assert.Equal(t, "count", countChart.Units)
352
+ assert.Equal(t, "line", countChart.Type)
353
+ assert.Len(t, countChart.Dimensions, 1)
354
+ assert.Equal(t, 30.0, countChart.Dimensions[0].Value)
355
+ assert.Equal(t, "absolute", countChart.Dimensions[0].Algo)
356
+
357
+ // Check sum chart
358
+ var sumChart *ChartDefinition
359
+ for _, chart := range charts {
360
+ if chart.Context == "test.histogram.sum" {
361
+ sumChart = chart
362
+ break
363
+ }
364
+ }
365
+ require.NotNil(t, sumChart, "Histogram sum chart should exist")
366
+ assert.Equal(t, "Test Histogram (Sum)", sumChart.Title)
367
+ assert.Equal(t, "ms", sumChart.Units)
368
+ assert.Equal(t, "line", sumChart.Type)
369
+ assert.Len(t, sumChart.Dimensions, 1)
370
+ assert.Equal(t, 200.0, sumChart.Dimensions[0].Value)
371
+
372
+ // Check buckets chart
373
+ var bucketsChart *ChartDefinition
374
+ for _, chart := range charts {
375
+ if chart.Context == "test.histogram.buckets" {
376
+ bucketsChart = chart
377
+ break
378
+ }
379
+ }
380
+ require.NotNil(t, bucketsChart, "Histogram buckets chart should exist")
381
+ assert.Equal(t, "Test Histogram (Buckets)", bucketsChart.Title)
382
+ assert.Equal(t, "count", bucketsChart.Units)
383
+ assert.Equal(t, "stacked", bucketsChart.Type)
384
+ assert.Len(t, bucketsChart.Dimensions, 3)
385
+
386
+ // Verify bucket values (we don't know exact order, so check all values are present)
387
+ bucketValues := []float64{10.0, 15.0, 5.0}
388
+ for _, dim := range bucketsChart.Dimensions {
389
+ assert.Contains(t, bucketValues, dim.Value)
390
+ }
391
+
392
+ case "exponential_histogram_metric":
393
+ // Check count chart
394
+ var countChart *ChartDefinition
395
+ for _, chart := range charts {
396
+ if chart.Context == "test.exponential_histogram.count" {
397
+ countChart = chart
398
+ break
399
+ }
400
+ }
401
+ require.NotNil(t, countChart, "Exponential histogram count chart should exist")
402
+ assert.Equal(t, "Test Exponential Histogram (Count)", countChart.Title)
403
+ assert.Equal(t, "count", countChart.Units)
404
+ assert.Equal(t, "line", countChart.Type)
405
+ assert.Len(t, countChart.Dimensions, 1)
406
+ assert.Equal(t, 30.0, countChart.Dimensions[0].Value)
407
+ assert.Equal(t, "incremental", countChart.Dimensions[0].Algo, "Delta temporality should use incremental algorithm")
408
+
409
+ // Check sum chart
410
+ var sumChart *ChartDefinition
411
+ for _, chart := range charts {
412
+ if chart.Context == "test.exponential_histogram.sum" {
413
+ sumChart = chart
414
+ break
415
+ }
416
+ }
417
+ require.NotNil(t, sumChart, "Exponential histogram sum chart should exist")
418
+ assert.Equal(t, "Test Exponential Histogram (Sum)", sumChart.Title)
419
+ assert.Equal(t, "ms", sumChart.Units)
420
+ assert.Equal(t, "line", sumChart.Type)
421
+ assert.Len(t, sumChart.Dimensions, 1)
422
+ assert.Equal(t, 200.0, sumChart.Dimensions[0].Value)
423
+
424
+ // Check distribution chart
425
+ var distChart *ChartDefinition
426
+ for _, chart := range charts {
427
+ if chart.Context == "test.exponential_histogram.distribution" {
428
+ distChart = chart
429
+ break
430
+ }
431
+ }
432
+ require.NotNil(t, distChart, "Exponential histogram distribution chart should exist")
433
+ assert.Equal(t, "Test Exponential Histogram (Distribution)", distChart.Title)
434
+ assert.Equal(t, "count", distChart.Units)
435
+ assert.Equal(t, "stacked", distChart.Type)
436
+ assert.Len(t, distChart.Dimensions, 3)
437
+
438
+ // Find the dimensions for positive, zero, and negative values
439
+ positiveValue := 0.0
440
+ zeroValue := 0.0
441
+ negativeValue := 0.0
442
+
443
+ for _, dim := range distChart.Dimensions {
444
+ if dim.Name == "Positive Values" {
445
+ positiveValue = dim.Value
446
+ } else if dim.Name == "Zero Values" {
447
+ zeroValue = dim.Value
448
+ } else if dim.Name == "Negative Values" {
449
+ negativeValue = dim.Value
450
+ }
451
+ }
452
+
453
+ assert.Equal(t, 15.0, positiveValue, "Positive bucket count should sum to 15")
454
+ assert.Equal(t, 5.0, zeroValue, "Zero bucket count should be 5")
455
+ assert.Equal(t, 10.0, negativeValue, "Negative bucket count should sum to 10")
456
+
457
+ case "summary_metric":
458
+ // Check count chart
459
+ var countChart *ChartDefinition
460
+ for _, chart := range charts {
461
+ if chart.Context == "test.summary.count" {
462
+ countChart = chart
463
+ break
464
+ }
465
+ }
466
+ require.NotNil(t, countChart, "Summary count chart should exist")
467
+ assert.Equal(t, "Test Summary (Count)", countChart.Title)
468
+ assert.Equal(t, "count", countChart.Units)
469
+ assert.Equal(t, "line", countChart.Type)
470
+ assert.Len(t, countChart.Dimensions, 1)
471
+ assert.Equal(t, 100.0, countChart.Dimensions[0].Value)
472
+
473
+ // Check sum chart
474
+ var sumChart *ChartDefinition
475
+ for _, chart := range charts {
476
+ if chart.Context == "test.summary.sum" {
477
+ sumChart = chart
478
+ break
479
+ }
480
+ }
481
+ require.NotNil(t, sumChart, "Summary sum chart should exist")
482
+ assert.Equal(t, "Test Summary (Sum)", sumChart.Title)
483
+ assert.Equal(t, "ms", sumChart.Units)
484
+ assert.Equal(t, "line", sumChart.Type)
485
+ assert.Len(t, sumChart.Dimensions, 1)
486
+ assert.Equal(t, 5000.0, sumChart.Dimensions[0].Value)
487
+
488
+ // Check quantiles chart
489
+ var quantilesChart *ChartDefinition
490
+ for _, chart := range charts {
491
+ if chart.Context == "test.summary.quantiles" {
492
+ quantilesChart = chart
493
+ break
494
+ }
495
+ }
496
+ require.NotNil(t, quantilesChart, "Summary quantiles chart should exist")
497
+ assert.Equal(t, "Test Summary (Quantiles)", quantilesChart.Title)
498
+ assert.Equal(t, "ms", quantilesChart.Units)
499
+ assert.Equal(t, "line", quantilesChart.Type)
500
+ assert.Len(t, quantilesChart.Dimensions, 5)
501
+
502
+ // Find dimensions for min, max, and p50
503
+ var minValue, maxValue, p50Value float64
504
+ for _, dim := range quantilesChart.Dimensions {
505
+ if dim.Name == "min" {
506
+ minValue = dim.Value
507
+ } else if dim.Name == "max" {
508
+ maxValue = dim.Value
509
+ } else if dim.Name == "p50" {
510
+ p50Value = dim.Value
511
+ }
512
+ }
513
+
514
+ assert.Equal(t, 1.0, minValue, "Minimum (p0) quantile should be 1.0")
515
+ assert.Equal(t, 100.0, maxValue, "Maximum (p100) quantile should be 100.0")
516
+ assert.Equal(t, 5.0, p50Value, "p50 quantile should be 5.0")
517
+
518
+ case "multiple_data_points_by_attribute":
519
+ assert.Len(t, charts, 2, "Should have two charts for the multiple data points test")
520
+
521
+ // Collect all dimension values to ensure we have both 100.0 and 200.0
522
+ values := make([]float64, 0, 2)
523
+ for _, chart := range charts {
524
+ assert.Equal(t, "test.gauge.multi", chart.Context, "Chart context should match metric name")
525
+ assert.Equal(t, "Test Gauge with Multiple Points", chart.Title)
526
+ assert.Equal(t, "bytes", chart.Units)
527
+
528
+ for _, dim := range chart.Dimensions {
529
+ values = append(values, dim.Value)
530
+ }
531
+ }
532
+
533
+ assert.Contains(t, values, 100.0, "Should have a dimension with value 100.0")
534
+ assert.Contains(t, values, 200.0, "Should have a dimension with value 200.0")
535
+
536
+ case "staleness_marker":
537
+ assert.Len(t, charts, 1, "Should have one chart for the staleness marker test")
538
+
539
+ for _, chart := range charts {
540
+ assert.Equal(t, "test.gauge.stale", chart.Context)
541
+ assert.Equal(t, "Test Gauge with Staleness Marker", chart.Title)
542
+ assert.Len(t, chart.Dimensions, 1, "Should have one dimension (non-stale point)")
543
+ assert.Equal(t, 100.0, chart.Dimensions[0].Value, "Dimension value should be 100.0 (from non-stale point)")
544
+ }
545
+
546
+ case "resource_and_datapoint_attributes_as_labels":
547
+ assert.Len(t, charts, 1, "Should have one chart for the labels test")
548
+
549
+ for _, chart := range charts {
550
+ assert.Equal(t, "test.labels", chart.Context)
551
+ assert.Equal(t, "test-service_test", chart.Family, "Family should include service name")
552
+
553
+ // Check for expected labels
554
+ labelMap := make(map[string]string)
555
+ for _, label := range chart.Labels {
556
+ labelMap[label.Name] = label.Value
557
+ }
558
+
559
+ assert.Equal(t, "production", labelMap["deployment.environment"], "Should have deployment.environment label")
560
+ assert.Equal(t, "test-service", labelMap["service.name"], "Should have service.name label")
561
+ assert.Equal(t, "host1", labelMap["host"], "Should have host label")
562
+ assert.Equal(t, "us-west", labelMap["region"], "Should have region label")
563
+
564
+ // Check dimension
565
+ assert.Len(t, chart.Dimensions, 1)
566
+ assert.Equal(t, 42.0, chart.Dimensions[0].Value)
567
+ }
568
+ }
569
+ })
570
+ }
571
+}
572
+
573
+// Helper functions tests
574
+
575
+func TestHelperFunctions(t *testing.T) {
576
+ // Test sanitizeID
577
+ t.Run("sanitizeID", func(t *testing.T) {
578
+ tests := map[string]struct {
579
+ input string
580
+ expected string
581
+ }{
582
+ "valid_id": {"valid_id", "valid_id"},
583
+ "spaces": {"test metric", "test_metric"},
584
+ "special_chars": {"test/metric:value", "test_metric_value"},
585
+ "starts_with_number": {"123test", "n_123test"},
586
+ "multiple_special_chars": {"test@metric#value", "test_metric_value"},
587
+ "empty_string": {"", "unknown"},
588
+ "very_long_id": {strings.Repeat("a", 150), strings.Repeat("a", 150)},
589
+ }
590
+
591
+ for name, tt := range tests {
592
+ t.Run(name, func(t *testing.T) {
593
+ result := sanitizeID(tt.input)
594
+ assert.Equal(t, tt.expected, result)
595
+ })
596
+ }
597
+ })
598
+
599
+ // Test generateChartID
600
+ t.Run("generateChartID", func(t *testing.T) {
601
+ // Test that long metric names are truncated in the chart ID
602
+ veryLongName := strings.Repeat("abcdefghij", 15) // 150 characters
603
+ attrHash := "testhash"
604
+ chartID := generateChartID(veryLongName, attrHash)
605
+
606
+ // Chart ID should be truncated to maxChartIDLength
607
+ assert.LessOrEqual(t, len(chartID), maxChartIDLength, "Chart ID should not exceed maxChartIDLength")
608
+
609
+ // Chart ID should still end with the attribute hash
610
+ assert.True(t, strings.HasSuffix(chartID, attrHash), "Chart ID should end with the attribute hash")
611
+ })
612
+
613
+ // Test attributesHash
614
+ t.Run("attributesHash", func(t *testing.T) {
615
+ // Test consistent hashing with different attribute orders
616
+ attrs1 := pcommon.NewMap()
617
+ attrs1.PutStr("a", "1")
618
+ attrs1.PutStr("b", "2")
619
+
620
+ attrs2 := pcommon.NewMap()
621
+ attrs2.PutStr("b", "2")
622
+ attrs2.PutStr("a", "1")
623
+
624
+ hash1 := attributesHash(attrs1)
625
+ hash2 := attributesHash(attrs2)
626
+
627
+ assert.Equal(t, hash1, hash2, "Hash should be consistent regardless of attribute order")
628
+
629
+ // Test empty attributes
630
+ emptyAttrs := pcommon.NewMap()
631
+ emptyHash := attributesHash(emptyAttrs)
632
+ assert.Equal(t, "default", emptyHash, "Empty attributes should hash to 'default'")
633
+ })
634
+
635
+ // Test getFamily
636
+ t.Run("getFamily", func(t *testing.T) {
637
+ // Test with service name
638
+ resourceAttrs := pcommon.NewMap()
639
+ resourceAttrs.PutStr("service.name", "test-service")
640
+
641
+ family := getFamily("test.metric", resourceAttrs)
642
+ assert.Equal(t, "test-service_test", family, "Family should include service name")
643
+
644
+ // Test without service name but with service namespace
645
+ resourceAttrs = pcommon.NewMap()
646
+ resourceAttrs.PutStr("service.namespace", "test-namespace")
647
+
648
+ family = getFamily("test.metric", resourceAttrs)
649
+ assert.Equal(t, "test_namespace_test", family, "Family should include service namespace")
650
+
651
+ // Test without service name or namespace
652
+ resourceAttrs = pcommon.NewMap()
653
+
654
+ family = getFamily("test.metric", resourceAttrs)
655
+ assert.Equal(t, "test", family, "Family should be based on metric name prefix")
656
+ })
657
+}
src/go/otel-collector/exporter/netdataexporter/exporter.go
+75
@@ -11,16 +11,34 @@ import (
11
type netdataExporter struct {
12
log *zap.Logger
13
conf *Config
14
+
15
+ api *netdataAPI
16
+
17
+ //MaxLabelCount int // Maximum number of labels to include per chart (0 = unlimited)
18
+ //UseShortIDs bool // Use shortened IDs for better performance
19
+ //GroupSimilarPoints bool // Group similar data points into a single dimension
20
+ //
21
+ //// State management
22
+ //charts map[string]*ChartDefinition // Map to store and track charts across iterations
23
+ //chartsMu sync.RWMutex // Mutex to protect the charts map during concurrent access
24
+ //lastUpdate time.Time // Track the last update time
25
+
26
+ charts map[string]*ChartDefinition
27
}
28
29
func newNetdataExporter(cfg component.Config, logger *zap.Logger) *netdataExporter {
30
return &netdataExporter{
31
log: logger,
32
conf: cfg.(*Config),
33
+ api: newNetdataStdoutApi(),
34
}
35
}
36
37
func (e *netdataExporter) consumeMetrics(ctx context.Context, pm pmetric.Metrics) error {
38
+ e.convert(pm)
39
+ e.sendCharts()
40
+ e.updateCharts(0)
41
+
42
return nil
43
}
44
@@ -31,3 +49,60 @@ func (e *netdataExporter) Start(_ context.Context, _ component.Host) error {
49
func (e *netdataExporter) Shutdown(context.Context) error {
50
return nil
51
}
52
+
53
+func (e *netdataExporter) sendCharts() {
54
+ for _, chart := range e.charts {
55
+ if chart.IsNew {
56
+ opts := ChartOpts{
57
+ TypeID: "",
58
+ ID: chart.ID,
59
+ Title: chart.Title,
60
+ Units: chart.Units,
61
+ Family: chart.Family,
62
+ Context: chart.Context,
63
+ ChartType: chart.Type,
64
+ Priority: 1000,
65
+ UpdateEvery: 1,
66
+ Options: chart.Options,
67
+ Plugin: "otel",
68
+ Module: "metrics",
69
+ }
70
+
71
+ e.api.chart(opts)
72
+ for _, label := range chart.Labels {
73
+ e.api.clabel(label.Name, label.Value)
74
+ }
75
+ e.api.clabelcommit()
76
+
77
+ for _, dim := range chart.Dimensions {
78
+ dimOpts := DimensionOpts{
79
+ ID: dim.ID,
80
+ Name: dim.Name,
81
+ Algorithm: dim.Algo,
82
+ Multiplier: 1,
83
+ Divisor: 1,
84
+ Options: "",
85
+ }
86
+ e.api.dimension(dimOpts)
87
+ }
88
+
89
+ chart.IsNew = false
90
+ }
91
+ }
92
+}
93
+
94
+func (e *netdataExporter) updateCharts(msSince int) {
95
+ for id, chart := range e.charts {
96
+ if len(chart.Dimensions) == 0 {
97
+ continue
98
+ }
99
+
100
+ e.api.begin(id, msSince)
101
+
102
+ for _, dim := range chart.Dimensions {
103
+ value := int64(dim.Value)
104
+ e.api.set(dim.ID, value)
105
+ }
106
+ e.api.end()
107
+ }
108
+}
src/go/otel-collector/exporter/netdataexporter/go.mod
+29
-28
@@ -4,14 +4,14 @@ go 1.24.0
4
5
require (
6
github.com/stretchr/testify v1.10.0
7
- go.opentelemetry.io/collector/component v1.30.0
8
- go.opentelemetry.io/collector/component/componenttest v0.124.0
9
- go.opentelemetry.io/collector/confmap v1.30.0
10
- go.opentelemetry.io/collector/consumer v1.30.0
11
- go.opentelemetry.io/collector/exporter v0.124.0
12
- go.opentelemetry.io/collector/exporter/exportertest v0.124.0
13
- go.opentelemetry.io/collector/exporter/xexporter v0.124.0
14
- go.opentelemetry.io/collector/pdata v1.30.0
7
+ go.opentelemetry.io/collector/component v1.31.0
8
+ go.opentelemetry.io/collector/component/componenttest v0.125.0
9
+ go.opentelemetry.io/collector/confmap v1.31.0
10
+ go.opentelemetry.io/collector/consumer v1.31.0
11
+ go.opentelemetry.io/collector/exporter v0.125.0
12
+ go.opentelemetry.io/collector/exporter/exportertest v0.125.0
13
+ go.opentelemetry.io/collector/exporter/xexporter v0.125.0
14
+ go.opentelemetry.io/collector/pdata v1.31.0
15
go.uber.org/goleak v1.3.0
16
go.uber.org/zap v1.27.0
17
)
@@ -27,27 +27,27 @@ require (
27
github.com/hashicorp/go-version v1.7.0 // indirect
28
github.com/json-iterator/go v1.1.12 // indirect
29
github.com/knadh/koanf/maps v0.1.2 // indirect
30
- github.com/knadh/koanf/providers/confmap v0.1.0 // indirect
31
- github.com/knadh/koanf/v2 v2.1.2 // indirect
30
+ github.com/knadh/koanf/providers/confmap v1.0.0 // indirect
31
+ github.com/knadh/koanf/v2 v2.2.0 // indirect
32
github.com/mitchellh/copystructure v1.2.0 // indirect
33
github.com/mitchellh/reflectwalk v1.0.2 // indirect
34
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
35
github.com/modern-go/reflect2 v1.0.2 // indirect
36
github.com/pmezard/go-difflib v1.0.0 // indirect
37
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
38
- go.opentelemetry.io/collector/config/configretry v1.30.0 // indirect
39
- go.opentelemetry.io/collector/consumer/consumererror v0.124.0 // indirect
40
- go.opentelemetry.io/collector/consumer/consumertest v0.124.0 // indirect
41
- go.opentelemetry.io/collector/consumer/xconsumer v0.124.0 // indirect
42
- go.opentelemetry.io/collector/extension v1.30.0 // indirect
43
- go.opentelemetry.io/collector/extension/xextension v0.124.0 // indirect
44
- go.opentelemetry.io/collector/featuregate v1.30.0 // indirect
45
- go.opentelemetry.io/collector/internal/telemetry v0.124.0 // indirect
46
- go.opentelemetry.io/collector/pdata/pprofile v0.124.0 // indirect
47
- go.opentelemetry.io/collector/pipeline v0.124.0 // indirect
48
- go.opentelemetry.io/collector/receiver v1.30.0 // indirect
49
- go.opentelemetry.io/collector/receiver/receivertest v0.124.0 // indirect
50
- go.opentelemetry.io/collector/receiver/xreceiver v0.124.0 // indirect
38
+ go.opentelemetry.io/collector/config/configretry v1.31.0 // indirect
39
+ go.opentelemetry.io/collector/consumer/consumererror v0.125.0 // indirect
40
+ go.opentelemetry.io/collector/consumer/consumertest v0.125.0 // indirect
41
+ go.opentelemetry.io/collector/consumer/xconsumer v0.125.0 // indirect
42
+ go.opentelemetry.io/collector/extension v1.31.0 // indirect
43
+ go.opentelemetry.io/collector/extension/xextension v0.125.0 // indirect
44
+ go.opentelemetry.io/collector/featuregate v1.31.0 // indirect
45
+ go.opentelemetry.io/collector/internal/telemetry v0.125.0 // indirect
46
+ go.opentelemetry.io/collector/pdata/pprofile v0.125.0 // indirect
47
+ go.opentelemetry.io/collector/pipeline v0.125.0 // indirect
48
+ go.opentelemetry.io/collector/receiver v1.31.0 // indirect
49
+ go.opentelemetry.io/collector/receiver/receivertest v0.125.0 // indirect
50
+ go.opentelemetry.io/collector/receiver/xreceiver v0.125.0 // indirect
51
go.opentelemetry.io/contrib/bridges/otelzap v0.10.0 // indirect
52
go.opentelemetry.io/otel v1.35.0 // indirect
53
go.opentelemetry.io/otel/log v0.11.0 // indirect
@@ -56,11 +56,12 @@ require (
56
go.opentelemetry.io/otel/sdk/metric v1.35.0 // indirect
57
go.opentelemetry.io/otel/trace v1.35.0 // indirect
58
go.uber.org/multierr v1.11.0 // indirect
59
- golang.org/x/net v0.37.0 // indirect
60
- golang.org/x/sys v0.31.0 // indirect
61
- golang.org/x/text v0.23.0 // indirect
62
- google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f // indirect
63
- google.golang.org/grpc v1.71.1 // indirect
59
+ golang.org/x/net v0.39.0 // indirect
60
+ golang.org/x/sys v0.32.0 // indirect
61
+ golang.org/x/text v0.24.0 // indirect
62
+ google.golang.org/genproto/googleapis/rpc v0.0.0-20250428153025-10db94c68c34 // indirect
63
+ google.golang.org/grpc v1.72.0 // indirect
64
google.golang.org/protobuf v1.36.6 // indirect
65
gopkg.in/yaml.v3 v3.0.1 // indirect
66
+ sigs.k8s.io/yaml v1.4.0 // indirect
67
)
src/go/otel-collector/exporter/netdataexporter/go.sum
+65
-60
@@ -14,6 +14,7 @@ github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
14
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
15
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
16
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
17
+github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
18
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
19
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
20
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
@@ -27,10 +28,10 @@ github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI
28
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
29
github.com/knadh/koanf/maps v0.1.2 h1:RBfmAW5CnZT+PJ1CVc1QSJKf4Xu9kxfQgYVQSu8hpbo=
30
github.com/knadh/koanf/maps v0.1.2/go.mod h1:npD/QZY3V6ghQDdcQzl1W4ICNVTkohC8E73eI2xW4yI=
30
-github.com/knadh/koanf/providers/confmap v0.1.0 h1:gOkxhHkemwG4LezxxN8DMOFopOPghxRVp7JbIvdvqzU=
31
-github.com/knadh/koanf/providers/confmap v0.1.0/go.mod h1:2uLhxQzJnyHKfxG927awZC7+fyHFdQkd697K4MdLnIU=
32
-github.com/knadh/koanf/v2 v2.1.2 h1:I2rtLRqXRy1p01m/utEtpZSSA6dcJbgGVuE27kW2PzQ=
33
-github.com/knadh/koanf/v2 v2.1.2/go.mod h1:Gphfaen0q1Fc1HTgJgSTC4oRX9R2R5ErYMZJy8fLJBo=
31
+github.com/knadh/koanf/providers/confmap v1.0.0 h1:mHKLJTE7iXEys6deO5p6olAiZdG5zwp8Aebir+/EaRE=
32
+github.com/knadh/koanf/providers/confmap v1.0.0/go.mod h1:txHYHiI2hAtF0/0sCmcuol4IDcuQbKTybiB1nOcUo1A=
33
+github.com/knadh/koanf/v2 v2.2.0 h1:FZFwd9bUjpb8DyCWARUBy5ovuhDs1lI87dOEn2K8UVU=
34
+github.com/knadh/koanf/v2 v2.2.0/go.mod h1:PSFru3ufQgTsI7IF+95rf9s8XA1+aHxKuO/W+dPoHEY=
35
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
36
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
37
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
@@ -56,52 +57,54 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
57
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
58
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
59
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
59
-go.opentelemetry.io/collector/component v1.30.0 h1:HXjqBHaQ47/EEuWdnkjr4Y3kRWvmyWIDvqa1Q262Fls=
60
-go.opentelemetry.io/collector/component v1.30.0/go.mod h1:vfM9kN+BM6oHBXWibquiprz8CVawxd4/aYy3nbhme3E=
61
-go.opentelemetry.io/collector/component/componenttest v0.124.0 h1:Wsc+DmDrWTFs/aEyjDA3slNwV+h/0NOyIR5Aywvr6Zw=
62
-go.opentelemetry.io/collector/component/componenttest v0.124.0/go.mod h1:NQ4ATOzMFc7QA06B993tq8o27DR0cu/JR/zK7slGJ3E=
63
-go.opentelemetry.io/collector/config/configretry v1.30.0 h1:sapni1tymwNiuI0PjqlRR5CvYxIQYT8tyjQGVJDkVPM=
64
-go.opentelemetry.io/collector/config/configretry v1.30.0/go.mod h1:QNnb+MCk7aS1k2EuGJMtlNCltzD7b8uC7Xel0Dxm1wQ=
65
-go.opentelemetry.io/collector/confmap v1.30.0 h1:Y0MXhjQCdMyJN9xZMWWdNPWs6ncMVf7YVnyAEN2dAcM=
66
-go.opentelemetry.io/collector/confmap v1.30.0/go.mod h1:9DdThVDIC3VsdtTb7DgT+HwusWOocoqDkd/TErEtQgA=
67
-go.opentelemetry.io/collector/consumer v1.30.0 h1:Nn6kFTH+EJbv13E0W+sNvWrTgbiFCRv8f6DaA2F1DQs=
68
-go.opentelemetry.io/collector/consumer v1.30.0/go.mod h1:edRyfk61ugdhCQ93PBLRZfYMVWjdMPpKP8z5QLyESf0=
69
-go.opentelemetry.io/collector/consumer/consumererror v0.124.0 h1:OmeJex0C8jcwyILG+eJIGDe6rGaR15fip+Rj3XyMTRY=
70
-go.opentelemetry.io/collector/consumer/consumererror v0.124.0/go.mod h1:A6WL/E70dUh9oFdQsL+aVYGL+d6UqiAhi7rIW/6gvDM=
71
-go.opentelemetry.io/collector/consumer/consumertest v0.124.0 h1:2arChG4RPrHW3lfVWlK/KDF7Y7qkUm/YAiBXh8oTue0=
72
-go.opentelemetry.io/collector/consumer/consumertest v0.124.0/go.mod h1:Hlu+EXbINHxVAyIT1baKO2d0j5odR3fLlLAiaP+JqQg=
73
-go.opentelemetry.io/collector/consumer/xconsumer v0.124.0 h1:/cut96EWVNoz6lIeGI9+EzS6UClMtnZkx5YIpkD0Xe0=
74
-go.opentelemetry.io/collector/consumer/xconsumer v0.124.0/go.mod h1:fHH/MpzFCRNk/4foiYE6BoXQCAMf5sJTO35uvzVrrd4=
75
-go.opentelemetry.io/collector/exporter v0.124.0 h1:ii+9tU/iSrPl4+YDvqFVflksA9hUYEzwMIpmvP4JZ8w=
76
-go.opentelemetry.io/collector/exporter v0.124.0/go.mod h1:Q8tOEwFu3CN8VGjE4H2yZcCRG9Q60foQIyZGKPD/jig=
77
-go.opentelemetry.io/collector/exporter/exportertest v0.124.0 h1:IOxA/4CiVWGPlmA0JofK6W4DzvwW1YJes09r6osluIE=
78
-go.opentelemetry.io/collector/exporter/exportertest v0.124.0/go.mod h1:2EmU8IwVJV79MmFBFFW1LCN0Ob2UZsEkX/mSUB06lbI=
79
-go.opentelemetry.io/collector/exporter/xexporter v0.124.0 h1:Itfn2+F4ki8hObOtPCecWBwGpuxakUYSsTwwkB5iUns=
80
-go.opentelemetry.io/collector/exporter/xexporter v0.124.0/go.mod h1:dNK/PPY02gA9BawIKHyVk8kIFdYvqVZ2A+LlMZucIPY=
81
-go.opentelemetry.io/collector/extension v1.30.0 h1:AJqntAp1p40Q1az2Vze3OHiMURq56KWnUxaLzs1ghaA=
82
-go.opentelemetry.io/collector/extension v1.30.0/go.mod h1:a21WpypFQp9x0Go7yMOknYmIKvdIoWGzjz+h1WMjzLk=
83
-go.opentelemetry.io/collector/extension/extensiontest v0.124.0 h1:pWfKxEqvq5vVdQy+UIerw5j7ZrXezxsfQfuUe8g/xVo=
84
-go.opentelemetry.io/collector/extension/extensiontest v0.124.0/go.mod h1:DLVRyW7tJt8TtYq0Wr5BUsM494YqDiIjN8YCmbVKqjs=
85
-go.opentelemetry.io/collector/extension/xextension v0.124.0 h1:Yzf11HXaiMHfS50Zy/CYKfJjoi+/w/tgRZdDQ2VIdW0=
86
-go.opentelemetry.io/collector/extension/xextension v0.124.0/go.mod h1:GeM0aSgwVSba3Bvvspuy1E+1aa/Q1CDxoK+e/xcJFVg=
87
-go.opentelemetry.io/collector/featuregate v1.30.0 h1:mx7+iP/FQnY7KO8qw/xE3Qd1MQkWcU8VgcqLNrJ8EU8=
88
-go.opentelemetry.io/collector/featuregate v1.30.0/go.mod h1:Y/KsHbvREENKvvN9RlpiWk/IGBK+CATBYzIIpU7nccc=
89
-go.opentelemetry.io/collector/internal/telemetry v0.124.0 h1:kzd1/ZYhLj4bt2pDB529mL4rIRrRacemXodFNxfhdWk=
90
-go.opentelemetry.io/collector/internal/telemetry v0.124.0/go.mod h1:ZjXjqV0dJ+6D4XGhTOxg/WHjnhdmXsmwmUSgALea66Y=
91
-go.opentelemetry.io/collector/pdata v1.30.0 h1:j3jyq9um436r6WzWySzexP2nLnFdmL5uVBYAlyr9nDM=
92
-go.opentelemetry.io/collector/pdata v1.30.0/go.mod h1:0Bxu1ktuj4wE7PIASNSvd0SdBscQ1PLtYasymJ13/Cs=
93
-go.opentelemetry.io/collector/pdata/pprofile v0.124.0 h1:ZjL9wKqzP4BHj0/F1jfGxs1Va8B7xmYayipZeNVoWJE=
94
-go.opentelemetry.io/collector/pdata/pprofile v0.124.0/go.mod h1:1EN3Gw5LSI4fSVma/Yfv/6nqeuYgRTm1/kmG5nE5Oyo=
95
-go.opentelemetry.io/collector/pdata/testdata v0.124.0 h1:vY+pWG7CQfzzGSB5+zGYHQOltRQr59Ek9QiPe+rI+NY=
96
-go.opentelemetry.io/collector/pdata/testdata v0.124.0/go.mod h1:lNH48lGhGv4CYk27fJecpsR1zYHmZjKgNrAprwjym0o=
97
-go.opentelemetry.io/collector/pipeline v0.124.0 h1:hKvhDyH2GPnNO8LGL34ugf36sY7EOXPjBvlrvBhsOdw=
98
-go.opentelemetry.io/collector/pipeline v0.124.0/go.mod h1:TO02zju/K6E+oFIOdi372Wk0MXd+Szy72zcTsFQwXl4=
99
-go.opentelemetry.io/collector/receiver v1.30.0 h1:XbgU4yT3Ld+hL9+jHcD/Kctcr3gXjpiFxKO+50pSayg=
100
-go.opentelemetry.io/collector/receiver v1.30.0/go.mod h1:U3cApz9PHiRMgN0WkZaz4o8mvj1+cVQYsyj2Nl1v3FQ=
101
-go.opentelemetry.io/collector/receiver/receivertest v0.124.0 h1:mx0290aXAo+wfjm4NgbKUodjT5SbS306zmk+AeqeVxE=
102
-go.opentelemetry.io/collector/receiver/receivertest v0.124.0/go.mod h1:3RpopRmIzx5T4zTStHJC0HHfd8YFWm8e9bia1HiuDtY=
103
-go.opentelemetry.io/collector/receiver/xreceiver v0.124.0 h1:YigTUKk8p/aIfqaT0ST7teT9KbLThWD5n2km83byftw=
104
-go.opentelemetry.io/collector/receiver/xreceiver v0.124.0/go.mod h1:NkTpmpAEDT17Dko4gpHUnRztrSkdSd6B0+Y4gfuCWIA=
60
+go.opentelemetry.io/collector/client v1.31.0 h1:PdmUJSx8FgFcrqm12pMwvdVp98aYSdaKjMqJandFIgE=
61
+go.opentelemetry.io/collector/client v1.31.0/go.mod h1:pSyJ1+XhsLP6nqJDP7uj3AFTw26z9mqCnRGyMw0Im8o=
62
+go.opentelemetry.io/collector/component v1.31.0 h1:9LzU8X1RhV3h8/QsAoTX23aFUfoJ3EUc9O/vK+hFpSI=
63
+go.opentelemetry.io/collector/component v1.31.0/go.mod h1:JbZl/KywXJxpUXPbt96qlEXJSym1zQ2hauMxYMuvlxM=
64
+go.opentelemetry.io/collector/component/componenttest v0.125.0 h1:E2mpnMQbkMpYoZ3Q8pHx4kod7kedjwRs1xqDpzCe/84=
65
+go.opentelemetry.io/collector/component/componenttest v0.125.0/go.mod h1:pQtsE1u/SPZdTphP5BZP64XbjXSq6wc+mDut5Ws/JDI=
66
+go.opentelemetry.io/collector/config/configretry v1.31.0 h1:GWl/UM7+xNCmXBz5lvaMxBIQTcNn1EcCvMjVvUwgOLg=
67
+go.opentelemetry.io/collector/config/configretry v1.31.0/go.mod h1:QNnb+MCk7aS1k2EuGJMtlNCltzD7b8uC7Xel0Dxm1wQ=
68
+go.opentelemetry.io/collector/confmap v1.31.0 h1:+AW5VJc1rCtgEyGd+1J5uSNw/kVZ98+lKO/pqXEwVvU=
69
+go.opentelemetry.io/collector/confmap v1.31.0/go.mod h1:TdutQlIoHDPXcZ2xZ0QWGRkSFC8oTKO61zTx569dvrY=
70
+go.opentelemetry.io/collector/consumer v1.31.0 h1:L+y66ywxLHnAxnUxv0JDwUf5bFj53kMxCCyEfRKlM7s=
71
+go.opentelemetry.io/collector/consumer v1.31.0/go.mod h1:rPsqy5ni+c6xNMUkOChleZYO/nInVY6eaBNZ1FmWJVk=
72
+go.opentelemetry.io/collector/consumer/consumererror v0.125.0 h1:Qq9SgbxlJoRn0952dj4lPJhcuBiqKzD1aNxCfa+Bz00=
73
+go.opentelemetry.io/collector/consumer/consumererror v0.125.0/go.mod h1:t/YDU7G2TxG27LbcUvgKo/l75TI5VApnnqC7FgKZds0=
74
+go.opentelemetry.io/collector/consumer/consumertest v0.125.0 h1:TUkxomGS4DAtjBvcWQd2UY4FDLLEKMQD6iOIDUr/5dM=
75
+go.opentelemetry.io/collector/consumer/consumertest v0.125.0/go.mod h1:vkHf3y85cFLDHARO/cTREVjLjOPAV+cQg7lkC44DWOY=
76
+go.opentelemetry.io/collector/consumer/xconsumer v0.125.0 h1:oTreUlk1KpMSWwuHFnstW+orrjGTyvs2xd3o/Dpy+hI=
77
+go.opentelemetry.io/collector/consumer/xconsumer v0.125.0/go.mod h1:FX0G37r0W+wXRgxxFtwEJ4rlsCB+p0cIaxtU3C4hskw=
78
+go.opentelemetry.io/collector/exporter v0.125.0 h1:GJxeCuOQVPndQzvzpZUFEv5njHuVnzBEuXgddRShiCM=
79
+go.opentelemetry.io/collector/exporter v0.125.0/go.mod h1:x+FFBRxWGk+GGaP7u+Bi+OcZoG5qK5vZmgFwI/t4ZwM=
80
+go.opentelemetry.io/collector/exporter/exportertest v0.125.0 h1:FFCEHKlTct0vl/657E1papmL3NicdcxY4ChZbHI3nWk=
81
+go.opentelemetry.io/collector/exporter/exportertest v0.125.0/go.mod h1:UQ6ETigK5yTASXGvjSlE7RcM8C6Ro+TcR8iqDHpXa2U=
82
+go.opentelemetry.io/collector/exporter/xexporter v0.125.0 h1:be5oK6+QOXvyXiCxfiTKxdo/TmjewvciCbC8iMKi/1s=
83
+go.opentelemetry.io/collector/exporter/xexporter v0.125.0/go.mod h1:ebfTFVtKR2eUiAQQc/cS1aBTV2OoFDvFjLiX+thE23s=
84
+go.opentelemetry.io/collector/extension v1.31.0 h1:DaqSl50jOA3BGtqPfPtSGJy4XwyXtQwvemVl/L9fDb4=
85
+go.opentelemetry.io/collector/extension v1.31.0/go.mod h1:SiRNOZIJ6R0JbHEvs3g84hPEmiys5CZyIlMOE1RQ85s=
86
+go.opentelemetry.io/collector/extension/extensiontest v0.125.0 h1:NYtQ42HBjfS5lnfmZdT8+ucq+i70JGLdvDN8V/drvIw=
87
+go.opentelemetry.io/collector/extension/extensiontest v0.125.0/go.mod h1:HABANc94xQmUtOSZokG5E6Z02GrHfKYSkQqOz+oCpPQ=
88
+go.opentelemetry.io/collector/extension/xextension v0.125.0 h1:4BOzKuI5jtNP74X7LMeezFidSYdg8ny3Epv4GzV7LO4=
89
+go.opentelemetry.io/collector/extension/xextension v0.125.0/go.mod h1:JNx5t/UnzxJiH2piNtko7Nj3E4x6YNkWxrVlpvpbm6w=
90
+go.opentelemetry.io/collector/featuregate v1.31.0 h1:20q7plPQZwmAiaYAa6l1m/i2qDITZuWlhjr4EkmeQls=
91
+go.opentelemetry.io/collector/featuregate v1.31.0/go.mod h1:Y/KsHbvREENKvvN9RlpiWk/IGBK+CATBYzIIpU7nccc=
92
+go.opentelemetry.io/collector/internal/telemetry v0.125.0 h1:6lcGOxw3dAg7LfXTKdN8ZjR+l7KvzLdEiPMhhLwG4r4=
93
+go.opentelemetry.io/collector/internal/telemetry v0.125.0/go.mod h1:5GyFslLqjZgq1DZTtFiluxYhhXrCofHgOOOybodDPGE=
94
+go.opentelemetry.io/collector/pdata v1.31.0 h1:P5WuLr1l2JcIvr6Dw2hl01ltp2ZafPnC4Isv+BLTBqU=
95
+go.opentelemetry.io/collector/pdata v1.31.0/go.mod h1:m41io9nWpy7aCm/uD1L9QcKiZwOP0ldj83JEA34dmlk=
96
+go.opentelemetry.io/collector/pdata/pprofile v0.125.0 h1:Qqlx8w1HpiYZ9RQqjmMQIysI0cHNO1nh3E/fCTeFysA=
97
+go.opentelemetry.io/collector/pdata/pprofile v0.125.0/go.mod h1:p/yK023VxAp8hm27/1G5DPTcMIpnJy3cHGAFUQZGyaQ=
98
+go.opentelemetry.io/collector/pdata/testdata v0.125.0 h1:due1Hl0EEVRVwfCkiamRy5E8lS6yalv0lo8Zl/SJtGw=
99
+go.opentelemetry.io/collector/pdata/testdata v0.125.0/go.mod h1:1GpEWlgdMrd+fWsBk37ZC2YmOP5YU3gFQ4rWuCu9g24=
100
+go.opentelemetry.io/collector/pipeline v0.125.0 h1:oitBgcAFqntDB4ihQJUHJSQ8IHqKFpPkaTVbTYdIUzM=
101
+go.opentelemetry.io/collector/pipeline v0.125.0/go.mod h1:TO02zju/K6E+oFIOdi372Wk0MXd+Szy72zcTsFQwXl4=
102
+go.opentelemetry.io/collector/receiver v1.31.0 h1:OSRrCWclb1QmGPnxFMxQsdegua4vlKpZESOtDKSzKeQ=
103
+go.opentelemetry.io/collector/receiver v1.31.0/go.mod h1:zPUiv3jgJGQSY01nx500cYJiEz6JfaR53BAvCW2tgGs=
104
+go.opentelemetry.io/collector/receiver/receivertest v0.125.0 h1:xV3Jm3OT7SfDpJ5mXhNmK/Nch7f41whA8k0q4XkaWT8=
105
+go.opentelemetry.io/collector/receiver/receivertest v0.125.0/go.mod h1:CoSPPn3kwVcAhdLOK5NVjMCVVjmCsFpBXU9h9I6Kdh8=
106
+go.opentelemetry.io/collector/receiver/xreceiver v0.125.0 h1:wQ1ZgCA0Y3EFWWZ6gZDGDXT7qV5IrqkisccUWhvmmTg=
107
+go.opentelemetry.io/collector/receiver/xreceiver v0.125.0/go.mod h1:5Kl/mtf6oIy+rizFcElkUpp3LEVTJnjAyos6z+FVsGc=
108
go.opentelemetry.io/contrib/bridges/otelzap v0.10.0 h1:ojdSRDvjrnm30beHOmwsSvLpoRF40MlwNCA+Oo93kXU=
109
go.opentelemetry.io/contrib/bridges/otelzap v0.10.0/go.mod h1:oTTm4g7NEtHSV2i/0FeVdPaPgUIZPfQkFbq0vbzqnv0=
110
go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ=
@@ -131,20 +134,20 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn
134
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
135
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
136
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
134
-golang.org/x/net v0.37.0 h1:1zLorHbz+LYj7MQlSf1+2tPIIgibq2eL5xkrGk6f+2c=
135
-golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
137
+golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY=
138
+golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E=
139
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
140
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
141
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
142
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
143
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
144
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
142
-golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
143
-golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
145
+golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
146
+golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
147
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
148
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
146
-golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
147
-golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
149
+golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0=
150
+golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU=
151
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
152
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
153
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
@@ -153,10 +156,10 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T
156
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
157
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
158
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
156
-google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f h1:OxYkA3wjPsZyBylwymxSHa7ViiW1Sml4ToBrncvFehI=
157
-google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f/go.mod h1:+2Yz8+CLJbIfL9z73EW45avw8Lmge3xVElCP9zEKi50=
158
-google.golang.org/grpc v1.71.1 h1:ffsFWr7ygTUscGPI0KKK6TLrGz0476KUvvsbqWK0rPI=
159
-google.golang.org/grpc v1.71.1/go.mod h1:H0GRtasmQOh9LkFoCPDu3ZrwUtD1YGE+b2vYBYd/8Ec=
159
+google.golang.org/genproto/googleapis/rpc v0.0.0-20250428153025-10db94c68c34 h1:h6p3mQqrmT1XkHVTfzLdNz1u7IhINeZkz67/xTbOuWs=
160
+google.golang.org/genproto/googleapis/rpc v0.0.0-20250428153025-10db94c68c34/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
161
+google.golang.org/grpc v1.72.0 h1:S7UkcVa60b5AAQTaO6ZKamFp1zMZSU0fGDK2WZLbBnM=
162
+google.golang.org/grpc v1.72.0/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM=
163
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
164
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
165
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
@@ -164,3 +167,5 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntN
167
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
168
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
169
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
170
+sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=
171
+sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=
src/go/otel-collector/exporter/netdataexporter/netdataapi.go
new
+128
@@ -0,0 +1,128 @@
1
+package netdataexporter
2
+
3
+import (
4
+ "io"
5
+ "os"
6
+ "strconv"
7
+ "sync"
8
+)
9
+
10
+type ChartOpts struct {
11
+ TypeID string
12
+ ID string
13
+ Name string
14
+ Title string
15
+ Units string
16
+ Family string
17
+ Context string
18
+ ChartType string
19
+ Priority int
20
+ UpdateEvery int
21
+ Options string
22
+ Plugin string
23
+ Module string
24
+}
25
+
26
+type DimensionOpts struct {
27
+ ID string
28
+ Name string
29
+ Algorithm string
30
+ Multiplier int
31
+ Divisor int
32
+ Options string
33
+}
34
+
35
+type safeWriter struct {
36
+ mx *sync.Mutex
37
+ w io.Writer
38
+}
39
+
40
+func (w *safeWriter) Write(p []byte) (n int, err error) {
41
+ w.mx.Lock()
42
+ n, err = w.w.Write(p)
43
+ w.mx.Unlock()
44
+ return n, err
45
+}
46
+
47
+func newNetdataStdoutApi() *netdataAPI {
48
+ w := &safeWriter{
49
+ mx: &sync.Mutex{},
50
+ w: os.Stdout,
51
+ }
52
+ return newNetdataApi(w)
53
+}
54
+
55
+func newNetdataApi(w io.Writer) *netdataAPI {
56
+ if w == nil {
57
+ panic("writer cannot be nil")
58
+ }
59
+ return &netdataAPI{w}
60
+}
61
+
62
+type netdataAPI struct {
63
+ io.Writer
64
+}
65
+
66
+const quotes = "' '"
67
+
68
+var (
69
+ newLine = []byte("\n")
70
+)
71
+
72
+func (a *netdataAPI) chart(opts ChartOpts) {
73
+ _, _ = a.Write([]byte("CHART " + "'" +
74
+ opts.TypeID + "." + opts.ID + quotes +
75
+ opts.Name + quotes +
76
+ opts.Title + quotes +
77
+ opts.Units + quotes +
78
+ opts.Family + quotes +
79
+ opts.Context + quotes +
80
+ opts.ChartType + quotes +
81
+ strconv.Itoa(opts.Priority) + quotes +
82
+ strconv.Itoa(opts.UpdateEvery) + quotes +
83
+ opts.Options + quotes +
84
+ opts.Plugin + quotes +
85
+ opts.Module + "'\n"))
86
+}
87
+
88
+func (a *netdataAPI) dimension(opts DimensionOpts) {
89
+ _, _ = a.Write([]byte("DIMENSION '" +
90
+ opts.ID + quotes +
91
+ opts.Name + quotes +
92
+ opts.Algorithm + quotes +
93
+ strconv.Itoa(opts.Multiplier) + quotes +
94
+ strconv.Itoa(opts.Divisor) + quotes +
95
+ opts.Options + "'\n"))
96
+}
97
+
98
+func (a *netdataAPI) clabel(key, value string) {
99
+ _, _ = a.Write([]byte("CLABEL '" +
100
+ key + quotes +
101
+ value + " '0'\n"))
102
+}
103
+
104
+// CLABELCOMMIT adds labels to the chart. Should be called after one or more CLABEL.
105
+func (a *netdataAPI) clabelcommit() {
106
+ _, _ = a.Write([]byte("CLABELCOMMIT\n"))
107
+}
108
+
109
+func (a *netdataAPI) begin(chartId string, msSince int) {
110
+ if msSince > 0 {
111
+ _, _ = a.Write([]byte("BEGIN " + "'" + chartId + "' " + strconv.Itoa(msSince) + "\n"))
112
+ } else {
113
+ _, _ = a.Write([]byte("BEGIN " + "'" + chartId + "'\n"))
114
+ }
115
+}
116
+
117
+func (a *netdataAPI) set(dimensionId string, value int64) {
118
+ _, _ = a.Write([]byte("SET '" + dimensionId + "' = " + strconv.FormatInt(value, 10) + "\n"))
119
+}
120
+
121
+// SETEMPTY sets an empty value for a dimension in the initialized chart.
122
+func (a *netdataAPI) setempty(id string) {
123
+ _, _ = a.Write([]byte("SET '" + id + "' = \n"))
124
+}
125
+
126
+func (a *netdataAPI) end() {
127
+ _, _ = a.Write([]byte("END\n\n"))
128
+}
src/go/otel-collector/exporter/netdataexporter/netdatachart.go
new
+28
@@ -0,0 +1,28 @@
1
+package netdataexporter
2
+
3
+//type ChartDefinition struct {
4
+// ID string // must be globally unique
5
+// Title string
6
+// Units string
7
+// Family string
8
+// Context string // metric name
9
+// Type string // line, area, stacked
10
+// Options string // set to "obsolete" to delete the chart, otherwise empty string
11
+// Labels []LabelDefinition
12
+// Dimensions []DimensionDefinition
13
+// IsNew bool // Indicates if this chart is new and needs to be sent to Netdata
14
+//}
15
+//
16
+//// LabelDefinition represents a Netdata chart label
17
+//type LabelDefinition struct {
18
+// Name string
19
+// Value string
20
+//}
21
+//
22
+//// DimensionDefinition represents a Netdata chart dimension
23
+//type DimensionDefinition struct {
24
+// ID string // must be unique within the chart
25
+// Name string // replaces ID in UI
26
+// Algo string // absolute (Gauge), incremental (Counter)
27
+// Value float64
28
+//}
src/go/otel-collector/release-config.yaml.in
+5
-5
@@ -8,13 +8,13 @@ dist:
8
debug_compilation: @DEBUG_BUILD@
9
10
receivers:
11
- - gomod: go.opentelemetry.io/collector/receiver/otlpreceiver v0.124.0
12
- - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/receiver/filelogreceiver v0.124.0
11
+ - gomod: go.opentelemetry.io/collector/receiver/otlpreceiver v0.125.0
12
+ - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/receiver/filelogreceiver v0.125.0
13
14
exporters:
15
- - gomod: go.opentelemetry.io/collector/exporter/debugexporter v0.124.0
16
- - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/exporter/fileexporter v0.124.0
17
- - gomod: go.opentelemetry.io/collector/exporter/otlpexporter v0.124.0
15
+ - gomod: go.opentelemetry.io/collector/exporter/debugexporter v0.125.0
16
+ - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/exporter/fileexporter v0.125.0
17
+ - gomod: go.opentelemetry.io/collector/exporter/otlpexporter v0.125.0
18
- gomod: github.com/netdata/netdata/otel-collector/exporter/journaldexporter v0.0.0
19
20
replaces: