Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix lifetime for sdk::ReadWriteLogRecord #3147

Open
wants to merge 8 commits into
base: main
Choose a base branch
from

Conversation

owent
Copy link
Member

@owent owent commented Nov 15, 2024

Fixes #3135
Fixes #2651

Changes

  • Add MixedAttributeMap to store both std::unordered_map<std::string, opentelemetry::common::AttributeValue> and AttributeMap
  • Copy both OwnedAttributeValue, std::vector<nostd::string_view> and bool array for ReadWriteLogRecord.

For significant contributions please make sure you have completed the following items:

  • CHANGELOG.md updated for non-trivial changes
  • Unit tests have been added
  • Changes in public API reviewed

@owent owent requested a review from a team as a code owner November 15, 2024 11:37
Copy link

netlify bot commented Nov 15, 2024

Deploy Preview for opentelemetry-cpp-api-docs canceled.

Name Link
🔨 Latest commit 5595d31
🔍 Latest deploy log https://app.netlify.com/sites/opentelemetry-cpp-api-docs/deploys/67410d1b97f17b00089829e7

Copy link

codecov bot commented Nov 15, 2024

Codecov Report

Attention: Patch coverage is 98.19820% with 2 lines in your changes missing coverage. Please review.

Project coverage is 88.08%. Comparing base (f1b5fbd) to head (5595d31).

Files with missing lines Patch % Lines
...include/opentelemetry/sdk/common/attribute_utils.h 98.10% 2 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #3147      +/-   ##
==========================================
+ Coverage   87.86%   88.08%   +0.22%     
==========================================
  Files         195      195              
  Lines        6151     6256     +105     
==========================================
+ Hits         5404     5510     +106     
+ Misses        747      746       -1     
Files with missing lines Coverage Δ
sdk/src/logs/read_write_log_record.cc 96.39% <100.00%> (ø)
...include/opentelemetry/sdk/common/attribute_utils.h 95.91% <98.10%> (+5.00%) ⬆️

... and 1 file with indirect coverage changes

---- 🚨 Try these New Features:

@owent owent changed the title [WIP]Fix lifetime for sdk::ReadWriteLogRecord Fix lifetime for sdk::ReadWriteLogRecord Nov 15, 2024
struct MixedAttributeMapStorage
{
std::unordered_map<std::string, opentelemetry::common::AttributeValue> attributes;
AttributeMap owened_attributes;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like a typo:

Suggested change
AttributeMap owened_attributes;
AttributeMap owned_attributes;

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, it's fixed now.

@sjinks
Copy link
Contributor

sjinks commented Nov 16, 2024

I don't know if this is critical, but this change breaks the ABI:

