diff --git a/core/monitoring/utils.go b/core/monitoring/utils.go index 0c522b3c63f..ddff32542ee 100644 --- a/core/monitoring/utils.go +++ b/core/monitoring/utils.go @@ -3,7 +3,7 @@ package monitoring import "go.opentelemetry.io/otel/attribute" func KvMapToOtelAttributes(kvmap map[string]string) []attribute.KeyValue { - otelKVs := make([]attribute.KeyValue, len(kvmap)) + otelKVs := make([]attribute.KeyValue, 0, len(kvmap)) for k, v := range kvmap { otelKVs = append(otelKVs, attribute.String(k, v)) } diff --git a/core/monitoring/utils_test.go b/core/monitoring/utils_test.go index 1fb7f012993..8403964b0b9 100644 --- a/core/monitoring/utils_test.go +++ b/core/monitoring/utils_test.go @@ -1,7 +1,48 @@ package monitoring -import "testing" +import ( + "github.com/stretchr/testify/assert" + "go.opentelemetry.io/otel/attribute" + "testing" +) -func Test_KvMapToOtelAttributes(t *testing.T) { +func TestKvMapToOtelAttributes(t *testing.T) { + tests := []struct { + name string + input map[string]string + expected []attribute.KeyValue + }{ + { + name: "empty map", + input: map[string]string{}, + expected: []attribute.KeyValue{}, + }, + { + name: "single key-value pair", + input: map[string]string{ + "key1": "value1", + }, + expected: []attribute.KeyValue{ + attribute.String("key1", "value1"), + }, + }, + { + name: "multiple key-value pairs", + input: map[string]string{ + "key1": "value1", + "key2": "value2", + }, + expected: []attribute.KeyValue{ + attribute.String("key1", "value1"), + attribute.String("key2", "value2"), + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := KvMapToOtelAttributes(tt.input) + assert.ElementsMatch(t, tt.expected, result, "unexpected KeyValue slice") + }) + } } diff --git a/core/scripts/go.mod b/core/scripts/go.mod index e2ed341146c..01fa94cf864 100644 --- a/core/scripts/go.mod +++ b/core/scripts/go.mod @@ -24,7 +24,7 @@ require ( github.com/prometheus/client_golang v1.20.0 github.com/shopspring/decimal v1.4.0 github.com/smartcontractkit/chainlink-automation v0.8.0 - github.com/smartcontractkit/chainlink-common v0.3.1-0.20241014122810-6c3cc4d0dc87 + github.com/smartcontractkit/chainlink-common v0.3.1-0.20241015212658-06ab6c310f4d github.com/smartcontractkit/chainlink/integration-tests v0.0.0-00010101000000-000000000000 github.com/smartcontractkit/chainlink/v2 v2.0.0-00010101000000-000000000000 github.com/smartcontractkit/libocr v0.0.0-20241007185508-adbe57025f12 diff --git a/core/scripts/go.sum b/core/scripts/go.sum index a523c075b2e..f6bc5d5e568 100644 --- a/core/scripts/go.sum +++ b/core/scripts/go.sum @@ -1076,6 +1076,7 @@ github.com/smartcontractkit/chainlink-ccip v0.0.0-20241014104242-9227e5c976a7 h1 github.com/smartcontractkit/chainlink-ccip v0.0.0-20241014104242-9227e5c976a7/go.mod h1:H4BTXnZBhwRdsAFjqWZpB1/f3IZnuB/Ql7pXPmokzXg= github.com/smartcontractkit/chainlink-common v0.3.1-0.20241014122810-6c3cc4d0dc87 h1:48qauRZcdxAOrgeko4RTm9ti4GGbSfzkcI4Dr/1FmjU= github.com/smartcontractkit/chainlink-common v0.3.1-0.20241014122810-6c3cc4d0dc87/go.mod h1:tsGgeEJc5SUSlfVGSX0wR0EkRU3pM58D6SKF97V68ko= +github.com/smartcontractkit/chainlink-common v0.3.1-0.20241015212658-06ab6c310f4d/go.mod h1:tsGgeEJc5SUSlfVGSX0wR0EkRU3pM58D6SKF97V68ko= github.com/smartcontractkit/chainlink-cosmos v0.5.1 h1:2xeZWh+4/w7xalTdAu8jqgFuxZ291aYTEwZhlQEv/BY= github.com/smartcontractkit/chainlink-cosmos v0.5.1/go.mod h1:c1wUtVxXUqW4PzuCQhuHaBDZFv9XAQjhKTqam7GLGIU= github.com/smartcontractkit/chainlink-data-streams v0.1.0 h1:wcRJRm7eqfbgN+Na+GjAe0/IUn6XwmSagFHqIWHHBGk= diff --git a/core/services/workflows/utils.go b/core/services/workflows/utils.go deleted file mode 100644 index f1d753660cf..00000000000 --- a/core/services/workflows/utils.go +++ /dev/null @@ -1,129 +0,0 @@ -package workflows - -import ( - "context" - "fmt" - "github.com/smartcontractkit/chainlink/v2/core/monitoring" - "go.opentelemetry.io/otel/attribute" - "reflect" -) - -type workflowContextKey struct{} - -var keystoneContextKey = workflowContextKey{} - -type KeystoneWorkflowLabels struct { - WorkflowExecutionID string - WorkflowID string -} - -func (k *KeystoneWorkflowLabels) ToMap() map[string]string { - labels := make(map[string]string) - - labels[monitoring.wIDKey] = k.WorkflowID - labels[monitoring.eIDKey] = k.WorkflowExecutionID - - return labels -} - -func (k *KeystoneWorkflowLabels) ToOtelAttributes() []attribute.KeyValue { - return []attribute.KeyValue{ - attribute.String(monitoring.wIDKey, k.WorkflowID), - attribute.String(monitoring.eIDKey, k.WorkflowExecutionID), - } -} - -// GetKeystoneLabelsFromContext extracts the KeystoneWorkflowLabels struct set on the -// unexported keystoneContextKey. Call NewKeystoneContext first before usage - -// if the key is unset or the value is not of the expected type GetKeystoneLabelsFromContext will error. -func GetKeystoneLabelsFromContext(ctx context.Context) (KeystoneWorkflowLabels, error) { - curLabelsAny := ctx.Value(keystoneContextKey) - curLabels, ok := curLabelsAny.(KeystoneWorkflowLabels) - if !ok { - return KeystoneWorkflowLabels{}, fmt.Errorf("context value with keystoneContextKey is not of type KeystoneWorkflowLabels") - } - - return curLabels, nil -} - -// NewKeystoneContext returns a context with the keystoneContextKey loaded. This enables -// the context to be consumed by GetKeystoneLabelsFromContext and KeystoneContextWithLabel. -// labels should not be nil. -func NewKeystoneContext(ctx context.Context, labels KeystoneWorkflowLabels) context.Context { - return context.WithValue(ctx, keystoneContextKey, labels) -} - -// KeystoneContextWithLabel extracts the Keystone Labels set on the passed in immutable context, -// sets the new desired label if valid, and then returns a new context with the updated labels -func KeystoneContextWithLabel(ctx context.Context, key string, value string) (context.Context, error) { - curLabels, err := GetKeystoneLabelsFromContext(ctx) - if err != nil { - return nil, err - } - - if monitoring.labelsMap[key] == nil { - return nil, fmt.Errorf("key %v is not a valid keystone label", key) - } - - reflectedLabels := reflect.ValueOf(&curLabels).Elem() - reflectedLabels.FieldByName(key).SetString(value) - - newLabels := reflectedLabels.Interface().(KeystoneWorkflowLabels) - return context.WithValue(ctx, keystoneContextKey, newLabels), nil -} - -// KeystoneContextWithLabels extracts the Keystone Labels set on the passed in immutable context, -// sets the new desired labels if valid, and then returns a new context with the updated labels -func KeystoneContextWithLabels(ctx context.Context, keyValues ...string) (context.Context, error) { - if len(keyValues)%2 != 0 { - return nil, fmt.Errorf("keyValues must be provided in key-value pairs") - } - - curLabels, err := GetKeystoneLabelsFromContext(ctx) - if err != nil { - return nil, err - } - - reflectedLabels := reflect.ValueOf(&curLabels).Elem() - - for i := 0; i < len(keyValues); i += 2 { - key := keyValues[i] - value := keyValues[i+1] - - if monitoring.labelsMap[key] == nil { - return nil, fmt.Errorf("key %v is not a valid keystone label", key) - } - - reflectedLabels.FieldByName(key).SetString(value) - } - - newLabels := reflectedLabels.Interface().(KeystoneWorkflowLabels) - return context.WithValue(ctx, keystoneContextKey, newLabels), nil -} - -func composeLabeledMsg(ctx context.Context, msg string) (string, error) { - structLabels, err := GetKeystoneLabelsFromContext(ctx) - if err != nil { - return "", fmt.Errorf("composing labeled message failed: %w", err) - } - - labels := structLabels.ToMap() - - // Populate labeled message in reverse - numLabels := len(monitoring.orderedLabelKeys) - for i := range numLabels { - msg = fmt.Sprintf("%v.%v", labels[monitoring.orderedLabelKeys[numLabels-1-i]], msg) - } - - return msg, nil -} - -func getOtelAttributesFromCtx(ctx context.Context) ([]attribute.KeyValue, error) { - labelsStruct, err := GetKeystoneLabelsFromContext(ctx) - if err != nil { - return nil, err - } - - otelLabels := labelsStruct.ToOtelAttributes() - return otelLabels, nil -} diff --git a/core/services/workflows/utils_test.go b/core/services/workflows/utils_test.go deleted file mode 100644 index 470b3b306ba..00000000000 --- a/core/services/workflows/utils_test.go +++ /dev/null @@ -1,54 +0,0 @@ -package workflows - -import ( - "fmt" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - "github.com/smartcontractkit/chainlink/v2/core/monitoring" - "github.com/stretchr/testify/require" - "testing" -) - -func Test_KeystoneContextLabels(t *testing.T) { - ctx := testutils.Context(t) - - expValues := KeystoneWorkflowLabels{ - WorkflowID: fmt.Sprintf("Test%v", monitoring.wIDKey), - WorkflowExecutionID: fmt.Sprintf("Test%v", monitoring.eIDKey), - } - hydratedContext1 := NewKeystoneContext(ctx, expValues) - - actValues, err := GetKeystoneLabelsFromContext(hydratedContext1) - require.NoError(t, err) - require.Equal(t, expValues.WorkflowID, actValues.WorkflowID) - require.Equal(t, expValues.WorkflowExecutionID, actValues.WorkflowExecutionID) - - hydratedContext2 := NewKeystoneContext(ctx, KeystoneWorkflowLabels{}) - hydratedContext2a, err := KeystoneContextWithLabel(hydratedContext2, monitoring.wIDKey, fmt.Sprintf("Test%v", monitoring.wIDKey)) - require.NoError(t, err) - actValues2, err := GetKeystoneLabelsFromContext(hydratedContext2a) - require.NoError(t, err) - require.Equal(t, expValues.WorkflowID, actValues2.WorkflowID) - -} - -func Test_ComposeLabeledMsg(t *testing.T) { - unlabeledMsgFormat := "test message: %v" - unlabeledMsgVal := fmt.Errorf("test error: %d", 0) - unlabeledMsg := fmt.Sprintf(unlabeledMsgFormat, unlabeledMsgVal) - - testWorkflowId := "TestWorkflowID" - testWorkflowExecutionId := "TestWorkflowExecutionID" - - ctx := testutils.Context(t) - labeledCtx := NewKeystoneContext(ctx, KeystoneWorkflowLabels{ - WorkflowID: testWorkflowId, - WorkflowExecutionID: testWorkflowExecutionId, - }) - - actualLabeledMsg, err := composeLabeledMsg(labeledCtx, unlabeledMsg) - require.NoError(t, err) - - expectedLabeledMsg := fmt.Sprintf("%v.%v.%v", testWorkflowId, testWorkflowExecutionId, unlabeledMsg) - require.Equal(t, expectedLabeledMsg, actualLabeledMsg) - -} diff --git a/integration-tests/go.mod b/integration-tests/go.mod index 3fd83398ead..068bd567558 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -40,7 +40,7 @@ require ( github.com/smartcontractkit/chain-selectors v1.0.27 github.com/smartcontractkit/chainlink-automation v0.8.0 github.com/smartcontractkit/chainlink-ccip v0.0.0-20241014104242-9227e5c976a7 - github.com/smartcontractkit/chainlink-common v0.3.1-0.20241014122810-6c3cc4d0dc87 + github.com/smartcontractkit/chainlink-common v0.3.1-0.20241015212658-06ab6c310f4d github.com/smartcontractkit/chainlink-testing-framework/havoc v1.50.0 github.com/smartcontractkit/chainlink-testing-framework/lib v1.50.11-0.20241011153842-b2804aed25b4 github.com/smartcontractkit/chainlink-testing-framework/lib/grafana v1.50.0 diff --git a/integration-tests/go.sum b/integration-tests/go.sum index 4be605913fb..665a2ec21d2 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -1406,6 +1406,7 @@ github.com/smartcontractkit/chainlink-ccip v0.0.0-20241014104242-9227e5c976a7 h1 github.com/smartcontractkit/chainlink-ccip v0.0.0-20241014104242-9227e5c976a7/go.mod h1:H4BTXnZBhwRdsAFjqWZpB1/f3IZnuB/Ql7pXPmokzXg= github.com/smartcontractkit/chainlink-common v0.3.1-0.20241014122810-6c3cc4d0dc87 h1:48qauRZcdxAOrgeko4RTm9ti4GGbSfzkcI4Dr/1FmjU= github.com/smartcontractkit/chainlink-common v0.3.1-0.20241014122810-6c3cc4d0dc87/go.mod h1:tsGgeEJc5SUSlfVGSX0wR0EkRU3pM58D6SKF97V68ko= +github.com/smartcontractkit/chainlink-common v0.3.1-0.20241015212658-06ab6c310f4d/go.mod h1:tsGgeEJc5SUSlfVGSX0wR0EkRU3pM58D6SKF97V68ko= github.com/smartcontractkit/chainlink-cosmos v0.5.1 h1:2xeZWh+4/w7xalTdAu8jqgFuxZ291aYTEwZhlQEv/BY= github.com/smartcontractkit/chainlink-cosmos v0.5.1/go.mod h1:c1wUtVxXUqW4PzuCQhuHaBDZFv9XAQjhKTqam7GLGIU= github.com/smartcontractkit/chainlink-data-streams v0.1.0 h1:wcRJRm7eqfbgN+Na+GjAe0/IUn6XwmSagFHqIWHHBGk= diff --git a/integration-tests/load/go.mod b/integration-tests/load/go.mod index 2cba6de8bdd..e1db3509dcb 100644 --- a/integration-tests/load/go.mod +++ b/integration-tests/load/go.mod @@ -15,7 +15,7 @@ require ( github.com/pkg/errors v0.9.1 github.com/rs/zerolog v1.33.0 github.com/slack-go/slack v0.12.2 - github.com/smartcontractkit/chainlink-common v0.3.1-0.20241014122810-6c3cc4d0dc87 + github.com/smartcontractkit/chainlink-common v0.3.1-0.20241015212658-06ab6c310f4d github.com/smartcontractkit/chainlink-testing-framework/lib v1.50.11-0.20241011153842-b2804aed25b4 github.com/smartcontractkit/chainlink-testing-framework/seth v1.50.1 github.com/smartcontractkit/chainlink-testing-framework/wasp v1.50.0 diff --git a/integration-tests/load/go.sum b/integration-tests/load/go.sum index 08971a251d6..563eb5e7be9 100644 --- a/integration-tests/load/go.sum +++ b/integration-tests/load/go.sum @@ -1383,6 +1383,7 @@ github.com/smartcontractkit/chainlink-ccip v0.0.0-20241014104242-9227e5c976a7 h1 github.com/smartcontractkit/chainlink-ccip v0.0.0-20241014104242-9227e5c976a7/go.mod h1:H4BTXnZBhwRdsAFjqWZpB1/f3IZnuB/Ql7pXPmokzXg= github.com/smartcontractkit/chainlink-common v0.3.1-0.20241014122810-6c3cc4d0dc87 h1:48qauRZcdxAOrgeko4RTm9ti4GGbSfzkcI4Dr/1FmjU= github.com/smartcontractkit/chainlink-common v0.3.1-0.20241014122810-6c3cc4d0dc87/go.mod h1:tsGgeEJc5SUSlfVGSX0wR0EkRU3pM58D6SKF97V68ko= +github.com/smartcontractkit/chainlink-common v0.3.1-0.20241015212658-06ab6c310f4d/go.mod h1:tsGgeEJc5SUSlfVGSX0wR0EkRU3pM58D6SKF97V68ko= github.com/smartcontractkit/chainlink-cosmos v0.5.1 h1:2xeZWh+4/w7xalTdAu8jqgFuxZ291aYTEwZhlQEv/BY= github.com/smartcontractkit/chainlink-cosmos v0.5.1/go.mod h1:c1wUtVxXUqW4PzuCQhuHaBDZFv9XAQjhKTqam7GLGIU= github.com/smartcontractkit/chainlink-data-streams v0.1.0 h1:wcRJRm7eqfbgN+Na+GjAe0/IUn6XwmSagFHqIWHHBGk=