|
5 | 5 |
|
6 | 6 | package io.opentelemetry.instrumentation.logback.appender.v1_0; |
7 | 7 |
|
8 | | -import static io.opentelemetry.instrumentation.testing.junit.code.SemconvCodeStabilityUtil.codeFileAndLineAssertions; |
9 | | -import static io.opentelemetry.instrumentation.testing.junit.code.SemconvCodeStabilityUtil.codeFunctionAssertions; |
10 | | -import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat; |
11 | 8 | import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.equalTo; |
12 | | -import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.satisfies; |
13 | | -import static io.opentelemetry.semconv.ExceptionAttributes.EXCEPTION_MESSAGE; |
14 | | -import static io.opentelemetry.semconv.ExceptionAttributes.EXCEPTION_STACKTRACE; |
15 | | -import static io.opentelemetry.semconv.ExceptionAttributes.EXCEPTION_TYPE; |
16 | 9 |
|
17 | | -import io.opentelemetry.api.common.AttributeKey; |
18 | | -import io.opentelemetry.api.logs.Severity; |
19 | | -import io.opentelemetry.api.trace.SpanContext; |
20 | 10 | import io.opentelemetry.instrumentation.testing.junit.AgentInstrumentationExtension; |
21 | 11 | import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension; |
22 | | -import io.opentelemetry.sdk.common.InstrumentationScopeInfo; |
23 | 12 | import io.opentelemetry.sdk.testing.assertj.AttributeAssertion; |
24 | 13 | import io.opentelemetry.semconv.incubating.ThreadIncubatingAttributes; |
25 | | -import java.util.ArrayList; |
26 | 14 | import java.util.Arrays; |
27 | | -import java.util.Collections; |
28 | 15 | import java.util.List; |
29 | | -import java.util.stream.Stream; |
30 | | -import org.junit.jupiter.api.Test; |
31 | 16 | import org.junit.jupiter.api.extension.RegisterExtension; |
32 | | -import org.junit.jupiter.params.ParameterizedTest; |
33 | | -import org.junit.jupiter.params.provider.Arguments; |
34 | | -import org.junit.jupiter.params.provider.MethodSource; |
35 | | -import org.slf4j.Logger; |
36 | | -import org.slf4j.LoggerFactory; |
37 | | -import org.slf4j.MDC; |
38 | | -import org.slf4j.Marker; |
39 | | -import org.slf4j.MarkerFactory; |
40 | 17 |
|
41 | | -class LogbackTest { |
| 18 | +class LogbackTest extends AbstractLogbackTest { |
42 | 19 |
|
43 | 20 | @RegisterExtension |
44 | 21 | static final InstrumentationExtension testing = AgentInstrumentationExtension.create(); |
45 | 22 |
|
46 | | - private static final Logger abcLogger = LoggerFactory.getLogger("abc"); |
47 | | - private static final Logger defLogger = LoggerFactory.getLogger("def"); |
48 | | - |
49 | | - private static Stream<Arguments> provideParameters() { |
50 | | - return Stream.of( |
51 | | - Arguments.of(false, false), |
52 | | - Arguments.of(false, true), |
53 | | - Arguments.of(true, false), |
54 | | - Arguments.of(true, true)); |
55 | | - } |
56 | | - |
57 | | - @ParameterizedTest |
58 | | - @MethodSource("provideParameters") |
59 | | - public void test(boolean logException, boolean withParent) throws InterruptedException { |
60 | | - test(abcLogger, Logger::debug, Logger::debug, logException, withParent, null, null, null); |
61 | | - testing.clearData(); |
62 | | - test( |
63 | | - abcLogger, |
64 | | - Logger::info, |
65 | | - Logger::info, |
66 | | - logException, |
67 | | - withParent, |
68 | | - "abc", |
69 | | - Severity.INFO, |
70 | | - "INFO"); |
71 | | - testing.clearData(); |
72 | | - test( |
73 | | - abcLogger, |
74 | | - Logger::warn, |
75 | | - Logger::warn, |
76 | | - logException, |
77 | | - withParent, |
78 | | - "abc", |
79 | | - Severity.WARN, |
80 | | - "WARN"); |
81 | | - testing.clearData(); |
82 | | - test( |
83 | | - abcLogger, |
84 | | - Logger::error, |
85 | | - Logger::error, |
86 | | - logException, |
87 | | - withParent, |
88 | | - "abc", |
89 | | - Severity.ERROR, |
90 | | - "ERROR"); |
91 | | - testing.clearData(); |
92 | | - test(defLogger, Logger::debug, Logger::debug, logException, withParent, null, null, null); |
93 | | - testing.clearData(); |
94 | | - test(defLogger, Logger::info, Logger::info, logException, withParent, null, null, null); |
95 | | - testing.clearData(); |
96 | | - test( |
97 | | - defLogger, |
98 | | - Logger::warn, |
99 | | - Logger::warn, |
100 | | - logException, |
101 | | - withParent, |
102 | | - "def", |
103 | | - Severity.WARN, |
104 | | - "WARN"); |
105 | | - testing.clearData(); |
106 | | - test( |
107 | | - defLogger, |
108 | | - Logger::error, |
109 | | - Logger::error, |
110 | | - logException, |
111 | | - withParent, |
112 | | - "def", |
113 | | - Severity.ERROR, |
114 | | - "ERROR"); |
115 | | - testing.clearData(); |
| 23 | + @Override |
| 24 | + protected InstrumentationExtension testing() { |
| 25 | + return testing; |
116 | 26 | } |
117 | 27 |
|
118 | | - private static void test( |
119 | | - Logger logger, |
120 | | - OneArgLoggerMethod oneArgLoggerMethod, |
121 | | - TwoArgLoggerMethod twoArgLoggerMethod, |
122 | | - boolean logException, |
123 | | - boolean withParent, |
124 | | - String expectedLoggerName, |
125 | | - Severity expectedSeverity, |
126 | | - String expectedSeverityText) |
127 | | - throws InterruptedException { |
128 | | - |
129 | | - // when |
130 | | - if (withParent) { |
131 | | - testing.runWithSpan( |
132 | | - "parent", |
133 | | - () -> performLogging(logger, oneArgLoggerMethod, twoArgLoggerMethod, logException)); |
134 | | - } else { |
135 | | - performLogging(logger, oneArgLoggerMethod, twoArgLoggerMethod, logException); |
136 | | - } |
137 | | - |
138 | | - // then |
139 | | - if (withParent) { |
140 | | - testing.waitForTraces(1); |
141 | | - } |
142 | | - |
143 | | - if (expectedSeverity != null) { |
144 | | - testing.waitAndAssertLogRecords( |
145 | | - logRecord -> { |
146 | | - logRecord |
147 | | - .hasBody("xyz: 123") |
148 | | - .hasInstrumentationScope( |
149 | | - InstrumentationScopeInfo.builder(expectedLoggerName).build()) |
150 | | - .hasSeverity(expectedSeverity) |
151 | | - .hasSeverityText(expectedSeverityText) |
152 | | - .hasSpanContext( |
153 | | - withParent |
154 | | - ? testing.spans().get(0).getSpanContext() |
155 | | - : SpanContext.getInvalid()); |
156 | | - |
157 | | - List<AttributeAssertion> attributeAsserts = new ArrayList<>(threadAssertions()); |
158 | | - |
159 | | - attributeAsserts.addAll(codeFunctionAssertions(LogbackTest.class, "performLogging")); |
160 | | - attributeAsserts.addAll(codeFileAndLineAssertions("LogbackTest.java")); |
161 | | - |
162 | | - if (logException) { |
163 | | - attributeAsserts.addAll( |
164 | | - Arrays.asList( |
165 | | - equalTo(EXCEPTION_TYPE, IllegalStateException.class.getName()), |
166 | | - equalTo(EXCEPTION_MESSAGE, "hello"), |
167 | | - satisfies( |
168 | | - EXCEPTION_STACKTRACE, v -> v.contains(LogbackTest.class.getName())))); |
169 | | - } |
170 | | - logRecord.hasAttributesSatisfyingExactly(attributeAsserts); |
171 | | - }); |
172 | | - } else { |
173 | | - Thread.sleep(500); // sleep a bit just to make sure no log is captured |
174 | | - assertThat(testing.logRecords()).isEmpty(); |
175 | | - } |
176 | | - } |
177 | | - |
178 | | - @Test |
179 | | - void testMdc() { |
180 | | - MDC.put("key1", "val1"); |
181 | | - MDC.put("key2", "val2"); |
182 | | - try { |
183 | | - abcLogger.info("xyz: {}", 123); |
184 | | - } finally { |
185 | | - MDC.clear(); |
186 | | - } |
187 | | - |
188 | | - List<AttributeAssertion> assertions = new ArrayList<>(); |
189 | | - assertions.addAll(threadAssertions()); |
190 | | - assertions.addAll(codeFileAndLineAssertions("LogbackTest.java")); |
191 | | - assertions.addAll(codeFunctionAssertions(LogbackTest.class, "testMdc")); |
192 | | - assertions.add(equalTo(AttributeKey.stringKey("key1"), "val1")); |
193 | | - assertions.add(equalTo(AttributeKey.stringKey("key2"), "val2")); |
194 | | - |
195 | | - testing.waitAndAssertLogRecords( |
196 | | - logRecord -> |
197 | | - logRecord |
198 | | - .hasBody("xyz: 123") |
199 | | - .hasInstrumentationScope(InstrumentationScopeInfo.builder("abc").build()) |
200 | | - .hasSeverity(Severity.INFO) |
201 | | - .hasSeverityText("INFO") |
202 | | - .hasAttributesSatisfyingExactly(assertions)); |
203 | | - } |
204 | | - |
205 | | - @Test |
206 | | - public void testMarker() { |
207 | | - |
208 | | - String markerName = "aMarker"; |
209 | | - Marker marker = MarkerFactory.getMarker(markerName); |
210 | | - |
211 | | - abcLogger.info(marker, "Message"); |
212 | | - |
213 | | - List<AttributeAssertion> assertions = codeFunctionAssertions(LogbackTest.class, "testMarker"); |
214 | | - assertions.addAll(threadAssertions()); |
215 | | - assertions.addAll(codeFileAndLineAssertions("LogbackTest.java")); |
216 | | - assertions.add( |
217 | | - equalTo( |
218 | | - AttributeKey.stringArrayKey("logback.marker"), Collections.singletonList(markerName))); |
219 | | - |
220 | | - testing.waitAndAssertLogRecords( |
221 | | - logRecord -> logRecord.hasAttributesSatisfyingExactly(assertions)); |
222 | | - } |
223 | | - |
224 | | - private static List<AttributeAssertion> threadAssertions() { |
| 28 | + @Override |
| 29 | + protected List<AttributeAssertion> threadAssertions() { |
225 | 30 | return Arrays.asList( |
226 | 31 | equalTo(ThreadIncubatingAttributes.THREAD_NAME, Thread.currentThread().getName()), |
227 | 32 | equalTo(ThreadIncubatingAttributes.THREAD_ID, Thread.currentThread().getId())); |
228 | 33 | } |
229 | 34 |
|
230 | | - private static void performLogging( |
231 | | - Logger logger, |
232 | | - OneArgLoggerMethod oneArgLoggerMethod, |
233 | | - TwoArgLoggerMethod twoArgLoggerMethod, |
234 | | - boolean logException) { |
235 | | - if (logException) { |
236 | | - twoArgLoggerMethod.call(logger, "xyz: {}", 123, new IllegalStateException("hello")); |
237 | | - } else { |
238 | | - oneArgLoggerMethod.call(logger, "xyz: {}", 123); |
239 | | - } |
240 | | - } |
241 | | - |
242 | | - @FunctionalInterface |
243 | | - interface OneArgLoggerMethod { |
244 | | - void call(Logger logger, String msg, Object arg); |
245 | | - } |
246 | | - |
247 | | - @FunctionalInterface |
248 | | - interface TwoArgLoggerMethod { |
249 | | - void call(Logger logger, String msg, Object arg1, Object arg2); |
| 35 | + @Override |
| 36 | + protected boolean expectEventName() { |
| 37 | + // TODO support event name in the agent once the attribute name is decided |
| 38 | + // see https://github.com/open-telemetry/semantic-conventions/issues/2913 |
| 39 | + return false; |
250 | 40 | } |
251 | 41 | } |
0 commit comments