Skip to content

Improve Log Attributes API #4416

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

Merged
merged 3 commits into from
May 22, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 42 additions & 6 deletions sentry/api/sentry.api
Original file line number Diff line number Diff line change
Expand Up @@ -2658,6 +2658,34 @@ public final class io/sentry/SentryAppStartProfilingOptions$JsonKeys {
public fun <init> ()V
}

public final class io/sentry/SentryAttribute {
public static fun booleanAttribute (Ljava/lang/String;Ljava/lang/Boolean;)Lio/sentry/SentryAttribute;
public static fun doubleAttribute (Ljava/lang/String;Ljava/lang/Double;)Lio/sentry/SentryAttribute;
public fun getName ()Ljava/lang/String;
public fun getType ()Lio/sentry/SentryAttributeType;
public fun getValue ()Ljava/lang/Object;
public static fun integerAttribute (Ljava/lang/String;Ljava/lang/Integer;)Lio/sentry/SentryAttribute;
public static fun named (Ljava/lang/String;Ljava/lang/Object;)Lio/sentry/SentryAttribute;
public static fun stringAttribute (Ljava/lang/String;Ljava/lang/String;)Lio/sentry/SentryAttribute;
}

public final class io/sentry/SentryAttributeType : java/lang/Enum {
public static final field BOOLEAN Lio/sentry/SentryAttributeType;
public static final field DOUBLE Lio/sentry/SentryAttributeType;
public static final field INTEGER Lio/sentry/SentryAttributeType;
public static final field STRING Lio/sentry/SentryAttributeType;
public fun apiName ()Ljava/lang/String;
public static fun valueOf (Ljava/lang/String;)Lio/sentry/SentryAttributeType;
public static fun values ()[Lio/sentry/SentryAttributeType;
}

public final class io/sentry/SentryAttributes {
public fun add (Lio/sentry/SentryAttribute;)V
public static fun fromMap (Ljava/util/Map;)Lio/sentry/SentryAttributes;
public fun getAttributes ()Ljava/util/Map;
public static fun of ([Lio/sentry/SentryAttribute;)Lio/sentry/SentryAttributes;
}

public final class io/sentry/SentryAutoDateProvider : io/sentry/SentryDateProvider {
public fun <init> ()V
public fun now ()Lio/sentry/SentryDate;
Expand Down Expand Up @@ -3077,6 +3105,7 @@ public final class io/sentry/SentryLogEvent$JsonKeys {
}

public final class io/sentry/SentryLogEventAttributeValue : io/sentry/JsonSerializable, io/sentry/JsonUnknown {
public fun <init> (Lio/sentry/SentryAttributeType;Ljava/lang/Object;)V
public fun <init> (Ljava/lang/String;Ljava/lang/Object;)V
public fun getType ()Ljava/lang/String;
public fun getUnknown ()Ljava/util/Map;
Expand Down Expand Up @@ -4711,9 +4740,8 @@ public abstract interface class io/sentry/logger/ILoggerApi {
public abstract fun fatal (Ljava/lang/String;[Ljava/lang/Object;)V
public abstract fun info (Ljava/lang/String;[Ljava/lang/Object;)V
public abstract fun log (Lio/sentry/SentryLogLevel;Lio/sentry/SentryDate;Ljava/lang/String;[Ljava/lang/Object;)V
public abstract fun log (Lio/sentry/SentryLogLevel;Lio/sentry/logger/SentryLogParameters;Ljava/lang/String;[Ljava/lang/Object;)V
public abstract fun log (Lio/sentry/SentryLogLevel;Ljava/lang/String;[Ljava/lang/Object;)V
public abstract fun log (Ljava/util/Map;Lio/sentry/SentryLogLevel;Lio/sentry/SentryDate;Ljava/lang/String;[Ljava/lang/Object;)V
public abstract fun log (Ljava/util/Map;Lio/sentry/SentryLogLevel;Ljava/lang/String;[Ljava/lang/Object;)V
public abstract fun trace (Ljava/lang/String;[Ljava/lang/Object;)V
public abstract fun warn (Ljava/lang/String;[Ljava/lang/Object;)V
}
Expand All @@ -4730,9 +4758,8 @@ public final class io/sentry/logger/LoggerApi : io/sentry/logger/ILoggerApi {
public fun fatal (Ljava/lang/String;[Ljava/lang/Object;)V
public fun info (Ljava/lang/String;[Ljava/lang/Object;)V
public fun log (Lio/sentry/SentryLogLevel;Lio/sentry/SentryDate;Ljava/lang/String;[Ljava/lang/Object;)V
public fun log (Lio/sentry/SentryLogLevel;Lio/sentry/logger/SentryLogParameters;Ljava/lang/String;[Ljava/lang/Object;)V
public fun log (Lio/sentry/SentryLogLevel;Ljava/lang/String;[Ljava/lang/Object;)V
public fun log (Ljava/util/Map;Lio/sentry/SentryLogLevel;Lio/sentry/SentryDate;Ljava/lang/String;[Ljava/lang/Object;)V
public fun log (Ljava/util/Map;Lio/sentry/SentryLogLevel;Ljava/lang/String;[Ljava/lang/Object;)V
public fun trace (Ljava/lang/String;[Ljava/lang/Object;)V
public fun warn (Ljava/lang/String;[Ljava/lang/Object;)V
}
Expand All @@ -4752,9 +4779,8 @@ public final class io/sentry/logger/NoOpLoggerApi : io/sentry/logger/ILoggerApi
public static fun getInstance ()Lio/sentry/logger/NoOpLoggerApi;
public fun info (Ljava/lang/String;[Ljava/lang/Object;)V
public fun log (Lio/sentry/SentryLogLevel;Lio/sentry/SentryDate;Ljava/lang/String;[Ljava/lang/Object;)V
public fun log (Lio/sentry/SentryLogLevel;Lio/sentry/logger/SentryLogParameters;Ljava/lang/String;[Ljava/lang/Object;)V
public fun log (Lio/sentry/SentryLogLevel;Ljava/lang/String;[Ljava/lang/Object;)V
public fun log (Ljava/util/Map;Lio/sentry/SentryLogLevel;Lio/sentry/SentryDate;Ljava/lang/String;[Ljava/lang/Object;)V
public fun log (Ljava/util/Map;Lio/sentry/SentryLogLevel;Ljava/lang/String;[Ljava/lang/Object;)V
public fun trace (Ljava/lang/String;[Ljava/lang/Object;)V
public fun warn (Ljava/lang/String;[Ljava/lang/Object;)V
}
Expand All @@ -4765,6 +4791,16 @@ public final class io/sentry/logger/NoOpLoggerBatchProcessor : io/sentry/logger/
public static fun getInstance ()Lio/sentry/logger/NoOpLoggerBatchProcessor;
}

public final class io/sentry/logger/SentryLogParameters {
public fun <init> ()V
public static fun create (Lio/sentry/SentryAttributes;)Lio/sentry/logger/SentryLogParameters;
public static fun create (Lio/sentry/SentryDate;Lio/sentry/SentryAttributes;)Lio/sentry/logger/SentryLogParameters;
public fun getAttributes ()Lio/sentry/SentryAttributes;
public fun getTimestamp ()Lio/sentry/SentryDate;
public fun setAttributes (Lio/sentry/SentryAttributes;)V
public fun setTimestamp (Lio/sentry/SentryDate;)V
}

public final class io/sentry/opentelemetry/OpenTelemetryUtil {
public fun <init> ()V
public static fun applyIgnoredSpanOrigins (Lio/sentry/SentryOptions;)V
Expand Down
57 changes: 57 additions & 0 deletions sentry/src/main/java/io/sentry/SentryAttribute.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package io.sentry;

import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

public final class SentryAttribute {

private final @NotNull String name;
private final @Nullable SentryAttributeType type;
private final @Nullable Object value;

private SentryAttribute(
final @NotNull String name,
final @Nullable SentryAttributeType type,
final @Nullable Object value) {
this.name = name;
this.type = type;
this.value = value;
}

public @NotNull String getName() {
return name;
}

public @Nullable SentryAttributeType getType() {
return type;
}

public @Nullable Object getValue() {
return value;
}

public static @NotNull SentryAttribute named(
final @NotNull String name, final @Nullable Object value) {
return new SentryAttribute(name, null, value);
}

public static @NotNull SentryAttribute booleanAttribute(
final @NotNull String name, final @Nullable Boolean value) {
return new SentryAttribute(name, SentryAttributeType.BOOLEAN, value);
}

public static @NotNull SentryAttribute integerAttribute(
final @NotNull String name, final @Nullable Integer value) {
return new SentryAttribute(name, SentryAttributeType.INTEGER, value);
}

public static @NotNull SentryAttribute doubleAttribute(
final @NotNull String name, final @Nullable Double value) {
return new SentryAttribute(name, SentryAttributeType.DOUBLE, value);
}

public static @NotNull SentryAttribute stringAttribute(
final @NotNull String name, final @Nullable String value) {
return new SentryAttribute(name, SentryAttributeType.STRING, value);
}
}
15 changes: 15 additions & 0 deletions sentry/src/main/java/io/sentry/SentryAttributeType.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package io.sentry;

import java.util.Locale;
import org.jetbrains.annotations.NotNull;

public enum SentryAttributeType {
STRING,
BOOLEAN,
INTEGER,
DOUBLE;

public @NotNull String apiName() {
return name().toLowerCase(Locale.ROOT);
}
}
54 changes: 54 additions & 0 deletions sentry/src/main/java/io/sentry/SentryAttributes.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package io.sentry;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

public final class SentryAttributes {

private final @NotNull Map<String, SentryAttribute> attributes;

private SentryAttributes(final @NotNull Map<String, SentryAttribute> attributes) {
this.attributes = attributes;
}

public void add(final @Nullable SentryAttribute attribute) {
if (attribute == null) {
return;
}
attributes.put(attribute.getName(), attribute);
}

public @NotNull Map<String, SentryAttribute> getAttributes() {
return attributes;
}

public static @NotNull SentryAttributes of(final @Nullable SentryAttribute... attributes) {
if (attributes == null) {
return new SentryAttributes(new ConcurrentHashMap<>());
}
final @NotNull SentryAttributes sentryAttributes =
new SentryAttributes(new ConcurrentHashMap<>(attributes.length));
for (SentryAttribute attribute : attributes) {
sentryAttributes.add(attribute);
}
return sentryAttributes;
}

public static @NotNull SentryAttributes fromMap(final @Nullable Map<String, Object> attributes) {
if (attributes == null) {
return new SentryAttributes(new ConcurrentHashMap<>());
}
final @NotNull SentryAttributes sentryAttributes =
new SentryAttributes(new ConcurrentHashMap<>(attributes.size()));
for (Map.Entry<String, Object> attribute : attributes.entrySet()) {
final @Nullable String key = attribute.getKey();
if (key != null) {
sentryAttributes.add(SentryAttribute.named(key, attribute.getValue()));
}
}

return sentryAttributes;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@ public SentryLogEventAttributeValue(final @NotNull String type, final @Nullable
}
}

public SentryLogEventAttributeValue(
final @NotNull SentryAttributeType type, final @Nullable Object value) {
this.type = type.apiName();
this.value = value;
}

public @NotNull String getType() {
return type;
}
Expand Down
10 changes: 1 addition & 9 deletions sentry/src/main/java/io/sentry/logger/ILoggerApi.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import io.sentry.SentryDate;
import io.sentry.SentryLogLevel;
import java.util.Map;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
Expand Down Expand Up @@ -31,15 +30,8 @@ void log(
@Nullable Object... args);

void log(
@Nullable Map<String, Object> attributes,
@NotNull SentryLogLevel level,
@Nullable String message,
@Nullable Object... args);

void log(
@Nullable Map<String, Object> attributes,
@NotNull SentryLogLevel level,
@Nullable SentryDate timestamp,
@NotNull SentryLogParameters params,
@Nullable String message,
@Nullable Object... args);
}
51 changes: 22 additions & 29 deletions sentry/src/main/java/io/sentry/logger/LoggerApi.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
import io.sentry.ISpan;
import io.sentry.PropagationContext;
import io.sentry.Scopes;
import io.sentry.SentryAttribute;
import io.sentry.SentryAttributeType;
import io.sentry.SentryAttributes;
import io.sentry.SentryDate;
import io.sentry.SentryLevel;
import io.sentry.SentryLogEvent;
Expand All @@ -17,7 +20,6 @@
import io.sentry.util.Platform;
import io.sentry.util.TracingUtils;
import java.util.HashMap;
import java.util.Map;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
Expand Down Expand Up @@ -66,7 +68,7 @@ public void log(
final @NotNull SentryLogLevel level,
final @Nullable String message,
final @Nullable Object... args) {
captureLog(null, level, null, message, args);
captureLog(level, SentryLogParameters.create(null, null), message, args);
}

@Override
Expand All @@ -75,33 +77,22 @@ public void log(
final @Nullable SentryDate timestamp,
final @Nullable String message,
final @Nullable Object... args) {
captureLog(null, level, timestamp, message, args);
captureLog(level, SentryLogParameters.create(timestamp, null), message, args);
}

@Override
public void log(
final @Nullable Map<String, Object> attributes,
final @NotNull SentryLogLevel level,
final @Nullable SentryDate timestamp,
final @NotNull SentryLogParameters params,
final @Nullable String message,
final @Nullable Object... args) {
captureLog(attributes, level, timestamp, message, args);
}

@Override
public void log(
final @Nullable Map<String, Object> attributes,
final @NotNull SentryLogLevel level,
final @Nullable String message,
final @Nullable Object... args) {
captureLog(attributes, level, null, message, args);
captureLog(level, params, message, args);
}

@SuppressWarnings("AnnotateFormatMethod")
private void captureLog(
final @Nullable Map<String, Object> attributes,
final @NotNull SentryLogLevel level,
final @Nullable SentryDate timestamp,
final @NotNull SentryLogParameters params,
final @Nullable String message,
final @Nullable Object... args) {
final @NotNull SentryOptions options = scopes.getOptions();
Expand All @@ -124,6 +115,7 @@ private void captureLog(
return;
}

final @Nullable SentryDate timestamp = params.getTimestamp();
final @NotNull SentryDate timestampToUse =
timestamp == null ? options.getDateProvider().now() : timestamp;
final @NotNull String messageToUse = maybeFormatMessage(message, args);
Expand All @@ -140,7 +132,7 @@ private void captureLog(
span == null ? propagationContext.getSpanId() : span.getSpanContext().getSpanId();
final SentryLogEvent logEvent =
new SentryLogEvent(traceId, timestampToUse, messageToUse, level);
logEvent.setAttributes(createAttributes(attributes, message, spanId, args));
logEvent.setAttributes(createAttributes(params.getAttributes(), message, spanId, args));
logEvent.setSeverityNumber(level.getSeverityNumber());

scopes.getClient().captureLog(logEvent, combinedScope);
Expand All @@ -167,24 +159,25 @@ private void captureLog(
}

private @NotNull HashMap<String, SentryLogEventAttributeValue> createAttributes(
final @Nullable Map<String, Object> incomingAttributes,
final @Nullable SentryAttributes incomingAttributes,
final @NotNull String message,
final @NotNull SpanId spanId,
final @Nullable Object... args) {
final @NotNull HashMap<String, SentryLogEventAttributeValue> attributes = new HashMap<>();

if (incomingAttributes != null) {
for (Map.Entry<String, Object> attributeEntry : incomingAttributes.entrySet()) {
final @Nullable Object value = attributeEntry.getValue();
final @NotNull String type = getType(value);
attributes.put(attributeEntry.getKey(), new SentryLogEventAttributeValue(type, value));
for (SentryAttribute attribute : incomingAttributes.getAttributes().values()) {
final @Nullable Object value = attribute.getValue();
final @NotNull SentryAttributeType type =
attribute.getType() == null ? getType(value) : attribute.getType();
attributes.put(attribute.getName(), new SentryLogEventAttributeValue(type, value));
}
}

if (args != null) {
int i = 0;
for (Object arg : args) {
final @NotNull String type = getType(arg);
final @NotNull SentryAttributeType type = getType(arg);
attributes.put(
"sentry.message.parameter." + i, new SentryLogEventAttributeValue(type, arg));
i++;
Expand Down Expand Up @@ -238,16 +231,16 @@ private void setServerName(
}
}

private @NotNull String getType(final @Nullable Object arg) {
private @NotNull SentryAttributeType getType(final @Nullable Object arg) {
if (arg instanceof Boolean) {
return "boolean";
return SentryAttributeType.BOOLEAN;
}
if (arg instanceof Integer) {
return "integer";
return SentryAttributeType.INTEGER;
}
if (arg instanceof Number) {
return "double";
return SentryAttributeType.DOUBLE;
}
return "string";
return SentryAttributeType.STRING;
}
}
Loading
Loading