diff --git a/.chloggen/arrow_exporter_by_metadata.yaml b/.chloggen/arrow_exporter_by_metadata.yaml new file mode 100644 index 000000000000..1411e5a13ab6 --- /dev/null +++ b/.chloggen/arrow_exporter_by_metadata.yaml @@ -0,0 +1,27 @@ +# Use this changelog template to create an entry for release notes. + +# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix' +change_type: enhancement + +# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver) +component: otelarrowexporter + +# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). +note: Allow separate arrow exporter per unique value of configured metadataKeys. + +# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists. +issues: [34178] + +# (Optional) One or more lines of additional information to render under the primary note. +# These lines will be padded with 2 spaces and then inserted directly into the document. +# Use pipe (|) for multiline entries. +subtext: + +# If your change doesn't affect end users or the exported elements of any package, +# you should instead start your pull request title with [chore] or use the "Skip Changelog" label. +# Optional: The change log or logs in which this entry should be included. +# e.g. '[user]' or '[user, api]' +# Include 'user' if the change is relevant to end users. +# Include 'api' if there is a change to a library API. +# Default: '[user]' +change_logs: [] \ No newline at end of file diff --git a/.chloggen/datadog-receiver-metrics-attributes-fix.yaml b/.chloggen/datadog-receiver-metrics-attributes-fix.yaml new file mode 100644 index 000000000000..9be880dbf5e9 --- /dev/null +++ b/.chloggen/datadog-receiver-metrics-attributes-fix.yaml @@ -0,0 +1,27 @@ +# Use this changelog template to create an entry for release notes. + +# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix' +change_type: bug_fix + +# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver) +component: datadogreceiver + +# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). +note: Fix numeric span attributes + +# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists. +issues: [35087] + +# (Optional) One or more lines of additional information to render under the primary note. +# These lines will be padded with 2 spaces and then inserted directly into the document. +# Use pipe (|) for multiline entries. +subtext: + +# If your change doesn't affect end users or the exported elements of any package, +# you should instead start your pull request title with [chore] or use the "Skip Changelog" label. +# Optional: The change log or logs in which this entry should be included. +# e.g. '[user]' or '[user, api]' +# Include 'user' if the change is relevant to end users. +# Include 'api' if there is a change to a library API. +# Default: '[user]' +change_logs: [user] diff --git a/.chloggen/ottl-faster-json.yaml b/.chloggen/ottl-faster-json.yaml new file mode 100644 index 000000000000..cd5daf89f32f --- /dev/null +++ b/.chloggen/ottl-faster-json.yaml @@ -0,0 +1,27 @@ +# Use this changelog template to create an entry for release notes. + +# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix' +change_type: enhancement + +# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver) +component: pkg/ottl + +# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). +note: Improved JSON unmarshaling performance by 10-20% by switching dependencies. + +# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists. +issues: [35130] + +# (Optional) One or more lines of additional information to render under the primary note. +# These lines will be padded with 2 spaces and then inserted directly into the document. +# Use pipe (|) for multiline entries. +subtext: + +# If your change doesn't affect end users or the exported elements of any package, +# you should instead start your pull request title with [chore] or use the "Skip Changelog" label. +# Optional: The change log or logs in which this entry should be included. +# e.g. '[user]' or '[user, api]' +# Include 'user' if the change is relevant to end users. +# Include 'api' if there is a change to a library API. +# Default: '[user]' +change_logs: [] diff --git a/.chloggen/ottl_time_func_locale_support.yaml b/.chloggen/ottl_time_func_locale_support.yaml new file mode 100644 index 000000000000..b58cd99ee91e --- /dev/null +++ b/.chloggen/ottl_time_func_locale_support.yaml @@ -0,0 +1,27 @@ +# Use this changelog template to create an entry for release notes. + +# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix' +change_type: enhancement + +# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver) +component: pkg/ottl + +# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). +note: Added support for locale in the Time converter + +# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists. +issues: [32978] + +# (Optional) One or more lines of additional information to render under the primary note. +# These lines will be padded with 2 spaces and then inserted directly into the document. +# Use pipe (|) for multiline entries. +subtext: + +# If your change doesn't affect end users or the exported elements of any package, +# you should instead start your pull request title with [chore] or use the "Skip Changelog" label. +# Optional: The change log or logs in which this entry should be included. +# e.g. '[user]' or '[user, api]' +# Include 'user' if the change is relevant to end users. +# Include 'api' if there is a change to a library API. +# Default: '[user]' +change_logs: [user] diff --git a/.chloggen/redaction-fix-logs.yaml b/.chloggen/redaction-fix-logs.yaml new file mode 100644 index 000000000000..ed781a7bbf1c --- /dev/null +++ b/.chloggen/redaction-fix-logs.yaml @@ -0,0 +1,27 @@ +# Use this changelog template to create an entry for release notes. + +# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix' +change_type: bug_fix + +# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver) +component: redactionprocessor + +# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). +note: Fix panic when using the redaction processor in a logs pipeline + +# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists. +issues: [35331] + +# (Optional) One or more lines of additional information to render under the primary note. +# These lines will be padded with 2 spaces and then inserted directly into the document. +# Use pipe (|) for multiline entries. +subtext: + +# If your change doesn't affect end users or the exported elements of any package, +# you should instead start your pull request title with [chore] or use the "Skip Changelog" label. +# Optional: The change log or logs in which this entry should be included. +# e.g. '[user]' or '[user, api]' +# Include 'user' if the change is relevant to end users. +# Include 'api' if there is a change to a library API. +# Default: '[user]' +change_logs: [] diff --git a/.chloggen/splunkhec-fix-invalid-data-access.yaml b/.chloggen/splunkhec-fix-invalid-data-access.yaml new file mode 100644 index 000000000000..4eeb3b235915 --- /dev/null +++ b/.chloggen/splunkhec-fix-invalid-data-access.yaml @@ -0,0 +1,28 @@ +# Use this changelog template to create an entry for release notes. + +# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix' +change_type: bug_fix + +# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver) +component: exporter/splunkhec + +# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). +note: Fix incorrect claim that the exporter doesn't mutate data when batching is enabled. + +# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists. +issues: [35306] + +# (Optional) One or more lines of additional information to render under the primary note. +# These lines will be padded with 2 spaces and then inserted directly into the document. +# Use pipe (|) for multiline entries. +subtext: | + The bug lead to runtime panics when the exporter was used with the batcher enabled in a fanout scenario. + +# If your change doesn't affect end users or the exported elements of any package, +# you should instead start your pull request title with [chore] or use the "Skip Changelog" label. +# Optional: The change log or logs in which this entry should be included. +# e.g. '[user]' or '[user, api]' +# Include 'user' if the change is relevant to end users. +# Include 'api' if there is a change to a library API. +# Default: '[user]' +change_logs: [] diff --git a/cmd/githubgen/codeowners.go b/cmd/githubgen/codeowners.go index 8c83abb53f14..d54448f83319 100644 --- a/cmd/githubgen/codeowners.go +++ b/cmd/githubgen/codeowners.go @@ -10,7 +10,7 @@ import ( "sort" "strings" - "github.com/google/go-github/v64/github" + "github.com/google/go-github/v65/github" ) const allowlistHeader = `# Code generated by githubgen. DO NOT EDIT. diff --git a/cmd/githubgen/go.mod b/cmd/githubgen/go.mod index 921c5e4046cb..9c64fa79df2c 100644 --- a/cmd/githubgen/go.mod +++ b/cmd/githubgen/go.mod @@ -3,7 +3,7 @@ module github.com/open-telemetry/opentelemetry-collector-contrib/cmd/githubgen go 1.22.0 require ( - github.com/google/go-github/v64 v64.0.0 + github.com/google/go-github/v65 v65.0.0 go.opentelemetry.io/collector/confmap v1.15.1-0.20240918193345-a3c0565031b0 go.opentelemetry.io/collector/confmap/provider/fileprovider v1.15.1-0.20240918193345-a3c0565031b0 gopkg.in/yaml.v3 v3.0.1 diff --git a/cmd/githubgen/go.sum b/cmd/githubgen/go.sum index 125140737774..ca6391af85fa 100644 --- a/cmd/githubgen/go.sum +++ b/cmd/githubgen/go.sum @@ -5,8 +5,8 @@ github.com/go-viper/mapstructure/v2 v2.1.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlnd github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-github/v64 v64.0.0 h1:4G61sozmY3eiPAjjoOHponXDBONm+utovTKbyUb2Qdg= -github.com/google/go-github/v64 v64.0.0/go.mod h1:xB3vqMQNdHzilXBiO2I+M7iEFtHf+DP/omBOv6tQzVo= +github.com/google/go-github/v65 v65.0.0 h1:pQ7BmO3DZivvFk92geC0jB0q2m3gyn8vnYPgV7GSLhQ= +github.com/google/go-github/v65 v65.0.0/go.mod h1:DvrqWo5hvsdhJvHd4WyVF9ttANN3BniqjP8uTFMNb60= github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= github.com/knadh/koanf/maps v0.1.1 h1:G5TjmUh2D7G2YWf5SQQqSiHRJEjaicvU0KpypqB3NIs= diff --git a/cmd/otelcontribcol/go.mod b/cmd/otelcontribcol/go.mod index 7db3b3d2079b..bef1b0b5cb19 100644 --- a/cmd/otelcontribcol/go.mod +++ b/cmd/otelcontribcol/go.mod @@ -514,7 +514,7 @@ require ( github.com/google/flatbuffers v24.3.25+incompatible // indirect github.com/google/gnostic-models v0.6.8 // indirect github.com/google/go-cmp v0.6.0 // indirect - github.com/google/go-github/v64 v64.0.0 // indirect + github.com/google/go-github/v65 v65.0.0 // indirect github.com/google/go-querystring v1.1.0 // indirect github.com/google/gofuzz v1.2.0 // indirect github.com/google/s2a-go v0.1.8 // indirect diff --git a/cmd/otelcontribcol/go.sum b/cmd/otelcontribcol/go.sum index 469adf70bde7..c4f6c325bda0 100644 --- a/cmd/otelcontribcol/go.sum +++ b/cmd/otelcontribcol/go.sum @@ -1489,8 +1489,8 @@ github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-github/v64 v64.0.0 h1:4G61sozmY3eiPAjjoOHponXDBONm+utovTKbyUb2Qdg= -github.com/google/go-github/v64 v64.0.0/go.mod h1:xB3vqMQNdHzilXBiO2I+M7iEFtHf+DP/omBOv6tQzVo= +github.com/google/go-github/v65 v65.0.0 h1:pQ7BmO3DZivvFk92geC0jB0q2m3gyn8vnYPgV7GSLhQ= +github.com/google/go-github/v65 v65.0.0/go.mod h1:DvrqWo5hvsdhJvHd4WyVF9ttANN3BniqjP8uTFMNb60= github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= diff --git a/connector/countconnector/go.mod b/connector/countconnector/go.mod index 69e6ed432c29..e5951ab94d15 100644 --- a/connector/countconnector/go.mod +++ b/connector/countconnector/go.mod @@ -29,6 +29,7 @@ require ( github.com/go-logr/stdr v1.2.2 // indirect github.com/go-viper/mapstructure/v2 v2.1.0 // indirect github.com/gobwas/glob v0.2.3 // indirect + github.com/goccy/go-json v0.10.3 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/google/uuid v1.6.0 // indirect github.com/hashicorp/golang-lru v0.5.4 // indirect diff --git a/connector/countconnector/go.sum b/connector/countconnector/go.sum index e99b1f2c5169..dcf0e68d1f5e 100644 --- a/connector/countconnector/go.sum +++ b/connector/countconnector/go.sum @@ -22,6 +22,8 @@ github.com/go-viper/mapstructure/v2 v2.1.0 h1:gHnMa2Y/pIxElCH2GlZZ1lZSsn6XMtufpG github.com/go-viper/mapstructure/v2 v2.1.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= +github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA= +github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= diff --git a/connector/routingconnector/go.mod b/connector/routingconnector/go.mod index 3d94bad93049..8067451dbb4c 100644 --- a/connector/routingconnector/go.mod +++ b/connector/routingconnector/go.mod @@ -24,6 +24,7 @@ require ( github.com/go-logr/stdr v1.2.2 // indirect github.com/go-viper/mapstructure/v2 v2.1.0 // indirect github.com/gobwas/glob v0.2.3 // indirect + github.com/goccy/go-json v0.10.3 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/google/uuid v1.6.0 // indirect github.com/hashicorp/golang-lru v0.5.4 // indirect diff --git a/connector/routingconnector/go.sum b/connector/routingconnector/go.sum index 2397dabc3ca3..20fea835b42a 100644 --- a/connector/routingconnector/go.sum +++ b/connector/routingconnector/go.sum @@ -21,6 +21,8 @@ github.com/go-viper/mapstructure/v2 v2.1.0 h1:gHnMa2Y/pIxElCH2GlZZ1lZSsn6XMtufpG github.com/go-viper/mapstructure/v2 v2.1.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= +github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA= +github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= diff --git a/connector/sumconnector/go.mod b/connector/sumconnector/go.mod index 95925bdff3cb..c455a1a59b5b 100644 --- a/connector/sumconnector/go.mod +++ b/connector/sumconnector/go.mod @@ -25,6 +25,7 @@ require ( github.com/go-logr/stdr v1.2.2 // indirect github.com/go-viper/mapstructure/v2 v2.1.0 // indirect github.com/gobwas/glob v0.2.3 // indirect + github.com/goccy/go-json v0.10.3 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/google/uuid v1.6.0 // indirect github.com/hashicorp/golang-lru v0.5.4 // indirect diff --git a/connector/sumconnector/go.sum b/connector/sumconnector/go.sum index dbe1345069ab..0b356ed6a740 100644 --- a/connector/sumconnector/go.sum +++ b/connector/sumconnector/go.sum @@ -20,6 +20,8 @@ github.com/go-viper/mapstructure/v2 v2.1.0 h1:gHnMa2Y/pIxElCH2GlZZ1lZSsn6XMtufpG github.com/go-viper/mapstructure/v2 v2.1.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= +github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA= +github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= diff --git a/examples/demo/client/go.mod b/examples/demo/client/go.mod index dc2551f00210..f7c14230e487 100644 --- a/examples/demo/client/go.mod +++ b/examples/demo/client/go.mod @@ -3,7 +3,7 @@ module github.com/open-telemetry/opentelemetry-collector-contrib/examples/demo/c go 1.22.0 require ( - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.55.0 go.opentelemetry.io/otel v1.30.0 go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.30.0 go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.30.0 diff --git a/examples/demo/client/go.sum b/examples/demo/client/go.sum index 17c5ddd2d7da..5503e518a50a 100644 --- a/examples/demo/client/go.sum +++ b/examples/demo/client/go.sum @@ -19,8 +19,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 h1:TT4fX+nBOA/+LUkobKGW1ydGcn+G3vRw9+g5HwCphpk= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0/go.mod h1:L7UH0GbB0p47T4Rri3uHjbpCFYrVrwc1I25QhNPiGK8= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.55.0 h1:ZIg3ZT/aQ7AfKqdwp7ECpOK6vHqquXXuyTjIO8ZdmPs= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.55.0/go.mod h1:DQAwmETtZV00skUwgD6+0U89g80NKsJE3DCKeLLPQMI= go.opentelemetry.io/otel v1.30.0 h1:F2t8sK4qf1fAmY9ua4ohFS/K+FUuOPemHUIXHtktrts= go.opentelemetry.io/otel v1.30.0/go.mod h1:tFw4Br9b7fOS+uEao81PJjVMjW/5fvNCbpsDIXqP0pc= go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.30.0 h1:WypxHH02KX2poqqbaadmkMYalGyy/vil4HE4PM4nRJc= diff --git a/examples/demo/server/go.mod b/examples/demo/server/go.mod index 8c5ea0a1dc69..da12f90aa50b 100644 --- a/examples/demo/server/go.mod +++ b/examples/demo/server/go.mod @@ -3,7 +3,7 @@ module github.com/open-telemetry/opentelemetry-collector-contrib/examples/demo/s go 1.22.0 require ( - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.55.0 go.opentelemetry.io/otel v1.30.0 go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.30.0 go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.30.0 diff --git a/examples/demo/server/go.sum b/examples/demo/server/go.sum index 17c5ddd2d7da..5503e518a50a 100644 --- a/examples/demo/server/go.sum +++ b/examples/demo/server/go.sum @@ -19,8 +19,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 h1:TT4fX+nBOA/+LUkobKGW1ydGcn+G3vRw9+g5HwCphpk= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0/go.mod h1:L7UH0GbB0p47T4Rri3uHjbpCFYrVrwc1I25QhNPiGK8= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.55.0 h1:ZIg3ZT/aQ7AfKqdwp7ECpOK6vHqquXXuyTjIO8ZdmPs= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.55.0/go.mod h1:DQAwmETtZV00skUwgD6+0U89g80NKsJE3DCKeLLPQMI= go.opentelemetry.io/otel v1.30.0 h1:F2t8sK4qf1fAmY9ua4ohFS/K+FUuOPemHUIXHtktrts= go.opentelemetry.io/otel v1.30.0/go.mod h1:tFw4Br9b7fOS+uEao81PJjVMjW/5fvNCbpsDIXqP0pc= go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.30.0 h1:WypxHH02KX2poqqbaadmkMYalGyy/vil4HE4PM4nRJc= diff --git a/exporter/honeycombmarkerexporter/go.mod b/exporter/honeycombmarkerexporter/go.mod index f928c55c941b..657939c92b01 100644 --- a/exporter/honeycombmarkerexporter/go.mod +++ b/exporter/honeycombmarkerexporter/go.mod @@ -32,6 +32,7 @@ require ( github.com/go-logr/stdr v1.2.2 // indirect github.com/go-viper/mapstructure/v2 v2.1.0 // indirect github.com/gobwas/glob v0.2.3 // indirect + github.com/goccy/go-json v0.10.3 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/snappy v0.0.4 // indirect github.com/google/uuid v1.6.0 // indirect diff --git a/exporter/honeycombmarkerexporter/go.sum b/exporter/honeycombmarkerexporter/go.sum index a116b5569fc3..c334d551aa24 100644 --- a/exporter/honeycombmarkerexporter/go.sum +++ b/exporter/honeycombmarkerexporter/go.sum @@ -26,6 +26,8 @@ github.com/go-viper/mapstructure/v2 v2.1.0 h1:gHnMa2Y/pIxElCH2GlZZ1lZSsn6XMtufpG github.com/go-viper/mapstructure/v2 v2.1.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= +github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA= +github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= diff --git a/exporter/otelarrowexporter/README.md b/exporter/otelarrowexporter/README.md index 4b3bcb0e4fd7..3538bbc4fe73 100644 --- a/exporter/otelarrowexporter/README.md +++ b/exporter/otelarrowexporter/README.md @@ -115,6 +115,17 @@ streams. - `prioritizer` (default: "leastloaded"): policy for distributing load across multiple streams. +### Matching Metadata Per Stream + +The following configuration values allow for separate streams per unique +metadata combinations: +- `metadata_keys` (default = empty): When set, this exporter will create one + arrow exporter instance per distinct combination of values in the + client.Metadata. +- `metadata_cardinality_limit` (default = 1000): When metadata_keys is not empty, + this setting limits the number of unique combinations of metadata key values + that will be processed over the lifetime of the exporter. + ### Network Configuration This component uses `round_robin` by default as the gRPC load diff --git a/exporter/otelarrowexporter/config.go b/exporter/otelarrowexporter/config.go index c512ee30119d..9786e203a3c5 100644 --- a/exporter/otelarrowexporter/config.go +++ b/exporter/otelarrowexporter/config.go @@ -5,6 +5,7 @@ package otelarrowexporter // import "github.com/open-telemetry/opentelemetry-col import ( "fmt" + "strings" "time" "github.com/open-telemetry/otel-arrow/pkg/config" @@ -45,6 +46,23 @@ type Config struct { // exporter is built and configured via code instead of yaml. // Uses include custom dialer, custom user-agent, etc. UserDialOptions []grpc.DialOption `mapstructure:"-"` + + // MetadataKeys is a list of client.Metadata keys that will be + // used to form distinct exporters. If this setting is empty, + // a single exporter instance will be used. When this setting + // is not empty, one exporter will be used per distinct + // combination of values for the listed metadata keys. + // + // Empty value and unset metadata are treated as distinct cases. + // + // Entries are case-insensitive. Duplicated entries will + // trigger a validation error. + MetadataKeys []string `mapstructure:"metadata_keys"` + + // MetadataCardinalityLimit indicates the maximum number of + // exporter instances that will be created through a distinct + // combination of MetadataKeys. + MetadataCardinalityLimit uint32 `mapstructure:"metadata_cardinality_limit"` } // ArrowConfig includes whether Arrow is enabled and the number of @@ -90,6 +108,24 @@ var _ component.Config = (*Config)(nil) var _ component.ConfigValidator = (*ArrowConfig)(nil) +func (cfg *Config) Validate() error { + err := cfg.Arrow.Validate() + if err != nil { + return err + } + + uniq := map[string]bool{} + for _, k := range cfg.MetadataKeys { + l := strings.ToLower(k) + if _, has := uniq[l]; has { + return fmt.Errorf("duplicate entry in metadata_keys: %q (case-insensitive)", l) + } + uniq[l] = true + } + + return nil +} + // Validate returns an error when the number of streams is less than 1. func (cfg *ArrowConfig) Validate() error { if cfg.NumStreams < 1 { diff --git a/exporter/otelarrowexporter/factory.go b/exporter/otelarrowexporter/factory.go index 0d3a078388e3..a868fa286d65 100644 --- a/exporter/otelarrowexporter/factory.go +++ b/exporter/otelarrowexporter/factory.go @@ -72,15 +72,16 @@ func createDefaultConfig() component.Config { } } -func (exp *baseExporter) helperOptions() []exporterhelper.Option { +func helperOptions(e exp) []exporterhelper.Option { + cfg := e.getConfig().(*Config) return []exporterhelper.Option{ exporterhelper.WithCapabilities(consumer.Capabilities{MutatesData: false}), - exporterhelper.WithTimeout(exp.config.TimeoutSettings), - exporterhelper.WithRetry(exp.config.RetryConfig), - exporterhelper.WithQueue(exp.config.QueueSettings), - exporterhelper.WithStart(exp.start), - exporterhelper.WithBatcher(exp.config.BatcherConfig), - exporterhelper.WithShutdown(exp.shutdown), + exporterhelper.WithTimeout(cfg.TimeoutSettings), + exporterhelper.WithRetry(cfg.RetryConfig), + exporterhelper.WithQueue(cfg.QueueSettings), + exporterhelper.WithStart(e.start), + exporterhelper.WithBatcher(cfg.BatcherConfig), + exporterhelper.WithShutdown(e.shutdown), } } @@ -103,13 +104,13 @@ func createTracesExporter( set exporter.Settings, cfg component.Config, ) (exporter.Traces, error) { - exp, err := newExporter(cfg, set, createArrowTracesStream) + e, err := newMetadataExporter(cfg, set, createArrowTracesStream) if err != nil { return nil, err } - return exporterhelper.NewTracesExporter(ctx, exp.settings, exp.config, - exp.pushTraces, - exp.helperOptions()..., + return exporterhelper.NewTracesExporter(ctx, e.getSettings(), e.getConfig(), + e.pushTraces, + helperOptions(e)..., ) } @@ -122,13 +123,13 @@ func createMetricsExporter( set exporter.Settings, cfg component.Config, ) (exporter.Metrics, error) { - exp, err := newExporter(cfg, set, createArrowMetricsStream) + e, err := newMetadataExporter(cfg, set, createArrowMetricsStream) if err != nil { return nil, err } - return exporterhelper.NewMetricsExporter(ctx, exp.settings, exp.config, - exp.pushMetrics, - exp.helperOptions()..., + return exporterhelper.NewMetricsExporter(ctx, e.getSettings(), e.getConfig(), + e.pushMetrics, + helperOptions(e)..., ) } @@ -141,12 +142,12 @@ func createLogsExporter( set exporter.Settings, cfg component.Config, ) (exporter.Logs, error) { - exp, err := newExporter(cfg, set, createArrowLogsStream) + e, err := newMetadataExporter(cfg, set, createArrowLogsStream) if err != nil { return nil, err } - return exporterhelper.NewLogsExporter(ctx, exp.settings, exp.config, - exp.pushLogs, - exp.helperOptions()..., + return exporterhelper.NewLogsExporter(ctx, e.getSettings(), e.getConfig(), + e.pushLogs, + helperOptions(e)..., ) } diff --git a/exporter/otelarrowexporter/factory_test.go b/exporter/otelarrowexporter/factory_test.go index 0ca198b1ddbe..7498a0403dd8 100644 --- a/exporter/otelarrowexporter/factory_test.go +++ b/exporter/otelarrowexporter/factory_test.go @@ -31,8 +31,7 @@ func TestCreateDefaultConfig(t *testing.T) { cfg := factory.CreateDefaultConfig() assert.NotNil(t, cfg, "failed to create default config") assert.NoError(t, componenttest.CheckConfigStruct(cfg)) - ocfg, ok := factory.CreateDefaultConfig().(*Config) - assert.True(t, ok) + ocfg := factory.CreateDefaultConfig().(*Config) assert.Equal(t, ocfg.RetryConfig, configretry.NewDefaultBackOffConfig()) assert.Equal(t, ocfg.QueueSettings, exporterhelper.NewDefaultQueueConfig()) assert.Equal(t, ocfg.TimeoutSettings, exporterhelper.NewDefaultTimeoutConfig()) diff --git a/exporter/otelarrowexporter/metadata.go b/exporter/otelarrowexporter/metadata.go new file mode 100644 index 000000000000..1d24bfc6cb81 --- /dev/null +++ b/exporter/otelarrowexporter/metadata.go @@ -0,0 +1,203 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package otelarrowexporter // import "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/otelarrowexporter" + +import ( + "context" + "errors" + "fmt" + "runtime" + "sort" + "strings" + "sync" + + arrowPkg "github.com/apache/arrow/go/v16/arrow" + "go.opentelemetry.io/collector/client" + "go.opentelemetry.io/collector/component" + "go.opentelemetry.io/collector/consumer/consumererror" + "go.opentelemetry.io/collector/exporter" + "go.opentelemetry.io/collector/pdata/plog" + "go.opentelemetry.io/collector/pdata/pmetric" + "go.opentelemetry.io/collector/pdata/ptrace" + "go.opentelemetry.io/otel/attribute" + "go.uber.org/multierr" + "google.golang.org/grpc/metadata" + + "github.com/open-telemetry/opentelemetry-collector-contrib/internal/otelarrow/compression/zstd" + "github.com/open-telemetry/opentelemetry-collector-contrib/internal/otelarrow/netstats" +) + +var ( + // errTooManyExporters is returned when the MetadataCardinalityLimit has been reached. + errTooManyExporters = consumererror.NewPermanent(errors.New("too many exporter metadata-value combinations")) +) + +type metadataExporter struct { + config *Config + settings exporter.Settings + scf streamClientFactory + host component.Host + + metadataKeys []string + exporters sync.Map + netReporter *netstats.NetworkReporter + + userAgent string + + // Guards the size and the storing logic to ensure no more than limit items are stored. + // If we are willing to allow "some" extra items than the limit this can be removed and size can be made atomic. + lock sync.Mutex + size int +} + +var _ exp = (*metadataExporter)(nil) + +func newMetadataExporter(cfg component.Config, set exporter.Settings, streamClientFactory streamClientFactory) (exp, error) { + oCfg := cfg.(*Config) + netReporter, err := netstats.NewExporterNetworkReporter(set) + if err != nil { + return nil, err + } + userAgent := fmt.Sprintf("%s/%s (%s/%s)", + set.BuildInfo.Description, set.BuildInfo.Version, runtime.GOOS, runtime.GOARCH) + + if !oCfg.Arrow.Disabled { + // Ignoring an error because Validate() was called. + _ = zstd.SetEncoderConfig(oCfg.Arrow.Zstd) + + userAgent += fmt.Sprintf(" ApacheArrow/%s (NumStreams/%d)", arrowPkg.PkgVersion, oCfg.Arrow.NumStreams) + } + // use lower-case, to be consistent with http/2 headers. + mks := make([]string, len(oCfg.MetadataKeys)) + for i, k := range oCfg.MetadataKeys { + mks[i] = strings.ToLower(k) + } + sort.Strings(mks) + if len(mks) == 0 { + return newExporter(cfg, set, streamClientFactory, userAgent, netReporter) + } + return &metadataExporter{ + config: oCfg, + settings: set, + scf: streamClientFactory, + metadataKeys: mks, + userAgent: userAgent, + netReporter: netReporter, + }, nil +} + +func (e *metadataExporter) getSettings() exporter.Settings { + return e.settings +} + +func (e *metadataExporter) getConfig() component.Config { + return e.config +} + +func (e *metadataExporter) start(_ context.Context, host component.Host) (err error) { + e.host = host + return nil +} + +func (e *metadataExporter) shutdown(ctx context.Context) error { + var err error + e.exporters.Range(func(_ any, value any) bool { + be := value.(exp) + err = multierr.Append(err, be.shutdown(ctx)) + return true + }) + return err +} + +func (e *metadataExporter) pushTraces(ctx context.Context, td ptrace.Traces) error { + s, mdata := e.getAttrSet(ctx, e.metadataKeys) + + be, err := e.getOrCreateExporter(ctx, s, mdata) + if err != nil { + return err + } + return be.pushTraces(ctx, td) +} + +func (e *metadataExporter) pushMetrics(ctx context.Context, md pmetric.Metrics) error { + s, mdata := e.getAttrSet(ctx, e.metadataKeys) + + be, err := e.getOrCreateExporter(ctx, s, mdata) + if err != nil { + return err + } + + return be.pushMetrics(ctx, md) +} + +func (e *metadataExporter) pushLogs(ctx context.Context, ld plog.Logs) error { + s, mdata := e.getAttrSet(ctx, e.metadataKeys) + + be, err := e.getOrCreateExporter(ctx, s, mdata) + if err != nil { + return err + } + + return be.pushLogs(ctx, ld) +} + +func (e *metadataExporter) getOrCreateExporter(ctx context.Context, s attribute.Set, md metadata.MD) (exp, error) { + e.lock.Lock() + defer e.lock.Unlock() + + if e.config.MetadataCardinalityLimit != 0 && e.size >= int(e.config.MetadataCardinalityLimit) { + return nil, errTooManyExporters + } + + v, ok := e.exporters.Load(s) + if ok { + return v.(exp), nil + } + + newExp, err := newExporter(e.config, e.settings, e.scf, e.userAgent, e.netReporter) + if err != nil { + return nil, fmt.Errorf("failed to create exporter: %w", err) + } + + var loaded bool + v, loaded = e.exporters.LoadOrStore(s, newExp) + if !loaded { + // set metadata keys for base exporter to add them to the outgoing context. + newExp.(*baseExporter).setMetadata(md) + + // Start the goroutine only if we added the object to the map, otherwise is already started. + err = newExp.start(ctx, e.host) + if err != nil { + e.exporters.Delete(s) + return nil, fmt.Errorf("failed to start exporter: %w", err) + } + + e.size++ + } + + return v.(exp), nil +} + +// getAttrSet is code taken from the core collector's batchprocessor multibatch logic. +// https://github.com/open-telemetry/opentelemetry-collector/blob/v0.107.0/processor/batchprocessor/batch_processor.go#L298 +func (e *metadataExporter) getAttrSet(ctx context.Context, keys []string) (attribute.Set, metadata.MD) { + // Get each metadata key value, form the corresponding + // attribute set for use as a map lookup key. + info := client.FromContext(ctx) + md := map[string][]string{} + var attrs []attribute.KeyValue + for _, k := range keys { + // Lookup the value in the incoming metadata, copy it + // into the outgoing metadata, and create a unique + // value for the attributeSet. + vs := info.Metadata.Get(k) + md[k] = vs + if len(vs) == 1 { + attrs = append(attrs, attribute.String(k, vs[0])) + } else { + attrs = append(attrs, attribute.StringSlice(k, vs)) + } + } + return attribute.NewSet(attrs...), metadata.MD(md) +} diff --git a/exporter/otelarrowexporter/metadata_test.go b/exporter/otelarrowexporter/metadata_test.go new file mode 100644 index 000000000000..ce18b5f1dee2 --- /dev/null +++ b/exporter/otelarrowexporter/metadata_test.go @@ -0,0 +1,209 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 +package otelarrowexporter + +import ( + "context" + "fmt" + "net" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "go.opentelemetry.io/collector/client" + "go.opentelemetry.io/collector/component/componenttest" + "go.opentelemetry.io/collector/config/configgrpc" + "go.opentelemetry.io/collector/config/configtls" + "go.opentelemetry.io/collector/consumer/consumererror" + "go.opentelemetry.io/collector/exporter/exportertest" + + "github.com/open-telemetry/opentelemetry-collector-contrib/internal/otelarrow/testdata" +) + +func TestSendTracesWithMetadata(t *testing.T) { + // Start an OTel-Arrow receiver. + ln, err := net.Listen("tcp", "localhost:") + require.NoError(t, err, "Failed to find an available address to run the gRPC server: %v", err) + rcv, err := otelArrowTracesReceiverOnGRPCServer(ln, false) + rcv.hasMetadata = true + rcv.spanCountByMetadata = make(map[string]int) + + rcv.start() + require.NoError(t, err, "Failed to start mock OTLP receiver") + // Also closes the connection. + defer rcv.srv.GracefulStop() + + // Start an OTLP exporter and point to the receiver. + factory := NewFactory() + cfg := createDefaultConfig().(*Config) + cfg.ClientConfig = configgrpc.ClientConfig{ + Endpoint: ln.Addr().String(), + TLSSetting: configtls.ClientConfig{ + Insecure: true, + }, + } + cfg.Arrow.MaxStreamLifetime = 100 * time.Second + + cfg.MetadataCardinalityLimit = 10 + cfg.MetadataKeys = []string{"key1", "key2"} + set := exportertest.NewNopSettings() + set.BuildInfo.Description = "Collector" + set.BuildInfo.Version = "1.2.3test" + bg := context.Background() + exp, err := factory.CreateTracesExporter(bg, set, cfg) + require.NoError(t, err) + require.NotNil(t, exp) + defer func() { + assert.NoError(t, exp.Shutdown(context.Background())) + }() + + host := componenttest.NewNopHost() + + assert.NoError(t, exp.Start(context.Background(), host)) + + // Ensure that initially there is no data in the receiver. + assert.EqualValues(t, 0, rcv.requestCount.Load()) + + callCtxs := []context.Context{ + client.NewContext(context.Background(), client.Info{ + Metadata: client.NewMetadata(map[string][]string{ + "key1": {"first"}, + "key2": {"second"}, + }), + }), + client.NewContext(context.Background(), client.Info{ + Metadata: client.NewMetadata(map[string][]string{ + "key1": {"third"}, + "key2": {"fourth"}, + }), + }), + } + + expectByContext := make([]int, len(callCtxs)) + + requestCount := 3 + spansPerRequest := 33 + for requestNum := 0; requestNum < requestCount; requestNum++ { + td := testdata.GenerateTraces(spansPerRequest) + spans := td.ResourceSpans().At(0).ScopeSpans().At(0).Spans() + for spanIndex := 0; spanIndex < spansPerRequest; spanIndex++ { + spans.At(spanIndex).SetName(fmt.Sprintf("%d-%d", requestNum, spanIndex)) + } + + num := requestNum % len(callCtxs) + expectByContext[num] += spansPerRequest + go func(n int) { + assert.NoError(t, exp.ConsumeTraces(callCtxs[n], td)) + }(num) + } + + assert.Eventually(t, func() bool { + return rcv.requestCount.Load() == int32(requestCount) + }, 1*time.Second, 5*time.Millisecond) + assert.Eventually(t, func() bool { + return rcv.totalItems.Load() == int32(requestCount*spansPerRequest) + }, 1*time.Second, 5*time.Millisecond) + assert.Eventually(t, func() bool { + rcv.mux.Lock() + defer rcv.mux.Unlock() + return len(callCtxs) == len(rcv.spanCountByMetadata) + }, 1*time.Second, 5*time.Millisecond) + + for idx, ctx := range callCtxs { + md := client.FromContext(ctx).Metadata + key := fmt.Sprintf("%s|%s", md.Get("key1"), md.Get("key2")) + require.Equal(t, expectByContext[idx], rcv.spanCountByMetadata[key]) + } +} + +func TestDuplicateMetadataKeys(t *testing.T) { + cfg := createDefaultConfig().(*Config) + cfg.MetadataKeys = []string{"myTOKEN", "mytoken"} + err := cfg.Validate() + require.Error(t, err) + require.Contains(t, err.Error(), "duplicate") + require.Contains(t, err.Error(), "mytoken") +} + +func TestMetadataExporterCardinalityLimit(t *testing.T) { + const cardLimit = 10 + // Start an OTel-Arrow receiver. + ln, err := net.Listen("tcp", "localhost:") + require.NoError(t, err, "Failed to find an available address to run the gRPC server: %v", err) + rcv, err := otelArrowTracesReceiverOnGRPCServer(ln, false) + rcv.hasMetadata = true + rcv.spanCountByMetadata = make(map[string]int) + + rcv.start() + require.NoError(t, err, "Failed to start mock OTLP receiver") + // Also closes the connection. + defer rcv.srv.GracefulStop() + + // Start an OTLP exporter and point to the receiver. + factory := NewFactory() + cfg := createDefaultConfig().(*Config) + cfg.ClientConfig = configgrpc.ClientConfig{ + Endpoint: ln.Addr().String(), + TLSSetting: configtls.ClientConfig{ + Insecure: true, + }, + } + cfg.Arrow.MaxStreamLifetime = 100 * time.Second + + // disable queue settings to allow for error backpropagation. + cfg.QueueSettings.Enabled = false + + cfg.MetadataCardinalityLimit = cardLimit + cfg.MetadataKeys = []string{"key1", "key2"} + set := exportertest.NewNopSettings() + bg := context.Background() + exp, err := factory.CreateTracesExporter(bg, set, cfg) + require.NoError(t, err) + require.NotNil(t, exp) + defer func() { + assert.NoError(t, exp.Shutdown(context.Background())) + }() + + host := componenttest.NewNopHost() + + assert.NoError(t, exp.Start(context.Background(), host)) + + // Ensure that initially there is no data in the receiver. + assert.EqualValues(t, 0, rcv.requestCount.Load()) + + for requestNum := 0; requestNum < cardLimit; requestNum++ { + td := testdata.GenerateTraces(1) + ctx := client.NewContext(bg, client.Info{ + Metadata: client.NewMetadata(map[string][]string{ + "key1": {fmt.Sprint(requestNum)}, + "key2": {fmt.Sprint(requestNum)}, + }), + }) + + assert.NoError(t, exp.ConsumeTraces(ctx, td)) + } + + td := testdata.GenerateTraces(1) + ctx := client.NewContext(bg, client.Info{ + Metadata: client.NewMetadata(map[string][]string{ + "key1": {"limit_exceeded"}, + "key2": {"limit_exceeded"}, + }), + }) + + // above the metadata cardinality limit. + err = exp.ConsumeTraces(ctx, td) + require.Error(t, err) + assert.True(t, consumererror.IsPermanent(err)) + assert.Contains(t, err.Error(), "too many") + + assert.Eventually(t, func() bool { + return rcv.requestCount.Load() == int32(cardLimit) + }, 1*time.Second, 5*time.Millisecond) + assert.Eventually(t, func() bool { + return rcv.totalItems.Load() == int32(cardLimit) + }, 1*time.Second, 5*time.Millisecond) + + require.Len(t, rcv.spanCountByMetadata, cardLimit) +} diff --git a/exporter/otelarrowexporter/otelarrow.go b/exporter/otelarrowexporter/otelarrow.go index a4a94496717e..07ccb25ea710 100644 --- a/exporter/otelarrowexporter/otelarrow.go +++ b/exporter/otelarrowexporter/otelarrow.go @@ -6,11 +6,8 @@ package otelarrowexporter // import "github.com/open-telemetry/opentelemetry-col import ( "context" "errors" - "fmt" - "runtime" "time" - arrowPkg "github.com/apache/arrow/go/v16/arrow" arrowRecord "github.com/open-telemetry/otel-arrow/pkg/otel/arrow_record" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/config/configcompression" @@ -37,6 +34,18 @@ import ( "github.com/open-telemetry/opentelemetry-collector-contrib/internal/otelarrow/netstats" ) +type exp interface { + getSettings() exporter.Settings + getConfig() component.Config + + start(context.Context, component.Host) error + shutdown(context.Context) error + + pushTraces(context.Context, ptrace.Traces) error + pushMetrics(context.Context, pmetric.Metrics) error + pushLogs(context.Context, plog.Logs) error +} + type baseExporter struct { // Input configuration. config *Config @@ -60,31 +69,19 @@ type baseExporter struct { streamClientFactory streamClientFactory } +var _ exp = (*baseExporter)(nil) + type streamClientFactory func(conn *grpc.ClientConn) arrow.StreamClientFunc // Crete new exporter and start it. The exporter will begin connecting but // this function may return before the connection is established. -func newExporter(cfg component.Config, set exporter.Settings, streamClientFactory streamClientFactory) (*baseExporter, error) { +func newExporter(cfg component.Config, set exporter.Settings, streamClientFactory streamClientFactory, userAgent string, netReporter *netstats.NetworkReporter) (exp, error) { oCfg := cfg.(*Config) if oCfg.Endpoint == "" { return nil, errors.New("OTLP exporter config requires an Endpoint") } - netReporter, err := netstats.NewExporterNetworkReporter(set) - if err != nil { - return nil, err - } - userAgent := fmt.Sprintf("%s/%s (%s/%s)", - set.BuildInfo.Description, set.BuildInfo.Version, runtime.GOOS, runtime.GOARCH) - - if !oCfg.Arrow.Disabled { - // Ignoring an error because Validate() was called. - _ = zstd.SetEncoderConfig(oCfg.Arrow.Zstd) - - userAgent += fmt.Sprintf(" ApacheArrow/%s (NumStreams/%d)", arrowPkg.PkgVersion, oCfg.Arrow.NumStreams) - } - return &baseExporter{ config: oCfg, settings: set, @@ -94,6 +91,18 @@ func newExporter(cfg component.Config, set exporter.Settings, streamClientFactor }, nil } +func (e *baseExporter) getSettings() exporter.Settings { + return e.settings +} + +func (e *baseExporter) getConfig() component.Config { + return e.config +} + +func (e *baseExporter) setMetadata(md metadata.MD) { + e.metadata = metadata.Join(e.metadata, md) +} + // start actually creates the gRPC connection. The client construction is deferred till this point as this // is the only place we get hold of Extensions which are required to construct auth round tripper. func (e *baseExporter) start(ctx context.Context, host component.Host) (err error) { @@ -114,7 +123,8 @@ func (e *baseExporter) start(ctx context.Context, host component.Host) (err erro for k, v := range e.config.ClientConfig.Headers { headers[k] = string(v) } - e.metadata = metadata.New(headers) + headerMetadata := metadata.New(headers) + e.metadata = metadata.Join(e.metadata, headerMetadata) e.callOptions = []grpc.CallOption{ grpc.WaitForReady(e.config.ClientConfig.WaitForReady), } diff --git a/exporter/otelarrowexporter/otelarrow_test.go b/exporter/otelarrowexporter/otelarrow_test.go index dfa73f7417cc..4c73c153f342 100644 --- a/exporter/otelarrowexporter/otelarrow_test.go +++ b/exporter/otelarrowexporter/otelarrow_test.go @@ -78,8 +78,10 @@ func (r *mockReceiver) setExportError(err error) { type mockTracesReceiver struct { ptraceotlp.UnimplementedGRPCServer mockReceiver - exportResponse func() ptraceotlp.ExportResponse - lastRequest ptrace.Traces + exportResponse func() ptraceotlp.ExportResponse + lastRequest ptrace.Traces + hasMetadata bool + spanCountByMetadata map[string]int } func (r *mockTracesReceiver) Export(ctx context.Context, req ptraceotlp.ExportRequest) (ptraceotlp.ExportResponse, error) { @@ -88,8 +90,14 @@ func (r *mockTracesReceiver) Export(ctx context.Context, req ptraceotlp.ExportRe r.totalItems.Add(int32(td.SpanCount())) r.mux.Lock() defer r.mux.Unlock() - r.lastRequest = td r.metadata, _ = metadata.FromIncomingContext(ctx) + if r.hasMetadata { + v1 := r.metadata.Get("key1") + v2 := r.metadata.Get("key2") + hashKey := fmt.Sprintf("%s|%s", v1, v2) + r.spanCountByMetadata[hashKey] += (td.SpanCount()) + } + r.lastRequest = td return r.exportResponse(), r.exportError } diff --git a/exporter/splunkhecexporter/batchperscope.go b/exporter/splunkhecexporter/batchperscope.go index 0c0c51361a7a..388ad525f84a 100644 --- a/exporter/splunkhecexporter/batchperscope.go +++ b/exporter/splunkhecexporter/batchperscope.go @@ -20,8 +20,9 @@ type perScopeBatcher struct { next consumer.Logs } +// Capabilities returns capabilities of the next consumer because perScopeBatcher doesn't mutate data itself. func (rb *perScopeBatcher) Capabilities() consumer.Capabilities { - return consumer.Capabilities{MutatesData: false} + return rb.next.Capabilities() } func (rb *perScopeBatcher) ConsumeLogs(ctx context.Context, logs plog.Logs) error { diff --git a/exporter/splunkhecexporter/factory_test.go b/exporter/splunkhecexporter/factory_test.go index 3a7f7d7f9328..b3349d74225d 100644 --- a/exporter/splunkhecexporter/factory_test.go +++ b/exporter/splunkhecexporter/factory_test.go @@ -11,6 +11,7 @@ import ( "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/config/confighttp" + "go.opentelemetry.io/collector/exporter/exporterbatcher" "go.opentelemetry.io/collector/exporter/exportertest" ) @@ -88,3 +89,34 @@ func TestFactory_CreateMetricsExporter(t *testing.T) { assert.NoError(t, err) assert.NotNil(t, te) } + +func TestFactory_EnabledBatchingMakesExporterMutable(t *testing.T) { + config := &Config{ + Token: "testToken", + ClientConfig: confighttp.ClientConfig{ + Endpoint: "https://example.com:8000", + }, + } + + me, err := createMetricsExporter(context.Background(), exportertest.NewNopSettings(), config) + require.NoError(t, err) + assert.False(t, me.Capabilities().MutatesData) + te, err := createTracesExporter(context.Background(), exportertest.NewNopSettings(), config) + require.NoError(t, err) + assert.False(t, te.Capabilities().MutatesData) + le, err := createLogsExporter(context.Background(), exportertest.NewNopSettings(), config) + require.NoError(t, err) + assert.False(t, le.Capabilities().MutatesData) + + config.BatcherConfig = exporterbatcher.NewDefaultConfig() + + me, err = createMetricsExporter(context.Background(), exportertest.NewNopSettings(), config) + require.NoError(t, err) + assert.True(t, me.Capabilities().MutatesData) + te, err = createTracesExporter(context.Background(), exportertest.NewNopSettings(), config) + require.NoError(t, err) + assert.True(t, te.Capabilities().MutatesData) + le, err = createLogsExporter(context.Background(), exportertest.NewNopSettings(), config) + require.NoError(t, err) + assert.True(t, le.Capabilities().MutatesData) +} diff --git a/internal/coreinternal/timeutils/parser.go b/internal/coreinternal/timeutils/parser.go index 7b15ca4054f4..82c5523292e1 100644 --- a/internal/coreinternal/timeutils/parser.go +++ b/internal/coreinternal/timeutils/parser.go @@ -4,6 +4,7 @@ package timeutils // import "github.com/open-telemetry/opentelemetry-collector-contrib/internal/coreinternal/timeutils" import ( + "errors" "fmt" "regexp" "strings" @@ -28,27 +29,15 @@ func ParseStrptime(layout string, value any, location *time.Location) (time.Time return ParseGotime(goLayout, value, location) } -// ParseLocalizedStrptime is like ParseStrptime, but instead of parsing a formatted time in -// English, it parses a value in foreign language, and returns the [time.Time] it represents. -// The language argument must be a well-formed BCP 47 language tag (e.g.: "en", "en-US"), and -// a known CLDR locale. +// ParseLocalizedStrptime is like ParseLocalizedGotime, but instead of using the native Go time layout, +// it uses the ctime-like format. func ParseLocalizedStrptime(layout string, value any, location *time.Location, language string) (time.Time, error) { goLayout, err := strptime.ToNative(layout) if err != nil { return time.Time{}, err } - stringValue, err := convertParsingValue(value) - if err != nil { - return time.Time{}, err - } - - translatedVal, err := lunes.Translate(goLayout, stringValue, language) - if err != nil { - return time.Time{}, err - } - - return ParseGotime(goLayout, translatedVal, location) + return ParseLocalizedGotime(goLayout, value, location, language) } func GetLocation(location *string, layout *string) (*time.Location, error) { @@ -69,6 +58,24 @@ func GetLocation(location *string, layout *string) (*time.Location, error) { return time.Local, nil } +// ParseLocalizedGotime is like ParseGotime, but instead of parsing a formatted time in +// English, it parses a value in foreign language, and returns the [time.Time] it represents. +// The language argument must be a well-formed BCP 47 language tag (e.g.: "en", "en-US"), and +// a known CLDR locale. +func ParseLocalizedGotime(layout string, value any, location *time.Location, language string) (time.Time, error) { + stringValue, err := convertParsingValue(value) + if err != nil { + return time.Time{}, err + } + + translatedVal, err := lunes.Translate(layout, stringValue, language) + if err != nil { + return time.Time{}, err + } + + return ParseGotime(layout, translatedVal, location) +} + func ParseGotime(layout string, value any, location *time.Location) (time.Time, error) { timeValue, err := parseGotime(layout, value, location) if err != nil { @@ -155,5 +162,21 @@ func ValidateGotime(layout string) error { return nil } +// ValidateLocale checks the given locale and returns an error if the language tag +// is not supported by the localized parser functions. +func ValidateLocale(locale string) error { + _, err := lunes.NewDefaultLocale(locale) + if err == nil { + return nil + } + + var e *lunes.ErrUnsupportedLocale + if errors.As(err, &e) { + return fmt.Errorf("unsupported locale '%s', value must be a supported BCP 47 language tag", locale) + } + + return fmt.Errorf("invalid locale '%s': %w", locale, err) +} + // Allows tests to override with deterministic value var Now = time.Now diff --git a/internal/coreinternal/timeutils/parser_test.go b/internal/coreinternal/timeutils/parser_test.go index 5d20725561b4..f83133c18589 100644 --- a/internal/coreinternal/timeutils/parser_test.go +++ b/internal/coreinternal/timeutils/parser_test.go @@ -165,3 +165,73 @@ func TestParseLocalizedStrptimeInvalidType(t *testing.T) { require.Error(t, err) require.ErrorContains(t, err, "cannot be parsed as a time") } + +func TestParseLocalizedGotime(t *testing.T) { + tests := []struct { + name string + format string + value any + language string + expected time.Time + location *time.Location + }{ + { + name: "Foreign language", + format: "January 02 Monday, 2006, 03:04:05 pm", + value: "Febrero 25 jueves, 1993, 02:03:04 p.m.", + expected: time.Date(1993, 2, 25, 14, 3, 4, 0, time.Local), + location: time.Local, + language: "es-ES", + }, + { + name: "Foreign language with location", + format: "Monday Jan _2 2006", + value: "mercoledì set 4 2024", + expected: time.Date(2024, 9, 4, 0, 0, 0, 0, time.UTC), + location: time.UTC, + language: "it-IT", + }, + { + name: "String value", + format: "January 02 Monday, 2006, 03:04:05 PM", + value: "March 12 Friday, 2004, 02:03:04 AM", + expected: time.Date(2004, 3, 12, 2, 3, 4, 0, time.Local), + location: time.Local, + language: "en", + }, + { + name: "Bytes value", + format: "Jan 02 Mon, 06, 03:04:05 PM", + value: []byte("Jun 10 Fri, 04, 02:03:04 AM"), + expected: time.Date(2004, 6, 10, 2, 3, 4, 0, time.Local), + location: time.Local, + language: "en-US", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result, err := ParseLocalizedGotime(tt.format, tt.value, tt.location, tt.language) + require.NoError(t, err) + assert.Equal(t, tt.expected.UnixNano(), result.UnixNano()) + }) + } +} + +func TestParseLocalizedGotimeInvalidType(t *testing.T) { + value := time.Now().UnixNano() + _, err := ParseLocalizedStrptime("Mon", value, time.Local, "en") + require.Error(t, err) + require.ErrorContains(t, err, "cannot be parsed as a time") +} + +func TestValidateLocale(t *testing.T) { + require.NoError(t, ValidateLocale("es")) + require.NoError(t, ValidateLocale("en-US")) + require.NoError(t, ValidateLocale("ca-ES-valencia")) +} + +func TestValidateLocaleUnsupported(t *testing.T) { + err := ValidateLocale("foo-bar") + require.ErrorContains(t, err, "unsupported locale 'foo-bar'") +} diff --git a/internal/filter/go.mod b/internal/filter/go.mod index 40356ee502de..e572ff10bd11 100644 --- a/internal/filter/go.mod +++ b/internal/filter/go.mod @@ -28,6 +28,7 @@ require ( github.com/go-logr/stdr v1.2.2 // indirect github.com/go-viper/mapstructure/v2 v2.1.0 // indirect github.com/gobwas/glob v0.2.3 // indirect + github.com/goccy/go-json v0.10.3 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/google/uuid v1.6.0 // indirect github.com/hashicorp/go-version v1.7.0 // indirect diff --git a/internal/filter/go.sum b/internal/filter/go.sum index 421a34876331..16d04f512c5a 100644 --- a/internal/filter/go.sum +++ b/internal/filter/go.sum @@ -24,6 +24,8 @@ github.com/go-viper/mapstructure/v2 v2.1.0 h1:gHnMa2Y/pIxElCH2GlZZ1lZSsn6XMtufpG github.com/go-viper/mapstructure/v2 v2.1.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= +github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA= +github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= diff --git a/pkg/batchperresourceattr/batchperresourceattr.go b/pkg/batchperresourceattr/batchperresourceattr.go index 92f55b6481da..510b41f6fca2 100644 --- a/pkg/batchperresourceattr/batchperresourceattr.go +++ b/pkg/batchperresourceattr/batchperresourceattr.go @@ -35,9 +35,9 @@ func NewMultiBatchPerResourceTraces(attrKeys []string, next consumer.Traces) con } } -// Capabilities implements the consumer interface. +// Capabilities returns the capabilities of the next consumer because batchTraces doesn't mutate data itself. func (bt *batchTraces) Capabilities() consumer.Capabilities { - return consumer.Capabilities{MutatesData: false} + return bt.next.Capabilities() } func (bt *batchTraces) ConsumeTraces(ctx context.Context, td ptrace.Traces) error { @@ -98,9 +98,9 @@ func NewMultiBatchPerResourceMetrics(attrKeys []string, next consumer.Metrics) c } } -// Capabilities implements the consumer interface. +// Capabilities returns the capabilities of the next consumer because batchMetrics doesn't mutate data itself. func (bt *batchMetrics) Capabilities() consumer.Capabilities { - return consumer.Capabilities{MutatesData: false} + return bt.next.Capabilities() } func (bt *batchMetrics) ConsumeMetrics(ctx context.Context, td pmetric.Metrics) error { @@ -159,9 +159,9 @@ func NewMultiBatchPerResourceLogs(attrKeys []string, next consumer.Logs) consume } } -// Capabilities implements the consumer interface. +// Capabilities returns the capabilities of the next consumer because batchLogs doesn't mutate data itself. func (bt *batchLogs) Capabilities() consumer.Capabilities { - return consumer.Capabilities{MutatesData: false} + return bt.next.Capabilities() } func (bt *batchLogs) ConsumeLogs(ctx context.Context, td plog.Logs) error { diff --git a/pkg/ottl/expression.go b/pkg/ottl/expression.go index c69c9f0e319a..ca3671e4ffa5 100644 --- a/pkg/ottl/expression.go +++ b/pkg/ottl/expression.go @@ -13,7 +13,7 @@ import ( "strconv" "time" - jsoniter "github.com/json-iterator/go" + "github.com/goccy/go-json" "go.opentelemetry.io/collector/pdata/pcommon" "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl/internal/ottlcommon" @@ -429,22 +429,25 @@ func (g StandardStringLikeGetter[K]) Get(ctx context.Context, tCtx K) (*string, case []byte: result = hex.EncodeToString(v) case pcommon.Map: - result, err = jsoniter.MarshalToString(v.AsRaw()) + resultBytes, err := json.Marshal(v.AsRaw()) if err != nil { return nil, err } + result = string(resultBytes) case pcommon.Slice: - result, err = jsoniter.MarshalToString(v.AsRaw()) + resultBytes, err := json.Marshal(v.AsRaw()) if err != nil { return nil, err } + result = string(resultBytes) case pcommon.Value: result = v.AsString() default: - result, err = jsoniter.MarshalToString(v) + resultBytes, err := json.Marshal(v) if err != nil { return nil, TypeError(fmt.Sprintf("unsupported type: %T", v)) } + result = string(resultBytes) } return &result, nil } diff --git a/pkg/ottl/go.mod b/pkg/ottl/go.mod index 14523a4a1a0b..3b719303e5db 100644 --- a/pkg/ottl/go.mod +++ b/pkg/ottl/go.mod @@ -6,9 +6,9 @@ require ( github.com/alecthomas/participle/v2 v2.1.1 github.com/elastic/go-grok v0.3.1 github.com/gobwas/glob v0.2.3 + github.com/goccy/go-json v0.10.3 github.com/google/uuid v1.6.0 github.com/iancoleman/strcase v0.3.0 - github.com/json-iterator/go v1.1.12 github.com/open-telemetry/opentelemetry-collector-contrib/internal/coreinternal v0.109.0 github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatatest v0.109.0 github.com/stretchr/testify v1.9.0 @@ -32,6 +32,7 @@ require ( github.com/go-logr/stdr v1.2.2 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/json-iterator/go v1.1.12 // indirect github.com/magefile/mage v1.15.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect diff --git a/pkg/ottl/go.sum b/pkg/ottl/go.sum index 5fd22889d40c..5eb62256c810 100644 --- a/pkg/ottl/go.sum +++ b/pkg/ottl/go.sum @@ -20,6 +20,8 @@ github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= +github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA= +github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= diff --git a/pkg/ottl/ottlfuncs/README.md b/pkg/ottl/ottlfuncs/README.md index 7c21b4cd6dcc..d818640c2409 100644 --- a/pkg/ottl/ottlfuncs/README.md +++ b/pkg/ottl/ottlfuncs/README.md @@ -1455,11 +1455,11 @@ Examples: ### Time -`Time(target, format, Optional[location])` +`Time(target, format, Optional[location], Optional[locale])` The `Time` Converter takes a string representation of a time and converts it to a Golang `time.Time`. -`target` is a string. `format` is a string, `location` is an optional string. +`target` is a string. `format` is a string, `location` is an optional string, `locale` is an optional string. If either `target` or `format` are nil, an error is returned. The parser used is the parser at [internal/coreinternal/parser](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/internal/coreinternal/timeutils). If the `target` and `format` do not follow the parsing rules used by this parser, an error is returned. @@ -1519,6 +1519,17 @@ Examples: - `Time("2012-11-01T22:08:41+0000 EST", "%Y-%m-%dT%H:%M:%S%z %Z")` - `Time("2023-05-26 12:34:56", "%Y-%m-%d %H:%M:%S", "America/New_York")` +`locale` specifies the input language of the `target` value. It is used to interpret timestamp values written in a specific language, +ensuring that the function can correctly parse the localized month names, day names, and periods of the day based on the provided language. + +The value must be a well-formed BCP 47 language tag, and a known [CLDR](https://cldr.unicode.org) v45 locale. +If not supplied, English (`en`) is used. + +Examples: + +- `Time("mercoledì set 4 2024", "%A %h %e %Y", "", "it")` +- `Time("Febrero 25 lunes, 2002, 02:03:04 p.m.", "%B %d %A, %Y, %r", "America/New_York", "es-ES")` + ### TraceID `TraceID(bytes)` diff --git a/pkg/ottl/ottlfuncs/func_parse_json.go b/pkg/ottl/ottlfuncs/func_parse_json.go index 637390177e87..011437424c1c 100644 --- a/pkg/ottl/ottlfuncs/func_parse_json.go +++ b/pkg/ottl/ottlfuncs/func_parse_json.go @@ -7,7 +7,7 @@ import ( "context" "fmt" - jsoniter "github.com/json-iterator/go" + "github.com/goccy/go-json" "go.opentelemetry.io/collector/pdata/pcommon" "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl" @@ -47,7 +47,7 @@ func parseJSON[K any](target ottl.StringGetter[K]) ottl.ExprFunc[K] { return nil, err } var parsedValue any - err = jsoniter.UnmarshalFromString(targetVal, &parsedValue) + err = json.Unmarshal([]byte(targetVal), &parsedValue) if err != nil { return nil, err } diff --git a/pkg/ottl/ottlfuncs/func_parse_json_test.go b/pkg/ottl/ottlfuncs/func_parse_json_test.go index 835f95d0bba5..b409fd646874 100644 --- a/pkg/ottl/ottlfuncs/func_parse_json_test.go +++ b/pkg/ottl/ottlfuncs/func_parse_json_test.go @@ -201,3 +201,63 @@ func Test_ParseJSON_Error(t *testing.T) { _, err := exprFunc(context.Background(), nil) assert.Error(t, err) } + +const benchData = `{ + "_id": "667cb0db02f4dfc7648b0f6b", + "index": 0, + "guid": "2e419732-8214-4e36-a158-d3ced0217ab6", + "isActive": true, + "balance": "$1,105.05", + "picture": "http://example.com/1", + "age": 22, + "eyeColor": "blue", + "name": "Vincent Knox", + "gender": "male", + "company": "ANIVET", + "email": "vincentknox@anivet.com", + "phone": "+1 (914) 599-2454", + "address": "483 Gerritsen Avenue, Succasunna, Massachusetts, 7803", + "about": "Elit aliqua qui amet duis esse eiusmod cillum proident quis amet elit tempor dolor exercitation. Eu ut tempor exercitation excepteur est. Lorem ad elit sit reprehenderit quis ad sunt laborum amet veniam commodo sit sunt aliqua. Sint incididunt eu ut est magna amet mollit qui deserunt nostrud labore ad. Nostrud officia proident occaecat et irure ut quis culpa mollit veniam. Laboris labore ea reprehenderit veniam mollit enim et proident ipsum id. In qui sit officia laborum.\r\nIn ad consectetur duis ad nisi proident. Non in officia do mollit amet sint voluptate minim nostrud voluptate elit. Veniam Lorem cillum fugiat adipisicing qui ea commodo irure tempor ipsum pariatur sit voluptate. Eiusmod cillum occaecat excepteur cillum aliquip laboris velit aute proident amet.\r\nIpsum sunt eiusmod do ut voluptate sit anim. Consequat nisi nisi consequat amet excepteur ea ad incididunt pariatur veniam exercitation eu ex in. Incididunt sint tempor pariatur Lorem do. Occaecat laborum ad ad id enim dolor deserunt ipsum amet Lorem Lorem. Cillum veniam labore eu do duis.\r\nCillum dolor eiusmod sit amet commodo voluptate pariatur ex irure eu culpa sunt. Incididunt non exercitation est pariatur est. Incididunt mollit Lorem velit ullamco excepteur esse quis id magna et ullamco labore. Laboris consequat tempor est ea amet enim et nisi amet officia dolore magna veniam. Nostrud officia consectetur ea culpa laborum et ut Lorem laboris.\r\nDeserunt labore ullamco dolor exercitation laboris consectetur nulla cupidatat duis. Occaecat quis velit deserunt culpa nostrud eiusmod elit fugiat nulla duis deserunt Lorem do. Proident anim proident aute amet pariatur et do irure. Ad magna qui elit consequat sit exercitation sit. Magna adipisicing id esse aliqua officia magna. Et veniam aliqua minim reprehenderit in culpa. Adipisicing quis eu do Lorem cupidatat consequat ad aute quis.\r\nIn aliquip ea laborum esse dolor reprehenderit qui sit culpa occaecat. Consectetur Lorem dolore adipisicing amet incididunt. Dolor veniam Lorem nulla ex. Eiusmod amet tempor sit eiusmod do reprehenderit proident sit commodo elit cupidatat.\r\nNulla nulla consequat cillum mollit tempor eiusmod irure deserunt amet et voluptate. Fugiat et veniam culpa eiusmod minim ex pariatur. Eiusmod adipisicing pariatur pariatur adipisicing in consequat cillum ut qui veniam amet incididunt ullamco anim.\r\nDolor nulla laborum tempor adipisicing qui id. Exercitation labore aliqua ut laborum velit cupidatat officia. Est qui dolor sint laboris aliqua ea nulla culpa.\r\nAute reprehenderit nulla elit nisi reprehenderit pariatur officia veniam dolore ea occaecat nostrud sunt fugiat. Cillum consequat labore nostrud veniam nisi ea proident est officia incididunt adipisicing qui sint nisi. Ad enim reprehenderit minim labore minim irure dolor. Voluptate commodo dolor excepteur est tempor dolor sunt esse fugiat ea eu et.\r\nIpsum sit velit deserunt aliqua eu labore ad esse eu. Duis eiusmod non exercitation consequat nulla. Enim elit consectetur pariatur sunt labore sunt dolore non do. Sint consequat aliqua tempor consectetur veniam minim. Veniam eu aute occaecat consectetur dolore ullamco dolore officia.\r\n", + "registered": "2023-06-08T12:29:06 +07:00", + "latitude": -59.802339, + "longitude": -160.473187, + "tags": [ + "pariatur", + "anim", + "id", + "duis", + "fugiat", + "qui", + "veniam" + ], + "friends": [ + { + "id": 0, + "name": "Hester Bruce" + }, + { + "id": 1, + "name": "Laurel Mcknight" + }, + { + "id": 2, + "name": "Wynn Moses" + } + ], + "greeting": "Hello, Vincent Knox! You have 1 unread messages.", + "favoriteFruit": "apple" +}` + +func BenchmarkParseJSON(b *testing.B) { + ctx := context.Background() + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + _, err := parseJSON(ottl.StandardStringGetter[any]{ + Getter: func(_ context.Context, _ any) (any, error) { + return benchData, nil + }, + })(ctx, nil) + require.NoError(b, err) + } +} diff --git a/pkg/ottl/ottlfuncs/func_time.go b/pkg/ottl/ottlfuncs/func_time.go index 44371a94de6e..af5e37326a4f 100644 --- a/pkg/ottl/ottlfuncs/func_time.go +++ b/pkg/ottl/ottlfuncs/func_time.go @@ -6,6 +6,7 @@ package ottlfuncs // import "github.com/open-telemetry/opentelemetry-collector-c import ( "context" "fmt" + "time" "github.com/open-telemetry/opentelemetry-collector-contrib/internal/coreinternal/timeutils" "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl" @@ -15,6 +16,7 @@ type TimeArguments[K any] struct { Time ottl.StringGetter[K] Format string Location ottl.Optional[string] + Locale ottl.Optional[string] } func NewTimeFactory[K any]() ottl.Factory[K] { @@ -27,10 +29,10 @@ func createTimeFunction[K any](_ ottl.FunctionContext, oArgs ottl.Arguments) (ot return nil, fmt.Errorf("TimeFactory args must be of type *TimeArguments[K]") } - return Time(args.Time, args.Format, args.Location) + return Time(args.Time, args.Format, args.Location, args.Locale) } -func Time[K any](inputTime ottl.StringGetter[K], format string, location ottl.Optional[string]) (ottl.ExprFunc[K], error) { +func Time[K any](inputTime ottl.StringGetter[K], format string, location ottl.Optional[string], locale ottl.Optional[string]) (ottl.ExprFunc[K], error) { if format == "" { return nil, fmt.Errorf("format cannot be nil") } @@ -49,6 +51,16 @@ func Time[K any](inputTime ottl.StringGetter[K], format string, location ottl.Op if err != nil { return nil, err } + + var inputTimeLocale *string + if !locale.IsEmpty() { + l := locale.Get() + if err = timeutils.ValidateLocale(l); err != nil { + return nil, err + } + inputTimeLocale = &l + } + return func(ctx context.Context, tCtx K) (any, error) { t, err := inputTime.Get(ctx, tCtx) if err != nil { @@ -57,7 +69,12 @@ func Time[K any](inputTime ottl.StringGetter[K], format string, location ottl.Op if t == "" { return nil, fmt.Errorf("time cannot be nil") } - timestamp, err := timeutils.ParseGotime(gotimeFormat, t, loc) + var timestamp time.Time + if inputTimeLocale != nil { + timestamp, err = timeutils.ParseLocalizedGotime(gotimeFormat, t, loc, *inputTimeLocale) + } else { + timestamp, err = timeutils.ParseGotime(gotimeFormat, t, loc) + } if err != nil { return nil, err } diff --git a/pkg/ottl/ottlfuncs/func_time_test.go b/pkg/ottl/ottlfuncs/func_time_test.go index cc9ce2a795f1..c98b094f39c7 100644 --- a/pkg/ottl/ottlfuncs/func_time_test.go +++ b/pkg/ottl/ottlfuncs/func_time_test.go @@ -24,6 +24,7 @@ func Test_Time(t *testing.T) { format string expected time.Time location string + locale string }{ { name: "simple short form", @@ -188,14 +189,52 @@ func Test_Time(t *testing.T) { format: "%Y-%m-%dT%H:%M:%S %Z", expected: time.Date(1986, 10, 01, 00, 17, 33, 00, time.FixedZone("MST", -7*60*60)), }, + { + name: "with locale", + time: &ottl.StandardStringGetter[any]{ + Getter: func(_ context.Context, _ any) (any, error) { + return "Febrero 25 lunes, 2002, 02:03:04 p.m.", nil + }, + }, + format: "%B %d %A, %Y, %r", + locale: "es-ES", + expected: time.Date(2002, 2, 25, 14, 03, 04, 0, time.Local), + }, + { + name: "with locale - date only", + time: &ottl.StandardStringGetter[any]{ + Getter: func(_ context.Context, _ any) (any, error) { + return "mercoledì set 4 2024", nil + }, + }, + format: "%A %h %e %Y", + locale: "it", + expected: time.Date(2024, 9, 4, 0, 0, 0, 0, time.Local), + }, + { + name: "with locale and location", + time: &ottl.StandardStringGetter[any]{ + Getter: func(_ context.Context, _ any) (any, error) { + return "Febrero 25 lunes, 2002, 02:03:04 p.m.", nil + }, + }, + format: "%B %d %A, %Y, %r", + location: "America/New_York", + locale: "es-ES", + expected: time.Date(2002, 2, 25, 14, 03, 04, 0, locationAmericaNewYork), + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - var locOptional ottl.Optional[string] + var locationOptional ottl.Optional[string] if tt.location != "" { - locOptional = ottl.NewTestingOptional(tt.location) + locationOptional = ottl.NewTestingOptional(tt.location) } - exprFunc, err := Time(tt.time, tt.format, locOptional) + var localeOptional ottl.Optional[string] + if tt.locale != "" { + localeOptional = ottl.NewTestingOptional(tt.locale) + } + exprFunc, err := Time(tt.time, tt.format, locationOptional, localeOptional) assert.NoError(t, err) result, err := exprFunc(nil, nil) assert.NoError(t, err) @@ -234,8 +273,9 @@ func Test_TimeError(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - var locOptional ottl.Optional[string] - exprFunc, err := Time[any](tt.time, tt.format, locOptional) + var locationOptional ottl.Optional[string] + var localeOptional ottl.Optional[string] + exprFunc, err := Time[any](tt.time, tt.format, locationOptional, localeOptional) require.NoError(t, err) _, err = exprFunc(context.Background(), nil) assert.ErrorContains(t, err, tt.expectedError) @@ -250,6 +290,7 @@ func Test_TimeFormatError(t *testing.T) { format string expectedError string location string + locale string }{ { name: "invalid short with no format", @@ -272,14 +313,29 @@ func Test_TimeFormatError(t *testing.T) { location: "Jupiter/Ganymede", expectedError: "unknown time zone Jupiter/Ganymede", }, + { + name: "with unsupported locale", + time: &ottl.StandardStringGetter[any]{ + Getter: func(_ context.Context, _ any) (any, error) { + return "2023-05-26 12:34:56", nil + }, + }, + format: "%Y-%m-%d %H:%M:%S", + locale: "foo-bar", + expectedError: "unsupported locale 'foo-bar'", + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - var locOptional ottl.Optional[string] + var locationOptional ottl.Optional[string] if tt.location != "" { - locOptional = ottl.NewTestingOptional(tt.location) + locationOptional = ottl.NewTestingOptional(tt.location) + } + var localeOptional ottl.Optional[string] + if tt.locale != "" { + localeOptional = ottl.NewTestingOptional(tt.locale) } - _, err := Time[any](tt.time, tt.format, locOptional) + _, err := Time[any](tt.time, tt.format, locationOptional, localeOptional) assert.ErrorContains(t, err, tt.expectedError) }) } @@ -465,7 +521,7 @@ func Benchmark_Time(t *testing.B) { if tt.location != "" { locOptional = ottl.NewTestingOptional(tt.location) } - exprFunc, err := Time(tt.time, tt.format, locOptional) + exprFunc, err := Time(tt.time, tt.format, locOptional, ottl.Optional[string]{}) assert.NoError(t, err) t.Run(tt.name, func(t *testing.B) { diff --git a/pkg/stanza/operator/input/windows/event.go b/pkg/stanza/operator/input/windows/event.go index 344eee57b905..f833fb8803fd 100644 --- a/pkg/stanza/operator/input/windows/event.go +++ b/pkg/stanza/operator/input/windows/event.go @@ -139,29 +139,6 @@ func (e *Event) Close() error { return nil } -func (e *Event) RenderRaw(buffer Buffer) (EventRaw, error) { - if e.handle == 0 { - return EventRaw{}, fmt.Errorf("event handle does not exist") - } - - bufferUsed, err := evtRender(0, e.handle, EvtRenderEventXML, buffer.SizeBytes(), buffer.FirstByte()) - if errors.Is(err, ErrorInsufficientBuffer) { - // If the bufferUsed is 0 return an error as we don't want to make a recursive call with no buffer - if *bufferUsed == 0 { - return EventRaw{}, errUnknownNextFrame - } - - buffer.UpdateSizeBytes(*bufferUsed) - return e.RenderRaw(buffer) - } - bytes, err := buffer.ReadBytes(*bufferUsed) - if err != nil { - return EventRaw{}, fmt.Errorf("failed to read bytes from buffer: %w", err) - } - - return unmarshalEventRaw(bytes) -} - // NewEvent will create a new event from an event handle. func NewEvent(handle uintptr) Event { return Event{ diff --git a/pkg/stanza/operator/input/windows/input.go b/pkg/stanza/operator/input/windows/input.go index 9fd525dcaa76..b4a9337ea073 100644 --- a/pkg/stanza/operator/input/windows/input.go +++ b/pkg/stanza/operator/input/windows/input.go @@ -232,8 +232,6 @@ func (i *Input) read(ctx context.Context) int { // processEvent will process and send an event retrieved from windows event log. func (i *Input) processEvent(ctx context.Context, event Event) { - remoteServer := i.remote.Server - var providerName string // The provider name is only retrieved if needed. if !i.raw || len(i.excludeProviders) > 0 { var err error @@ -253,13 +251,12 @@ func (i *Input) processEvent(ctx context.Context, event Event) { } if i.raw { - rawEvent, err := event.RenderRaw(i.buffer) + rawEvent, err := event.RenderSimple(i.buffer) if err != nil { i.Logger().Error("Failed to render raw event", zap.Error(err)) return } - rawEvent.RemoteServer = remoteServer i.sendEventRaw(ctx, rawEvent) return } @@ -275,7 +272,6 @@ func (i *Input) processEvent(ctx context.Context, event Event) { if publisher.Valid() { formattedEvent, err := event.RenderFormatted(i.buffer, publisher) if err == nil { - formattedEvent.RemoteServer = remoteServer i.sendEvent(ctx, formattedEvent) return } @@ -290,7 +286,6 @@ func (i *Input) processEvent(ctx context.Context, event Event) { return } - simpleEvent.RemoteServer = remoteServer i.sendEvent(ctx, simpleEvent) } @@ -309,9 +304,8 @@ func (i *Input) sendEvent(ctx context.Context, eventXML EventXML) { } // sendEventRaw will send EventRaw as an entry to the operator's output. -func (i *Input) sendEventRaw(ctx context.Context, eventRaw EventRaw) { - body := eventRaw.parseBody() - entry, err := i.NewEntry(body) +func (i *Input) sendEventRaw(ctx context.Context, eventRaw EventXML) { + entry, err := i.NewEntry(eventRaw.Original) if err != nil { i.Logger().Error("Failed to create entry", zap.Error(err)) return diff --git a/pkg/stanza/operator/input/windows/raw.go b/pkg/stanza/operator/input/windows/raw.go deleted file mode 100644 index 7a489b4b1be0..000000000000 --- a/pkg/stanza/operator/input/windows/raw.go +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 - -package windows // import "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/stanza/operator/input/windows" - -import ( - "encoding/xml" - "fmt" - "time" - - "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/stanza/entry" -) - -// EventRaw is the rendered xml of an event, however, its message is the original XML of the entire event. -type EventRaw struct { - TimeCreated TimeCreated `xml:"System>TimeCreated"` - RenderedLevel string `xml:"RenderingInfo>Level"` - Level string `xml:"System>Level"` - Body string `xml:"-"` - RemoteServer string `xml:"RemoteServer,omitempty"` -} - -// parseTimestamp will parse the timestamp of the event. -func (e *EventRaw) parseTimestamp() time.Time { - if timestamp, err := time.Parse(time.RFC3339Nano, e.TimeCreated.SystemTime); err == nil { - return timestamp - } - return time.Now() -} - -// parseRenderedSeverity will parse the severity of the event. -func (e *EventRaw) parseRenderedSeverity() entry.Severity { - switch e.RenderedLevel { - case "": - return e.parseSeverity() - case "Critical": - return entry.Fatal - case "Error": - return entry.Error - case "Warning": - return entry.Warn - case "Information": - return entry.Info - default: - return entry.Default - } -} - -// parseSeverity will parse the severity of the event when RenderingInfo is not populated -func (e *EventRaw) parseSeverity() entry.Severity { - switch e.Level { - case "1": - return entry.Fatal - case "2": - return entry.Error - case "3": - return entry.Warn - case "4": - return entry.Info - default: - return entry.Default - } -} - -// parseBody will parse a body from the event. -func (e *EventRaw) parseBody() string { - return e.Body -} - -// unmarshalEventRaw will unmarshal EventRaw from xml bytes. -func unmarshalEventRaw(bytes []byte) (EventRaw, error) { - var eventRaw EventRaw - if err := xml.Unmarshal(bytes, &eventRaw); err != nil { - return EventRaw{}, fmt.Errorf("failed to unmarshal xml bytes into event: %w (%s)", err, string(bytes)) - } - eventRaw.Body = string(bytes) - return eventRaw, nil -} diff --git a/pkg/stanza/operator/input/windows/raw_test.go b/pkg/stanza/operator/input/windows/raw_test.go deleted file mode 100644 index 10e36d9154ee..000000000000 --- a/pkg/stanza/operator/input/windows/raw_test.go +++ /dev/null @@ -1,93 +0,0 @@ -// Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 - -package windows - -import ( - "os" - "path/filepath" - "testing" - "time" - - "github.com/stretchr/testify/require" - - "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/stanza/entry" -) - -func TestParseValidTimestampRaw(t *testing.T) { - raw := EventRaw{ - TimeCreated: TimeCreated{ - SystemTime: "2020-07-30T01:01:01.123456789Z", - }, - } - timestamp := raw.parseTimestamp() - expected, _ := time.Parse(time.RFC3339Nano, "2020-07-30T01:01:01.123456789Z") - require.Equal(t, expected, timestamp) -} - -func TestParseInvalidTimestampRaw(t *testing.T) { - raw := EventRaw{ - TimeCreated: TimeCreated{ - SystemTime: "invalid", - }, - } - timestamp := raw.parseTimestamp() - require.Equal(t, time.Now().Year(), timestamp.Year()) - require.Equal(t, time.Now().Month(), timestamp.Month()) - require.Equal(t, time.Now().Day(), timestamp.Day()) -} - -func TestParseSeverityRaw(t *testing.T) { - rawRenderedCritical := EventRaw{RenderedLevel: "Critical"} - rawRenderedError := EventRaw{RenderedLevel: "Error"} - rawRenderedWarning := EventRaw{RenderedLevel: "Warning"} - rawRenderedInformation := EventRaw{RenderedLevel: "Information"} - rawRenderedUnknown := EventRaw{RenderedLevel: "Unknown"} - rawCritical := EventRaw{Level: "1"} - rawError := EventRaw{Level: "2"} - rawWarning := EventRaw{Level: "3"} - rawInformation := EventRaw{Level: "4"} - rawUnknown := EventRaw{Level: "0"} - require.Equal(t, entry.Fatal, rawRenderedCritical.parseRenderedSeverity()) - require.Equal(t, entry.Error, rawRenderedError.parseRenderedSeverity()) - require.Equal(t, entry.Warn, rawRenderedWarning.parseRenderedSeverity()) - require.Equal(t, entry.Info, rawRenderedInformation.parseRenderedSeverity()) - require.Equal(t, entry.Default, rawRenderedUnknown.parseRenderedSeverity()) - require.Equal(t, entry.Fatal, rawCritical.parseRenderedSeverity()) - require.Equal(t, entry.Error, rawError.parseRenderedSeverity()) - require.Equal(t, entry.Warn, rawWarning.parseRenderedSeverity()) - require.Equal(t, entry.Info, rawInformation.parseRenderedSeverity()) - require.Equal(t, entry.Default, rawUnknown.parseRenderedSeverity()) -} - -func TestParseBodyRaw(t *testing.T) { - raw := EventRaw{ - Body: "foo", - } - - require.Equal(t, "foo", raw.parseBody()) -} - -func TestInvalidUnmarshalRaw(t *testing.T) { - _, err := unmarshalEventRaw([]byte("Test \n Invalid \t Unmarshal")) - require.Error(t, err) - -} - -func TestUnmarshalRaw(t *testing.T) { - data, err := os.ReadFile(filepath.Join("testdata", "xmlSample.xml")) - require.NoError(t, err) - - event, err := unmarshalEventRaw(data) - require.NoError(t, err) - - raw := EventRaw{ - TimeCreated: TimeCreated{ - SystemTime: "2022-04-22T10:20:52.3778625Z", - }, - Level: "4", - Body: string(data), - } - - require.Equal(t, raw, event) -} diff --git a/pkg/stanza/operator/input/windows/xml.go b/pkg/stanza/operator/input/windows/xml.go index dcfe4199f35c..1ef1cccfe820 100644 --- a/pkg/stanza/operator/input/windows/xml.go +++ b/pkg/stanza/operator/input/windows/xml.go @@ -13,6 +13,7 @@ import ( // EventXML is the rendered xml of an event. type EventXML struct { + Original string `xml:"-"` EventID EventID `xml:"System>EventID"` Provider Provider `xml:"System>Provider"` Computer string `xml:"System>Computer"` @@ -180,15 +181,6 @@ func parseEventData(eventData EventData) map[string]any { return outputMap } -// unmarshalEventXML will unmarshal EventXML from xml bytes. -func unmarshalEventXML(bytes []byte) (EventXML, error) { - var eventXML EventXML - if err := xml.Unmarshal(bytes, &eventXML); err != nil { - return EventXML{}, fmt.Errorf("failed to unmarshal xml bytes into event: %w (%s)", err, string(bytes)) - } - return eventXML, nil -} - // EventID is the identifier of the event. type EventID struct { Qualifiers uint16 `xml:"Qualifiers,attr"` @@ -267,3 +259,13 @@ func (e Execution) asMap() map[string]any { return result } + +// unmarshalEventXML will unmarshal EventXML from xml bytes. +func unmarshalEventXML(bytes []byte) (EventXML, error) { + var eventXML EventXML + if err := xml.Unmarshal(bytes, &eventXML); err != nil { + return EventXML{}, fmt.Errorf("failed to unmarshal xml bytes into event: %w (%s)", err, string(bytes)) + } + eventXML.Original = string(bytes) + return eventXML, nil +} diff --git a/pkg/stanza/operator/input/windows/xml_test.go b/pkg/stanza/operator/input/windows/xml_test.go index 622cc99eb053..05bb47dd49bb 100644 --- a/pkg/stanza/operator/input/windows/xml_test.go +++ b/pkg/stanza/operator/input/windows/xml_test.go @@ -479,6 +479,7 @@ func TestUnmarshalWithEventData(t *testing.T) { {Name: "Source", Value: "RulesEngine"}}, }, Keywords: []string{"0x80000000000000"}, + Original: string(data), } require.Equal(t, xml, event) @@ -516,6 +517,7 @@ func TestUnmarshalWithAnonymousEventDataEntries(t *testing.T) { Keywords: []string{"0x80000000000000"}, Security: &Security{}, Execution: &Execution{}, + Original: string(data), } require.Equal(t, xml, event) @@ -554,6 +556,7 @@ func TestUnmarshalWithUserData(t *testing.T) { ProcessID: 1472, ThreadID: 7784, }, + Original: string(data), } require.Equal(t, xml, event) diff --git a/processor/attributesprocessor/go.mod b/processor/attributesprocessor/go.mod index 25f6d5422a1c..bd1348db4cd4 100644 --- a/processor/attributesprocessor/go.mod +++ b/processor/attributesprocessor/go.mod @@ -30,6 +30,7 @@ require ( github.com/go-logr/stdr v1.2.2 // indirect github.com/go-viper/mapstructure/v2 v2.1.0 // indirect github.com/gobwas/glob v0.2.3 // indirect + github.com/goccy/go-json v0.10.3 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/google/uuid v1.6.0 // indirect github.com/hashicorp/go-version v1.7.0 // indirect diff --git a/processor/attributesprocessor/go.sum b/processor/attributesprocessor/go.sum index 06ee06ad1415..0487a966967e 100644 --- a/processor/attributesprocessor/go.sum +++ b/processor/attributesprocessor/go.sum @@ -24,6 +24,8 @@ github.com/go-viper/mapstructure/v2 v2.1.0 h1:gHnMa2Y/pIxElCH2GlZZ1lZSsn6XMtufpG github.com/go-viper/mapstructure/v2 v2.1.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= +github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA= +github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= diff --git a/processor/filterprocessor/go.mod b/processor/filterprocessor/go.mod index ba1cf94a4979..5fa60b82dedd 100644 --- a/processor/filterprocessor/go.mod +++ b/processor/filterprocessor/go.mod @@ -34,6 +34,7 @@ require ( github.com/go-logr/stdr v1.2.2 // indirect github.com/go-viper/mapstructure/v2 v2.1.0 // indirect github.com/gobwas/glob v0.2.3 // indirect + github.com/goccy/go-json v0.10.3 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/google/uuid v1.6.0 // indirect github.com/hashicorp/go-version v1.7.0 // indirect diff --git a/processor/filterprocessor/go.sum b/processor/filterprocessor/go.sum index 622dcae915f8..2a03658cd261 100644 --- a/processor/filterprocessor/go.sum +++ b/processor/filterprocessor/go.sum @@ -24,6 +24,8 @@ github.com/go-viper/mapstructure/v2 v2.1.0 h1:gHnMa2Y/pIxElCH2GlZZ1lZSsn6XMtufpG github.com/go-viper/mapstructure/v2 v2.1.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= +github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA= +github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= diff --git a/processor/redactionprocessor/processor.go b/processor/redactionprocessor/processor.go index ae07d3819a3f..f2aecf84b286 100644 --- a/processor/redactionprocessor/processor.go +++ b/processor/redactionprocessor/processor.go @@ -106,7 +106,7 @@ func (s *redaction) processResourceLog(ctx context.Context, rl plog.ResourceLogs for j := 0; j < rl.ScopeLogs().Len(); j++ { ils := rl.ScopeLogs().At(j) - for k := 0; k < rl.ScopeLogs().Len(); k++ { + for k := 0; k < ils.LogRecords().Len(); k++ { log := ils.LogRecords().At(k) s.processAttrs(ctx, log.Attributes()) } diff --git a/processor/redactionprocessor/processor_test.go b/processor/redactionprocessor/processor_test.go index acc11d817c81..3405dc2eb2ea 100644 --- a/processor/redactionprocessor/processor_test.go +++ b/processor/redactionprocessor/processor_test.go @@ -565,6 +565,7 @@ func runLogsTest( inBatch := plog.NewLogs() rl := inBatch.ResourceLogs().AppendEmpty() ils := rl.ScopeLogs().AppendEmpty() + _ = rl.ScopeLogs().AppendEmpty() library := ils.Scope() library.SetName("first-library") diff --git a/processor/routingprocessor/go.mod b/processor/routingprocessor/go.mod index 3e1496ebb4e8..8d59029f40c0 100644 --- a/processor/routingprocessor/go.mod +++ b/processor/routingprocessor/go.mod @@ -37,6 +37,7 @@ require ( github.com/go-logr/stdr v1.2.2 // indirect github.com/go-viper/mapstructure/v2 v2.1.0 // indirect github.com/gobwas/glob v0.2.3 // indirect + github.com/goccy/go-json v0.10.3 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/snappy v0.0.4 // indirect github.com/google/uuid v1.6.0 // indirect diff --git a/processor/routingprocessor/go.sum b/processor/routingprocessor/go.sum index 016d08a74baf..749bbd9dab05 100644 --- a/processor/routingprocessor/go.sum +++ b/processor/routingprocessor/go.sum @@ -24,6 +24,8 @@ github.com/go-viper/mapstructure/v2 v2.1.0 h1:gHnMa2Y/pIxElCH2GlZZ1lZSsn6XMtufpG github.com/go-viper/mapstructure/v2 v2.1.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= +github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA= +github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= diff --git a/processor/spanprocessor/go.mod b/processor/spanprocessor/go.mod index 8443086b33fc..34a544320981 100644 --- a/processor/spanprocessor/go.mod +++ b/processor/spanprocessor/go.mod @@ -28,6 +28,7 @@ require ( github.com/go-logr/stdr v1.2.2 // indirect github.com/go-viper/mapstructure/v2 v2.1.0 // indirect github.com/gobwas/glob v0.2.3 // indirect + github.com/goccy/go-json v0.10.3 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/google/uuid v1.6.0 // indirect github.com/hashicorp/go-version v1.7.0 // indirect diff --git a/processor/spanprocessor/go.sum b/processor/spanprocessor/go.sum index 4c57fa047dfa..07cec51d8a48 100644 --- a/processor/spanprocessor/go.sum +++ b/processor/spanprocessor/go.sum @@ -22,6 +22,8 @@ github.com/go-viper/mapstructure/v2 v2.1.0 h1:gHnMa2Y/pIxElCH2GlZZ1lZSsn6XMtufpG github.com/go-viper/mapstructure/v2 v2.1.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= +github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA= +github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= diff --git a/processor/tailsamplingprocessor/go.mod b/processor/tailsamplingprocessor/go.mod index 5a43ce35d928..3f9533ddd893 100644 --- a/processor/tailsamplingprocessor/go.mod +++ b/processor/tailsamplingprocessor/go.mod @@ -37,6 +37,7 @@ require ( github.com/go-logr/stdr v1.2.2 // indirect github.com/go-viper/mapstructure/v2 v2.1.0 // indirect github.com/gobwas/glob v0.2.3 // indirect + github.com/goccy/go-json v0.10.3 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/hashicorp/go-version v1.7.0 // indirect github.com/hashicorp/golang-lru v0.5.4 // indirect diff --git a/processor/tailsamplingprocessor/go.sum b/processor/tailsamplingprocessor/go.sum index 4d85a9c5de5e..ad162fbb6db3 100644 --- a/processor/tailsamplingprocessor/go.sum +++ b/processor/tailsamplingprocessor/go.sum @@ -20,6 +20,8 @@ github.com/go-viper/mapstructure/v2 v2.1.0 h1:gHnMa2Y/pIxElCH2GlZZ1lZSsn6XMtufpG github.com/go-viper/mapstructure/v2 v2.1.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= +github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA= +github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= diff --git a/processor/transformprocessor/go.mod b/processor/transformprocessor/go.mod index 9f2e39d2e37f..e5e6c1c0048d 100644 --- a/processor/transformprocessor/go.mod +++ b/processor/transformprocessor/go.mod @@ -37,6 +37,7 @@ require ( github.com/go-logr/stdr v1.2.2 // indirect github.com/go-viper/mapstructure/v2 v2.1.0 // indirect github.com/gobwas/glob v0.2.3 // indirect + github.com/goccy/go-json v0.10.3 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/google/uuid v1.6.0 // indirect github.com/hashicorp/go-version v1.7.0 // indirect diff --git a/processor/transformprocessor/go.sum b/processor/transformprocessor/go.sum index 4c57fa047dfa..07cec51d8a48 100644 --- a/processor/transformprocessor/go.sum +++ b/processor/transformprocessor/go.sum @@ -22,6 +22,8 @@ github.com/go-viper/mapstructure/v2 v2.1.0 h1:gHnMa2Y/pIxElCH2GlZZ1lZSsn6XMtufpG github.com/go-viper/mapstructure/v2 v2.1.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= +github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA= +github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= diff --git a/receiver/datadogreceiver/internal/translator/traces_translator.go b/receiver/datadogreceiver/internal/translator/traces_translator.go index a401d7a34ac8..0b92812cf2e0 100644 --- a/receiver/datadogreceiver/internal/translator/traces_translator.go +++ b/receiver/datadogreceiver/internal/translator/traces_translator.go @@ -119,6 +119,11 @@ func ToTraces(payload *pb.TracerPayload, req *http.Request) ptrace.Traces { newSpan.Attributes().PutStr(k, v) } } + for k, v := range span.GetMetrics() { + if k = translateDatadogKeyToOTel(k); len(k) > 0 { + newSpan.Attributes().PutDouble(k, v) + } + } switch span.Meta[datadogSpanKindKey] { case "server": diff --git a/receiver/datadogreceiver/internal/translator/traces_translator_test.go b/receiver/datadogreceiver/internal/translator/traces_translator_test.go index c197d5bb6d74..73c7f55de821 100644 --- a/receiver/datadogreceiver/internal/translator/traces_translator_test.go +++ b/receiver/datadogreceiver/internal/translator/traces_translator_test.go @@ -8,6 +8,7 @@ import ( "fmt" "io" "net/http" + "strconv" "testing" pb "github.com/DataDog/datadog-agent/pkg/proto/pbgo/trace" @@ -28,7 +29,7 @@ var data = [2]any{ 2: "elasticsearch.version", 3: "7.0", 4: "my-name", - 5: "X", + 5: "numeric_attribute", 6: "my-service", 7: "my-resource", 8: "_sampling_priority_v1", @@ -86,26 +87,27 @@ func TestTracePayloadV05Unmarshalling(t *testing.T) { require.NoError(t, traces.UnmarshalMsgDictionary(payload), "Must not error when marshaling content") req, _ := http.NewRequest(http.MethodPost, "/v0.5/traces", io.NopCloser(bytes.NewReader(payload))) - translated := ToTraces(&pb.TracerPayload{ - LanguageName: req.Header.Get(header.Lang), - LanguageVersion: req.Header.Get(header.LangVersion), - TracerVersion: req.Header.Get(header.TracerVersion), - Chunks: traceChunksFromTraces(traces), - }, req) + tracePayloads, _ := HandleTracesPayload(req) + assert.Len(t, tracePayloads, 1, "Expected one translated payload") + tracePayload := tracePayloads[0] + translated := ToTraces(tracePayload, req) assert.Equal(t, 1, translated.SpanCount(), "Span Count wrong") span := translated.ResourceSpans().At(0).ScopeSpans().At(0).Spans().At(0) assert.NotNil(t, span) - assert.Equal(t, 9, span.Attributes().Len(), "missing attributes") + assert.Equal(t, "my-name", span.Name()) + assert.Equal(t, 10, span.Attributes().Len(), "missing attributes") value, exists := span.Attributes().Get("service.name") - serviceVersionValue, _ := span.Attributes().Get("service.version") assert.True(t, exists, "service.name missing") assert.Equal(t, "my-service", value.AsString(), "service.name attribute value incorrect") - assert.Equal(t, "my-name", span.Name()) + serviceVersionValue, _ := span.Attributes().Get("service.version") assert.Equal(t, "1.0.1", serviceVersionValue.AsString()) spanResource, _ := span.Attributes().Get("dd.span.Resource") assert.Equal(t, "my-resource", spanResource.Str()) spanResource1, _ := span.Attributes().Get("sampling.priority") assert.Equal(t, fmt.Sprintf("%f", 1.0), spanResource1.Str()) + numericAttributeValue, _ := span.Attributes().Get("numeric_attribute") + numericAttributeFloat, _ := strconv.ParseFloat(numericAttributeValue.AsString(), 64) + assert.Equal(t, 1.2, numericAttributeFloat) } func TestTracePayloadV07Unmarshalling(t *testing.T) { diff --git a/receiver/githubreceiver/go.mod b/receiver/githubreceiver/go.mod index cd5edc63ed8a..2d6da14376e0 100644 --- a/receiver/githubreceiver/go.mod +++ b/receiver/githubreceiver/go.mod @@ -5,7 +5,7 @@ go 1.22.0 require ( github.com/Khan/genqlient v0.7.0 github.com/google/go-cmp v0.6.0 - github.com/google/go-github/v64 v64.0.0 + github.com/google/go-github/v65 v65.0.0 github.com/open-telemetry/opentelemetry-collector-contrib/pkg/golden v0.109.0 github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatatest v0.109.0 github.com/stretchr/testify v1.9.0 diff --git a/receiver/githubreceiver/go.sum b/receiver/githubreceiver/go.sum index 1b4a3bb3c2c7..baeb9fe42b43 100644 --- a/receiver/githubreceiver/go.sum +++ b/receiver/githubreceiver/go.sum @@ -33,8 +33,8 @@ github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEW github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-github/v64 v64.0.0 h1:4G61sozmY3eiPAjjoOHponXDBONm+utovTKbyUb2Qdg= -github.com/google/go-github/v64 v64.0.0/go.mod h1:xB3vqMQNdHzilXBiO2I+M7iEFtHf+DP/omBOv6tQzVo= +github.com/google/go-github/v65 v65.0.0 h1:pQ7BmO3DZivvFk92geC0jB0q2m3gyn8vnYPgV7GSLhQ= +github.com/google/go-github/v65 v65.0.0/go.mod h1:DvrqWo5hvsdhJvHd4WyVF9ttANN3BniqjP8uTFMNb60= github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= diff --git a/receiver/githubreceiver/internal/scraper/githubscraper/github_scraper_test.go b/receiver/githubreceiver/internal/scraper/githubscraper/github_scraper_test.go index 56fb777911b7..22eecc168454 100644 --- a/receiver/githubreceiver/internal/scraper/githubscraper/github_scraper_test.go +++ b/receiver/githubreceiver/internal/scraper/githubscraper/github_scraper_test.go @@ -11,7 +11,7 @@ import ( "testing" "time" - "github.com/google/go-github/v64/github" + "github.com/google/go-github/v65/github" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component/componenttest" diff --git a/receiver/githubreceiver/internal/scraper/githubscraper/helpers.go b/receiver/githubreceiver/internal/scraper/githubscraper/helpers.go index e49a43ce1f6f..a7664f68337d 100644 --- a/receiver/githubreceiver/internal/scraper/githubscraper/helpers.go +++ b/receiver/githubreceiver/internal/scraper/githubscraper/helpers.go @@ -12,7 +12,7 @@ import ( "time" "github.com/Khan/genqlient/graphql" - "github.com/google/go-github/v64/github" + "github.com/google/go-github/v65/github" ) const ( diff --git a/receiver/githubreceiver/internal/scraper/githubscraper/helpers_test.go b/receiver/githubreceiver/internal/scraper/githubscraper/helpers_test.go index 1edaec0bc111..f7a2fcc1f900 100644 --- a/receiver/githubreceiver/internal/scraper/githubscraper/helpers_test.go +++ b/receiver/githubreceiver/internal/scraper/githubscraper/helpers_test.go @@ -15,7 +15,7 @@ import ( "time" "github.com/Khan/genqlient/graphql" - "github.com/google/go-github/v64/github" + "github.com/google/go-github/v65/github" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/receiver/receivertest" ) diff --git a/receiver/googlecloudspannerreceiver/internal/filter/itemcardinality_test.go b/receiver/googlecloudspannerreceiver/internal/filter/itemcardinality_test.go index e89d2dafd500..071ba7573ea5 100644 --- a/receiver/googlecloudspannerreceiver/internal/filter/itemcardinality_test.go +++ b/receiver/googlecloudspannerreceiver/internal/filter/itemcardinality_test.go @@ -4,6 +4,7 @@ package filter import ( + "runtime" "testing" "time" @@ -122,6 +123,9 @@ func TestItemCardinalityFilter_Shutdown(t *testing.T) { } func TestItemCardinalityFilter_Filter(t *testing.T) { + if runtime.GOOS == "windows" { + t.Skip("Skipping test on Windows due to https://github.com/open-telemetry/opentelemetry-collector-contrib/issues/32397") + } items := initialItems(t) logger := zaptest.NewLogger(t) filter, err := NewItemCardinalityFilter(metricName, totalLimit, limitByTimestamp, itemActivityPeriod, logger) @@ -175,6 +179,9 @@ func TestItemCardinalityFilter_Filter(t *testing.T) { } func TestItemCardinalityFilter_FilterItems(t *testing.T) { + if runtime.GOOS == "windows" { + t.Skip("Skipping test on Windows due to https://github.com/open-telemetry/opentelemetry-collector-contrib/issues/32397") + } items := initialItemsWithSameTimestamp(t) logger := zaptest.NewLogger(t) filter, err := NewItemCardinalityFilter(metricName, totalLimit, limitByTimestamp, itemActivityPeriod, logger) diff --git a/receiver/kubeletstatsreceiver/internal/kubelet/metadata.go b/receiver/kubeletstatsreceiver/internal/kubelet/metadata.go index dd0fff332716..954a01f03cd3 100644 --- a/receiver/kubeletstatsreceiver/internal/kubelet/metadata.go +++ b/receiver/kubeletstatsreceiver/internal/kubelet/metadata.go @@ -9,7 +9,7 @@ import ( "regexp" "strings" - conventions "go.opentelemetry.io/collector/semconv/v1.6.1" + conventions "go.opentelemetry.io/collector/semconv/v1.27.0" v1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/types" stats "k8s.io/kubelet/pkg/apis/stats/v1alpha1" diff --git a/receiver/prometheusreceiver/internal/metrics_adjuster.go b/receiver/prometheusreceiver/internal/metrics_adjuster.go index 8df2fba334c4..060450cc0f53 100644 --- a/receiver/prometheusreceiver/internal/metrics_adjuster.go +++ b/receiver/prometheusreceiver/internal/metrics_adjuster.go @@ -10,7 +10,7 @@ import ( "go.opentelemetry.io/collector/pdata/pcommon" "go.opentelemetry.io/collector/pdata/pmetric" - semconv "go.opentelemetry.io/collector/semconv/v1.25.0" + semconv "go.opentelemetry.io/collector/semconv/v1.27.0" "go.uber.org/zap" "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatautil" diff --git a/receiver/prometheusreceiver/internal/metrics_adjuster_test.go b/receiver/prometheusreceiver/internal/metrics_adjuster_test.go index 8faa1d4ab23f..fd1f4f8818da 100644 --- a/receiver/prometheusreceiver/internal/metrics_adjuster_test.go +++ b/receiver/prometheusreceiver/internal/metrics_adjuster_test.go @@ -10,7 +10,7 @@ import ( "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/pcommon" "go.opentelemetry.io/collector/pdata/pmetric" - semconv "go.opentelemetry.io/collector/semconv/v1.25.0" + semconv "go.opentelemetry.io/collector/semconv/v1.27.0" "go.uber.org/zap" ) diff --git a/receiver/prometheusreceiver/internal/prom_to_otlp_test.go b/receiver/prometheusreceiver/internal/prom_to_otlp_test.go index 37197e498217..bea18664e51c 100644 --- a/receiver/prometheusreceiver/internal/prom_to_otlp_test.go +++ b/receiver/prometheusreceiver/internal/prom_to_otlp_test.go @@ -9,7 +9,7 @@ import ( "github.com/prometheus/prometheus/model/labels" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/pdata/pcommon" - conventions "go.opentelemetry.io/collector/semconv/v1.25.0" + conventions "go.opentelemetry.io/collector/semconv/v1.27.0" "github.com/open-telemetry/opentelemetry-collector-contrib/internal/common/testutil" ) diff --git a/receiver/prometheusreceiver/internal/transaction_test.go b/receiver/prometheusreceiver/internal/transaction_test.go index c2900187bbac..6b72d14d2422 100644 --- a/receiver/prometheusreceiver/internal/transaction_test.go +++ b/receiver/prometheusreceiver/internal/transaction_test.go @@ -25,7 +25,7 @@ import ( "go.opentelemetry.io/collector/pdata/pmetric" "go.opentelemetry.io/collector/receiver/receiverhelper" "go.opentelemetry.io/collector/receiver/receivertest" - conventions "go.opentelemetry.io/collector/semconv/v1.25.0" + conventions "go.opentelemetry.io/collector/semconv/v1.27.0" "go.uber.org/zap" "go.uber.org/zap/zaptest/observer" ) diff --git a/receiver/prometheusreceiver/metrics_receiver_helper_test.go b/receiver/prometheusreceiver/metrics_receiver_helper_test.go index 0ab15d8c885b..7cc923d3dc7f 100644 --- a/receiver/prometheusreceiver/metrics_receiver_helper_test.go +++ b/receiver/prometheusreceiver/metrics_receiver_helper_test.go @@ -32,7 +32,7 @@ import ( "go.opentelemetry.io/collector/pdata/pcommon" "go.opentelemetry.io/collector/pdata/pmetric" "go.opentelemetry.io/collector/receiver/receivertest" - semconv "go.opentelemetry.io/collector/semconv/v1.25.0" + semconv "go.opentelemetry.io/collector/semconv/v1.27.0" "gopkg.in/yaml.v2" "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/prometheusreceiver/internal" diff --git a/receiver/prometheusreceiver/metrics_receiver_labels_test.go b/receiver/prometheusreceiver/metrics_receiver_labels_test.go index ebc4744bbbca..f7eb6289c1cd 100644 --- a/receiver/prometheusreceiver/metrics_receiver_labels_test.go +++ b/receiver/prometheusreceiver/metrics_receiver_labels_test.go @@ -11,7 +11,7 @@ import ( "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/pdata/pcommon" "go.opentelemetry.io/collector/pdata/pmetric" - semconv "go.opentelemetry.io/collector/semconv/v1.25.0" + semconv "go.opentelemetry.io/collector/semconv/v1.27.0" ) const targetExternalLabels = ` diff --git a/receiver/pulsarreceiver/zipkin_unmarshaler_test.go b/receiver/pulsarreceiver/zipkin_unmarshaler_test.go index 1e2765511c2e..cb76c000273b 100644 --- a/receiver/pulsarreceiver/zipkin_unmarshaler_test.go +++ b/receiver/pulsarreceiver/zipkin_unmarshaler_test.go @@ -15,7 +15,7 @@ import ( "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/pdata/pcommon" "go.opentelemetry.io/collector/pdata/ptrace" - conventions "go.opentelemetry.io/collector/semconv/v1.6.1" + conventions "go.opentelemetry.io/collector/semconv/v1.27.0" "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/translator/zipkin/zipkinv2" ) diff --git a/receiver/receivercreator/receiver_test.go b/receiver/receivercreator/receiver_test.go index c9478ba02584..37872d9f2055 100644 --- a/receiver/receivercreator/receiver_test.go +++ b/receiver/receivercreator/receiver_test.go @@ -20,7 +20,7 @@ import ( "go.opentelemetry.io/collector/otelcol/otelcoltest" "go.opentelemetry.io/collector/pdata/pmetric" "go.opentelemetry.io/collector/receiver/receivertest" - semconv "go.opentelemetry.io/collector/semconv/v1.18.0" + semconv "go.opentelemetry.io/collector/semconv/v1.27.0" "github.com/open-telemetry/opentelemetry-collector-contrib/extension/observer" "github.com/open-telemetry/opentelemetry-collector-contrib/internal/sharedcomponent" diff --git a/receiver/sapmreceiver/trace_receiver_test.go b/receiver/sapmreceiver/trace_receiver_test.go index 80436b4e29ab..e047a7601270 100644 --- a/receiver/sapmreceiver/trace_receiver_test.go +++ b/receiver/sapmreceiver/trace_receiver_test.go @@ -28,7 +28,7 @@ import ( "go.opentelemetry.io/collector/pdata/ptrace" "go.opentelemetry.io/collector/receiver" "go.opentelemetry.io/collector/receiver/receivertest" - conventions "go.opentelemetry.io/collector/semconv/v1.6.1" + conventions "go.opentelemetry.io/collector/semconv/v1.27.0" "github.com/open-telemetry/opentelemetry-collector-contrib/internal/common/testutil" "github.com/open-telemetry/opentelemetry-collector-contrib/internal/splunk" @@ -93,8 +93,8 @@ func grpcFixture(t1 time.Time) *model.Batch { StartTime: t1, Duration: 10 * time.Minute, Tags: []model.KeyValue{ - model.String(conventions.OtelStatusDescription, "Stale indices"), - model.String(conventions.OtelStatusCode, "ERROR"), + model.String(conventions.AttributeOTelStatusDescription, "Stale indices"), + model.String(conventions.AttributeOTelStatusCode, "ERROR"), model.Bool("error", true), }, References: []model.SpanRef{ @@ -112,8 +112,8 @@ func grpcFixture(t1 time.Time) *model.Batch { StartTime: t1.Add(10 * time.Minute), Duration: 2 * time.Second, Tags: []model.KeyValue{ - model.String(conventions.OtelStatusDescription, "Frontend crash"), - model.String(conventions.OtelStatusCode, "ERROR"), + model.String(conventions.AttributeOTelStatusDescription, "Frontend crash"), + model.String(conventions.AttributeOTelStatusCode, "ERROR"), model.Bool("error", true), }, }, diff --git a/receiver/skywalkingreceiver/internal/metrics/skywalkingproto_to_metrics.go b/receiver/skywalkingreceiver/internal/metrics/skywalkingproto_to_metrics.go index 442e9b0b44e9..95a4ec66e137 100644 --- a/receiver/skywalkingreceiver/internal/metrics/skywalkingproto_to_metrics.go +++ b/receiver/skywalkingreceiver/internal/metrics/skywalkingproto_to_metrics.go @@ -8,7 +8,7 @@ import ( "go.opentelemetry.io/collector/pdata/pcommon" "go.opentelemetry.io/collector/pdata/pmetric" - semconv "go.opentelemetry.io/collector/semconv/v1.18.0" + semconv "go.opentelemetry.io/collector/semconv/v1.27.0" common "skywalking.apache.org/repo/goapi/collect/common/v3" agent "skywalking.apache.org/repo/goapi/collect/language/agent/v3" )