feat(logs): custom attributes API by JoshuaMoelans · Pull Request #1435 · getsentry/sentry-native

fixes #1405

docs PR: getsentry/sentry-docs#15491 (comment)

With the logs_with_attributes option set to true, we can still parse the message string as a format string, but we take the first varg passed into sentry_log_X as an attributes object.
If the passed-in value is not a sentry_value_t object, we will just ignore it (as long as it is still a sentry_value_t type, otherwise we hit UNREACHABLE("invalid value type"); when trying to parse it)

sentry_options_set_logs_with_attributes(options, true);
...
sentry_value_t attributes = sentry_value_new_object();
sentry_value_t attr = sentry_value_new_attribute(sentry_value_new_string("my_attribute"), NULL);
sentry_value_t attr_2 = sentry_value_new_attribute(sentry_value_new_int64(INT64_MAX), "fermions");
sentry_value_t attr_3 = sentry_value_new_attribute(sentry_value_new_int64(INT64_MIN), "bosons");
sentry_value_set_by_key(attributes, "my.custom.attribute", attr);
sentry_value_set_by_key(attributes, "number.first", attr_2);
sentry_value_set_by_key(attributes, "number.second", attr_3);

sentry_log_debug("logging with %d custom attributes", attributes, 3);

sentry_log_debug("logging with %s custom attributes", sentry_value_new_object(), "no");

Which shows up in the UI as such:

Screenshot 2025-10-31 at 13 35 00

This is also useful for downstream SDKs which might not need string interpolation, but still want to pass down message.parameter.X attributes:

sentry_value_t param_attributes = sentry_value_new_object();
sentry_value_t param_attr = sentry_value_new_attribute(sentry_value_new_string("parameter"), NULL);
sentry_value_set_by_key(param_attributes,"message.parameter.0", param_attr);
sentry_log_fatal("logging with a custom parameter attributes", param_attributes);

‼️ custom attributes take precedence over the default attributes, except for sentry.message.parameter.X values; if you pass in a string with format specifiers, these are used for the message parameter values.

sentry_value_t param_attributes = sentry_value_new_object();
sentry_value_t param_attr = sentry_value_new_attribute(sentry_value_new_string("parameter"), NULL);
sentry_value_t param_attr_2 = sentry_value_new_attribute(sentry_value_new_string("custom-sdk-name"), NULL);
sentry_value_set_by_key(param_attributes, "sentry.message.parameter.0", param_attr);
sentry_value_set_by_key(param_attributes, "sentry.sdk.name", param_attr_2);
sentry_log_fatal("logging with a custom parameter %s attributes", param_attributes, "and format-string");

--> the custom-sdk-name shows up, but the sentry.message.parameter.0 value is "and format-string", not "parameter".
Screenshot 2025-11-03 at 15 11 55