From 3b846d626174288a76bca4db489c3e3e87c00bfc Mon Sep 17 00:00:00 2001 From: Bhavna Jindal Date: Mon, 28 Oct 2024 12:06:36 -0700 Subject: [PATCH 01/10] Add PID as an attribute in each sample --- reporter/otlp_reporter.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/reporter/otlp_reporter.go b/reporter/otlp_reporter.go index ec08578e..d2a8d95a 100644 --- a/reporter/otlp_reporter.go +++ b/reporter/otlp_reporter.go @@ -81,6 +81,7 @@ type traceEvents struct { mappingEnds []libpf.Address mappingFileOffsets []uint64 timestamps []uint64 // in nanoseconds + pid uint64 } // attrKeyValue is a helper to populate Profile.attribute_table. @@ -185,6 +186,7 @@ func (r *OTLPReporter) ReportTraceEvent(trace *libpf.Trace, meta *TraceEventMeta mappingEnds: trace.MappingEnd, mappingFileOffsets: trace.MappingFileOffsets, timestamps: []uint64{uint64(meta.Timestamp)}, + pid: uint64(meta.PID), } } @@ -652,6 +654,7 @@ func (r *OTLPReporter) getProfile() (profile *profiles.Profile, startTS, endTS u {key: string(semconv.ContainerIDKey), value: traceKey.containerID}, {key: string(semconv.ThreadNameKey), value: traceKey.comm}, {key: string(semconv.ServiceNameKey), value: traceKey.apmServiceName}, + {key: string(semconv.ProcessPIDKey), value: strconv.FormatUint(traceInfo.pid, 10)}, }, attributeMap) sample.LocationsLength = uint64(len(traceInfo.frameTypes)) locationIndex += sample.LocationsLength From eab2981c5433f618445d304ee3de2808423e2a40 Mon Sep 17 00:00:00 2001 From: Bhavna Jindal Date: Tue, 29 Oct 2024 06:25:26 -0700 Subject: [PATCH 02/10] use traceAndMetaKey to store PID --- reporter/otlp_reporter.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/reporter/otlp_reporter.go b/reporter/otlp_reporter.go index d2a8d95a..e0f00087 100644 --- a/reporter/otlp_reporter.go +++ b/reporter/otlp_reporter.go @@ -70,6 +70,7 @@ type traceAndMetaKey struct { apmServiceName string // containerID is annotated based on PID information containerID string + pid string } // traceEvents holds known information about a trace. @@ -81,7 +82,6 @@ type traceEvents struct { mappingEnds []libpf.Address mappingFileOffsets []uint64 timestamps []uint64 // in nanoseconds - pid uint64 } // attrKeyValue is a helper to populate Profile.attribute_table. @@ -170,6 +170,7 @@ func (r *OTLPReporter) ReportTraceEvent(trace *libpf.Trace, meta *TraceEventMeta comm: meta.Comm, apmServiceName: meta.APMServiceName, containerID: containerID, + pid: strconv.FormatUint(uint64(meta.PID), 10), } if events, exists := (*traceEventsMap)[key]; exists { @@ -186,7 +187,6 @@ func (r *OTLPReporter) ReportTraceEvent(trace *libpf.Trace, meta *TraceEventMeta mappingEnds: trace.MappingEnd, mappingFileOffsets: trace.MappingFileOffsets, timestamps: []uint64{uint64(meta.Timestamp)}, - pid: uint64(meta.PID), } } @@ -654,7 +654,7 @@ func (r *OTLPReporter) getProfile() (profile *profiles.Profile, startTS, endTS u {key: string(semconv.ContainerIDKey), value: traceKey.containerID}, {key: string(semconv.ThreadNameKey), value: traceKey.comm}, {key: string(semconv.ServiceNameKey), value: traceKey.apmServiceName}, - {key: string(semconv.ProcessPIDKey), value: strconv.FormatUint(traceInfo.pid, 10)}, + {key: string(semconv.ProcessPIDKey), value: traceKey.pid}, }, attributeMap) sample.LocationsLength = uint64(len(traceInfo.frameTypes)) locationIndex += sample.LocationsLength From 12b35c18e1cdf2a72a24c592c6536dcd4bee3d67 Mon Sep 17 00:00:00 2001 From: Bhavna Jindal Date: Fri, 1 Nov 2024 07:24:28 -0700 Subject: [PATCH 03/10] Addition to testcase for pid as an attribute in sample --- reporter/otlp_reporter_test.go | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/reporter/otlp_reporter_test.go b/reporter/otlp_reporter_test.go index d9c2844f..e64c13d2 100644 --- a/reporter/otlp_reporter_test.go +++ b/reporter/otlp_reporter_test.go @@ -26,6 +26,7 @@ func TestGetSampleAttributes(t *testing.T) { comm: "", apmServiceName: "", containerID: "", + pid: "", }, }, attributeMap: make(map[string]uint64), @@ -40,16 +41,18 @@ func TestGetSampleAttributes(t *testing.T) { comm: "comm1", apmServiceName: "apmServiceName1", containerID: "containerID1", + pid: "pid1", }, { hash: libpf.TraceHash{}, comm: "comm1", apmServiceName: "apmServiceName1", containerID: "containerID1", + pid: "pid1", }, }, attributeMap: make(map[string]uint64), - expectedIndices: [][]uint64{{0, 1, 2}, {0, 1, 2}}, + expectedIndices: [][]uint64{{0, 1, 2, 3}, {0, 1, 2, 3}}, expectedAttributeTable: []*common.KeyValue{ { Key: "container.id", @@ -69,6 +72,12 @@ func TestGetSampleAttributes(t *testing.T) { Value: &common.AnyValue_StringValue{StringValue: "apmServiceName1"}, }, }, + { + Key: "process.pid", + Value: &common.AnyValue{ + Value: &common.AnyValue_StringValue{StringValue: "pid1"}, + }, + }, }, }, "different": { @@ -79,16 +88,18 @@ func TestGetSampleAttributes(t *testing.T) { comm: "comm1", apmServiceName: "apmServiceName1", containerID: "containerID1", + pid: "pid1", }, { hash: libpf.TraceHash{}, comm: "comm2", apmServiceName: "apmServiceName2", containerID: "containerID2", + pid: "pid2", }, }, attributeMap: make(map[string]uint64), - expectedIndices: [][]uint64{{0, 1, 2}, {3, 4, 5}}, + expectedIndices: [][]uint64{{0, 1, 2, 3}, {4, 5, 6, 7}}, expectedAttributeTable: []*common.KeyValue{ { Key: "container.id", @@ -108,6 +119,12 @@ func TestGetSampleAttributes(t *testing.T) { Value: &common.AnyValue_StringValue{StringValue: "apmServiceName1"}, }, }, + { + Key: "process.pid", + Value: &common.AnyValue{ + Value: &common.AnyValue_StringValue{StringValue: "pid1"}, + }, + }, { Key: "container.id", Value: &common.AnyValue{ @@ -126,6 +143,12 @@ func TestGetSampleAttributes(t *testing.T) { Value: &common.AnyValue_StringValue{StringValue: "apmServiceName2"}, }, }, + { + Key: "process.pid", + Value: &common.AnyValue{ + Value: &common.AnyValue_StringValue{StringValue: "pid2"}, + }, + }, }, }, } @@ -140,6 +163,7 @@ func TestGetSampleAttributes(t *testing.T) { {key: string(semconv.ContainerIDKey), value: k.containerID}, {key: string(semconv.ThreadNameKey), value: k.comm}, {key: string(semconv.ServiceNameKey), value: k.apmServiceName}, + {key: string(semconv.ProcessPIDKey), value: k.pid}, }, tc.attributeMap)) } require.Equal(t, tc.expectedIndices, indices) From 5cd8eb075a43cb494dbe64a6847fec755568f0eb Mon Sep 17 00:00:00 2001 From: Bhavna Jindal Date: Mon, 4 Nov 2024 07:39:19 -0800 Subject: [PATCH 04/10] update addProfileAttributes to support intValue --- reporter/otlp_reporter.go | 33 +++++++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/reporter/otlp_reporter.go b/reporter/otlp_reporter.go index e0f00087..745f38fe 100644 --- a/reporter/otlp_reporter.go +++ b/reporter/otlp_reporter.go @@ -11,6 +11,7 @@ import ( "fmt" "maps" "os" + "reflect" "regexp" "slices" "strconv" @@ -70,7 +71,7 @@ type traceAndMetaKey struct { apmServiceName string // containerID is annotated based on PID information containerID string - pid string + pid int64 } // traceEvents holds known information about a trace. @@ -87,7 +88,7 @@ type traceEvents struct { // attrKeyValue is a helper to populate Profile.attribute_table. type attrKeyValue struct { key string - value string + value any } // OTLPReporter receives and transforms information to be OTLP/profiles compliant. @@ -170,7 +171,7 @@ func (r *OTLPReporter) ReportTraceEvent(trace *libpf.Trace, meta *TraceEventMeta comm: meta.Comm, apmServiceName: meta.APMServiceName, containerID: containerID, - pid: strconv.FormatUint(uint64(meta.PID), 10), + pid: int64(meta.PID), } if events, exists := (*traceEventsMap)[key]; exists { @@ -731,10 +732,30 @@ func addProfileAttributes(profile *profiles.Profile, indices := make([]uint64, 0, len(attributes)) addAttr := func(attr attrKeyValue) { - if attr.value == "" { + var attributeCompositeKey string + var attributeValue common.AnyValue + + valueType := reflect.TypeOf(attr.value) + if valueType != reflect.TypeOf("") && valueType != reflect.TypeOf(int64(0)) { return } - attributeCompositeKey := attr.key + "_" + attr.value + + if valString, ok := attr.value.(string); ok { + if valString == "" { + return + } + attributeCompositeKey = attr.key + "_" + valString + attributeValue = common.AnyValue{Value: &common.AnyValue_StringValue{StringValue: valString}} + } + + if valInt, ok := attr.value.(int64); ok { + if valInt == 0 { + return + } + attributeCompositeKey = attr.key + "_" + strconv.Itoa(int(valInt)) + attributeValue = common.AnyValue{Value: &common.AnyValue_IntValue{IntValue: int64(valInt)}} + } + if attributeIndex, exists := attributeMap[attributeCompositeKey]; exists { indices = append(indices, attributeIndex) return @@ -743,7 +764,7 @@ func addProfileAttributes(profile *profiles.Profile, indices = append(indices, newIndex) profile.AttributeTable = append(profile.AttributeTable, &common.KeyValue{ Key: attr.key, - Value: &common.AnyValue{Value: &common.AnyValue_StringValue{StringValue: attr.value}}, + Value: &attributeValue, }) attributeMap[attributeCompositeKey] = newIndex } From 2a1d9505c19e21f4a61ef4cb9571b7b21017002a Mon Sep 17 00:00:00 2001 From: Bhavna Jindal Date: Mon, 4 Nov 2024 07:39:54 -0800 Subject: [PATCH 05/10] update testcase with pid as int64 --- reporter/otlp_reporter_test.go | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/reporter/otlp_reporter_test.go b/reporter/otlp_reporter_test.go index e64c13d2..3993e397 100644 --- a/reporter/otlp_reporter_test.go +++ b/reporter/otlp_reporter_test.go @@ -26,7 +26,7 @@ func TestGetSampleAttributes(t *testing.T) { comm: "", apmServiceName: "", containerID: "", - pid: "", + pid: 0, }, }, attributeMap: make(map[string]uint64), @@ -41,14 +41,14 @@ func TestGetSampleAttributes(t *testing.T) { comm: "comm1", apmServiceName: "apmServiceName1", containerID: "containerID1", - pid: "pid1", + pid: 1234, }, { hash: libpf.TraceHash{}, comm: "comm1", apmServiceName: "apmServiceName1", containerID: "containerID1", - pid: "pid1", + pid: 1234, }, }, attributeMap: make(map[string]uint64), @@ -75,7 +75,7 @@ func TestGetSampleAttributes(t *testing.T) { { Key: "process.pid", Value: &common.AnyValue{ - Value: &common.AnyValue_StringValue{StringValue: "pid1"}, + Value: &common.AnyValue_IntValue{IntValue: 1234}, }, }, }, @@ -88,14 +88,14 @@ func TestGetSampleAttributes(t *testing.T) { comm: "comm1", apmServiceName: "apmServiceName1", containerID: "containerID1", - pid: "pid1", + pid: 1234, }, { hash: libpf.TraceHash{}, comm: "comm2", apmServiceName: "apmServiceName2", containerID: "containerID2", - pid: "pid2", + pid: 6789, }, }, attributeMap: make(map[string]uint64), @@ -122,7 +122,7 @@ func TestGetSampleAttributes(t *testing.T) { { Key: "process.pid", Value: &common.AnyValue{ - Value: &common.AnyValue_StringValue{StringValue: "pid1"}, + Value: &common.AnyValue_IntValue{IntValue: 1234}, }, }, { @@ -146,7 +146,7 @@ func TestGetSampleAttributes(t *testing.T) { { Key: "process.pid", Value: &common.AnyValue{ - Value: &common.AnyValue_StringValue{StringValue: "pid2"}, + Value: &common.AnyValue_IntValue{IntValue: 6789}, }, }, }, From 5cb3920052ce8616fb17ac0f57c6a733486332a6 Mon Sep 17 00:00:00 2001 From: Bhavna Jindal Date: Mon, 4 Nov 2024 10:22:43 -0800 Subject: [PATCH 06/10] use type assertion instead of reflect package --- reporter/otlp_reporter.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/reporter/otlp_reporter.go b/reporter/otlp_reporter.go index 745f38fe..b7a66b93 100644 --- a/reporter/otlp_reporter.go +++ b/reporter/otlp_reporter.go @@ -11,7 +11,6 @@ import ( "fmt" "maps" "os" - "reflect" "regexp" "slices" "strconv" @@ -735,8 +734,10 @@ func addProfileAttributes(profile *profiles.Profile, var attributeCompositeKey string var attributeValue common.AnyValue - valueType := reflect.TypeOf(attr.value) - if valueType != reflect.TypeOf("") && valueType != reflect.TypeOf(int64(0)) { + switch attr.value.(type) { + case string, int64: + //Supported types, continue to handling below + default: return } From 92013aaef650ba26524e5eed6c7bf76e89b3cd04 Mon Sep 17 00:00:00 2001 From: Bhavna Jindal Date: Tue, 5 Nov 2024 07:20:49 -0800 Subject: [PATCH 07/10] use generics to support IntValue in attributes --- reporter/otlp_reporter.go | 47 +++++++++++++++------------------- reporter/otlp_reporter_test.go | 16 +++++++----- 2 files changed, 31 insertions(+), 32 deletions(-) diff --git a/reporter/otlp_reporter.go b/reporter/otlp_reporter.go index b7a66b93..dd3544d5 100644 --- a/reporter/otlp_reporter.go +++ b/reporter/otlp_reporter.go @@ -85,9 +85,9 @@ type traceEvents struct { } // attrKeyValue is a helper to populate Profile.attribute_table. -type attrKeyValue struct { +type attrKeyValue[T string | int64] struct { key string - value any + value T } // OTLPReporter receives and transforms information to be OTLP/profiles compliant. @@ -552,7 +552,7 @@ func (r *OTLPReporter) getProfile() (profile *profiles.Profile, startTS, endTS u // Walk every frame of the trace. for i := range traceInfo.frameTypes { - frameAttributes := addProfileAttributes(profile, []attrKeyValue{ + frameAttributes := addProfileAttributes(profile, []attrKeyValue[string]{ {key: "profile.frame.type", value: traceInfo.frameTypes[i].String()}, }, attributeMap) @@ -585,7 +585,7 @@ func (r *OTLPReporter) getProfile() (profile *profiles.Profile, startTS, endTS u fileName = execInfo.fileName } - mappingAttributes := addProfileAttributes(profile, []attrKeyValue{ + mappingAttributes := addProfileAttributes(profile, []attrKeyValue[string]{ // Once SemConv and its Go package is released with the new // semantic convention for build_id, replace these hard coded // strings. @@ -650,12 +650,13 @@ func (r *OTLPReporter) getProfile() (profile *profiles.Profile, startTS, endTS u profile.Location = append(profile.Location, loc) } - sample.Attributes = addProfileAttributes(profile, []attrKeyValue{ + sample.Attributes = append(addProfileAttributes(profile, []attrKeyValue[string]{ {key: string(semconv.ContainerIDKey), value: traceKey.containerID}, {key: string(semconv.ThreadNameKey), value: traceKey.comm}, {key: string(semconv.ServiceNameKey), value: traceKey.apmServiceName}, + }, attributeMap), addProfileAttributes(profile, []attrKeyValue[int64]{ {key: string(semconv.ProcessPIDKey), value: traceKey.pid}, - }, attributeMap) + }, attributeMap)...) sample.LocationsLength = uint64(len(traceInfo.frameTypes)) locationIndex += sample.LocationsLength @@ -726,35 +727,29 @@ func createFunctionEntry(funcMap map[funcInfo]uint64, // addProfileAttributes adds attributes to Profile.attribute_table and returns // the indices to these attributes. -func addProfileAttributes(profile *profiles.Profile, - attributes []attrKeyValue, attributeMap map[string]uint64) []uint64 { +func addProfileAttributes[T string | int64](profile *profiles.Profile, + attributes []attrKeyValue[T], attributeMap map[string]uint64) []uint64 { indices := make([]uint64, 0, len(attributes)) - addAttr := func(attr attrKeyValue) { + addAttr := func(attr attrKeyValue[T]) { var attributeCompositeKey string var attributeValue common.AnyValue - switch attr.value.(type) { - case string, int64: - //Supported types, continue to handling below - default: - return - } - - if valString, ok := attr.value.(string); ok { - if valString == "" { + switch val := any(attr.value).(type) { + case string: + if val == "" { return } - attributeCompositeKey = attr.key + "_" + valString - attributeValue = common.AnyValue{Value: &common.AnyValue_StringValue{StringValue: valString}} - } - - if valInt, ok := attr.value.(int64); ok { - if valInt == 0 { + attributeCompositeKey = attr.key + "_" + val + attributeValue = common.AnyValue{Value: &common.AnyValue_StringValue{StringValue: val}} + case int64: + if val == 0 { return } - attributeCompositeKey = attr.key + "_" + strconv.Itoa(int(valInt)) - attributeValue = common.AnyValue{Value: &common.AnyValue_IntValue{IntValue: int64(valInt)}} + attributeCompositeKey = attr.key + "_" + strconv.Itoa(int(val)) + attributeValue = common.AnyValue{Value: &common.AnyValue_IntValue{IntValue: int64(val)}} + default: + return } if attributeIndex, exists := attributeMap[attributeCompositeKey]; exists { diff --git a/reporter/otlp_reporter_test.go b/reporter/otlp_reporter_test.go index 3993e397..ded9d761 100644 --- a/reporter/otlp_reporter_test.go +++ b/reporter/otlp_reporter_test.go @@ -159,12 +159,16 @@ func TestGetSampleAttributes(t *testing.T) { t.Run(name, func(t *testing.T) { indices := make([][]uint64, 0) for _, k := range tc.k { - indices = append(indices, addProfileAttributes(tc.profile, []attrKeyValue{ - {key: string(semconv.ContainerIDKey), value: k.containerID}, - {key: string(semconv.ThreadNameKey), value: k.comm}, - {key: string(semconv.ServiceNameKey), value: k.apmServiceName}, - {key: string(semconv.ProcessPIDKey), value: k.pid}, - }, tc.attributeMap)) + indices = append(indices, append(addProfileAttributes(tc.profile, + []attrKeyValue[string]{ + {key: string(semconv.ContainerIDKey), value: k.containerID}, + {key: string(semconv.ThreadNameKey), value: k.comm}, + {key: string(semconv.ServiceNameKey), value: k.apmServiceName}, + }, tc.attributeMap), + addProfileAttributes(tc.profile, + []attrKeyValue[int64]{ + {key: string(semconv.ProcessPIDKey), value: k.pid}, + }, tc.attributeMap)...)) } require.Equal(t, tc.expectedIndices, indices) require.Equal(t, tc.expectedAttributeTable, tc.profile.AttributeTable) From 80def2230d721ef733b159a842fa9d4c41c2a217 Mon Sep 17 00:00:00 2001 From: Bhavna Jindal Date: Tue, 5 Nov 2024 07:43:38 -0800 Subject: [PATCH 08/10] fix for golangcli-lint. remove unnecessary converion --- reporter/otlp_reporter.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reporter/otlp_reporter.go b/reporter/otlp_reporter.go index dd3544d5..1cb461af 100644 --- a/reporter/otlp_reporter.go +++ b/reporter/otlp_reporter.go @@ -747,7 +747,7 @@ func addProfileAttributes[T string | int64](profile *profiles.Profile, return } attributeCompositeKey = attr.key + "_" + strconv.Itoa(int(val)) - attributeValue = common.AnyValue{Value: &common.AnyValue_IntValue{IntValue: int64(val)}} + attributeValue = common.AnyValue{Value: &common.AnyValue_IntValue{IntValue: val}} default: return } From 82541785fe9c2c25d71bd0b8f02b926b93bc3015 Mon Sep 17 00:00:00 2001 From: Bhavna Jindal Date: Tue, 5 Nov 2024 09:07:49 -0800 Subject: [PATCH 09/10] Add error log and support empty values in attribute --- reporter/otlp_reporter.go | 7 +------ reporter/otlp_reporter_test.go | 31 ++++++++++++++++++++++++++++--- 2 files changed, 29 insertions(+), 9 deletions(-) diff --git a/reporter/otlp_reporter.go b/reporter/otlp_reporter.go index 1cb461af..d01bafb7 100644 --- a/reporter/otlp_reporter.go +++ b/reporter/otlp_reporter.go @@ -737,18 +737,13 @@ func addProfileAttributes[T string | int64](profile *profiles.Profile, switch val := any(attr.value).(type) { case string: - if val == "" { - return - } attributeCompositeKey = attr.key + "_" + val attributeValue = common.AnyValue{Value: &common.AnyValue_StringValue{StringValue: val}} case int64: - if val == 0 { - return - } attributeCompositeKey = attr.key + "_" + strconv.Itoa(int(val)) attributeValue = common.AnyValue{Value: &common.AnyValue_IntValue{IntValue: val}} default: + log.Error("Unsupported attribute value type. Only string and int64 are supported at this time.") return } diff --git a/reporter/otlp_reporter_test.go b/reporter/otlp_reporter_test.go index ded9d761..bdfc22ed 100644 --- a/reporter/otlp_reporter_test.go +++ b/reporter/otlp_reporter_test.go @@ -29,9 +29,34 @@ func TestGetSampleAttributes(t *testing.T) { pid: 0, }, }, - attributeMap: make(map[string]uint64), - expectedIndices: [][]uint64{make([]uint64, 0, 4)}, - expectedAttributeTable: nil, + attributeMap: make(map[string]uint64), + expectedIndices: [][]uint64{{0, 1, 2, 3}}, + expectedAttributeTable: []*common.KeyValue{ + { + Key: "container.id", + Value: &common.AnyValue{ + Value: &common.AnyValue_StringValue{StringValue: ""}, + }, + }, + { + Key: "thread.name", + Value: &common.AnyValue{ + Value: &common.AnyValue_StringValue{StringValue: ""}, + }, + }, + { + Key: "service.name", + Value: &common.AnyValue{ + Value: &common.AnyValue_StringValue{StringValue: ""}, + }, + }, + { + Key: "process.pid", + Value: &common.AnyValue{ + Value: &common.AnyValue_IntValue{IntValue: 0}, + }, + }, + }, }, "duplicate": { profile: &profiles.Profile{}, From 9f1e46634dbf6ab55a1bee4e9bf9099355bbc57a Mon Sep 17 00:00:00 2001 From: Bhavna Jindal Date: Tue, 5 Nov 2024 10:19:41 -0800 Subject: [PATCH 10/10] Fix error msg length --- reporter/otlp_reporter.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reporter/otlp_reporter.go b/reporter/otlp_reporter.go index d01bafb7..fa5cf2d0 100644 --- a/reporter/otlp_reporter.go +++ b/reporter/otlp_reporter.go @@ -743,7 +743,7 @@ func addProfileAttributes[T string | int64](profile *profiles.Profile, attributeCompositeKey = attr.key + "_" + strconv.Itoa(int(val)) attributeValue = common.AnyValue{Value: &common.AnyValue_IntValue{IntValue: val}} default: - log.Error("Unsupported attribute value type. Only string and int64 are supported at this time.") + log.Error("Unsupported attribute value type. Only string and int64 are supported.") return }