Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 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
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## Unreleased

### Fixes

- Only set log template for logging integrations if formatted message differs from template ([#4682](https://github.com/getsentry/sentry-java/pull/4682))

### Features

- Add support for Spring Boot 4 and Spring 7 ([#4601](https://github.com/getsentry/sentry-java/pull/4601))
Expand Down
15 changes: 13 additions & 2 deletions sentry-jul/src/main/java/io/sentry/jul/SentryHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -154,9 +154,19 @@ protected void captureLog(@NotNull LogRecord loggingEvent) {
message = loggingEvent.getResourceBundle().getString(loggingEvent.getMessage());
}

attributes.add(SentryAttribute.stringAttribute("sentry.message.template", message));
String formattedMessage = null;
boolean formattingFailed = false;
try {
formattedMessage = maybeFormatted(arguments, message);
} catch (RuntimeException e) {
formattedMessage = message;
formattingFailed = true;
}

if (formattingFailed || !formattedMessage.equals(message)) {
attributes.add(SentryAttribute.stringAttribute("sentry.message.template", message));
}

final @NotNull String formattedMessage = maybeFormatted(arguments, message);
final @NotNull SentryLogParameters params = SentryLogParameters.create(attributes);
params.setOrigin("auto.log.jul");

Expand All @@ -170,6 +180,7 @@ protected void captureLog(@NotNull LogRecord loggingEvent) {
return formatMessage(message, arguments);
} catch (RuntimeException e) {
// local formatting failed, sending raw message instead of formatted message
throw e;
}
}

Expand Down
95 changes: 95 additions & 0 deletions sentry-jul/src/test/kotlin/io/sentry/jul/SentryHandlerTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ class SentryHandlerTest {
val configureWithLogManager: Boolean = false,
val transport: ITransport = mock(),
contextTags: List<String>? = null,
printfStyle: Boolean = true,
) {
var logger: Logger
var handler: SentryHandler
Expand All @@ -49,6 +50,7 @@ class SentryHandlerTest {
handler.setMinimumBreadcrumbLevel(minimumBreadcrumbLevel)
handler.setMinimumEventLevel(minimumEventLevel)
handler.setMinimumLevel(minimumLevel)
handler.setPrintfStyle(printfStyle)
Comment thread
cursor[bot] marked this conversation as resolved.
Outdated
handler.level = Level.ALL
logger.handlers.forEach { logger.removeHandler(it) }
logger.addHandler(handler)
Expand Down Expand Up @@ -476,4 +478,97 @@ class SentryHandlerTest {
verify(fixture.transport)
.send(checkLogs { event -> assertEquals(SentryLogLevel.ERROR, event.items.first().level) })
}

@Test
fun `does not set template on log when logging message without parameters`() {
fixture = Fixture(minimumLevel = Level.SEVERE)
fixture.logger.severe("testing message without parameters")

Sentry.flush(1000)

verify(fixture.transport)
.send(
checkLogs { logs ->
val log = logs.items.first()
assertEquals("testing message without parameters", log.body)
assertNull(log.attributes?.get("sentry.message.template"))
}
)
}

@Test
fun `sets template on log when logging message with parameters`() {
fixture = Fixture(minimumLevel = Level.SEVERE)
fixture.logger.log(Level.SEVERE, "testing message {0}", arrayOf("param"))

Sentry.flush(1000)

verify(fixture.transport)
.send(
checkLogs { logs ->
val log = logs.items.first()
assertEquals("testing message param", log.body)
assertEquals("testing message {0}", log.attributes?.get("sentry.message.template")?.value)
assertEquals("param", log.attributes?.get("sentry.message.parameter.0")?.value)
}
)
}

@Test
fun `sets template on log when logging message with parameters and using printfStyle`() {
fixture = Fixture(minimumLevel = Level.SEVERE, printfStyle = true)
fixture.logger.log(Level.SEVERE, "testing message %s", arrayOf("param"))

Sentry.flush(1000)

verify(fixture.transport)
.send(
checkLogs { logs ->
val log = logs.items.first()
assertEquals("testing message param", log.body)
assertEquals("testing message %s", log.attributes?.get("sentry.message.template")?.value)
assertEquals("param", log.attributes?.get("sentry.message.parameter.0")?.value)
}
)
}

@Test
fun `sets template on log when logging message with parameters and formatting fails`() {
fixture = Fixture(minimumLevel = Level.SEVERE)
fixture.logger.log(Level.SEVERE, "testing message {0} {1}", arrayOf(1))

Sentry.flush(1000)

verify(fixture.transport)
.send(
checkLogs { logs ->
val log = logs.items.first()
assertEquals("testing message {0} {1}", log.body)
assertEquals(
"testing message {0} {1}",
log.attributes?.get("sentry.message.template")?.value,
)
assertEquals(1, log.attributes?.get("sentry.message.parameter.0")?.value)
assertNull(log.attributes?.get("sentry.message.parameter.1"))
}
)
}

@Test
fun `sets template on log when logging message with parameters and formatting fails due to 0 args`() {
fixture = Fixture(minimumLevel = Level.SEVERE, printfStyle = true)
fixture.logger.log(Level.SEVERE, "testing message %d", emptyArray())

Sentry.flush(1000)

verify(fixture.transport)
.send(
checkLogs { logs ->
val log = logs.items.first()
assertEquals("testing message %d", log.body)
assertEquals("testing message %d", log.attributes?.get("sentry.message.template")?.value)
assertNull(log.attributes?.get("sentry.message.parameter.0"))
}
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -222,11 +222,14 @@ protected void captureLog(@NotNull LogEvent loggingEvent) {
final @Nullable Object[] arguments = loggingEvent.getMessage().getParameters();
final @NotNull SentryAttributes attributes = SentryAttributes.of();

attributes.add(
SentryAttribute.stringAttribute(
"sentry.message.template", loggingEvent.getMessage().getFormat()));

final @Nullable String nonFormattedMessage = loggingEvent.getMessage().getFormat();
final @NotNull String formattedMessage = loggingEvent.getMessage().getFormattedMessage();

if (nonFormattedMessage != null && !formattedMessage.equals(nonFormattedMessage)) {
attributes.add(
SentryAttribute.stringAttribute("sentry.message.template", nonFormattedMessage));
}

final @NotNull SentryLogParameters params = SentryLogParameters.create(attributes);
params.setOrigin("auto.log.log4j2");

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -183,15 +183,18 @@ protected void captureLog(@NotNull ILoggingEvent loggingEvent) {

@Nullable Object[] arguments = null;
final @NotNull SentryAttributes attributes = SentryAttributes.of();
final @NotNull String formattedMessage = formatted(loggingEvent);

// if encoder is set we treat message+params as PII as encoders may be used to mask/strip PII
if (encoder == null || ScopesAdapter.getInstance().getOptions().isSendDefaultPii()) {
attributes.add(
SentryAttribute.stringAttribute("sentry.message.template", loggingEvent.getMessage()));
final @Nullable String nonFormattedMessage = loggingEvent.getMessage();
if (nonFormattedMessage != null && !formattedMessage.equals(nonFormattedMessage)) {
attributes.add(
SentryAttribute.stringAttribute("sentry.message.template", nonFormattedMessage));
}
arguments = loggingEvent.getArgumentArray();
}

final @NotNull String formattedMessage = formatted(loggingEvent);
final @NotNull SentryLogParameters params = SentryLogParameters.create(attributes);
params.setOrigin("auto.log.logback");

Expand Down
Loading