|
10 | 10 | import ch.qos.logback.core.Appender;
|
11 | 11 | import io.opentelemetry.instrumentation.logback.appender.v1_0.OpenTelemetryAppender;
|
12 | 12 | import java.util.Iterator;
|
| 13 | +import java.util.Optional; |
13 | 14 | import org.slf4j.ILoggerFactory;
|
14 | 15 | import org.slf4j.Logger;
|
15 | 16 | import org.slf4j.LoggerFactory;
|
@@ -53,35 +54,130 @@ private static boolean isAssignableFrom(Class<?> type, Class<?>... supportedType
|
53 | 54 | @Override
|
54 | 55 | public void onApplicationEvent(ApplicationEvent event) {
|
55 | 56 | if (event instanceof ApplicationEnvironmentPreparedEvent // Event for which
|
56 |
| - // org.springframework.boot.context.logging.LoggingApplicationListener |
57 |
| - // initializes logging |
58 |
| - && !isOpenTelemetryAppenderAlreadyConfigured()) { |
59 |
| - ch.qos.logback.classic.Logger logger = |
60 |
| - (ch.qos.logback.classic.Logger) |
61 |
| - LoggerFactory.getILoggerFactory().getLogger(Logger.ROOT_LOGGER_NAME); |
62 |
| - |
63 |
| - OpenTelemetryAppender appender = new OpenTelemetryAppender(); |
64 |
| - appender.start(); |
65 |
| - logger.addAppender(appender); |
| 57 | + // org.springframework.boot.context.logging.LoggingApplicationListener |
| 58 | + // initializes logging |
| 59 | + ) { |
| 60 | + Optional<OpenTelemetryAppender> existingOpenTelemetryAppender = findOpenTelemetryAppender(); |
| 61 | + ApplicationEnvironmentPreparedEvent applicationEnvironmentPreparedEvent = |
| 62 | + (ApplicationEnvironmentPreparedEvent) event; |
| 63 | + if (existingOpenTelemetryAppender.isPresent()) { |
| 64 | + reInitializeOpenTelemetryAppender( |
| 65 | + existingOpenTelemetryAppender, applicationEnvironmentPreparedEvent); |
| 66 | + } else { |
| 67 | + addOpenTelemetryAppender(applicationEnvironmentPreparedEvent); |
| 68 | + } |
| 69 | + } |
| 70 | + } |
| 71 | + |
| 72 | + private static void reInitializeOpenTelemetryAppender( |
| 73 | + Optional<OpenTelemetryAppender> existingOpenTelemetryAppender, |
| 74 | + ApplicationEnvironmentPreparedEvent applicationEnvironmentPreparedEvent) { |
| 75 | + OpenTelemetryAppender openTelemetryAppender = existingOpenTelemetryAppender.get(); |
| 76 | + // The OpenTelemetry appender is stopped and restarted from the |
| 77 | + // org.springframework.boot.context.logging.LoggingApplicationListener.initialize |
| 78 | + // method. |
| 79 | + // The OpenTelemetryAppender initializes the LoggingEventMapper in the start() method. So, here |
| 80 | + // we stop the OpenTelemetry appender before its re-initialization and its restart. |
| 81 | + openTelemetryAppender.stop(); |
| 82 | + initializeOpenTelemetryAppenderFromProperties( |
| 83 | + applicationEnvironmentPreparedEvent, openTelemetryAppender); |
| 84 | + openTelemetryAppender.start(); |
| 85 | + } |
| 86 | + |
| 87 | + private static void addOpenTelemetryAppender( |
| 88 | + ApplicationEnvironmentPreparedEvent applicationEnvironmentPreparedEvent) { |
| 89 | + ch.qos.logback.classic.Logger logger = |
| 90 | + (ch.qos.logback.classic.Logger) |
| 91 | + LoggerFactory.getILoggerFactory().getLogger(Logger.ROOT_LOGGER_NAME); |
| 92 | + OpenTelemetryAppender openTelemetryAppender = new OpenTelemetryAppender(); |
| 93 | + initializeOpenTelemetryAppenderFromProperties( |
| 94 | + applicationEnvironmentPreparedEvent, openTelemetryAppender); |
| 95 | + openTelemetryAppender.start(); |
| 96 | + logger.addAppender(openTelemetryAppender); |
| 97 | + } |
| 98 | + |
| 99 | + private static void initializeOpenTelemetryAppenderFromProperties( |
| 100 | + ApplicationEnvironmentPreparedEvent applicationEnvironmentPreparedEvent, |
| 101 | + OpenTelemetryAppender openTelemetryAppender) { |
| 102 | + |
| 103 | + // Implemented in the same way as the |
| 104 | + // org.springframework.boot.context.logging.LoggingApplicationListener, config properties not |
| 105 | + // available |
| 106 | + Boolean codeAttribute = |
| 107 | + evaluateBooleanProperty( |
| 108 | + applicationEnvironmentPreparedEvent, |
| 109 | + "otel.instrumentation.logback-appender.experimental.capture-code-attributes"); |
| 110 | + if (codeAttribute != null) { |
| 111 | + openTelemetryAppender.setCaptureCodeAttributes(codeAttribute.booleanValue()); |
| 112 | + } |
| 113 | + |
| 114 | + Boolean markerAttribute = |
| 115 | + evaluateBooleanProperty( |
| 116 | + applicationEnvironmentPreparedEvent, |
| 117 | + "otel.instrumentation.logback-appender.experimental.capture-marker-attribute"); |
| 118 | + if (markerAttribute != null) { |
| 119 | + openTelemetryAppender.setCaptureMarkerAttribute(markerAttribute.booleanValue()); |
66 | 120 | }
|
| 121 | + |
| 122 | + Boolean keyValuePairAttributes = |
| 123 | + evaluateBooleanProperty( |
| 124 | + applicationEnvironmentPreparedEvent, |
| 125 | + "otel.instrumentation.logback-appender.experimental.capture-key-value-pair-attributes"); |
| 126 | + if (keyValuePairAttributes != null) { |
| 127 | + openTelemetryAppender.setCaptureKeyValuePairAttributes(keyValuePairAttributes.booleanValue()); |
| 128 | + } |
| 129 | + |
| 130 | + Boolean logAttributes = |
| 131 | + evaluateBooleanProperty( |
| 132 | + applicationEnvironmentPreparedEvent, |
| 133 | + "otel.instrumentation.logback-appender.experimental-log-attributes"); |
| 134 | + if (logAttributes != null) { |
| 135 | + openTelemetryAppender.setCaptureExperimentalAttributes(logAttributes.booleanValue()); |
| 136 | + } |
| 137 | + |
| 138 | + Boolean loggerContextAttributes = |
| 139 | + evaluateBooleanProperty( |
| 140 | + applicationEnvironmentPreparedEvent, |
| 141 | + "otel.instrumentation.logback-appender.experimental.capture-logger-context-attributes"); |
| 142 | + if (loggerContextAttributes != null) { |
| 143 | + openTelemetryAppender.setCaptureLoggerContext(loggerContextAttributes.booleanValue()); |
| 144 | + } |
| 145 | + |
| 146 | + String mdcAttributeProperty = |
| 147 | + applicationEnvironmentPreparedEvent |
| 148 | + .getEnvironment() |
| 149 | + .getProperty( |
| 150 | + "otel.instrumentation.logback-appender.experimental.capture-mdc-attributes", |
| 151 | + String.class); |
| 152 | + if (mdcAttributeProperty != null) { |
| 153 | + openTelemetryAppender.setCaptureMdcAttributes(mdcAttributeProperty); |
| 154 | + } |
| 155 | + } |
| 156 | + |
| 157 | + private static Boolean evaluateBooleanProperty( |
| 158 | + ApplicationEnvironmentPreparedEvent applicationEnvironmentPreparedEvent, String property) { |
| 159 | + return applicationEnvironmentPreparedEvent |
| 160 | + .getEnvironment() |
| 161 | + .getProperty(property, Boolean.class); |
67 | 162 | }
|
68 | 163 |
|
69 |
| - private static boolean isOpenTelemetryAppenderAlreadyConfigured() { |
| 164 | + private static Optional<OpenTelemetryAppender> findOpenTelemetryAppender() { |
70 | 165 | ILoggerFactory loggerFactorySpi = LoggerFactory.getILoggerFactory();
|
71 | 166 | if (!(loggerFactorySpi instanceof LoggerContext)) {
|
72 |
| - return false; |
| 167 | + return Optional.empty(); |
73 | 168 | }
|
74 | 169 | LoggerContext loggerContext = (LoggerContext) loggerFactorySpi;
|
75 | 170 | for (ch.qos.logback.classic.Logger logger : loggerContext.getLoggerList()) {
|
76 | 171 | Iterator<Appender<ILoggingEvent>> appenderIterator = logger.iteratorForAppenders();
|
77 | 172 | while (appenderIterator.hasNext()) {
|
78 | 173 | Appender<ILoggingEvent> appender = appenderIterator.next();
|
79 | 174 | if (appender instanceof OpenTelemetryAppender) {
|
80 |
| - return true; |
| 175 | + OpenTelemetryAppender openTelemetryAppender = (OpenTelemetryAppender) appender; |
| 176 | + return Optional.of(openTelemetryAppender); |
81 | 177 | }
|
82 | 178 | }
|
83 | 179 | }
|
84 |
| - return false; |
| 180 | + return Optional.empty(); |
85 | 181 | }
|
86 | 182 |
|
87 | 183 | @Override
|
|
0 commit comments