2525import io .sentry .protocol .Message ;
2626import io .sentry .protocol .SdkVersion ;
2727import io .sentry .util .CollectionUtils ;
28+ import io .sentry .util .ContextTagsUtil ;
29+
2830import java .util .Arrays ;
2931import java .util .Collections ;
3032import java .util .List ;
3133import java .util .Map ;
3234import java .util .Objects ;
3335import java .util .Optional ;
3436import java .util .stream .Collectors ;
37+
3538import org .apache .logging .log4j .Level ;
3639import org .apache .logging .log4j .core .Filter ;
3740import org .apache .logging .log4j .core .LogEvent ;
4447import org .jetbrains .annotations .NotNull ;
4548import org .jetbrains .annotations .Nullable ;
4649
47- /** Appender for Log4j2 in charge of sending the logged events to a Sentry server. */
50+ /**
51+ * Appender for Log4j2 in charge of sending the logged events to a Sentry server.
52+ */
4853@ Plugin (name = "Sentry" , category = "Core" , elementType = "appender" , printObject = true )
4954@ Open
5055public class SentryAppender extends AbstractAppender {
@@ -61,49 +66,49 @@ public class SentryAppender extends AbstractAppender {
6166
6267 static {
6368 SentryIntegrationPackageStorage .getInstance ()
64- .addPackage ("maven:io.sentry:sentry-log4j2" , BuildConfig .VERSION_NAME );
69+ .addPackage ("maven:io.sentry:sentry-log4j2" , BuildConfig .VERSION_NAME );
6570 }
6671
6772 /**
6873 * @deprecated This constructor is deprecated. Please use {@link #SentryAppender(String, Filter,
69- * String, Level, Level, Level, Boolean, ITransportFactory, IScopes, String[])} instead.
74+ * String, Level, Level, Level, Boolean, ITransportFactory, IScopes, String[])} instead.
7075 */
7176 @ Deprecated
7277 @ SuppressWarnings ("InlineMeSuggester" )
7378 public SentryAppender (
74- final @ NotNull String name ,
75- final @ Nullable Filter filter ,
76- final @ Nullable String dsn ,
77- final @ Nullable Level minimumBreadcrumbLevel ,
78- final @ Nullable Level minimumEventLevel ,
79- final @ Nullable Boolean debug ,
80- final @ Nullable ITransportFactory transportFactory ,
81- final @ NotNull IScopes scopes ,
82- final @ Nullable String [] contextTags ) {
79+ final @ NotNull String name ,
80+ final @ Nullable Filter filter ,
81+ final @ Nullable String dsn ,
82+ final @ Nullable Level minimumBreadcrumbLevel ,
83+ final @ Nullable Level minimumEventLevel ,
84+ final @ Nullable Boolean debug ,
85+ final @ Nullable ITransportFactory transportFactory ,
86+ final @ NotNull IScopes scopes ,
87+ final @ Nullable String [] contextTags ) {
8388 this (
84- name ,
85- filter ,
86- dsn ,
87- minimumBreadcrumbLevel ,
88- minimumEventLevel ,
89- null ,
90- debug ,
91- transportFactory ,
92- scopes ,
93- contextTags );
89+ name ,
90+ filter ,
91+ dsn ,
92+ minimumBreadcrumbLevel ,
93+ minimumEventLevel ,
94+ null ,
95+ debug ,
96+ transportFactory ,
97+ scopes ,
98+ contextTags );
9499 }
95100
96101 public SentryAppender (
97- final @ NotNull String name ,
98- final @ Nullable Filter filter ,
99- final @ Nullable String dsn ,
100- final @ Nullable Level minimumBreadcrumbLevel ,
101- final @ Nullable Level minimumEventLevel ,
102- final @ Nullable Level minimumLevel ,
103- final @ Nullable Boolean debug ,
104- final @ Nullable ITransportFactory transportFactory ,
105- final @ NotNull IScopes scopes ,
106- final @ Nullable String [] contextTags ) {
102+ final @ NotNull String name ,
103+ final @ Nullable Filter filter ,
104+ final @ Nullable String dsn ,
105+ final @ Nullable Level minimumBreadcrumbLevel ,
106+ final @ Nullable Level minimumEventLevel ,
107+ final @ Nullable Level minimumLevel ,
108+ final @ Nullable Boolean debug ,
109+ final @ Nullable ITransportFactory transportFactory ,
110+ final @ NotNull IScopes scopes ,
111+ final @ Nullable String [] contextTags ) {
107112 super (name , filter , null , true , null );
108113 this .dsn = dsn ;
109114 if (minimumBreadcrumbLevel != null ) {
@@ -124,64 +129,64 @@ public SentryAppender(
124129 /**
125130 * Create a Sentry Appender.
126131 *
127- * @param name The name of the Appender.
132+ * @param name The name of the Appender.
128133 * @param minimumBreadcrumbLevel The min. level of the breadcrumb.
129- * @param minimumEventLevel The min. level of the event.
130- * @param minimumLevel The min. level of the log event.
131- * @param dsn the Sentry DSN.
132- * @param debug if Sentry debug mode should be on
133- * @param filter The filter, if any, to use.
134+ * @param minimumEventLevel The min. level of the event.
135+ * @param minimumLevel The min. level of the log event.
136+ * @param dsn the Sentry DSN.
137+ * @param debug if Sentry debug mode should be on
138+ * @param filter The filter, if any, to use.
134139 * @return The SentryAppender.
135140 */
136141 @ PluginFactory
137142 public static @ Nullable SentryAppender createAppender (
138- @ Nullable @ PluginAttribute ("name" ) final String name ,
139- @ Nullable @ PluginAttribute ("minimumBreadcrumbLevel" ) final Level minimumBreadcrumbLevel ,
140- @ Nullable @ PluginAttribute ("minimumEventLevel" ) final Level minimumEventLevel ,
141- @ Nullable @ PluginAttribute ("minimumLevel" ) final Level minimumLevel ,
142- @ Nullable @ PluginAttribute ("dsn" ) final String dsn ,
143- @ Nullable @ PluginAttribute ("debug" ) final Boolean debug ,
144- @ Nullable @ PluginElement ("filter" ) final Filter filter ,
145- @ Nullable @ PluginAttribute ("contextTags" ) final String contextTags ) {
143+ @ Nullable @ PluginAttribute ("name" ) final String name ,
144+ @ Nullable @ PluginAttribute ("minimumBreadcrumbLevel" ) final Level minimumBreadcrumbLevel ,
145+ @ Nullable @ PluginAttribute ("minimumEventLevel" ) final Level minimumEventLevel ,
146+ @ Nullable @ PluginAttribute ("minimumLevel" ) final Level minimumLevel ,
147+ @ Nullable @ PluginAttribute ("dsn" ) final String dsn ,
148+ @ Nullable @ PluginAttribute ("debug" ) final Boolean debug ,
149+ @ Nullable @ PluginElement ("filter" ) final Filter filter ,
150+ @ Nullable @ PluginAttribute ("contextTags" ) final String contextTags ) {
146151
147152 if (name == null ) {
148153 LOGGER .error ("No name provided for SentryAppender" );
149154 return null ;
150155 }
151156 return new SentryAppender (
152- name ,
153- filter ,
154- dsn ,
155- minimumBreadcrumbLevel ,
156- minimumEventLevel ,
157- minimumLevel ,
158- debug ,
159- null ,
160- ScopesAdapter .getInstance (),
161- contextTags != null ? contextTags .split ("," ) : null );
157+ name ,
158+ filter ,
159+ dsn ,
160+ minimumBreadcrumbLevel ,
161+ minimumEventLevel ,
162+ minimumLevel ,
163+ debug ,
164+ null ,
165+ ScopesAdapter .getInstance (),
166+ contextTags != null ? contextTags .split ("," ) : null );
162167 }
163168
164169 @ Override
165170 public void start () {
166171 try {
167172 Sentry .init (
168- options -> {
169- options .setEnableExternalConfiguration (true );
170- options .setInitPriority (InitPriority .LOWEST );
171- options .setDsn (dsn );
172- if (debug != null ) {
173- options .setDebug (debug );
174- }
175- options .setSentryClientName (
176- BuildConfig .SENTRY_LOG4J2_SDK_NAME + "/" + BuildConfig .VERSION_NAME );
177- options .setSdkVersion (createSdkVersion (options ));
178- if (contextTags != null ) {
179- for (final String contextTag : contextTags ) {
180- options .addContextTag (contextTag );
181- }
173+ options -> {
174+ options .setEnableExternalConfiguration (true );
175+ options .setInitPriority (InitPriority .LOWEST );
176+ options .setDsn (dsn );
177+ if (debug != null ) {
178+ options .setDebug (debug );
179+ }
180+ options .setSentryClientName (
181+ BuildConfig .SENTRY_LOG4J2_SDK_NAME + "/" + BuildConfig .VERSION_NAME );
182+ options .setSdkVersion (createSdkVersion (options ));
183+ if (contextTags != null ) {
184+ for (final String contextTag : contextTags ) {
185+ options .addContextTag (contextTag );
182186 }
183- Optional .ofNullable (transportFactory ).ifPresent (options ::setTransportFactory );
184- });
187+ }
188+ Optional .ofNullable (transportFactory ).ifPresent (options ::setTransportFactory );
189+ });
185190 } catch (IllegalArgumentException e ) {
186191 LOGGER .warn ("Failed to init Sentry during appender initialization: " + e .getMessage ());
187192 }
@@ -192,7 +197,7 @@ public void start() {
192197 @ Override
193198 public void append (final @ NotNull LogEvent eventObject ) {
194199 if (scopes .getOptions ().getLogs ().isEnabled ()
195- && eventObject .getLevel ().isMoreSpecificThan (minimumLevel )) {
200+ && eventObject .getLevel ().isMoreSpecificThan (minimumLevel )) {
196201 captureLog (eventObject );
197202 }
198203 if (eventObject .getLevel ().isMoreSpecificThan (minimumEventLevel )) {
@@ -227,7 +232,12 @@ protected void captureLog(@NotNull LogEvent loggingEvent) {
227232
228233 if (nonFormattedMessage != null && !formattedMessage .equals (nonFormattedMessage )) {
229234 attributes .add (
230- SentryAttribute .stringAttribute ("sentry.message.template" , nonFormattedMessage ));
235+ SentryAttribute .stringAttribute ("sentry.message.template" , nonFormattedMessage ));
236+ }
237+
238+ final Map <String , String > contextData = loggingEvent .getContextData ().toMap ();
239+ if (contextData != null ) {
240+ ContextTagsUtil .applyContextTagsToLogAttributes (attributes , contextData );
231241 }
232242
233243 final @ NotNull SentryLogParameters params = SentryLogParameters .create (attributes );
@@ -259,8 +269,8 @@ protected void captureLog(@NotNull LogEvent loggingEvent) {
259269 final Mechanism mechanism = new Mechanism ();
260270 mechanism .setType (MECHANISM_TYPE );
261271 final Throwable mechanismException =
262- new ExceptionMechanismException (
263- mechanism , throwableInformation .getThrowable (), Thread .currentThread ());
272+ new ExceptionMechanismException (
273+ mechanism , throwableInformation .getThrowable (), Thread .currentThread ());
264274 event .setThrowable (mechanismException );
265275 }
266276
@@ -273,21 +283,14 @@ protected void captureLog(@NotNull LogEvent loggingEvent) {
273283 }
274284
275285 final Map <String , String > contextData =
276- CollectionUtils .filterMapEntries (
277- loggingEvent .getContextData ().toMap (), entry -> entry .getValue () != null );
286+ CollectionUtils .filterMapEntries (
287+ loggingEvent .getContextData ().toMap (), entry -> entry .getValue () != null );
278288 if (!contextData .isEmpty ()) {
279289 // get tags from ScopesAdapter options to allow getting the correct tags if Sentry has been
280290 // initialized somewhere else
281291 final List <String > contextTags = scopes .getOptions ().getContextTags ();
282- if (contextTags != null && !contextTags .isEmpty ()) {
283- for (final String contextTag : contextTags ) {
284- // if mdc tag is listed in SentryOptions, apply as event tag
285- if (contextData .containsKey (contextTag )) {
286- event .setTag (contextTag , contextData .get (contextTag ));
287- // remove from all tags applied to logging event
288- contextData .remove (contextTag );
289- }
290- }
292+ if (contextTags != null ) {
293+ ContextTagsUtil .applyContextTagsToEvent (event , contextTags , contextData );
291294 }
292295 // put the rest of mdc tags in contexts
293296 if (!contextData .isEmpty ()) {
@@ -301,9 +304,9 @@ protected void captureLog(@NotNull LogEvent loggingEvent) {
301304 private @ NotNull List <String > toParams (final @ Nullable Object [] arguments ) {
302305 if (arguments != null ) {
303306 return Arrays .stream (arguments )
304- .filter (Objects ::nonNull )
305- .map (Object ::toString )
306- .collect (Collectors .toList ());
307+ .filter (Objects ::nonNull )
308+ .map (Object ::toString )
309+ .collect (Collectors .toList ());
307310 } else {
308311 return Collections .emptyList ();
309312 }
0 commit comments