Skip to content

Commit 8b0c9c6

Browse files
jpnurmiclaude
andcommitted
fix(logs): avoid modifying custom per-log attributes (#1500)
Allow reusing attribute objects across multiple log calls, as documented. Co-Authored-By: Claude Opus 4.5 <[email protected]>
1 parent 9993fc6 commit 8b0c9c6

File tree

4 files changed

+39
-9
lines changed

4 files changed

+39
-9
lines changed

src/sentry_logs.c

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -243,10 +243,7 @@ static sentry_value_t
243243
construct_log(sentry_level_t level, const char *message, va_list args)
244244
{
245245
sentry_value_t log = sentry_value_new_object();
246-
sentry_value_t attributes = sentry_value_new_null();
247-
SENTRY_WITH_SCOPE (scope) {
248-
attributes = sentry__value_clone(scope->attributes);
249-
}
246+
sentry_value_t attributes = sentry_value_new_object();
250247

251248
SENTRY_WITH_OPTIONS (options) {
252249
// Extract custom attributes if the option is enabled
@@ -258,16 +255,15 @@ construct_log(sentry_level_t level, const char *message, va_list args)
258255
va_end(args_copy);
259256
if (sentry_value_get_type(custom_attributes)
260257
== SENTRY_VALUE_TYPE_OBJECT) {
261-
// Merge global attributes INTO per-log attributes
262-
// (per-log attributes take precedence for conflicts)
263-
sentry__value_merge_objects(custom_attributes, attributes);
258+
// Clone custom attributes first (per-log attributes take
259+
// precedence for conflicts)
264260
sentry_value_decref(attributes);
265-
attributes = custom_attributes;
261+
attributes = sentry__value_clone(custom_attributes);
266262
} else {
267263
SENTRY_DEBUG("Discarded custom attributes on log: non-object "
268264
"sentry_value_t passed in");
269-
sentry_value_decref(custom_attributes);
270265
}
266+
sentry_value_decref(custom_attributes);
271267
}
272268

273269
// Format the message with remaining args (or all args if not using

src/sentry_scope.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -779,6 +779,8 @@ void
779779
sentry__scope_apply_attributes(const sentry_scope_t *scope,
780780
sentry_value_t telemetry, sentry_value_t attributes)
781781
{
782+
sentry__value_merge_objects(attributes, scope->attributes);
783+
782784
sentry_value_t trace_id = sentry_value_get_by_key(
783785
sentry_value_get_by_key(scope->propagation_context, "trace"),
784786
"trace_id");

tests/unit/test_logs.c

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -379,3 +379,34 @@ SENTRY_TEST(logs_custom_attributes_with_format_strings)
379379
TEST_CHECK(!validation_data.has_validation_error);
380380
TEST_CHECK_INT_EQUAL(validation_data.called_count, 1);
381381
}
382+
383+
SENTRY_TEST(logs_custom_attributes_not_modified)
384+
{
385+
SENTRY_TEST_OPTIONS_NEW(options);
386+
sentry_options_set_dsn(options, "https://[email protected]/42");
387+
sentry_options_set_enable_logs(options, true);
388+
sentry_options_set_logs_with_attributes(options, true);
389+
sentry_init(options);
390+
391+
sentry_set_attribute("global.key",
392+
sentry_value_new_attribute(
393+
sentry_value_new_string("global_value"), NULL));
394+
395+
sentry_value_t attrs = sentry_value_new_object();
396+
sentry_value_set_by_key(attrs, "local.key",
397+
sentry_value_new_attribute(
398+
sentry_value_new_string("local_value"), NULL));
399+
sentry_value_incref(attrs);
400+
401+
sentry_log_info("Test message", attrs);
402+
403+
// attrs should still contain only local.key, not global.key
404+
TEST_CHECK_INT_EQUAL(sentry_value_get_length(attrs), 1);
405+
TEST_CHECK(
406+
!sentry_value_is_null(sentry_value_get_by_key(attrs, "local.key")));
407+
TEST_CHECK(
408+
sentry_value_is_null(sentry_value_get_by_key(attrs, "global.key")));
409+
410+
sentry_value_decref(attrs);
411+
sentry_close();
412+
}

tests/unit/tests.inc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ XX(iso_time)
9393
XX(lazy_attachments)
9494
XX(logger_enable_disable_functionality)
9595
XX(logger_level)
96+
XX(logs_custom_attributes_not_modified)
9697
XX(logs_custom_attributes_with_format_strings)
9798
XX(logs_disabled_by_default)
9899
XX(logs_force_flush)

0 commit comments

Comments
 (0)