From 3c2c018e7028ec55e974a37d9c7996bd7b6a271d Mon Sep 17 00:00:00 2001 From: Lalit Kumar Bhasin Date: Wed, 11 Sep 2024 08:42:49 -0700 Subject: [PATCH 01/11] initial commit --- opentelemetry-sdk/src/growable_array.rs | 194 ++++++++++++++++++++++++ opentelemetry-sdk/src/logs/record.rs | 21 +++ 2 files changed, 215 insertions(+) diff --git a/opentelemetry-sdk/src/growable_array.rs b/opentelemetry-sdk/src/growable_array.rs index f174bedea2..a3b3b66b19 100644 --- a/opentelemetry-sdk/src/growable_array.rs +++ b/opentelemetry-sdk/src/growable_array.rs @@ -87,6 +87,41 @@ impl< self.count + self.overflow.as_ref().map_or(0, Vec::len) } + /// Deletes the element matching the given value from the array. + /// + /// Returns the deleted value if found, or `None` otherwise. + #[allow(dead_code)] + pub(crate) fn delete_by_value(&mut self, value: &T) -> Option { + // Search and remove from inline array + if let Some(index) = self.inline[..self.count].iter().position(|v| v == value) { + let removed_value = self.inline[index].clone(); + + // Manually shift elements to the left + for i in index..self.count - 1 { + self.inline[i] = self.inline[i + 1].clone(); + } + // Fill the last spot in inline array with an element from overflow or default + self.inline[self.count - 1] = if let Some(ref mut overflow) = self.overflow { + overflow.pop().unwrap_or_default() + } else { + Default::default() + }; + + self.count -= 1; + return Some(removed_value); + } + + // Search and remove from overflow vector + if let Some(ref mut overflow) = self.overflow { + if let Some(index) = overflow.iter().position(|v| v == value) { + return Some(overflow.remove(index)); + } + } + + // Value not found + None + } + /// Returns an iterator over the elements in the `GrowableArray`. /// /// The iterator yields elements from the internal array (`initial`) first, followed by elements @@ -106,6 +141,26 @@ impl< .chain(self.overflow.as_ref().unwrap().iter()) } } + + /// Returns a mutable iterator over the elements in the `GrowableArray`. + /// + /// The iterator yields elements from the internal array (`initial`) first, followed by elements + /// from the vector (`overflow`) if present. This allows for efficient iteration over both + /// stack-allocated and heap-allocated portions. + /// + #[allow(dead_code)] + #[inline] + pub(crate) fn iter_mut(&mut self) -> impl Iterator { + if self.overflow.is_none() || self.overflow.as_ref().unwrap().is_empty() { + self.inline.iter_mut().take(self.count).chain([].iter_mut()) // Chaining with an empty array + // so that both `if` and `else` branch return the same type + } else { + self.inline + .iter_mut() + .take(self.count) + .chain(self.overflow.as_mut().unwrap().iter_mut()) + } + } } // Implement `IntoIterator` for `GrowableArray` @@ -371,4 +426,143 @@ mod tests { } assert_eq!(iter.next(), None); } + + #[test] + fn test_mut_iter_all_cases() { + let mut collection = GrowableArray::::new(); + + // Case 1: Try to modify values in an empty list + for value in collection.iter_mut() { + *value *= 2; // This should not be executed + } + assert_eq!(collection.len(), 0); + assert_eq!(collection.get(0), None); + + // Case 2: Add a single element and modify it + collection.push(5); + for value in collection.iter_mut() { + *value *= 2; + } + assert_eq!(collection.get(0), Some(&10)); + assert_eq!(collection.len(), 1); + + // Case 3: Add more elements and modify them + for i in 1..10 { + collection.push(i); + } + for (i, value) in collection.iter_mut().enumerate() { + *value = i as i32 * 3; // Set values to i * 3 + } + for i in 0..10 { + assert_eq!(collection.get(i), Some(&(i as i32 * 3))); + } + } + #[test] + fn test_delete_by_value_from_inline() { + let mut collection = GrowableArray::::new(); + for i in 0..DEFAULT_MAX_INLINE_CAPACITY { + collection.push(i as i32); + } + assert_eq!(collection.len(), DEFAULT_MAX_INLINE_CAPACITY); + + // Delete a value from the inline array + let removed = collection.delete_by_value(&3); + assert_eq!(removed, Some(3)); + assert_eq!(collection.len(), DEFAULT_MAX_INLINE_CAPACITY - 1); + + // Ensure the array shifted correctly and the value was removed + for i in 0..3 { + assert_eq!(collection.get(i), Some(&(i as i32))); + } + for i in 3..collection.len() { + assert_eq!(collection.get(i), Some(&((i + 1) as i32))); + } + + // Try to delete a value not in the array + let non_existent = collection.delete_by_value(&99); + assert_eq!(non_existent, None); + } + + #[test] + fn test_delete_by_value_from_overflow() { + let mut collection = GrowableArray::::new(); + // Fill inline array + for i in 0..DEFAULT_MAX_INLINE_CAPACITY { + collection.push(i as i32); + } + // Add elements to the overflow + for i in DEFAULT_MAX_INLINE_CAPACITY..(DEFAULT_MAX_INLINE_CAPACITY + 5) { + collection.push(i as i32); + } + assert_eq!(collection.len(), DEFAULT_MAX_INLINE_CAPACITY + 5); + + // Delete a value from the overflow vector + let removed = collection.delete_by_value(&12); + assert_eq!(removed, Some(12)); + assert_eq!(collection.len(), DEFAULT_MAX_INLINE_CAPACITY + 4); + + // Ensure the rest of the elements are in order + for i in 0..DEFAULT_MAX_INLINE_CAPACITY { + assert_eq!(collection.get(i), Some(&(i as i32))); + } + assert_eq!(collection.get(DEFAULT_MAX_INLINE_CAPACITY), Some(&10)); + assert_eq!(collection.get(DEFAULT_MAX_INLINE_CAPACITY + 1), Some(&11)); + assert_eq!(collection.get(DEFAULT_MAX_INLINE_CAPACITY + 2), Some(&13)); + } + + #[test] + fn test_delete_last_element() { + let mut collection = GrowableArray::::new(); + collection.push(10); + assert_eq!(collection.len(), 1); + + // Delete the only element in the collection + let removed = collection.delete_by_value(&10); + assert_eq!(removed, Some(10)); + assert_eq!(collection.len(), 0); + + // Ensure it's empty + assert_eq!(collection.get(0), None); + } + + #[test] + fn test_delete_multiple_values() { + let mut collection = GrowableArray::::new(); + for i in 0..DEFAULT_MAX_INLINE_CAPACITY { + collection.push(i as i32); + } + + // Delete multiple values + assert_eq!(collection.delete_by_value(&2), Some(2)); + assert_eq!(collection.len(), DEFAULT_MAX_INLINE_CAPACITY - 1); + assert_eq!(collection.delete_by_value(&4), Some(4)); + assert_eq!(collection.len(), DEFAULT_MAX_INLINE_CAPACITY - 2); + + // Ensure the elements are still correct + assert_eq!(collection.get(2), Some(&3)); + assert_eq!(collection.get(3), Some(&5)); + } + + #[test] + fn test_delete_by_value_empty_array() { + let mut collection = GrowableArray::::new(); + + // Try to delete from an empty array + let removed = collection.delete_by_value(&5); + assert_eq!(removed, None); + assert_eq!(collection.len(), 0); + } + + #[test] + fn test_delete_by_value_not_in_array() { + let mut collection = GrowableArray::::new(); + collection.push(1); + collection.push(2); + collection.push(3); + + // Try to delete a value not present + let removed = collection.delete_by_value(&10); + assert_eq!(removed, None); + assert_eq!(collection.len(), 3); + } } diff --git a/opentelemetry-sdk/src/logs/record.rs b/opentelemetry-sdk/src/logs/record.rs index 78713598d8..9face4494b 100644 --- a/opentelemetry-sdk/src/logs/record.rs +++ b/opentelemetry-sdk/src/logs/record.rs @@ -124,6 +124,27 @@ impl LogRecord { .flatten() .any(|(k, v)| k == key && v == value) } + + /// Updates the attribute with the specified key. + pub fn update_attribute(&mut self, key: K, value: V) -> bool + where + K: Into, + V: Into, + { + let key = key.into(); + if let Some(attr) = self.attributes.iter_mut().find(|opt| { + if let Some((k, _)) = opt { + k == &key + } else { + false + } + }) { + *attr = Some((key, value.into())); + true + } else { + false + } + } } /// TraceContext stores the trace context for logs that have an associated From 0afbd2d789f83e79dfcc6585eaafa64ba27ede7e Mon Sep 17 00:00:00 2001 From: Lalit Kumar Bhasin Date: Thu, 12 Sep 2024 08:38:30 -0700 Subject: [PATCH 02/11] add delete --- opentelemetry-sdk/src/growable_array.rs | 99 ++++++++++++---- opentelemetry-sdk/src/logs/log_processor.rs | 68 ++++++++++- opentelemetry-sdk/src/logs/record.rs | 123 +++++++++++++++++--- 3 files changed, 251 insertions(+), 39 deletions(-) diff --git a/opentelemetry-sdk/src/growable_array.rs b/opentelemetry-sdk/src/growable_array.rs index a3b3b66b19..ab637fccd0 100644 --- a/opentelemetry-sdk/src/growable_array.rs +++ b/opentelemetry-sdk/src/growable_array.rs @@ -74,7 +74,9 @@ impl< if index < self.count { Some(&self.inline[index]) } else if let Some(ref overflow) = self.overflow { - overflow.get(index - MAX_INLINE_CAPACITY) + // Ensure that the index is within bounds for the overflow vector + let overflow_index = index - self.count; + overflow.get(overflow_index) } else { None } @@ -87,33 +89,64 @@ impl< self.count + self.overflow.as_ref().map_or(0, Vec::len) } - /// Deletes the element matching the given value from the array. + /// Deletes the element matching the given value from the array while preserving the order. + /// + /// This function performs the following operations: + /// + /// - Searches the internal array (`inline`) for the specified value. + /// - If the value is found in the internal array: + /// - Removes the value. + /// - Shifts the remaining elements in the array to the left to fill the gap, preserving the order. + /// - If an overflow vector exists: + /// - Moves the first element from the overflow vector into the last position of the internal array. + /// - If the value is not found in the internal array, searches the heap-allocated vector (`overflow`). + /// - If the value is found in the overflow vector, it is removed, and the remaining elements in the vector are shifted left to maintain order. + /// + /// # Arguments + /// + /// - `value`: A reference to the value to be deleted. + /// + /// # Returns + /// + /// - `Some(T)`: The deleted value, if found. + /// - `None`: If the value was not found in either the array or the vector. /// - /// Returns the deleted value if found, or `None` otherwise. #[allow(dead_code)] - pub(crate) fn delete_by_value(&mut self, value: &T) -> Option { + pub(crate) fn delete_item(&mut self, item: &T) -> Option { // Search and remove from inline array - if let Some(index) = self.inline[..self.count].iter().position(|v| v == value) { + if let Some(index) = self.inline[..self.count].iter().position(|v| v == item) { let removed_value = self.inline[index].clone(); - // Manually shift elements to the left + // Shift elements to the left to fill the gap for i in index..self.count - 1 { self.inline[i] = self.inline[i + 1].clone(); } - // Fill the last spot in inline array with an element from overflow or default - self.inline[self.count - 1] = if let Some(ref mut overflow) = self.overflow { - overflow.pop().unwrap_or_default() + + // Check if we can move an element from the overflow into the inline array + let moved_from_overflow = if let Some(ref mut overflow) = self.overflow { + if let Some(first_from_overflow) = overflow.first().cloned() { + self.inline[self.count - 1] = first_from_overflow; + overflow.remove(0); // Remove the first element from overflow + true + } else { + self.inline[self.count - 1] = Default::default(); + false + } } else { - Default::default() + self.inline[self.count - 1] = Default::default(); + false }; - self.count -= 1; + // Only decrement count if no item was moved from the overflow + if !moved_from_overflow { + self.count -= 1; + } return Some(removed_value); } // Search and remove from overflow vector if let Some(ref mut overflow) = self.overflow { - if let Some(index) = overflow.iter().position(|v| v == value) { + if let Some(index) = overflow.iter().position(|v| v == item) { return Some(overflow.remove(index)); } } @@ -466,7 +499,7 @@ mod tests { assert_eq!(collection.len(), DEFAULT_MAX_INLINE_CAPACITY); // Delete a value from the inline array - let removed = collection.delete_by_value(&3); + let removed = collection.delete_item(&3); assert_eq!(removed, Some(3)); assert_eq!(collection.len(), DEFAULT_MAX_INLINE_CAPACITY - 1); @@ -479,7 +512,7 @@ mod tests { } // Try to delete a value not in the array - let non_existent = collection.delete_by_value(&99); + let non_existent = collection.delete_item(&99); assert_eq!(non_existent, None); } @@ -497,7 +530,7 @@ mod tests { assert_eq!(collection.len(), DEFAULT_MAX_INLINE_CAPACITY + 5); // Delete a value from the overflow vector - let removed = collection.delete_by_value(&12); + let removed = collection.delete_item(&12); assert_eq!(removed, Some(12)); assert_eq!(collection.len(), DEFAULT_MAX_INLINE_CAPACITY + 4); @@ -517,7 +550,7 @@ mod tests { assert_eq!(collection.len(), 1); // Delete the only element in the collection - let removed = collection.delete_by_value(&10); + let removed = collection.delete_item(&10); assert_eq!(removed, Some(10)); assert_eq!(collection.len(), 0); @@ -533,9 +566,9 @@ mod tests { } // Delete multiple values - assert_eq!(collection.delete_by_value(&2), Some(2)); + assert_eq!(collection.delete_item(&2), Some(2)); assert_eq!(collection.len(), DEFAULT_MAX_INLINE_CAPACITY - 1); - assert_eq!(collection.delete_by_value(&4), Some(4)); + assert_eq!(collection.delete_item(&4), Some(4)); assert_eq!(collection.len(), DEFAULT_MAX_INLINE_CAPACITY - 2); // Ensure the elements are still correct @@ -548,7 +581,7 @@ mod tests { let mut collection = GrowableArray::::new(); // Try to delete from an empty array - let removed = collection.delete_by_value(&5); + let removed = collection.delete_item(&5); assert_eq!(removed, None); assert_eq!(collection.len(), 0); } @@ -561,8 +594,34 @@ mod tests { collection.push(3); // Try to delete a value not present - let removed = collection.delete_by_value(&10); + let removed = collection.delete_item(&10); assert_eq!(removed, None); assert_eq!(collection.len(), 3); } + + #[test] + fn test_delete_from_inline_and_replace_with_overflow() { + let mut collection = GrowableArray::::new(); + + // Fill inline array + for i in 0..DEFAULT_MAX_INLINE_CAPACITY { + collection.push(i as i32); + } // [0,1,2,3,4,5,6,7,8,9] + + // Add overflow elements + for i in DEFAULT_MAX_INLINE_CAPACITY..(DEFAULT_MAX_INLINE_CAPACITY + 3) { + collection.push(i as i32); + } // [0,1,2,3,4,5,6,7,8,9,10,11,12] + // Before delete, ensure that the count is correct + assert_eq!(collection.len(), DEFAULT_MAX_INLINE_CAPACITY + 3); + + // Delete an inline value and ensure that an overflow value takes its place + let removed = collection.delete_item(&5); // Deleting from inline + assert_eq!(removed, Some(5)); + // [0,1,2,3,4,6,7,8,9,10,11,12] + assert_eq!(collection.len(), DEFAULT_MAX_INLINE_CAPACITY + 2); + + // The last inline position should now be filled with the first overflow element + assert_eq!(collection.get(DEFAULT_MAX_INLINE_CAPACITY - 1), Some(&10)); + } } diff --git a/opentelemetry-sdk/src/logs/log_processor.rs b/opentelemetry-sdk/src/logs/log_processor.rs index b615acb9b8..d06222e8bc 100644 --- a/opentelemetry-sdk/src/logs/log_processor.rs +++ b/opentelemetry-sdk/src/logs/log_processor.rs @@ -824,6 +824,11 @@ mod tests { Key::from_static_str("processed_by"), AnyValue::String("FirstProcessor".into()), ); + record.add_attribute( + Key::from_static_str("key1"), + AnyValue::String("val1".into()), + ); + // update body record.body = Some("Updated by FirstProcessor".into()); @@ -853,6 +858,51 @@ mod tests { &Key::from_static_str("processed_by"), &AnyValue::String("FirstProcessor".into()) )); + record.update_attribute( + &Key::from_static_str("processed_by"), + &AnyValue::from("SecondProcessor"), + ); + let _ = record.delete_attribute(&Key::from_static_str("key1")); + assert!( + record.body.clone().unwrap() + == AnyValue::String("Updated by FirstProcessor".into()) + ); + self.logs + .lock() + .unwrap() + .push((record.clone(), instrumentation.clone())); + } + + fn force_flush(&self) -> LogResult<()> { + Ok(()) + } + + fn shutdown(&self) -> LogResult<()> { + Ok(()) + } + } + + #[derive(Debug)] + struct ThirdProcessor { + pub(crate) logs: Arc>>, + } + + impl LogProcessor for ThirdProcessor { + fn emit(&self, record: &mut LogRecord, instrumentation: &InstrumentationLibrary) { + assert!(record.attributes_contains( + &Key::from_static_str("processed_by"), + &AnyValue::String("SecondProcessor".into()) + )); + record.update_attribute( + &Key::from_static_str("processed_by"), + &AnyValue::from("ThirdProcessor"), + ); + assert!(!record.attributes_contains( + &Key::from_static_str("key1"), + &AnyValue::String("value1".into()) + )); + + let _ = record.delete_attribute(&Key::from_static_str("key1")); assert!( record.body.clone().unwrap() == AnyValue::String("Updated by FirstProcessor".into()) @@ -871,10 +921,12 @@ mod tests { Ok(()) } } + #[test] fn test_log_data_modification_by_multiple_processors() { let first_processor_logs = Arc::new(Mutex::new(Vec::new())); let second_processor_logs = Arc::new(Mutex::new(Vec::new())); + let third_processor_logs = Arc::new(Mutex::new(Vec::new())); let first_processor = FirstProcessor { logs: Arc::clone(&first_processor_logs), @@ -882,10 +934,14 @@ mod tests { let second_processor = SecondProcessor { logs: Arc::clone(&second_processor_logs), }; + let third_processor = ThirdProcessor { + logs: Arc::clone(&third_processor_logs), + }; let logger_provider = LoggerProvider::builder() .with_log_processor(first_processor) .with_log_processor(second_processor) + .with_log_processor(third_processor) .build(); let logger = logger_provider.logger("test-logger"); @@ -896,9 +952,11 @@ mod tests { assert_eq!(first_processor_logs.lock().unwrap().len(), 1); assert_eq!(second_processor_logs.lock().unwrap().len(), 1); + assert_eq!(third_processor_logs.lock().unwrap().len(), 1); let first_log = &first_processor_logs.lock().unwrap()[0]; let second_log = &second_processor_logs.lock().unwrap()[0]; + let third_log = &third_processor_logs.lock().unwrap()[0]; assert!(first_log.0.attributes_contains( &Key::from_static_str("processed_by"), @@ -906,7 +964,11 @@ mod tests { )); assert!(second_log.0.attributes_contains( &Key::from_static_str("processed_by"), - &AnyValue::String("FirstProcessor".into()) + &AnyValue::String("SecondProcessor".into()) + )); + assert!(third_log.0.attributes_contains( + &Key::from_static_str("processed_by"), + &AnyValue::String("ThirdProcessor".into()) )); assert!( @@ -917,5 +979,9 @@ mod tests { second_log.0.body.clone().unwrap() == AnyValue::String("Updated by FirstProcessor".into()) ); + assert!( + third_log.0.body.clone().unwrap() + == AnyValue::String("Updated by FirstProcessor".into()) + ); } } diff --git a/opentelemetry-sdk/src/logs/record.rs b/opentelemetry-sdk/src/logs/record.rs index 9face4494b..b1f581705b 100644 --- a/opentelemetry-sdk/src/logs/record.rs +++ b/opentelemetry-sdk/src/logs/record.rs @@ -1,4 +1,5 @@ use crate::growable_array::GrowableArray; +use opentelemetry::logs::LogRecord as _; use opentelemetry::{ logs::{AnyValue, Severity}, trace::{SpanContext, SpanId, TraceFlags, TraceId}, @@ -125,25 +126,74 @@ impl LogRecord { .any(|(k, v)| k == key && v == value) } - /// Updates the attribute with the specified key. - pub fn update_attribute(&mut self, key: K, value: V) -> bool - where - K: Into, - V: Into, - { - let key = key.into(); - if let Some(attr) = self.attributes.iter_mut().find(|opt| { - if let Some((k, _)) = opt { - k == &key - } else { - false + /// Updates the first occurrence of an attribute with the specified key. + /// + /// This method searches for the first occurrence of the attribute with the given key + /// in the `attributes` collection. If the key is found, its value is updated with the + /// provided value. If the key is not found, the attribute is added. + /// + /// # Arguments + /// + /// - `key`: A reference to the key of the attribute to update. + /// - `value`: A reference to the new value for the attribute. + /// + /// # Returns + /// + /// - `Some(AnyValue)`: The old value of the attribute if found and updated. + /// - `None`: If the attribute was not found, and a new one was added. + /// + pub fn update_attribute(&mut self, key: &Key, value: &AnyValue) -> Option { + // First, search for the attribute mutably + if let Some(attr) = self + .attributes + .iter_mut() + .find(|opt| opt.as_ref().map(|(k, _)| k == key).unwrap_or(false)) + { + // Take the old value and update the attribute + let old_value = attr.take().map(|(_, v)| v); + *attr = Some((key.clone(), value.clone())); + return old_value; + } + + // If not found, add a new attribute + self.add_attribute(key.clone(), value.clone()); + None + } + + /// Deletes the first occurrence of an attribute with the specified key. + /// + /// This method first searches for the attribute with the given key in the `attributes` + /// collection. If the attribute is found, it then calls the `delete_item` method from + /// the `GrowableArray` to remove it. + /// + /// # Arguments + /// + /// - `key`: A reference to the key of the attribute to delete. + /// + /// # Returns + /// + /// - `Some((Key, AnyValue))`: The deleted key-value pair if found. + /// - `None`: If the attribute was not found. + /// + pub fn delete_attribute(&mut self, key: &Key) -> Option<(Key, AnyValue)> { + // First, find the position of the attribute (this is an immutable borrow). + let position = self + .attributes + .iter() + .position(|opt| opt.as_ref().map(|(k, _)| k == key).unwrap_or(false)); + + // Now drop the immutable borrow before we proceed with the mutable borrow. + if let Some(position) = position { + // Mutably borrow attributes and remove the item + if let Some(attribute) = self.attributes.get(position).and_then(|opt| opt.clone()) { + // Clone the attribute before passing it to delete_item + let cloned_attribute = attribute.clone(); + // Use delete_item to remove the found attribute + self.attributes.delete_item(&Some(attribute)); + return Some(cloned_attribute); } - }) { - *attr = Some((key, value.into())); - true - } else { - false } + None } } @@ -173,7 +223,7 @@ impl From<&SpanContext> for TraceContext { #[cfg(test)] mod tests { use super::*; - use opentelemetry::logs::{AnyValue, LogRecord as _, Severity}; + use opentelemetry::logs::{AnyValue, Severity}; use std::borrow::Cow; use std::time::SystemTime; @@ -313,4 +363,41 @@ mod tests { assert_eq!(log_record_borrowed, log_record_owned); } + + #[test] + fn test_update_attribute() { + let mut log_record = LogRecord::default(); + let key = Key::new("key1"); + let value = AnyValue::String("value1".into()); + let updated_value = AnyValue::String("updated_value".into()); + + // Add a new attribute + assert!(log_record.update_attribute(&key, &value).is_none()); + assert!(log_record.attributes_contains(&key, &value)); + + // Update the existing attribute + assert_eq!( + log_record.update_attribute(&key, &updated_value), + Some(value) + ); + assert!(log_record.attributes_contains(&key, &updated_value)); + } + + #[test] + fn test_delete_attribute() { + let mut log_record = LogRecord::default(); + let key = Key::new("key1"); + let value = AnyValue::String("value1".into()); + + // Add an attribute + log_record.add_attribute(key.clone(), value.clone()); + assert!(log_record.attributes_contains(&key, &value)); + + // Delete the attribute + let deleted_attribute = log_record.delete_attribute(&key); + assert_eq!(deleted_attribute, Some((key.clone(), value.clone()))); + + // Ensure it is deleted + assert!(!log_record.attributes_contains(&key, &value)); + } } From f552ea1095779160d4596a733d5a894b3c3a3903 Mon Sep 17 00:00:00 2001 From: Lalit Kumar Bhasin Date: Thu, 12 Sep 2024 09:00:09 -0700 Subject: [PATCH 03/11] revert growablearray::get to original --- opentelemetry-sdk/src/growable_array.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/opentelemetry-sdk/src/growable_array.rs b/opentelemetry-sdk/src/growable_array.rs index ab637fccd0..2e9c5fdd79 100644 --- a/opentelemetry-sdk/src/growable_array.rs +++ b/opentelemetry-sdk/src/growable_array.rs @@ -74,9 +74,7 @@ impl< if index < self.count { Some(&self.inline[index]) } else if let Some(ref overflow) = self.overflow { - // Ensure that the index is within bounds for the overflow vector - let overflow_index = index - self.count; - overflow.get(overflow_index) + overflow.get(index - MAX_INLINE_CAPACITY) } else { None } From 472c5832661175eb19671d6b75c3acabc033c823 Mon Sep 17 00:00:00 2001 From: Lalit Kumar Bhasin Date: Fri, 13 Sep 2024 11:25:54 +0530 Subject: [PATCH 04/11] Update opentelemetry-sdk/src/growable_array.rs Co-authored-by: Cijo Thomas --- opentelemetry-sdk/src/growable_array.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/opentelemetry-sdk/src/growable_array.rs b/opentelemetry-sdk/src/growable_array.rs index 2e9c5fdd79..9b552e1e0c 100644 --- a/opentelemetry-sdk/src/growable_array.rs +++ b/opentelemetry-sdk/src/growable_array.rs @@ -107,7 +107,7 @@ impl< /// # Returns /// /// - `Some(T)`: The deleted value, if found. - /// - `None`: If the value was not found in either the array or the vector. + /// - `None`: If the value was found in neither the array nor the vector /// #[allow(dead_code)] pub(crate) fn delete_item(&mut self, item: &T) -> Option { From a4d6f6b9bf078f7a791a1008d55520a14c9ff663 Mon Sep 17 00:00:00 2001 From: Lalit Kumar Bhasin Date: Fri, 13 Sep 2024 03:40:00 -0700 Subject: [PATCH 05/11] update to own the value --- opentelemetry-sdk/src/logs/log_processor.rs | 4 ++-- opentelemetry-sdk/src/logs/record.rs | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/opentelemetry-sdk/src/logs/log_processor.rs b/opentelemetry-sdk/src/logs/log_processor.rs index d06222e8bc..f825e89f1d 100644 --- a/opentelemetry-sdk/src/logs/log_processor.rs +++ b/opentelemetry-sdk/src/logs/log_processor.rs @@ -860,7 +860,7 @@ mod tests { )); record.update_attribute( &Key::from_static_str("processed_by"), - &AnyValue::from("SecondProcessor"), + AnyValue::from("SecondProcessor"), ); let _ = record.delete_attribute(&Key::from_static_str("key1")); assert!( @@ -895,7 +895,7 @@ mod tests { )); record.update_attribute( &Key::from_static_str("processed_by"), - &AnyValue::from("ThirdProcessor"), + AnyValue::from("ThirdProcessor"), ); assert!(!record.attributes_contains( &Key::from_static_str("key1"), diff --git a/opentelemetry-sdk/src/logs/record.rs b/opentelemetry-sdk/src/logs/record.rs index b1f581705b..8e99811f2f 100644 --- a/opentelemetry-sdk/src/logs/record.rs +++ b/opentelemetry-sdk/src/logs/record.rs @@ -142,7 +142,7 @@ impl LogRecord { /// - `Some(AnyValue)`: The old value of the attribute if found and updated. /// - `None`: If the attribute was not found, and a new one was added. /// - pub fn update_attribute(&mut self, key: &Key, value: &AnyValue) -> Option { + pub fn update_attribute(&mut self, key: &Key, value: AnyValue) -> Option { // First, search for the attribute mutably if let Some(attr) = self .attributes @@ -151,7 +151,7 @@ impl LogRecord { { // Take the old value and update the attribute let old_value = attr.take().map(|(_, v)| v); - *attr = Some((key.clone(), value.clone())); + *attr = Some((key.clone(), value)); return old_value; } @@ -372,12 +372,12 @@ mod tests { let updated_value = AnyValue::String("updated_value".into()); // Add a new attribute - assert!(log_record.update_attribute(&key, &value).is_none()); + assert!(log_record.update_attribute(&key, value.clone()).is_none()); assert!(log_record.attributes_contains(&key, &value)); // Update the existing attribute assert_eq!( - log_record.update_attribute(&key, &updated_value), + log_record.update_attribute(&key, updated_value.clone()), Some(value) ); assert!(log_record.attributes_contains(&key, &updated_value)); From 7f0ef9a77cc1935c079e19f5ee5177c17997e747 Mon Sep 17 00:00:00 2001 From: Lalit Kumar Bhasin Date: Fri, 13 Sep 2024 03:41:37 -0700 Subject: [PATCH 06/11] update doc comment --- opentelemetry-sdk/src/logs/record.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/opentelemetry-sdk/src/logs/record.rs b/opentelemetry-sdk/src/logs/record.rs index 8e99811f2f..f5cf4e80c2 100644 --- a/opentelemetry-sdk/src/logs/record.rs +++ b/opentelemetry-sdk/src/logs/record.rs @@ -135,7 +135,7 @@ impl LogRecord { /// # Arguments /// /// - `key`: A reference to the key of the attribute to update. - /// - `value`: A reference to the new value for the attribute. + /// - `value`: A new value for the attribute. /// /// # Returns /// From fdbeb231d4c3edc486a4cde7767cff4b2084dc51 Mon Sep 17 00:00:00 2001 From: Lalit Kumar Bhasin Date: Fri, 13 Sep 2024 06:22:59 -0700 Subject: [PATCH 07/11] fix test --- opentelemetry-sdk/src/growable_array.rs | 116 ++++++++++++++------ opentelemetry-sdk/src/logs/log_processor.rs | 4 +- opentelemetry-sdk/src/logs/record.rs | 51 ++++----- 3 files changed, 110 insertions(+), 61 deletions(-) diff --git a/opentelemetry-sdk/src/growable_array.rs b/opentelemetry-sdk/src/growable_array.rs index 9b552e1e0c..776350480e 100644 --- a/opentelemetry-sdk/src/growable_array.rs +++ b/opentelemetry-sdk/src/growable_array.rs @@ -87,40 +87,91 @@ impl< self.count + self.overflow.as_ref().map_or(0, Vec::len) } - /// Deletes the element matching the given value from the array while preserving the order. + /// Removes the first element matching the given value from the array. + /// + /// This function searches both the internal array (`inline`) and the heap-allocated + /// vector (`overflow`) for the specified value. If found, it calls `delete_at` to + /// perform the deletion and preserve the order of the remaining elements. + /// + /// # Arguments + /// + /// - `item`: A reference to the value to be deleted. + /// + /// # Returns + /// + /// - `Some(T)`: The deleted value, if found. + /// - `None`: If the value was not found in either the array or the vector. + /// + #[allow(dead_code)] + pub(crate) fn remove_first(&mut self, item: &T) -> Option { + // Search for the item using `iter()` and get its index + let index = self.iter().position(|v| v == item)?; + + // Use `delete_at()` to remove the item by index + self.remove_at(index) + } + + /// Remove all elements matching the given value from the array. + /// + /// This function searches both the internal array (`inline`) and the heap-allocated + /// vector (`overflow`) for the specified value. If found, it removes all occurrences. + /// + /// # Arguments + /// + /// - `item`: A reference to the value to be deleted. + /// + /// # Returns + /// + /// - The number of deleted occurrences of the value. + #[allow(dead_code)] + /// Remove all elements matching the given value from the array. + pub(crate) fn remove(&mut self, item: &T) -> usize { + let mut deleted_count = 0; + + // Loop to find and delete all occurrences + while let Some(index) = { + let position = self.iter().position(|v| v == item); + position + } { + self.remove_at(index); + deleted_count += 1; + } + + deleted_count + } + + /// Removes the element at a specific position (index) while preserving the order. /// /// This function performs the following operations: /// - /// - Searches the internal array (`inline`) for the specified value. - /// - If the value is found in the internal array: - /// - Removes the value. - /// - Shifts the remaining elements in the array to the left to fill the gap, preserving the order. + /// - If the index points to an element in the internal array (`inline`): + /// - Removes the element at the specified index. + /// - Shifts the remaining elements in the internal array to the left to fill the gap, preserving the order. /// - If an overflow vector exists: - /// - Moves the first element from the overflow vector into the last position of the internal array. - /// - If the value is not found in the internal array, searches the heap-allocated vector (`overflow`). - /// - If the value is found in the overflow vector, it is removed, and the remaining elements in the vector are shifted left to maintain order. + /// - Moves the first element from the overflow vector into the last position of the internal array, if available. + /// - If the index points to an element in the overflow vector: + /// - The element is removed directly from the overflow vector. /// /// # Arguments /// - /// - `value`: A reference to the value to be deleted. + /// - `index`: The index of the element to be deleted. /// /// # Returns /// - /// - `Some(T)`: The deleted value, if found. - /// - `None`: If the value was found in neither the array nor the vector + /// - `Some(T)`: The deleted element, if found. + /// - `None`: If the index is out of bounds for both the internal array and the overflow vector. /// #[allow(dead_code)] - pub(crate) fn delete_item(&mut self, item: &T) -> Option { - // Search and remove from inline array - if let Some(index) = self.inline[..self.count].iter().position(|v| v == item) { + pub(crate) fn remove_at(&mut self, index: usize) -> Option { + if index < self.count { let removed_value = self.inline[index].clone(); - // Shift elements to the left to fill the gap + // Shift elements in inline array to the left for i in index..self.count - 1 { self.inline[i] = self.inline[i + 1].clone(); } - // Check if we can move an element from the overflow into the inline array + // Handle moving an overflow element to inline, if available let moved_from_overflow = if let Some(ref mut overflow) = self.overflow { if let Some(first_from_overflow) = overflow.first().cloned() { self.inline[self.count - 1] = first_from_overflow; @@ -135,21 +186,22 @@ impl< false }; - // Only decrement count if no item was moved from the overflow + // Only decrement count if no item was moved from overflow if !moved_from_overflow { self.count -= 1; } return Some(removed_value); } - // Search and remove from overflow vector + // Handle removing from the overflow vector if let Some(ref mut overflow) = self.overflow { - if let Some(index) = overflow.iter().position(|v| v == item) { - return Some(overflow.remove(index)); + let overflow_index = index - MAX_INLINE_CAPACITY; + if overflow_index < overflow.len() { + return Some(overflow.remove(overflow_index)); } } - // Value not found + // Index out of bounds None } @@ -497,7 +549,7 @@ mod tests { assert_eq!(collection.len(), DEFAULT_MAX_INLINE_CAPACITY); // Delete a value from the inline array - let removed = collection.delete_item(&3); + let removed = collection.remove_first(&3); assert_eq!(removed, Some(3)); assert_eq!(collection.len(), DEFAULT_MAX_INLINE_CAPACITY - 1); @@ -510,7 +562,7 @@ mod tests { } // Try to delete a value not in the array - let non_existent = collection.delete_item(&99); + let non_existent = collection.remove_first(&99); assert_eq!(non_existent, None); } @@ -528,7 +580,7 @@ mod tests { assert_eq!(collection.len(), DEFAULT_MAX_INLINE_CAPACITY + 5); // Delete a value from the overflow vector - let removed = collection.delete_item(&12); + let removed = collection.remove_first(&12); assert_eq!(removed, Some(12)); assert_eq!(collection.len(), DEFAULT_MAX_INLINE_CAPACITY + 4); @@ -548,7 +600,7 @@ mod tests { assert_eq!(collection.len(), 1); // Delete the only element in the collection - let removed = collection.delete_item(&10); + let removed = collection.remove_first(&10); assert_eq!(removed, Some(10)); assert_eq!(collection.len(), 0); @@ -564,9 +616,9 @@ mod tests { } // Delete multiple values - assert_eq!(collection.delete_item(&2), Some(2)); + assert_eq!(collection.remove(&2), 1); assert_eq!(collection.len(), DEFAULT_MAX_INLINE_CAPACITY - 1); - assert_eq!(collection.delete_item(&4), Some(4)); + assert_eq!(collection.remove(&4), 1); assert_eq!(collection.len(), DEFAULT_MAX_INLINE_CAPACITY - 2); // Ensure the elements are still correct @@ -579,7 +631,7 @@ mod tests { let mut collection = GrowableArray::::new(); // Try to delete from an empty array - let removed = collection.delete_item(&5); + let removed = collection.remove_first(&5); assert_eq!(removed, None); assert_eq!(collection.len(), 0); } @@ -592,8 +644,8 @@ mod tests { collection.push(3); // Try to delete a value not present - let removed = collection.delete_item(&10); - assert_eq!(removed, None); + let removed = collection.remove(&10); + assert_eq!(removed, 0); assert_eq!(collection.len(), 3); } @@ -614,8 +666,8 @@ mod tests { assert_eq!(collection.len(), DEFAULT_MAX_INLINE_CAPACITY + 3); // Delete an inline value and ensure that an overflow value takes its place - let removed = collection.delete_item(&5); // Deleting from inline - assert_eq!(removed, Some(5)); + let removed = collection.remove(&5); // Deleting from inline + assert_eq!(removed, 1); // [0,1,2,3,4,6,7,8,9,10,11,12] assert_eq!(collection.len(), DEFAULT_MAX_INLINE_CAPACITY + 2); diff --git a/opentelemetry-sdk/src/logs/log_processor.rs b/opentelemetry-sdk/src/logs/log_processor.rs index f825e89f1d..b90214521e 100644 --- a/opentelemetry-sdk/src/logs/log_processor.rs +++ b/opentelemetry-sdk/src/logs/log_processor.rs @@ -862,7 +862,7 @@ mod tests { &Key::from_static_str("processed_by"), AnyValue::from("SecondProcessor"), ); - let _ = record.delete_attribute(&Key::from_static_str("key1")); + let _ = record.remove_attribute(&Key::from_static_str("key1")); assert!( record.body.clone().unwrap() == AnyValue::String("Updated by FirstProcessor".into()) @@ -902,7 +902,7 @@ mod tests { &AnyValue::String("value1".into()) )); - let _ = record.delete_attribute(&Key::from_static_str("key1")); + let _ = record.remove_attribute(&Key::from_static_str("key1")); assert!( record.body.clone().unwrap() == AnyValue::String("Updated by FirstProcessor".into()) diff --git a/opentelemetry-sdk/src/logs/record.rs b/opentelemetry-sdk/src/logs/record.rs index f5cf4e80c2..fc815074fd 100644 --- a/opentelemetry-sdk/src/logs/record.rs +++ b/opentelemetry-sdk/src/logs/record.rs @@ -160,40 +160,37 @@ impl LogRecord { None } - /// Deletes the first occurrence of an attribute with the specified key. + /// Removes all occurrences of an attribute with the specified key. /// - /// This method first searches for the attribute with the given key in the `attributes` - /// collection. If the attribute is found, it then calls the `delete_item` method from - /// the `GrowableArray` to remove it. + /// This method searches for all occurrences of the attribute with the given key + /// in the `attributes` collection and removes them. /// /// # Arguments /// - /// - `key`: A reference to the key of the attribute to delete. + /// - `key`: A reference to the key of the attribute to remove. /// /// # Returns /// - /// - `Some((Key, AnyValue))`: The deleted key-value pair if found. - /// - `None`: If the attribute was not found. + /// - The number of removed occurrences of the key. /// - pub fn delete_attribute(&mut self, key: &Key) -> Option<(Key, AnyValue)> { - // First, find the position of the attribute (this is an immutable borrow). - let position = self - .attributes - .iter() - .position(|opt| opt.as_ref().map(|(k, _)| k == key).unwrap_or(false)); - - // Now drop the immutable borrow before we proceed with the mutable borrow. - if let Some(position) = position { - // Mutably borrow attributes and remove the item - if let Some(attribute) = self.attributes.get(position).and_then(|opt| opt.clone()) { - // Clone the attribute before passing it to delete_item - let cloned_attribute = attribute.clone(); - // Use delete_item to remove the found attribute - self.attributes.delete_item(&Some(attribute)); - return Some(cloned_attribute); - } + pub fn remove_attribute(&mut self, key: &Key) -> usize { + let mut deleted_count = 0; + + // Loop to find and remove all occurrences + while let Some(index) = { + // Isolate the immutable borrow in a block scope + let position = self + .attributes + .iter() + .position(|opt| opt.as_ref().map(|(k, _)| k == key).unwrap_or(false)); + position + } { + // Now proceed with the mutable borrow and remove the item + self.attributes.remove_at(index); + deleted_count += 1; } - None + + deleted_count } } @@ -394,8 +391,8 @@ mod tests { assert!(log_record.attributes_contains(&key, &value)); // Delete the attribute - let deleted_attribute = log_record.delete_attribute(&key); - assert_eq!(deleted_attribute, Some((key.clone(), value.clone()))); + let del_count = log_record.remove_attribute(&key); + assert_eq!(del_count, 1); // Ensure it is deleted assert!(!log_record.attributes_contains(&key, &value)); From f165a39ea3d7342f07829f6d20dbf920f2c1e79d Mon Sep 17 00:00:00 2001 From: Lalit Kumar Bhasin Date: Fri, 13 Sep 2024 06:42:39 -0700 Subject: [PATCH 08/11] fix unit test --- opentelemetry-sdk/src/growable_array.rs | 132 ++++-------------------- 1 file changed, 19 insertions(+), 113 deletions(-) diff --git a/opentelemetry-sdk/src/growable_array.rs b/opentelemetry-sdk/src/growable_array.rs index 776350480e..433b923e75 100644 --- a/opentelemetry-sdk/src/growable_array.rs +++ b/opentelemetry-sdk/src/growable_array.rs @@ -87,59 +87,6 @@ impl< self.count + self.overflow.as_ref().map_or(0, Vec::len) } - /// Removes the first element matching the given value from the array. - /// - /// This function searches both the internal array (`inline`) and the heap-allocated - /// vector (`overflow`) for the specified value. If found, it calls `delete_at` to - /// perform the deletion and preserve the order of the remaining elements. - /// - /// # Arguments - /// - /// - `item`: A reference to the value to be deleted. - /// - /// # Returns - /// - /// - `Some(T)`: The deleted value, if found. - /// - `None`: If the value was not found in either the array or the vector. - /// - #[allow(dead_code)] - pub(crate) fn remove_first(&mut self, item: &T) -> Option { - // Search for the item using `iter()` and get its index - let index = self.iter().position(|v| v == item)?; - - // Use `delete_at()` to remove the item by index - self.remove_at(index) - } - - /// Remove all elements matching the given value from the array. - /// - /// This function searches both the internal array (`inline`) and the heap-allocated - /// vector (`overflow`) for the specified value. If found, it removes all occurrences. - /// - /// # Arguments - /// - /// - `item`: A reference to the value to be deleted. - /// - /// # Returns - /// - /// - The number of deleted occurrences of the value. - #[allow(dead_code)] - /// Remove all elements matching the given value from the array. - pub(crate) fn remove(&mut self, item: &T) -> usize { - let mut deleted_count = 0; - - // Loop to find and delete all occurrences - while let Some(index) = { - let position = self.iter().position(|v| v == item); - position - } { - self.remove_at(index); - deleted_count += 1; - } - - deleted_count - } - /// Removes the element at a specific position (index) while preserving the order. /// /// This function performs the following operations: @@ -541,15 +488,15 @@ mod tests { } } #[test] - fn test_delete_by_value_from_inline() { + fn test_remove_at_inline() { let mut collection = GrowableArray::::new(); for i in 0..DEFAULT_MAX_INLINE_CAPACITY { collection.push(i as i32); } assert_eq!(collection.len(), DEFAULT_MAX_INLINE_CAPACITY); - // Delete a value from the inline array - let removed = collection.remove_first(&3); + // Remove a value from the inline array using remove_at + let removed = collection.remove_at(3); assert_eq!(removed, Some(3)); assert_eq!(collection.len(), DEFAULT_MAX_INLINE_CAPACITY - 1); @@ -561,13 +508,13 @@ mod tests { assert_eq!(collection.get(i), Some(&((i + 1) as i32))); } - // Try to delete a value not in the array - let non_existent = collection.remove_first(&99); + // Try to remove a value out of bounds + let non_existent = collection.remove_at(99); assert_eq!(non_existent, None); } #[test] - fn test_delete_by_value_from_overflow() { + fn test_remove_at_overflow() { let mut collection = GrowableArray::::new(); // Fill inline array for i in 0..DEFAULT_MAX_INLINE_CAPACITY { @@ -579,8 +526,8 @@ mod tests { } assert_eq!(collection.len(), DEFAULT_MAX_INLINE_CAPACITY + 5); - // Delete a value from the overflow vector - let removed = collection.remove_first(&12); + // Remove a value from the overflow vector using remove_at + let removed = collection.remove_at(DEFAULT_MAX_INLINE_CAPACITY + 2); assert_eq!(removed, Some(12)); assert_eq!(collection.len(), DEFAULT_MAX_INLINE_CAPACITY + 4); @@ -594,13 +541,13 @@ mod tests { } #[test] - fn test_delete_last_element() { + fn test_remove_at_last_element() { let mut collection = GrowableArray::::new(); collection.push(10); assert_eq!(collection.len(), 1); - // Delete the only element in the collection - let removed = collection.remove_first(&10); + // Remove the only element in the collection using remove_at + let removed = collection.remove_at(0); assert_eq!(removed, Some(10)); assert_eq!(collection.len(), 0); @@ -609,66 +556,25 @@ mod tests { } #[test] - fn test_delete_multiple_values() { - let mut collection = GrowableArray::::new(); - for i in 0..DEFAULT_MAX_INLINE_CAPACITY { - collection.push(i as i32); - } - - // Delete multiple values - assert_eq!(collection.remove(&2), 1); - assert_eq!(collection.len(), DEFAULT_MAX_INLINE_CAPACITY - 1); - assert_eq!(collection.remove(&4), 1); - assert_eq!(collection.len(), DEFAULT_MAX_INLINE_CAPACITY - 2); - - // Ensure the elements are still correct - assert_eq!(collection.get(2), Some(&3)); - assert_eq!(collection.get(3), Some(&5)); - } - - #[test] - fn test_delete_by_value_empty_array() { - let mut collection = GrowableArray::::new(); - - // Try to delete from an empty array - let removed = collection.remove_first(&5); - assert_eq!(removed, None); - assert_eq!(collection.len(), 0); - } - - #[test] - fn test_delete_by_value_not_in_array() { - let mut collection = GrowableArray::::new(); - collection.push(1); - collection.push(2); - collection.push(3); - - // Try to delete a value not present - let removed = collection.remove(&10); - assert_eq!(removed, 0); - assert_eq!(collection.len(), 3); - } - - #[test] - fn test_delete_from_inline_and_replace_with_overflow() { + fn test_remove_at_from_inline_and_replace_with_overflow() { let mut collection = GrowableArray::::new(); // Fill inline array for i in 0..DEFAULT_MAX_INLINE_CAPACITY { collection.push(i as i32); - } // [0,1,2,3,4,5,6,7,8,9] + } // Add overflow elements for i in DEFAULT_MAX_INLINE_CAPACITY..(DEFAULT_MAX_INLINE_CAPACITY + 3) { collection.push(i as i32); - } // [0,1,2,3,4,5,6,7,8,9,10,11,12] - // Before delete, ensure that the count is correct + } + + // Before removing, ensure that the count is correct assert_eq!(collection.len(), DEFAULT_MAX_INLINE_CAPACITY + 3); - // Delete an inline value and ensure that an overflow value takes its place - let removed = collection.remove(&5); // Deleting from inline - assert_eq!(removed, 1); - // [0,1,2,3,4,6,7,8,9,10,11,12] + // Remove an inline value and ensure that an overflow value takes its place using remove_at + let removed = collection.remove_at(5); + assert_eq!(removed, Some(5)); assert_eq!(collection.len(), DEFAULT_MAX_INLINE_CAPACITY + 2); // The last inline position should now be filled with the first overflow element From 58795e7642a5e9071eed0b4f9c7072c63f141a8b Mon Sep 17 00:00:00 2001 From: Lalit Kumar Bhasin Date: Fri, 13 Sep 2024 06:55:15 -0700 Subject: [PATCH 09/11] update CHANGELOG --- opentelemetry-sdk/CHANGELOG.md | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/opentelemetry-sdk/CHANGELOG.md b/opentelemetry-sdk/CHANGELOG.md index 876e1a973c..20c3fecfc8 100644 --- a/opentelemetry-sdk/CHANGELOG.md +++ b/opentelemetry-sdk/CHANGELOG.md @@ -5,7 +5,17 @@ - Update `async-std` dependency version to 1.13 - *Breaking* - Remove support for `MetricProducer` which allowed metrics from external sources to be sent through OpenTelemetry. - [#2105](https://github.com/open-telemetry/opentelemetry-rust/pull/2105) + [#2105](https://github.com/open-telemetry/opentelemetry-rust/pull/2105) +- Added Two new methods to the LogRecord struct's public API: +```rust + update_attribute(&Key, &AnyValue) -> Option +``` + - Updates the value of the first occurrence of an attribute with the specified key. + - If the key exists, the old value is returned. If not, the new key-value pair is added, and None is returned. +```rust +delete_attribute(&mut self, key: &Key) -> usize +``` +Removes all occurrences of attributes with the specified key and returns the count of deleted attributes. ## v0.25.0 From 2c56a96e6b2ad8f923d1846442d169f04dc474cf Mon Sep 17 00:00:00 2001 From: Lalit Kumar Bhasin Date: Fri, 13 Sep 2024 06:57:31 -0700 Subject: [PATCH 10/11] more changelog changes --- opentelemetry-sdk/CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/opentelemetry-sdk/CHANGELOG.md b/opentelemetry-sdk/CHANGELOG.md index 20c3fecfc8..dd164a4756 100644 --- a/opentelemetry-sdk/CHANGELOG.md +++ b/opentelemetry-sdk/CHANGELOG.md @@ -13,9 +13,9 @@ - Updates the value of the first occurrence of an attribute with the specified key. - If the key exists, the old value is returned. If not, the new key-value pair is added, and None is returned. ```rust -delete_attribute(&mut self, key: &Key) -> usize +remove_attribute(&mut self, key: &Key) -> usize ``` -Removes all occurrences of attributes with the specified key and returns the count of deleted attributes. +- Removes all occurrences of attributes with the specified key and returns the count of deleted attributes. ## v0.25.0 From dc0dce1de9273646fd75ccbb6597e9532fd7fc00 Mon Sep 17 00:00:00 2001 From: Lalit Kumar Bhasin Date: Thu, 19 Dec 2024 10:34:24 -0800 Subject: [PATCH 11/11] merge conflict --- opentelemetry-sdk/src/logs/log_processor.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/opentelemetry-sdk/src/logs/log_processor.rs b/opentelemetry-sdk/src/logs/log_processor.rs index 8ced33163b..836fdd2849 100644 --- a/opentelemetry-sdk/src/logs/log_processor.rs +++ b/opentelemetry-sdk/src/logs/log_processor.rs @@ -1318,11 +1318,11 @@ mod tests { #[derive(Debug)] struct ThirdProcessor { - pub(crate) logs: Arc>>, + pub(crate) logs: Arc>>, } impl LogProcessor for ThirdProcessor { - fn emit(&self, record: &mut LogRecord, instrumentation: &InstrumentationLibrary) { + fn emit(&self, record: &mut LogRecord, instrumentation: &InstrumentationScope) { assert!(record.attributes_contains( &Key::from_static_str("processed_by"), &AnyValue::String("SecondProcessor".into())