From db0f59fbffeb617341e97e9e01c3567453ff9597 Mon Sep 17 00:00:00 2001 From: Tamir David Date: Sun, 18 Aug 2024 17:55:23 +0300 Subject: [PATCH 1/2] Head sampling crd (#1445) I've added @RonFed CRD additions for Head-sampling + change in the relevant places in the code. --------- Co-authored-by: Tamir David --- .../odigos.io_instrumentationconfigs.yaml | 96 +++++++++++++++++-- .../odigos/v1alpha1/attributecondition.go | 61 ++++++++++++ .../v1alpha1/attributesandsamplerrule.go | 52 ++++++++++ .../odigos/v1alpha1/headsamplingconfig.go | 52 ++++++++++ .../v1alpha1/instrumentationlibraryconfig.go | 12 +-- .../v1alpha1/instrumentationlibraryid.go | 51 ++++++++++ .../odigos/v1alpha1/sdkconfig.go | 9 ++ .../odigos/applyconfiguration/utils.go | 8 ++ api/go.mod | 2 +- .../v1alpha1/instrumentatioconfig_types.go | 71 +++++++++++++- api/odigos/v1alpha1/zz_generated.deepcopy.go | 74 ++++++++++++++ .../instrumentationlibraries.go | 2 +- 12 files changed, 473 insertions(+), 17 deletions(-) create mode 100644 api/generated/odigos/applyconfiguration/odigos/v1alpha1/attributecondition.go create mode 100644 api/generated/odigos/applyconfiguration/odigos/v1alpha1/attributesandsamplerrule.go create mode 100644 api/generated/odigos/applyconfiguration/odigos/v1alpha1/headsamplingconfig.go create mode 100644 api/generated/odigos/applyconfiguration/odigos/v1alpha1/instrumentationlibraryid.go diff --git a/api/config/crd/bases/odigos.io_instrumentationconfigs.yaml b/api/config/crd/bases/odigos.io_instrumentationconfigs.yaml index 4f06b7a5f..ce772b872 100644 --- a/api/config/crd/bases/odigos.io_instrumentationconfigs.yaml +++ b/api/config/crd/bases/odigos.io_instrumentationconfigs.yaml @@ -119,16 +119,100 @@ spec: The SDKs are identified by the programming language they are written in. items: properties: + headSamplerConfig: + description: |- + HeadSamplingConfig is a set sampling rules. + This config currently only applies to root spans. + In the Future we might add another level of configuration base on the parent span (ParentBased Sampling) + properties: + attributesAndSamplerRules: + items: + description: |- + AttributesAndSamplerRule is a set of AttributeCondition that are ANDed together. + If all attribute conditions evaluate to true, the AND sampler evaluates to true, + and the fraction is used to determine the sampling decision. + If any of the attribute compare samplers evaluate to false, + the fraction is not used and the rule is skipped. + An "empty" AttributesAndSamplerRule with no attribute conditions is considered to always evaluate to true. + and the fraction is used to determine the sampling decision. + This entity is refered to a rule in Odigos terminology for head-sampling. + properties: + attributeConditions: + items: + description: '''Operand'' represents the attributes + and values that an operator acts upon in an expression' + properties: + key: + description: attribute key (e.g. "url.path") + type: string + operator: + description: The operator to use to compare + the attribute value. + enum: + - equals + - notEquals + - endWith + - startWith + type: string + val: + description: currently only string values are + supported. + type: string + required: + - key + - val + type: object + type: array + fraction: + default: 1 + description: |- + The fraction of spans to sample, in the range [0, 1]. + If the fraction is 0, no spans are sampled. + If the fraction is 1, all spans are sampled. + type: number + required: + - attributeConditions + - fraction + type: object + type: array + fallbackFraction: + default: 1 + description: |- + Used as a fallback if all rules evaluate to false, + it may be empty - in this case the default value will be 1 - all spans are sampled. + it should be a float value in the range [0, 1] - the fraction of spans to sample. + a value of 0 means no spans are sampled if none of the rules evaluate to true. + type: number + required: + - attributesAndSamplerRules + - fallbackFraction + type: object instrumentationLibraryConfigs: description: configurations for the instrumentation libraries the the SDK should use items: properties: - instrumentationLibraryName: - description: |- - The name of the instrumentation library - - Node.js: The name of the npm package: `@opentelemetry/instrumentation-` - type: string + libraryId: + properties: + libraryName: + description: |- + The name of the instrumentation library + - Node.js: The name of the npm package: `@opentelemetry/instrumentation-` + type: string + spanKind: + description: |- + SpanKind is only supported by Golang and will be ignored for any other SDK language. + In Go, SpanKind is used because the same instrumentation library can be utilized for different span kinds (e.g., client/server). + enum: + - client + - server + - producer + - consumer + - internal + type: string + required: + - libraryName + type: object traceConfig: properties: enabled: @@ -140,7 +224,7 @@ spec: type: boolean type: object required: - - instrumentationLibraryName + - libraryId type: object type: array language: diff --git a/api/generated/odigos/applyconfiguration/odigos/v1alpha1/attributecondition.go b/api/generated/odigos/applyconfiguration/odigos/v1alpha1/attributecondition.go new file mode 100644 index 000000000..e2ba16d4e --- /dev/null +++ b/api/generated/odigos/applyconfiguration/odigos/v1alpha1/attributecondition.go @@ -0,0 +1,61 @@ +/* +Copyright 2022. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + v1alpha1 "github.com/odigos-io/odigos/api/odigos/v1alpha1" + attribute "go.opentelemetry.io/otel/attribute" +) + +// AttributeConditionApplyConfiguration represents a declarative configuration of the AttributeCondition type for use +// with apply. +type AttributeConditionApplyConfiguration struct { + Key *attribute.Key `json:"key,omitempty"` + Val *string `json:"val,omitempty"` + Operator *v1alpha1.Operator `json:"operator,omitempty"` +} + +// AttributeConditionApplyConfiguration constructs a declarative configuration of the AttributeCondition type for use with +// apply. +func AttributeCondition() *AttributeConditionApplyConfiguration { + return &AttributeConditionApplyConfiguration{} +} + +// WithKey sets the Key field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Key field is set to the value of the last call. +func (b *AttributeConditionApplyConfiguration) WithKey(value attribute.Key) *AttributeConditionApplyConfiguration { + b.Key = &value + return b +} + +// WithVal sets the Val field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Val field is set to the value of the last call. +func (b *AttributeConditionApplyConfiguration) WithVal(value string) *AttributeConditionApplyConfiguration { + b.Val = &value + return b +} + +// WithOperator sets the Operator field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Operator field is set to the value of the last call. +func (b *AttributeConditionApplyConfiguration) WithOperator(value v1alpha1.Operator) *AttributeConditionApplyConfiguration { + b.Operator = &value + return b +} diff --git a/api/generated/odigos/applyconfiguration/odigos/v1alpha1/attributesandsamplerrule.go b/api/generated/odigos/applyconfiguration/odigos/v1alpha1/attributesandsamplerrule.go new file mode 100644 index 000000000..2427981f1 --- /dev/null +++ b/api/generated/odigos/applyconfiguration/odigos/v1alpha1/attributesandsamplerrule.go @@ -0,0 +1,52 @@ +/* +Copyright 2022. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1alpha1 + +// AttributesAndSamplerRuleApplyConfiguration represents a declarative configuration of the AttributesAndSamplerRule type for use +// with apply. +type AttributesAndSamplerRuleApplyConfiguration struct { + AttributeConditions []AttributeConditionApplyConfiguration `json:"attributeConditions,omitempty"` + Fraction *float64 `json:"fraction,omitempty"` +} + +// AttributesAndSamplerRuleApplyConfiguration constructs a declarative configuration of the AttributesAndSamplerRule type for use with +// apply. +func AttributesAndSamplerRule() *AttributesAndSamplerRuleApplyConfiguration { + return &AttributesAndSamplerRuleApplyConfiguration{} +} + +// WithAttributeConditions adds the given value to the AttributeConditions field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, values provided by each call will be appended to the AttributeConditions field. +func (b *AttributesAndSamplerRuleApplyConfiguration) WithAttributeConditions(values ...*AttributeConditionApplyConfiguration) *AttributesAndSamplerRuleApplyConfiguration { + for i := range values { + if values[i] == nil { + panic("nil value passed to WithAttributeConditions") + } + b.AttributeConditions = append(b.AttributeConditions, *values[i]) + } + return b +} + +// WithFraction sets the Fraction field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Fraction field is set to the value of the last call. +func (b *AttributesAndSamplerRuleApplyConfiguration) WithFraction(value float64) *AttributesAndSamplerRuleApplyConfiguration { + b.Fraction = &value + return b +} diff --git a/api/generated/odigos/applyconfiguration/odigos/v1alpha1/headsamplingconfig.go b/api/generated/odigos/applyconfiguration/odigos/v1alpha1/headsamplingconfig.go new file mode 100644 index 000000000..2eee097a5 --- /dev/null +++ b/api/generated/odigos/applyconfiguration/odigos/v1alpha1/headsamplingconfig.go @@ -0,0 +1,52 @@ +/* +Copyright 2022. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1alpha1 + +// HeadSamplingConfigApplyConfiguration represents a declarative configuration of the HeadSamplingConfig type for use +// with apply. +type HeadSamplingConfigApplyConfiguration struct { + AttributesAndSamplerRules []AttributesAndSamplerRuleApplyConfiguration `json:"attributesAndSamplerRules,omitempty"` + FallbackFraction *float64 `json:"fallbackFraction,omitempty"` +} + +// HeadSamplingConfigApplyConfiguration constructs a declarative configuration of the HeadSamplingConfig type for use with +// apply. +func HeadSamplingConfig() *HeadSamplingConfigApplyConfiguration { + return &HeadSamplingConfigApplyConfiguration{} +} + +// WithAttributesAndSamplerRules adds the given value to the AttributesAndSamplerRules field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, values provided by each call will be appended to the AttributesAndSamplerRules field. +func (b *HeadSamplingConfigApplyConfiguration) WithAttributesAndSamplerRules(values ...*AttributesAndSamplerRuleApplyConfiguration) *HeadSamplingConfigApplyConfiguration { + for i := range values { + if values[i] == nil { + panic("nil value passed to WithAttributesAndSamplerRules") + } + b.AttributesAndSamplerRules = append(b.AttributesAndSamplerRules, *values[i]) + } + return b +} + +// WithFallbackFraction sets the FallbackFraction field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the FallbackFraction field is set to the value of the last call. +func (b *HeadSamplingConfigApplyConfiguration) WithFallbackFraction(value float64) *HeadSamplingConfigApplyConfiguration { + b.FallbackFraction = &value + return b +} diff --git a/api/generated/odigos/applyconfiguration/odigos/v1alpha1/instrumentationlibraryconfig.go b/api/generated/odigos/applyconfiguration/odigos/v1alpha1/instrumentationlibraryconfig.go index bf2d6a357..3ee719d0b 100644 --- a/api/generated/odigos/applyconfiguration/odigos/v1alpha1/instrumentationlibraryconfig.go +++ b/api/generated/odigos/applyconfiguration/odigos/v1alpha1/instrumentationlibraryconfig.go @@ -20,8 +20,8 @@ package v1alpha1 // InstrumentationLibraryConfigApplyConfiguration represents a declarative configuration of the InstrumentationLibraryConfig type for use // with apply. type InstrumentationLibraryConfigApplyConfiguration struct { - InstrumentationLibraryName *string `json:"instrumentationLibraryName,omitempty"` - TraceConfig *InstrumentationLibraryConfigTracesApplyConfiguration `json:"traceConfig,omitempty"` + InstrumentationLibraryId *InstrumentationLibraryIdApplyConfiguration `json:"libraryId,omitempty"` + TraceConfig *InstrumentationLibraryConfigTracesApplyConfiguration `json:"traceConfig,omitempty"` } // InstrumentationLibraryConfigApplyConfiguration constructs a declarative configuration of the InstrumentationLibraryConfig type for use with @@ -30,11 +30,11 @@ func InstrumentationLibraryConfig() *InstrumentationLibraryConfigApplyConfigurat return &InstrumentationLibraryConfigApplyConfiguration{} } -// WithInstrumentationLibraryName sets the InstrumentationLibraryName field in the declarative configuration to the given value +// WithInstrumentationLibraryId sets the InstrumentationLibraryId field in the declarative configuration to the given value // and returns the receiver, so that objects can be built by chaining "With" function invocations. -// If called multiple times, the InstrumentationLibraryName field is set to the value of the last call. -func (b *InstrumentationLibraryConfigApplyConfiguration) WithInstrumentationLibraryName(value string) *InstrumentationLibraryConfigApplyConfiguration { - b.InstrumentationLibraryName = &value +// If called multiple times, the InstrumentationLibraryId field is set to the value of the last call. +func (b *InstrumentationLibraryConfigApplyConfiguration) WithInstrumentationLibraryId(value *InstrumentationLibraryIdApplyConfiguration) *InstrumentationLibraryConfigApplyConfiguration { + b.InstrumentationLibraryId = value return b } diff --git a/api/generated/odigos/applyconfiguration/odigos/v1alpha1/instrumentationlibraryid.go b/api/generated/odigos/applyconfiguration/odigos/v1alpha1/instrumentationlibraryid.go new file mode 100644 index 000000000..f5306d0ac --- /dev/null +++ b/api/generated/odigos/applyconfiguration/odigos/v1alpha1/instrumentationlibraryid.go @@ -0,0 +1,51 @@ +/* +Copyright 2022. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + common "github.com/odigos-io/odigos/common" +) + +// InstrumentationLibraryIdApplyConfiguration represents a declarative configuration of the InstrumentationLibraryId type for use +// with apply. +type InstrumentationLibraryIdApplyConfiguration struct { + InstrumentationLibraryName *string `json:"libraryName,omitempty"` + SpanKind *common.SpanKind `json:"spanKind,omitempty"` +} + +// InstrumentationLibraryIdApplyConfiguration constructs a declarative configuration of the InstrumentationLibraryId type for use with +// apply. +func InstrumentationLibraryId() *InstrumentationLibraryIdApplyConfiguration { + return &InstrumentationLibraryIdApplyConfiguration{} +} + +// WithInstrumentationLibraryName sets the InstrumentationLibraryName field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the InstrumentationLibraryName field is set to the value of the last call. +func (b *InstrumentationLibraryIdApplyConfiguration) WithInstrumentationLibraryName(value string) *InstrumentationLibraryIdApplyConfiguration { + b.InstrumentationLibraryName = &value + return b +} + +// WithSpanKind sets the SpanKind field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the SpanKind field is set to the value of the last call. +func (b *InstrumentationLibraryIdApplyConfiguration) WithSpanKind(value common.SpanKind) *InstrumentationLibraryIdApplyConfiguration { + b.SpanKind = &value + return b +} diff --git a/api/generated/odigos/applyconfiguration/odigos/v1alpha1/sdkconfig.go b/api/generated/odigos/applyconfiguration/odigos/v1alpha1/sdkconfig.go index 34bbbd29a..8e9521b53 100644 --- a/api/generated/odigos/applyconfiguration/odigos/v1alpha1/sdkconfig.go +++ b/api/generated/odigos/applyconfiguration/odigos/v1alpha1/sdkconfig.go @@ -26,6 +26,7 @@ import ( type SdkConfigApplyConfiguration struct { Language *common.ProgrammingLanguage `json:"language,omitempty"` InstrumentationLibraryConfigs []InstrumentationLibraryConfigApplyConfiguration `json:"instrumentationLibraryConfigs,omitempty"` + HeadSamplingConfig *HeadSamplingConfigApplyConfiguration `json:"headSamplerConfig,omitempty"` } // SdkConfigApplyConfiguration constructs a declarative configuration of the SdkConfig type for use with @@ -54,3 +55,11 @@ func (b *SdkConfigApplyConfiguration) WithInstrumentationLibraryConfigs(values . } return b } + +// WithHeadSamplingConfig sets the HeadSamplingConfig field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the HeadSamplingConfig field is set to the value of the last call. +func (b *SdkConfigApplyConfiguration) WithHeadSamplingConfig(value *HeadSamplingConfigApplyConfiguration) *SdkConfigApplyConfiguration { + b.HeadSamplingConfig = value + return b +} diff --git a/api/generated/odigos/applyconfiguration/utils.go b/api/generated/odigos/applyconfiguration/utils.go index dfbbffd15..72efff442 100644 --- a/api/generated/odigos/applyconfiguration/utils.go +++ b/api/generated/odigos/applyconfiguration/utils.go @@ -33,6 +33,10 @@ func ForKind(kind schema.GroupVersionKind) interface{} { // Group=odigos.io, Version=v1alpha1 case v1alpha1.SchemeGroupVersion.WithKind("Attribute"): return &odigosv1alpha1.AttributeApplyConfiguration{} + case v1alpha1.SchemeGroupVersion.WithKind("AttributeCondition"): + return &odigosv1alpha1.AttributeConditionApplyConfiguration{} + case v1alpha1.SchemeGroupVersion.WithKind("AttributesAndSamplerRule"): + return &odigosv1alpha1.AttributesAndSamplerRuleApplyConfiguration{} case v1alpha1.SchemeGroupVersion.WithKind("CollectorGatewayConfiguration"): return &odigosv1alpha1.CollectorGatewayConfigurationApplyConfiguration{} case v1alpha1.SchemeGroupVersion.WithKind("CollectorsGroup"): @@ -51,6 +55,8 @@ func ForKind(kind schema.GroupVersionKind) interface{} { return &odigosv1alpha1.DestinationStatusApplyConfiguration{} case v1alpha1.SchemeGroupVersion.WithKind("EnvVar"): return &odigosv1alpha1.EnvVarApplyConfiguration{} + case v1alpha1.SchemeGroupVersion.WithKind("HeadSamplingConfig"): + return &odigosv1alpha1.HeadSamplingConfigApplyConfiguration{} case v1alpha1.SchemeGroupVersion.WithKind("InstrumentationConfig"): return &odigosv1alpha1.InstrumentationConfigApplyConfiguration{} case v1alpha1.SchemeGroupVersion.WithKind("InstrumentationConfigSpec"): @@ -67,6 +73,8 @@ func ForKind(kind schema.GroupVersionKind) interface{} { return &odigosv1alpha1.InstrumentationLibraryConfigApplyConfiguration{} case v1alpha1.SchemeGroupVersion.WithKind("InstrumentationLibraryConfigTraces"): return &odigosv1alpha1.InstrumentationLibraryConfigTracesApplyConfiguration{} + case v1alpha1.SchemeGroupVersion.WithKind("InstrumentationLibraryId"): + return &odigosv1alpha1.InstrumentationLibraryIdApplyConfiguration{} case v1alpha1.SchemeGroupVersion.WithKind("InstrumentationLibraryOptions"): return &odigosv1alpha1.InstrumentationLibraryOptionsApplyConfiguration{} case v1alpha1.SchemeGroupVersion.WithKind("InstrumentationLibraryStatus"): diff --git a/api/go.mod b/api/go.mod index acf8ee16d..bb587b9d2 100644 --- a/api/go.mod +++ b/api/go.mod @@ -47,7 +47,7 @@ require ( github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/spf13/pflag v1.0.5 // indirect - go.opentelemetry.io/otel v1.28.0 // indirect + go.opentelemetry.io/otel v1.28.0 go.opentelemetry.io/otel/trace v1.28.0 // indirect golang.org/x/mod v0.17.0 // indirect golang.org/x/net v0.26.0 // indirect diff --git a/api/odigos/v1alpha1/instrumentatioconfig_types.go b/api/odigos/v1alpha1/instrumentatioconfig_types.go index 32544a8b5..6a80df432 100644 --- a/api/odigos/v1alpha1/instrumentatioconfig_types.go +++ b/api/odigos/v1alpha1/instrumentatioconfig_types.go @@ -2,6 +2,7 @@ package v1alpha1 import ( "github.com/odigos-io/odigos/common" + "go.opentelemetry.io/otel/attribute" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -41,16 +42,80 @@ type SdkConfig struct { // configurations for the instrumentation libraries the the SDK should use InstrumentationLibraryConfigs []InstrumentationLibraryConfig `json:"instrumentationLibraryConfigs"` + + // HeadSamplingConfig is a set sampling rules. + // This config currently only applies to root spans. + // In the Future we might add another level of configuration base on the parent span (ParentBased Sampling) + HeadSamplingConfig HeadSamplingConfig `json:"headSamplerConfig,omitempty"` +} + +// 'Operand' represents the attributes and values that an operator acts upon in an expression +type AttributeCondition struct { + // attribute key (e.g. "url.path") + Key attribute.Key `json:"key"` + // currently only string values are supported. + Val string `json:"val"` + // The operator to use to compare the attribute value. + Operator Operator `json:"operator,omitempty"` +} + +// +kubebuilder:validation:Enum=equals;notEquals;endWith;startWith +// +kubebuilder:default:=equals +type Operator string + +const ( + Equals Operator = "equals" + NotEquals Operator = "notEquals" + EndWith Operator = "endWith" + StartWith Operator = "startWith" +) + +// AttributesAndSamplerRule is a set of AttributeCondition that are ANDed together. +// If all attribute conditions evaluate to true, the AND sampler evaluates to true, +// and the fraction is used to determine the sampling decision. +// If any of the attribute compare samplers evaluate to false, +// the fraction is not used and the rule is skipped. +// An "empty" AttributesAndSamplerRule with no attribute conditions is considered to always evaluate to true. +// and the fraction is used to determine the sampling decision. +// This entity is refered to a rule in Odigos terminology for head-sampling. +type AttributesAndSamplerRule struct { + AttributeConditions []AttributeCondition `json:"attributeConditions"` + // The fraction of spans to sample, in the range [0, 1]. + // If the fraction is 0, no spans are sampled. + // If the fraction is 1, all spans are sampled. + // +kubebuilder:default:=1 + Fraction float64 `json:"fraction"` +} + +// HeadSamplingConfig is a set of attribute rules. +// The first attribute rule that evaluates to true is used to determine the sampling decision based on its fraction. +// +// If none of the rules evaluate to true, the fallback fraction is used to determine the sampling decision. +type HeadSamplingConfig struct { + AttributesAndSamplerRules []AttributesAndSamplerRule `json:"attributesAndSamplerRules"` + // Used as a fallback if all rules evaluate to false, + // it may be empty - in this case the default value will be 1 - all spans are sampled. + // it should be a float value in the range [0, 1] - the fraction of spans to sample. + // a value of 0 means no spans are sampled if none of the rules evaluate to true. + // +kubebuilder:default:=1 + FallbackFraction float64 `json:"fallbackFraction"` } type InstrumentationLibraryConfig struct { - // The name of the instrumentation library - // - Node.js: The name of the npm package: `@opentelemetry/instrumentation-` - InstrumentationLibraryName string `json:"instrumentationLibraryName"` + InstrumentationLibraryId InstrumentationLibraryId `json:"libraryId"` TraceConfig *InstrumentationLibraryConfigTraces `json:"traceConfig,omitempty"` } +type InstrumentationLibraryId struct { + // The name of the instrumentation library + // - Node.js: The name of the npm package: `@opentelemetry/instrumentation-` + InstrumentationLibraryName string `json:"libraryName"` + // SpanKind is only supported by Golang and will be ignored for any other SDK language. + // In Go, SpanKind is used because the same instrumentation library can be utilized for different span kinds (e.g., client/server). + SpanKind common.SpanKind `json:"spanKind,omitempty"` +} + type InstrumentationLibraryConfigTraces struct { // Whether the instrumentation library is enabled to record traces. // When false, it is expected that the instrumentation library does not produce any spans regardless of any other configuration. diff --git a/api/odigos/v1alpha1/zz_generated.deepcopy.go b/api/odigos/v1alpha1/zz_generated.deepcopy.go index ae2bf71d2..417c21da1 100644 --- a/api/odigos/v1alpha1/zz_generated.deepcopy.go +++ b/api/odigos/v1alpha1/zz_generated.deepcopy.go @@ -42,6 +42,41 @@ func (in *Attribute) DeepCopy() *Attribute { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AttributeCondition) DeepCopyInto(out *AttributeCondition) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AttributeCondition. +func (in *AttributeCondition) DeepCopy() *AttributeCondition { + if in == nil { + return nil + } + out := new(AttributeCondition) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AttributesAndSamplerRule) DeepCopyInto(out *AttributesAndSamplerRule) { + *out = *in + if in.AttributeConditions != nil { + in, out := &in.AttributeConditions, &out.AttributeConditions + *out = make([]AttributeCondition, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AttributesAndSamplerRule. +func (in *AttributesAndSamplerRule) DeepCopy() *AttributesAndSamplerRule { + if in == nil { + return nil + } + out := new(AttributesAndSamplerRule) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *CollectorGatewayConfiguration) DeepCopyInto(out *CollectorGatewayConfiguration) { *out = *in @@ -294,6 +329,28 @@ func (in *EnvVar) DeepCopy() *EnvVar { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HeadSamplingConfig) DeepCopyInto(out *HeadSamplingConfig) { + *out = *in + if in.AttributesAndSamplerRules != nil { + in, out := &in.AttributesAndSamplerRules, &out.AttributesAndSamplerRules + *out = make([]AttributesAndSamplerRule, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HeadSamplingConfig. +func (in *HeadSamplingConfig) DeepCopy() *HeadSamplingConfig { + if in == nil { + return nil + } + out := new(HeadSamplingConfig) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *InstrumentationConfig) DeepCopyInto(out *InstrumentationConfig) { *out = *in @@ -511,6 +568,7 @@ func (in *InstrumentationLibrary) DeepCopy() *InstrumentationLibrary { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *InstrumentationLibraryConfig) DeepCopyInto(out *InstrumentationLibraryConfig) { *out = *in + out.InstrumentationLibraryId = in.InstrumentationLibraryId if in.TraceConfig != nil { in, out := &in.TraceConfig, &out.TraceConfig *out = new(InstrumentationLibraryConfigTraces) @@ -548,6 +606,21 @@ func (in *InstrumentationLibraryConfigTraces) DeepCopy() *InstrumentationLibrary return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *InstrumentationLibraryId) DeepCopyInto(out *InstrumentationLibraryId) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InstrumentationLibraryId. +func (in *InstrumentationLibraryId) DeepCopy() *InstrumentationLibraryId { + if in == nil { + return nil + } + out := new(InstrumentationLibraryId) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *InstrumentationLibraryOptions) DeepCopyInto(out *InstrumentationLibraryOptions) { *out = *in @@ -972,6 +1045,7 @@ func (in *SdkConfig) DeepCopyInto(out *SdkConfig) { (*in)[i].DeepCopyInto(&(*out)[i]) } } + in.HeadSamplingConfig.DeepCopyInto(&out.HeadSamplingConfig) } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SdkConfig. diff --git a/opampserver/pkg/sdkconfig/configsections/instrumentationlibraries.go b/opampserver/pkg/sdkconfig/configsections/instrumentationlibraries.go index 8e069aa87..975779278 100644 --- a/opampserver/pkg/sdkconfig/configsections/instrumentationlibraries.go +++ b/opampserver/pkg/sdkconfig/configsections/instrumentationlibraries.go @@ -30,7 +30,7 @@ func CalcInstrumentationLibrariesRemoteConfig(ctx context.Context, kubeClient cl } instrumentationLibrariesConfig = append(instrumentationLibrariesConfig, RemoteConfigInstrumentationLibrary{ - Name: instrumentationConfig.InstrumentationLibraryName, + Name: instrumentationConfig.InstrumentationLibraryId.InstrumentationLibraryName, Traces: RemoteConfigInstrumentationLibraryTraces{ Enabled: tracesEnabled, }, From 8b286ad58f71979a3affed8cde3b3a65e249a95c Mon Sep 17 00:00:00 2001 From: yodigos Date: Mon, 19 Aug 2024 09:43:49 +0300 Subject: [PATCH 2/2] feat: Recognizing Nginx Apps (#1453) --- .../odigos.io_instrumentationconfigs.yaml | 2 ++ .../odigos.io_instrumentedapplications.yaml | 1 + common/lang_detection.go | 3 ++- procdiscovery/pkg/inspectors/langdetect.go | 2 ++ procdiscovery/pkg/inspectors/nginx/nginx.go | 24 +++++++++++++++++++ 5 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 procdiscovery/pkg/inspectors/nginx/nginx.go diff --git a/api/config/crd/bases/odigos.io_instrumentationconfigs.yaml b/api/config/crd/bases/odigos.io_instrumentationconfigs.yaml index ce772b872..6eaec9bcb 100644 --- a/api/config/crd/bases/odigos.io_instrumentationconfigs.yaml +++ b/api/config/crd/bases/odigos.io_instrumentationconfigs.yaml @@ -75,6 +75,7 @@ spec: - dotnet - javascript - mysql + - nginx - unknown - ignored type: string @@ -236,6 +237,7 @@ spec: - dotnet - javascript - mysql + - nginx - unknown - ignored type: string diff --git a/api/config/crd/bases/odigos.io_instrumentedapplications.yaml b/api/config/crd/bases/odigos.io_instrumentedapplications.yaml index 4f1f5310d..7d59771af 100644 --- a/api/config/crd/bases/odigos.io_instrumentedapplications.yaml +++ b/api/config/crd/bases/odigos.io_instrumentedapplications.yaml @@ -110,6 +110,7 @@ spec: - dotnet - javascript - mysql + - nginx - unknown - ignored type: string diff --git a/common/lang_detection.go b/common/lang_detection.go index a1cfe0ec2..c5bd4f135 100644 --- a/common/lang_detection.go +++ b/common/lang_detection.go @@ -5,7 +5,7 @@ type ProgramLanguageDetails struct { RuntimeVersion string } -// +kubebuilder:validation:Enum=java;python;go;dotnet;javascript;mysql;unknown;ignored +// +kubebuilder:validation:Enum=java;python;go;dotnet;javascript;mysql;nginx;unknown;ignored type ProgrammingLanguage string const ( @@ -17,6 +17,7 @@ const ( // This is an experimental feature, It is not a language // but in order to avoid huge refactoring we are adding it here for now MySQLProgrammingLanguage ProgrammingLanguage = "mysql" + NginxProgrammingLanguage ProgrammingLanguage = "nginx" // Used when the language detection is not successful for all the available inspectors UnknownProgrammingLanguage ProgrammingLanguage = "unknown" // Ignored is used when the odigos is configured to ignore the process/container diff --git a/procdiscovery/pkg/inspectors/langdetect.go b/procdiscovery/pkg/inspectors/langdetect.go index 8b114a2ee..5fd1d81d8 100644 --- a/procdiscovery/pkg/inspectors/langdetect.go +++ b/procdiscovery/pkg/inspectors/langdetect.go @@ -2,6 +2,7 @@ package inspectors import ( "fmt" + "github.com/odigos-io/odigos/procdiscovery/pkg/inspectors/nginx" "github.com/odigos-io/odigos/common" "github.com/odigos-io/odigos/procdiscovery/pkg/inspectors/dotnet" @@ -32,6 +33,7 @@ var inspectorsList = []inspector{ &dotnet.DotnetInspector{}, &nodejs.NodejsInspector{}, &mysql.MySQLInspector{}, + &nginx.NginxInspector{}, } // DetectLanguage returns the detected language for the process or diff --git a/procdiscovery/pkg/inspectors/nginx/nginx.go b/procdiscovery/pkg/inspectors/nginx/nginx.go new file mode 100644 index 000000000..bb3722cc9 --- /dev/null +++ b/procdiscovery/pkg/inspectors/nginx/nginx.go @@ -0,0 +1,24 @@ +package nginx + +import ( + "strings" + + "github.com/odigos-io/odigos/common" + "github.com/odigos-io/odigos/procdiscovery/pkg/process" +) + +// This is an experimental feature, It is not a language +// but in order to avoid huge refactoring we are adding it as a language for now +type NginxInspector struct{} + +const NginxProcessName = "nginx" + +func (j *NginxInspector) Inspect(p *process.Details) (common.ProgramLanguageDetails, bool) { + var programLanguageDetails common.ProgramLanguageDetails + if strings.Contains(p.CmdLine, NginxProcessName) || strings.Contains(p.ExeName, NginxProcessName) { + programLanguageDetails.Language = common.NginxProgrammingLanguage + return programLanguageDetails, true + } + + return programLanguageDetails, false +}