|
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