  • Problems with Data Types, High Severity
    • read_write_log_record.h, namespace opentelemetry::v1::sdk::logs, class ReadWriteLogRecord
      • Change: Size of this class has been increased from 176 bytes to 464 bytes.
      • Effect:
        1. An object of this class can be allocated by the applications and old size will be hardcoded at the compile time. Call of any exported constructor will break the memory of neighboring objects on the stack or heap.
        2. The memory layout and size of subclasses will be changed.
  • Problems with Data Types, Low Severity
    • read_write_log_record.h, namespace opentelemetry::v1::sdk::logs, class ReadWriteLogRecord
      • Change: Type of field attributes_map_ has been changed from std::unordered_map<std::__cxx11::basic_string<char>, absl::otel_v1::variant<bool>, std::hash<std::__cxx11::basic_string<char> >, std::equal_to<std::__cxx11::basic_string<char> > > (56 bytes) to opentelemetry::v1::sdk::common::MixedAttributeMap (184 bytes)
      • Change: Type of field body_ has been changed from opentelemetry::v1::common::AttributeValue (24 bytes) to opentelemetry::v1::sdk::common::MixedAttributeMap (184 bytes)
      • Effect: Size of the inclusive type has been changed.

To reproduce:

cmake -B build -DBUILD_SHARED_LIBS=ON -DCMAKE_CXX_FLAGS="-Og -g3" --fresh
cmake --build build -j$(nproc) --clean-first
cmake --install build --prefix ORIG
wget https://patch-diff.githubusercontent.com/raw/open-telemetry/opentelemetry-cpp/pull/3147.diff
patch -p1 < 3147.diff
cmake --build build -j$(nproc)
cmake --install build --prefix NEW
mkdir dumps
for i in ORIG/lib/*.so; do abi-dumper "$i" -o "dumps/orig-$(basename "$i").dump" -lver orig; done
for i in NEW/lib/*.so; do abi-dumper "$i" -o "dumps/new-$(basename "$i").dump" -lver new; done
for i in NEW/lib/*.so; do abi-compliance-checker -l "$(basename "$i")" -old "dumps/orig-$(basename "$i").dump" -new "dumps/new-$(basename "$i").dump; done

It will show smth like

...
Preparing, please wait ...
Comparing ABIs ...
Comparing APIs ...
Creating compatibility report ...
Binary compatibility: 85.3%
Source compatibility: 100%
Total binary compatibility problems: 1, warnings: 2
Total source compatibility problems: 0, warnings: 0
Report: compat_reports/libopentelemetry_logs.so/orig_to_new/compat_report.html
...

Screenshot_20241116_131753

@owent
Copy link
Member Author

owent commented Nov 16, 2024

I don't know if this is critical, but this change breaks the ABI:

  • Problems with Data Types, High Severity

    • read_write_log_record.h, namespace opentelemetry::v1::sdk::logs, class ReadWriteLogRecord

      • Change: Size of this class has been increased from 176 bytes to 464 bytes.

      • Effect:

        1. An object of this class can be allocated by the applications and old size will be hardcoded at the compile time. Call of any exported constructor will break the memory of neighboring objects on the stack or heap.
        2. The memory layout and size of subclasses will be changed.
  • Problems with Data Types, Low Severity

    • read_write_log_record.h, namespace opentelemetry::v1::sdk::logs, class ReadWriteLogRecord

      • Change: Type of field attributes_map_ has been changed from std::unordered_map<std::__cxx11::basic_string<char>, absl::otel_v1::variant<bool>, std::hash<std::__cxx11::basic_string<char> >, std::equal_to<std::__cxx11::basic_string<char> > > (56 bytes) to opentelemetry::v1::sdk::common::MixedAttributeMap (184 bytes)
      • Change: Type of field body_ has been changed from opentelemetry::v1::common::AttributeValue (24 bytes) to opentelemetry::v1::sdk::common::MixedAttributeMap (184 bytes)
      • Effect: Size of the inclusive type has been changed.

To reproduce:

cmake -B build -DBUILD_SHARED_LIBS=ON -DCMAKE_CXX_FLAGS="-Og -g3" --fresh
cmake --build build -j$(nproc) --clean-first
cmake --install build --prefix ORIG
wget https://patch-diff.githubusercontent.com/raw/open-telemetry/opentelemetry-cpp/pull/3147.diff
patch -p1 < 3147.diff
cmake --build build -j$(nproc)
cmake --install build --prefix NEW
mkdir dumps
for i in ORIG/lib/*.so; do abi-dumper "$i" -o "dumps/orig-$(basename "$i").dump" -lver orig; done
for i in NEW/lib/*.so; do abi-dumper "$i" -o "dumps/new-$(basename "$i").dump" -lver new; done
for i in NEW/lib/*.so; do abi-compliance-checker -l "$(basename "$i")" -old "dumps/orig-$(basename "$i").dump" -new "dumps/new-$(basename "$i").dump; done

It will show smth like

...
Preparing, please wait ...
Comparing ABIs ...
Comparing APIs ...
Creating compatibility report ...
Binary compatibility: 85.3%
Source compatibility: 100%
Total binary compatibility problems: 1, warnings: 2
Total source compatibility problems: 0, warnings: 0
Report: compat_reports/libopentelemetry_logs.so/orig_to_new/compat_report.html
...

Screenshot_20241116_131753

If I didn't miss anything, I think we only need to keep ABI compatibility for api. These changes keep API compatibility for sdk and exporters.

@sjinks
Copy link
Contributor

sjinks commented Nov 16, 2024

I think we only need to keep ABI compatibility for API.

I noticed that the library does not have a SOVERSION and thought that the changes could break the existing consumers (I know that Alpine Linux ships OpenTelemetry C++ libraries). That's why I asked :-)

@owent
Copy link
Member Author

owent commented Nov 18, 2024

I think we only need to keep ABI compatibility for API.

I noticed that the library does not have a SOVERSION and thought that the changes could break the existing consumers (I know that Alpine Linux ships OpenTelemetry C++ libraries). That's why I asked :-)

If we build otel-cpp with cmake, we can use -DOTELCPP_VERSIONED_LIBS=ON to set SOVERSION. I'm not familar with bazel

I think we only need to keep ABI compatibility for API.

I noticed that the library does not have a SOVERSION and thought that the changes could break the existing consumers (I know that Alpine Linux ships OpenTelemetry C++ libraries). That's why I asked :-)

Thanks. I noticed #3110 and agree with the SOVERSION idea. Let's continue discussing it there.

@lalitb
Copy link
Member

lalitb commented Nov 22, 2024

@owent Thanks for the PR. With the use of the MixedAttributeMap construct, ReadWriteLogRecord now maintains both owning and non-owning values for attributes and body. While this ensures flexibility, it also introduces extra overhead when only non-owning types are required by specific custom exporters.

How about having two separate recordables:

  • ReadWriteLogRecord - Retains the current behavior, maintaining non-owning values for attributes and body.
  • LogRecordData (Similar to SpanData) - this new structure would store owning values, and used for ostream exporter.

@owent
Copy link
Member Author

owent commented Nov 22, 2024

@owent Thanks for the PR. With the use of the MixedAttributeMap construct, ReadWriteLogRecord now maintains both owning and non-owning values for attributes and body. While this ensures flexibility, it also introduces extra overhead when only non-owning types are required by specific custom exporters.

How about having two separate recordables:

  • ReadWriteLogRecord - Retains the current behavior, maintaining non-owning values for attributes and body.
  • LogRecordData (Similar to SpanData) - this new structure would store owning values, and used for ostream exporter.

Good point. I will try to implement them later.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
3 participants