Repository navigation
Expand file tree
/
Copy pathSentryLog4j2Initializer.java
More file actions
133 lines (116 loc) · 5.02 KB
/
Copy pathSentryLog4j2Initializer.java
File metadata and controls
133 lines (116 loc) · 5.02 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
package io.sentry.spring.boot4;
import com.jakewharton.nopen.annotation.Open;
import io.sentry.ScopesAdapter;
import io.sentry.log4j2.SentryAppender;
import io.sentry.util.Objects;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.config.LoggerConfig;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.context.event.GenericApplicationListener;
import org.springframework.core.ResolvableType;
/** Registers {@link SentryAppender} after Spring context gets refreshed. */
@Open
public class SentryLog4j2Initializer implements GenericApplicationListener {
private static final Logger logger = LoggerFactory.getLogger(SentryLog4j2Initializer.class);
private static final String SENTRY_APPENDER_NAME = "SENTRY_APPENDER";
private final @NotNull SentryProperties sentryProperties;
private final @NotNull List<String> loggers;
@Nullable private SentryAppender sentryAppender;
public SentryLog4j2Initializer(final @NotNull SentryProperties sentryProperties) {
this.sentryProperties = Objects.requireNonNull(sentryProperties, "properties are required");
loggers = sentryProperties.getLogging().getLoggers();
}
@Override
public boolean supportsEventType(final @NotNull ResolvableType eventType) {
return eventType.getRawClass() != null
&& ContextRefreshedEvent.class.isAssignableFrom(eventType.getRawClass());
}
@Override
public void onApplicationEvent(final @NotNull ApplicationEvent event) {
final Object context = LogManager.getContext(false);
if (!(context instanceof LoggerContext loggerContext)) {
logger.info(
"Sentry Log4j2 appender was not configured because Log4j2 Core is not the active logging backend. Log4j2 API calls may be routed through SLF4J.");
return;
}
final Configuration configuration = loggerContext.getConfiguration();
boolean changed = false;
for (final String loggerName : normalizeLoggerNames(loggers)) {
final LoggerConfig loggerConfig = getOrCreateLoggerConfig(configuration, loggerName);
if (!isSentryAppenderRegistered(loggerConfig)) {
loggerConfig.addAppender(getSentryAppender(configuration), null, null);
changed = true;
}
}
if (changed) {
loggerContext.updateLoggers(configuration);
}
}
private @NotNull LoggerConfig getOrCreateLoggerConfig(
final @NotNull Configuration configuration, final @NotNull String loggerName) {
if (LogManager.ROOT_LOGGER_NAME.equals(loggerName)) {
return configuration.getRootLogger();
}
final LoggerConfig loggerConfig = configuration.getLoggerConfig(loggerName);
if (loggerName.equals(loggerConfig.getName())) {
return loggerConfig;
}
final LoggerConfig newLoggerConfig = new LoggerConfig(loggerName, null, true);
newLoggerConfig.setParent(loggerConfig);
configuration.addLogger(loggerName, newLoggerConfig);
return newLoggerConfig;
}
private @NotNull SentryAppender getSentryAppender(final @NotNull Configuration configuration) {
if (sentryAppender == null) {
sentryAppender =
new SentryAppender(
SENTRY_APPENDER_NAME,
null,
null,
toLog4jLevel(sentryProperties.getLogging().getMinimumBreadcrumbLevel()),
toLog4jLevel(sentryProperties.getLogging().getMinimumEventLevel()),
toLog4jLevel(sentryProperties.getLogging().getMinimumLevel()),
null,
null,
ScopesAdapter.getInstance(),
null);
sentryAppender.start();
configuration.addAppender(sentryAppender);
}
return sentryAppender;
}
private @NotNull Set<String> normalizeLoggerNames(final @NotNull List<String> loggerNames) {
final Set<String> normalized = new LinkedHashSet<>();
for (final String loggerName : loggerNames) {
if (loggerName == null || loggerName.trim().isEmpty()) {
continue;
}
normalized.add(normalizeLoggerName(loggerName.trim()));
}
return normalized;
}
private boolean isSentryAppenderRegistered(final @NotNull LoggerConfig loggerConfig) {
return loggerConfig.getAppenders().values().stream()
.anyMatch(appender -> appender.getClass().equals(SentryAppender.class));
}
private @NotNull String normalizeLoggerName(final @NotNull String loggerName) {
if (org.slf4j.Logger.ROOT_LOGGER_NAME.equals(loggerName)) {
return LogManager.ROOT_LOGGER_NAME;
}
return loggerName;
}
private @Nullable Level toLog4jLevel(final @Nullable org.slf4j.event.Level slf4jLevel) {
return slf4jLevel == null ? null : Level.getLevel(slf4jLevel.name());
}
}