Skip to content

Ensure that log attributes of Object type are stringified #4409

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

Open
wants to merge 1 commit into
base: feat/logs-attributes-in-api
Choose a base branch
from

Conversation

lcian
Copy link
Member

@lcian lcian commented May 15, 2025

📜 Description

Ensures we stringify objects properly and adds attributes of other types to the de/serialization test.

#skip-changelog

@lcian lcian changed the base branch from main to feat/logs-attributes-in-api May 15, 2025 15:43
@lcian lcian changed the title [WIP] Attributes de/serialization fixes [WIP] Log attributes de/serialization fixes May 15, 2025
Comment on lines 18 to 22
if (value != null && this.type.equals("string")) {
this.value = value.toString();
} else {
this.value = value;
}
Copy link
Member Author

@lcian lcian May 15, 2025

Choose a reason for hiding this comment

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

Need to do this otherwise the object could get serialized as JSON and not as a String.
Example:

public class Point {
  public int x;
  public int y;

  public Point(int x, int y) {
    this.x = x;
    this.y = y;
  }

  @Override
  public String toString() {
    return "Point(" + x + ", " + y + ")";
  }
}

Send it as an attribute/format string param and it serializes as

"sentry.message.parameter.0":{"type":"string","value":{"x":10,"y":20}}}}]}

So with the JSON representation, which will not get ingested. We need to call toString on it.

It will appear in the formatted message though as String.format will call toString, so that's another reason why I think it's correct to call toString on it.

Copy link
Contributor

github-actions bot commented May 15, 2025

Performance metrics 🚀

  Plain With Sentry Diff
Startup time 438.62 ms 448.16 ms 9.54 ms
Size 1.58 MiB 2.08 MiB 510.55 KiB

Baseline results on branch: feat/logs-attributes-in-api

Startup times

Revision Plain With Sentry Diff
878e381 402.20 ms 417.65 ms 15.45 ms
93da41e 429.70 ms 484.57 ms 54.87 ms

App size

Revision Plain With Sentry Diff
878e381 1.58 MiB 2.08 MiB 510.51 KiB
93da41e 1.58 MiB 2.08 MiB 510.52 KiB

Previous results on branch: lcian/fix/attributes-de-serialization

Startup times

Revision Plain With Sentry Diff
aff133e 438.25 ms 479.80 ms 41.55 ms

App size

Revision Plain With Sentry Diff
aff133e 1.58 MiB 2.08 MiB 510.54 KiB

@lcian lcian changed the title [WIP] Log attributes de/serialization fixes Stringify log attributes if needed and improve serialization test May 15, 2025
@lcian lcian force-pushed the lcian/fix/attributes-de-serialization branch from a9bc5ac to 1914d83 Compare May 15, 2025 18:20
@lcian lcian changed the title Stringify log attributes if needed and improve serialization test Stringify object log attributes May 15, 2025
@lcian lcian changed the title Stringify object log attributes Ensure that log attributes of Object type are stringified May 15, 2025
@getsentry getsentry deleted a comment from github-actions bot May 15, 2025
@lcian lcian marked this pull request as ready for review May 15, 2025 18:59
@@ -15,7 +15,11 @@ public final class SentryLogEventAttributeValue implements JsonUnknown, JsonSeri

public SentryLogEventAttributeValue(final @NotNull String type, final @Nullable Object value) {
this.type = type;
this.value = value;
if (value != null && type.equals("string")) {
Copy link
Member

Choose a reason for hiding this comment

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

so we don't have a dedicated object type? I think this looks a bit ugly from an API standpoint to specify a string type and then pass an object in 😬

I think our UI supports building trees based on the dot-convention, so how I'd image it looking in pseudocode:

// we get this as an input
"point" to SentryLogEventAttributeValue("object", Point(20,30))

// we now know it's an object type so we should dismember it via reflection
val parentKey = "point"
for (field in getDeclaredFields) {
  // do this recursively for nested objects
  serialize(parentKey + "." + field.name to SentryLogEventAttributeValue(field.type, field.value))
}

Do you think that would be feasible? The object type is only on the SDK level but does not get passed to our backend. Kind of like our JsonObjectSerializer does via reflection.

Copy link
Member Author

Choose a reason for hiding this comment

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

I was wondering how objects were actually serialized as JSON :)

So, for what it's worth this SentryLogEventAttributeValue is not really meant to be used directly by users, I think it should be marked ApiStatus.Internal.
We expect the user to call log(attributes, ...) where attributes is a Map<String, Object>.
So we could have an object type that we use internally, also I think we should really use an enum for the type and not a string.

Anyway, I think yours is a cool idea, I just don't know if that's what a user would expect to see there, or if they would rather see value.toString() as the attribute value. In the Java world I would say people would expect value.toString(), what do you think?
Let me also check internally what we expect from an end product prespective because this could apply to many other platforms.

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

Successfully merging this pull request may close these issues.

2 participants