1616import io .sentry .InitPriority ;
1717import io .sentry .ScopesAdapter ;
1818import io .sentry .Sentry ;
19+ import io .sentry .SentryAttribute ;
20+ import io .sentry .SentryAttributes ;
1921import io .sentry .SentryEvent ;
2022import io .sentry .SentryIntegrationPackageStorage ;
2123import io .sentry .SentryLevel ;
24+ import io .sentry .SentryLogLevel ;
2225import io .sentry .SentryOptions ;
2326import io .sentry .exception .ExceptionMechanismException ;
27+ import io .sentry .logger .SentryLogParameters ;
2428import io .sentry .protocol .Mechanism ;
2529import io .sentry .protocol .Message ;
2630import io .sentry .protocol .SdkVersion ;
@@ -46,6 +50,7 @@ public class SentryAppender extends UnsynchronizedAppenderBase<ILoggingEvent> {
4650 private @ Nullable ITransportFactory transportFactory ;
4751 private @ NotNull Level minimumBreadcrumbLevel = Level .INFO ;
4852 private @ NotNull Level minimumEventLevel = Level .ERROR ;
53+ private @ NotNull Level minimumLevel = Level .INFO ;
4954 private @ Nullable Encoder <ILoggingEvent > encoder ;
5055
5156 static {
@@ -78,6 +83,9 @@ public void start() {
7883
7984 @ Override
8085 protected void append (@ NotNull ILoggingEvent eventObject ) {
86+ if (options .getLogs ().isEnabled () && eventObject .getLevel ().isGreaterOrEqual (minimumLevel )) {
87+ captureLog (eventObject );
88+ }
8189 if (eventObject .getLevel ().isGreaterOrEqual (minimumEventLevel )) {
8290 final Hint hint = new Hint ();
8391 hint .set (SENTRY_SYNTHETIC_EXCEPTION , eventObject );
@@ -162,6 +170,32 @@ protected void append(@NotNull ILoggingEvent eventObject) {
162170 return event ;
163171 }
164172
173+ /**
174+ * Captures a Sentry log from Logback's {@link ILoggingEvent}.
175+ *
176+ * @param loggingEvent the logback event
177+ */
178+ // for the Android compatibility we must use old Java Date class
179+ @ SuppressWarnings ("JdkObsolete" )
180+ protected void captureLog (@ NotNull ILoggingEvent loggingEvent ) {
181+ final @ NotNull SentryLogLevel sentryLevel = toSentryLogLevel (loggingEvent .getLevel ());
182+
183+ @ Nullable Object [] arguments = null ;
184+ final @ NotNull SentryAttributes attributes = SentryAttributes .of ();
185+
186+ // if encoder is set we treat message+params as PII as encoders may be used to mask/strip PII
187+ if (encoder == null || options .isSendDefaultPii ()) {
188+ attributes .add (
189+ SentryAttribute .stringAttribute ("sentry.message.template" , loggingEvent .getMessage ()));
190+ arguments = loggingEvent .getArgumentArray ();
191+ }
192+
193+ final @ NotNull String formattedMessage = formatted (loggingEvent );
194+ final @ NotNull SentryLogParameters params = SentryLogParameters .create (attributes );
195+
196+ Sentry .logger ().log (sentryLevel , params , formattedMessage , arguments );
197+ }
198+
165199 private String formatted (@ NotNull ILoggingEvent loggingEvent ) {
166200 if (encoder != null ) {
167201 try {
@@ -218,6 +252,26 @@ private String formatted(@NotNull ILoggingEvent loggingEvent) {
218252 }
219253 }
220254
255+ /**
256+ * Transforms a {@link Level} into an {@link SentryLogLevel}.
257+ *
258+ * @param level original level as defined in log4j.
259+ * @return log level used within sentry.
260+ */
261+ private static @ NotNull SentryLogLevel toSentryLogLevel (@ NotNull Level level ) {
262+ if (level .isGreaterOrEqual (Level .ERROR )) {
263+ return SentryLogLevel .ERROR ;
264+ } else if (level .isGreaterOrEqual (Level .WARN )) {
265+ return SentryLogLevel .WARN ;
266+ } else if (level .isGreaterOrEqual (Level .INFO )) {
267+ return SentryLogLevel .INFO ;
268+ } else if (level .isGreaterOrEqual (Level .DEBUG )) {
269+ return SentryLogLevel .DEBUG ;
270+ } else {
271+ return SentryLogLevel .TRACE ;
272+ }
273+ }
274+
221275 private @ NotNull SdkVersion createSdkVersion (@ NotNull SentryOptions sentryOptions ) {
222276 SdkVersion sdkVersion = sentryOptions .getSdkVersion ();
223277
@@ -258,6 +312,16 @@ public void setMinimumEventLevel(final @Nullable Level minimumEventLevel) {
258312 return minimumEventLevel ;
259313 }
260314
315+ public void setMinimumLevel (final @ Nullable Level minimumLevel ) {
316+ if (minimumLevel != null ) {
317+ this .minimumLevel = minimumLevel ;
318+ }
319+ }
320+
321+ public @ NotNull Level getMinimumLevel () {
322+ return minimumLevel ;
323+ }
324+
261325 @ ApiStatus .Internal
262326 void setTransportFactory (final @ Nullable ITransportFactory transportFactory ) {
263327 this .transportFactory = transportFactory ;
0 commit comments