2 * Copyright © 2016-2018 European Support Limited
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package org.openecomp.sdc.logging.slf4j;
19 import static org.openecomp.sdc.logging.slf4j.SLF4JLoggerWrapper.AuditField.BEGIN_TIMESTAMP;
20 import static org.openecomp.sdc.logging.slf4j.SLF4JLoggerWrapper.AuditField.CLIENT_IP_ADDRESS;
21 import static org.openecomp.sdc.logging.slf4j.SLF4JLoggerWrapper.AuditField.ELAPSED_TIME;
22 import static org.openecomp.sdc.logging.slf4j.SLF4JLoggerWrapper.AuditField.END_TIMESTAMP;
23 import static org.openecomp.sdc.logging.slf4j.SLF4JLoggerWrapper.AuditField.RESPONSE_CODE;
24 import static org.openecomp.sdc.logging.slf4j.SLF4JLoggerWrapper.AuditField.RESPONSE_DESCRIPTION;
25 import static org.openecomp.sdc.logging.slf4j.SLF4JLoggerWrapper.AuditField.STATUS_CODE;
26 import static org.testng.Assert.assertEquals;
27 import static org.testng.Assert.assertNotNull;
28 import static org.testng.Assert.assertNull;
30 import java.lang.reflect.InvocationHandler;
31 import java.lang.reflect.Method;
32 import java.lang.reflect.Proxy;
33 import java.util.Arrays;
35 import org.openecomp.sdc.logging.api.AuditData;
36 import org.openecomp.sdc.logging.api.StatusCode;
37 import org.slf4j.Logger;
39 import org.testng.annotations.Test;
42 * Unit-test of SLF4J implementation of Logger.
47 @SuppressWarnings("CheckStyle")
48 public class SLF4JLoggerWrapperTest {
51 public void auditDoesNotFailWhenInputNull() {
52 new SLF4JLoggerWrapper(this.getClass()).audit(null);
56 public void beginTimeAvailableWhenPassed() {
57 SpyLogger spy = createSpy();
58 long start = System.currentTimeMillis();
59 new SLF4JLoggerWrapper(spy).audit(AuditData.builder().startTime(start).build());
60 assertNotNull(spy.mdc().get(BEGIN_TIMESTAMP.asKey()));
64 public void entTimeAvailableWhenPassed() {
65 SpyLogger spy = createSpy();
66 long end = System.currentTimeMillis();
67 new SLF4JLoggerWrapper(spy).audit(AuditData.builder().endTime(end).build());
68 assertNotNull(spy.mdc().get(END_TIMESTAMP.asKey()));
72 public void elapsedTimeAvailableWhenPassed() {
73 SpyLogger spy = createSpy();
74 long start = System.currentTimeMillis();
75 new SLF4JLoggerWrapper(spy).audit(AuditData.builder()
76 .startTime(start).endTime(start).build());
77 assertNotNull(spy.mdc().get(ELAPSED_TIME.asKey()));
81 public void statusCodeAvailableWhenPassed() {
82 SpyLogger spy = createSpy();
83 new SLF4JLoggerWrapper(spy).audit(AuditData.builder().statusCode(StatusCode.COMPLETE).build());
84 assertEquals(spy.mdc().get(STATUS_CODE.asKey()), StatusCode.COMPLETE.name());
88 public void statusCodeEmptyWhenNotPassed() {
89 SpyLogger spy = createSpy();
90 new SLF4JLoggerWrapper(spy).audit(AuditData.builder().build());
91 assertNull(spy.mdc().get(STATUS_CODE.asKey()));
95 public void responseCodeAvailableWhenPassed() {
96 final String responseCode = "SpyResponse";
97 SpyLogger spy = createSpy();
98 new SLF4JLoggerWrapper(spy).audit(AuditData.builder().responseCode(responseCode).build());
99 assertEquals(spy.mdc().get(RESPONSE_CODE.asKey()), responseCode);
103 public void responseCodeEmptyWhenNotPassed() {
104 SpyLogger spy = createSpy();
105 new SLF4JLoggerWrapper(spy).audit(AuditData.builder().build());
106 assertNull(spy.mdc().get(RESPONSE_CODE.asKey()));
110 public void responseDescriptionAvailableWhenPassed() {
111 final String responseDescription = "SpyDescription";
112 SpyLogger spy = createSpy();
113 new SLF4JLoggerWrapper(spy).audit(AuditData.builder().responseDescription(responseDescription).build());
114 assertEquals(spy.mdc().get(RESPONSE_DESCRIPTION.asKey()), responseDescription);
118 public void responseDescriptionEmptyWhenNotPassed() {
119 SpyLogger spy = createSpy();
120 new SLF4JLoggerWrapper(spy).audit(AuditData.builder().build());
121 assertNull(spy.mdc().get(RESPONSE_DESCRIPTION.asKey()));
125 public void clientIpAddressAvailableWhenPassed() {
126 final String ipAddress = "10.56.20.20";
127 SpyLogger spy = createSpy();
128 new SLF4JLoggerWrapper(spy).audit(AuditData.builder().clientIpAddress(ipAddress).build());
129 assertEquals(spy.mdc().get(CLIENT_IP_ADDRESS.asKey()), ipAddress);
133 public void clientIpAddressEmptyWhenNotPassed() {
134 SpyLogger spy = createSpy();
135 new SLF4JLoggerWrapper(spy).audit(AuditData.builder().build());
136 assertNull(spy.mdc().get(CLIENT_IP_ADDRESS.asKey()));
140 public void elapsedTimeEqualsDifferenceBetweenStartAndEnd() {
141 SpyLogger spy = createSpy();
142 final long diff = 1024;
143 long start = System.currentTimeMillis();
144 long end = start + diff;
145 new SLF4JLoggerWrapper(spy).audit(AuditData.builder().startTime(start).endTime(end).build());
146 assertEquals(spy.mdc().get(ELAPSED_TIME.asKey()), Long.toString(diff));
149 interface SpyLogger extends Logger {
151 Map<String, String> mdc();
155 * Creates a in instance of Logger that can be used to track MDC changes as part of an invocation of
158 * @return object that implements {@link SpyLogger}
160 private static SpyLogger createSpy() {
162 // build a dynamic proxy to avoid implementing the long list of Logger methods
163 // when we actually need just Logger.info() with the audit marker
164 ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
165 return SpyLogger.class.cast(
166 Proxy.newProxyInstance(classLoader, new Class<?>[]{SpyLogger.class}, new SpyingInvocationHandler()));
169 private static class SpyingInvocationHandler implements InvocationHandler {
171 private Map<String, String> mdc;
174 public Object invoke(Object proxy, Method method, Object[] args) {
176 if (isReturnMdcMethod(method)) {
180 if (!isAuditMethod(method, args)) {
181 throw new UnsupportedOperationException("Method " + method.getName() + " with arguments "
182 + Arrays.toString(args) + " wasn't supposed to be called");
189 private boolean isAuditMethod(Method method, Object[] args) {
190 return (method.getName().equals("info") && args.length > 0 && args[0].equals(Markers.AUDIT));
193 private void storeEffectiveMdc() {
194 mdc = MDC.getCopyOfContextMap();
197 private boolean isReturnMdcMethod(Method method) {
198 return method.equals(SpyLogger.class.getDeclaredMethods()[0]);