diff --git a/sdk/log/record.go b/sdk/log/record.go index 3f6fec5f375..d153fd8b3fd 100644 --- a/sdk/log/record.go +++ b/sdk/log/record.go @@ -27,6 +27,10 @@ var logAttrDropped = sync.OnceFunc(func() { global.Warn("limit reached: dropping log Record attributes") }) +var logKeyValuePairDropped = sync.OnceFunc(func() { + global.Warn("key duplication: dropping key-value pair") +}) + // indexPool is a pool of index maps used for de-duplication. var indexPool = sync.Pool{ New: func() any { return make(map[string]int) }, @@ -100,13 +104,17 @@ type Record struct { } func (r *Record) addDropped(n int) { - logAttrDropped() r.dropped += n + if n > 0 { + logAttrDropped() + } } func (r *Record) setDropped(n int) { - logAttrDropped() r.dropped = n + if n > 0 { + logAttrDropped() + } } // EventName returns the event name. @@ -195,14 +203,15 @@ func (r *Record) AddAttributes(attrs ...log.KeyValue) { if n == 0 { // Avoid the more complex duplicate map lookups below. var drop int + if !r.allowDupKeys { - attrs, drop = dedup(attrs) - r.setDropped(drop) + attrs = dedup(attrs) + r.setDropped(0) } attrs, drop := head(attrs, r.attributeCountLimit) + r.addDropped(drop) - r.addAttrs(attrs) return } @@ -212,33 +221,34 @@ func (r *Record) AddAttributes(attrs ...log.KeyValue) { rIndex := r.attrIndex() defer putIndex(rIndex) - // Unique attrs that need to be added to r. This uses the same underlying - // array as attrs. - // - // Note, do not iterate attrs twice by just calling dedup(attrs) here. - unique := attrs[:0] - // Used to find duplicates within attrs itself. The index value is the - // index of the element in unique. - uIndex := getIndex() - defer putIndex(uIndex) - - // Deduplicate attrs within the scope of all existing attributes. - for _, a := range attrs { - // Last-value-wins for any duplicates in attrs. - idx, found := uIndex[a.Key] - if found { - r.addDropped(1) - unique[idx] = a - continue - } - idx, found = rIndex[a.Key] - if found { - // New attrs overwrite any existing with the same key. - r.addDropped(1) - if idx < 0 { - r.front[-(idx + 1)] = a - } else { + // Unique attrs that need to be added to r. This uses the same underlying + // array as attrs. + // + // Note, do not iterate attrs twice by just calling dedup(attrs) here. + unique := attrs[:0] + // Used to find duplicates within attrs itself. The index value is the + // index of the element in unique. + uIndex := getIndex() + defer putIndex(uIndex) + + // Deduplicate attrs within the scope of all existing attributes. + for _, a := range attrs { + // Last-value-wins for any duplicates in attrs. + idx, found := uIndex[a.Key] + if found { + logKeyValuePairDropped() + unique[idx] = a + continue + } + + idx, found = rIndex[a.Key] + if found { + // New attrs overwrite any existing with the same key. + logKeyValuePairDropped() + if idx < 0 { + r.front[-(idx + 1)] = a + }else { r.back[idx] = a } } else { @@ -256,7 +266,8 @@ func (r *Record) AddAttributes(attrs ...log.KeyValue) { // Do not use head(attrs, r.attributeCountLimit - n) here. If // (r.attributeCountLimit - n) <= 0 attrs needs to be emptied. last := max(0, r.attributeCountLimit-n) - r.addDropped(len(attrs) - last) + dropped := len(attrs) - last + r.addDropped(dropped) attrs = attrs[:last] } @@ -304,10 +315,12 @@ func (r *Record) addAttrs(attrs []log.KeyValue) { // SetAttributes sets (and overrides) attributes to the log record. func (r *Record) SetAttributes(attrs ...log.KeyValue) { var drop int + r.setDropped(0) + if !r.allowDupKeys { - attrs, drop = dedup(attrs) - r.setDropped(drop) + attrs = dedup(attrs) + r.setDropped(0) } attrs, drop = head(attrs, r.attributeCountLimit) @@ -337,7 +350,7 @@ func head(kvs []log.KeyValue, n int) (out []log.KeyValue, dropped int) { } // dedup deduplicates kvs front-to-back with the last value saved. -func dedup(kvs []log.KeyValue) (unique []log.KeyValue, dropped int) { +func dedup(kvs []log.KeyValue) (unique []log.KeyValue) { index := getIndex() defer putIndex(index) @@ -345,14 +358,14 @@ func dedup(kvs []log.KeyValue) (unique []log.KeyValue, dropped int) { for _, a := range kvs { idx, found := index[a.Key] if found { - dropped++ unique[idx] = a + logKeyValuePairDropped() } else { unique = append(unique, a) index[a.Key] = len(unique) - 1 } } - return unique, dropped + return unique } // AttributesLen returns the number of attributes in the log record. @@ -436,14 +449,15 @@ func (r *Record) applyValueLimits(val log.Value) log.Value { } val = log.SliceValue(sl...) case log.KindMap: + kvs := val.AsMap() if !r.allowDupKeys { // Deduplicate then truncate. Do not do at the same time to avoid // wasted truncation operations. var dropped int - kvs, dropped = dedup(kvs) - r.addDropped(dropped) + kvs = dedup(kvs) } + for i := range kvs { kvs[i] = r.applyAttrLimits(kvs[i]) } diff --git a/sdk/log/record_test.go b/sdk/log/record_test.go index 8132dc59585..c292a6cfedd 100644 --- a/sdk/log/record_test.go +++ b/sdk/log/record_test.go @@ -204,12 +204,12 @@ func TestRecordClone(t *testing.T) { } func TestRecordDroppedAttributes(t *testing.T) { - orig := logAttrDropped - t.Cleanup(func() { logAttrDropped = orig }) + orig := logKeyValuePairDropped + t.Cleanup(func() { logKeyValuePairDropped = orig }) for i := 1; i < attributesInlineCount*5; i++ { var called bool - logAttrDropped = func() { called = true } + logKeyValuePairDropped = func() { called = true } r := new(Record) r.attributeCountLimit = 1