Commit 4606a338 authored by Kishore Battula's avatar Kishore Battula
Browse files

Added Slf4jLogger Implementation

parent d5afd917
......@@ -79,7 +79,7 @@
<dependency>
<groupId>org.opengroup.osdu</groupId>
<artifactId>os-core-common</artifactId>
<version>0.0.13</version>
<version>0.3.4</version>
</dependency>
<!-- Azure dependencies -->
......@@ -124,12 +124,6 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
<version>2.2.4.RELEASE</version>
<exclusions>
<exclusion>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.microsoft.azure</groupId>
......
package org.opengroup.osdu.azure.filters;
import org.opengroup.osdu.azure.logging.AzureLogger;
import org.opengroup.osdu.core.common.logging.JaxRsDpsLog;
import org.opengroup.osdu.core.common.model.http.DpsHeaders;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;
import javax.inject.Inject;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
......@@ -30,10 +30,10 @@ public final class TransactionLogFilter implements Filter {
DpsHeaders.DATA_PARTITION_ID,
DpsHeaders.CONTENT_TYPE);
private static final String START_LOG_TEMPLATE = "Start Web-API %s %s %s";
private static final String END_LOG_TEMPLATE = "End Web-API %s %s %s timeTaken:%d";
private static final String END_LOG_TEMPLATE = "End Web-API %s %s %s status=%d time=%d ms";
@Inject
private AzureLogger azureLogger;
@Autowired
private JaxRsDpsLog jaxRsDpsLog;
/**
* Filter logic.
......@@ -60,7 +60,7 @@ public final class TransactionLogFilter implements Filter {
* @param request Request Object.
*/
private void logTransactionStart(final HttpServletRequest request) {
azureLogger.info(LOGGER_NAME, String.format(START_LOG_TEMPLATE, request.getMethod(), request.getServletPath(),
jaxRsDpsLog.info(LOGGER_NAME, String.format(START_LOG_TEMPLATE, request.getMethod(), request.getServletPath(),
getRequestHeadersString(request)));
}
......@@ -72,8 +72,8 @@ public final class TransactionLogFilter implements Filter {
*/
private void logTransactionEnd(final HttpServletRequest request, final HttpServletResponse response,
final long timeTaken) {
azureLogger.info(LOGGER_NAME, String.format(END_LOG_TEMPLATE, request.getMethod(), request.getServletPath(),
getResponseHeadersString(response), timeTaken));
jaxRsDpsLog.info(LOGGER_NAME, String.format(END_LOG_TEMPLATE, request.getMethod(), request.getServletPath(),
getResponseHeadersString(response), response.getStatus(), timeTaken));
}
......@@ -83,7 +83,7 @@ public final class TransactionLogFilter implements Filter {
* @return String representation of request headers.
*/
private String getRequestHeadersString(final HttpServletRequest request) {
return getHeadersString(s -> request.getHeader(s));
return getHeadersString(request::getHeader);
}
/**
......@@ -92,7 +92,7 @@ public final class TransactionLogFilter implements Filter {
* @return String representation of response headers.
*/
private String getResponseHeadersString(final HttpServletResponse response) {
return getHeadersString(s -> response.getHeader(s));
return getHeadersString(response::getHeader);
}
/**
......
package org.opengroup.osdu.azure.logging;
import org.opengroup.osdu.core.common.logging.JaxRsDpsLog;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* A wrapper on {@link JaxRsDpsLog}.
*/
@Component
public class AzureLogger {
@Autowired
private JaxRsDpsLog jaxRsDpsLog;
/**
* To log info messages.
* @param loggerName Name of the logger. Generally Fully qualified class name is used. e.g className.class
* @param message Message to log
*/
public void info(final String loggerName, final String message) {
jaxRsDpsLog.info(message);
}
/**
* To log info messages.
* @param loggerName Name of the logger. Generally Fully qualified class name is used. e.g className.class
* @param message Message to log
*/
public void warn(final String loggerName, final String message) {
jaxRsDpsLog.warning(message);
}
/**
* To log info messages.
* @param loggerName Name of the logger. Generally Fully qualified class name is used. e.g className.class
* @param message Message to log
* @param e exception to log
*/
public void warn(final String loggerName, final String message, final Exception e) {
jaxRsDpsLog.warning(message, e);
}
/**
* To log info messages.
* @param loggerName Name of the logger. Generally Fully qualified class name is used. e.g className.class
* @param message Message to log
*/
public void error(final String loggerName, final String message) {
jaxRsDpsLog.error(message);
}
/**
* To log info messages.
* @param loggerName Name of the logger. Generally Fully qualified class name is used. e.g className.class
* @param message Message to log
* @param e exception to log
*/
public void error(final String loggerName, final String message, final Exception e) {
jaxRsDpsLog.error(message, e);
}
}
package org.opengroup.osdu.azure.logging;
import org.opengroup.osdu.core.common.logging.ILogger;
import org.opengroup.osdu.core.common.logging.audit.AuditPayload;
import org.opengroup.osdu.core.common.model.http.HeadersToLog;
import org.opengroup.osdu.core.common.model.http.Request;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;
import java.util.Map;
/**
* {@link ILogger} implementation with Slf4J Logger.
*/
@Component
@Primary
@ConditionalOnProperty(value = "logging.slf4jlogger.enabled", havingValue = "true", matchIfMissing = false)
public final class Slf4JLogger implements ILogger {
private static final String DEFAULT_LOGGER_NAME = Slf4JLogger.class.getName();
@Autowired
private HeadersToLog headersToLog;
@Autowired
private Slf4jLoggerFactory slf4jLoggerFactory;
@Override
public void audit(final String logPrefix, final AuditPayload auditPayload, final Map<String, String> headers) {
this.audit(DEFAULT_LOGGER_NAME, logPrefix, auditPayload, headers);
}
@Override
public void audit(final String loggerName, final String logPrefix, final AuditPayload payload, final Map<String, String> headers) {
slf4jLoggerFactory.getLogger(loggerName).info("{} {} {}", logPrefix, payload,
this.headersToLog.createStandardLabelsFromMap(headers));
}
@Override
public void request(final String logPrefix, final Request request, final Map<String, String> headers) {
this.request(DEFAULT_LOGGER_NAME, logPrefix, request, headers);
}
@Override
public void request(final String loggerName, final String logPrefix, final Request request, final Map<String, String> headers) {
slf4jLoggerFactory.getLogger(loggerName).info("{} {} {}", logPrefix, request,
this.headersToLog.createStandardLabelsFromMap(headers));
}
@Override
public void info(final String logPrefix, final String message, final Map<String, String> headers) {
this.info(DEFAULT_LOGGER_NAME, logPrefix, message, headers);
}
@Override
public void info(final String loggerName, final String logPrefix, final String message, final Map<String, String> headers) {
slf4jLoggerFactory.getLogger(loggerName).info("{} {} {}", logPrefix, message,
this.headersToLog.createStandardLabelsFromMap(headers));
}
@Override
public void warning(final String logPrefix, final String message, final Map<String, String> headers) {
this.warning(DEFAULT_LOGGER_NAME, logPrefix, message, headers);
}
@Override
public void warning(final String loggerName, final String logPrefix, final String message, final Map<String, String> headers) {
slf4jLoggerFactory.getLogger(loggerName).warn("{} {} {}", logPrefix, message,
this.headersToLog.createStandardLabelsFromMap(headers));
}
@Override
public void warning(final String logPrefix, final String message, final Exception e, final Map<String, String> headers) {
this.warning(DEFAULT_LOGGER_NAME, logPrefix, message, e, headers);
}
@Override
public void warning(final String loggerName, final String logPrefix, final String message, final Exception ex, final Map<String, String> headers) {
slf4jLoggerFactory.getLogger(loggerName).warn("{} {} {}", logPrefix, message,
this.headersToLog.createStandardLabelsFromMap(headers), ex);
}
@Override
public void error(final String logPrefix, final String message, final Map<String, String> headers) {
this.error(DEFAULT_LOGGER_NAME, logPrefix, message, headers);
}
@Override
public void error(final String loggerName, final String logPrefix, final String message, final Map<String, String> headers) {
slf4jLoggerFactory.getLogger(loggerName).error("{} {} {}", logPrefix, message,
this.headersToLog.createStandardLabelsFromMap(headers));
}
@Override
public void error(final String logPrefix, final String message, final Exception e,
final Map<String, String> headers) {
this.error(DEFAULT_LOGGER_NAME, logPrefix, message, e, headers);
}
@Override
public void error(final String loggerName, final String logPrefix, final String message, final Exception ex, final Map<String, String> headers) {
slf4jLoggerFactory.getLogger(loggerName).error("{} {} {}", logPrefix, message,
this.headersToLog.createStandardLabelsFromMap(headers), ex);
}
@Override
public void close() throws Exception {
// do nothing
}
}
package org.opengroup.osdu.azure.logging;
import org.opengroup.osdu.core.common.model.http.HeadersToLog;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.Collections;
/**
* Creating beans needed for Slf4JLogger.
*/
@Configuration
public class Slf4JLoggerConfiguration {
/**
* Bean for HeadersToLog used in {@link Slf4JLogger}.
* @return {@link HeadersToLog} instance
*/
@Bean
public HeadersToLog headersToLog() {
return new HeadersToLog(Collections.emptyList());
}
}
package org.opengroup.osdu.azure.logging;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
/**
* Factory for slf4j logger instances.
*/
@Component
public final class Slf4jLoggerFactory {
/**
* Returns slf4j logger instance based on name.
* @param loggerName name of the logger
* @return {@link Logger} instance
*/
public Logger getLogger(final String loggerName) {
return LoggerFactory.getLogger(loggerName);
}
}
......@@ -23,15 +23,20 @@
</Properties>
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} %5p ${hostName} --- [%15.15t] %-40.40c{1.} : %m%n%ex"/>
</Console>
<ApplicationInsightsAppender name="aiAppender">
</ApplicationInsightsAppender>
</Appenders>
<Loggers>
<Root level="trace">
<!-- TODO: In future it will be changed to warn-->
<Root level="info">
<AppenderRef ref="Console" />
<AppenderRef ref="aiAppender" />
</Root>
<logger name="TxnLogger" level="info" additivity="false">
<AppenderRef ref="Console" />
<AppenderRef ref="aiAppender" />
</logger>
</Loggers>
</Configuration>
\ No newline at end of file
......@@ -7,7 +7,7 @@ import org.mockito.ArgumentCaptor;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.opengroup.osdu.azure.logging.AzureLogger;
import org.opengroup.osdu.core.common.logging.JaxRsDpsLog;
import org.opengroup.osdu.core.common.model.http.DpsHeaders;
import javax.servlet.FilterChain;
......@@ -26,6 +26,7 @@ import static org.mockito.Mockito.when;
*/
@ExtendWith(MockitoExtension.class)
public class TransactionLogFilterTest {
private static final int STATUS_CODE = 200;
@Mock
private HttpServletRequest servletRequest;
@Mock
......@@ -33,31 +34,32 @@ public class TransactionLogFilterTest {
@Mock
private FilterChain filterChain;
@Mock
private AzureLogger azureLogger;
private JaxRsDpsLog jaxRsDpsLog;
@InjectMocks
private TransactionLogFilter logFilter;
@BeforeEach
public void setup() {
when(servletResponse.getStatus()).thenReturn(STATUS_CODE);
}
@Test
public void testStartAndEndMessagesAreLoggedProperly() throws Exception {
final String startLogMessage = "Start Web-API PUT records Headers: {correlation-id:abc}";
final String endMessage = "End Web-API PUT records Headers: {correlation-id:abc} timeTaken:";
final String endMessage = "End Web-API PUT records Headers: {correlation-id:abc} status=200 time=";
when(servletRequest.getMethod()).thenReturn("PUT");
when(servletRequest.getServletPath()).thenReturn("records");
when(servletRequest.getHeader(eq(DpsHeaders.CORRELATION_ID))).thenReturn("abc");
when(servletResponse.getHeader(eq(DpsHeaders.CORRELATION_ID))).thenReturn("abc");
final ArgumentCaptor<String> logMessageCaptor = ArgumentCaptor.forClass(String.class);
doNothing().when(azureLogger).info(eq("TxnLogger"), logMessageCaptor.capture());
doNothing().when(jaxRsDpsLog).info(eq("TxnLogger"), logMessageCaptor.capture());
this.logFilter.doFilter(servletRequest, servletResponse, filterChain);
verify(servletRequest, times(2)).getMethod();
verify(servletRequest, times(2)).getServletPath();
verify(servletRequest, times(2)).getHeader(eq(DpsHeaders.CORRELATION_ID));
verify(servletResponse, times(2)).getHeader(eq(DpsHeaders.CORRELATION_ID));
verify(servletResponse, times(1)).getStatus();
assertEquals(2, logMessageCaptor.getAllValues().size());
assertEquals(startLogMessage, logMessageCaptor.getAllValues().get(0));
assertEquals(true, logMessageCaptor.getAllValues().get(1).startsWith(endMessage));
......@@ -66,14 +68,15 @@ public class TransactionLogFilterTest {
@Test
public void testStartAndEndMessagesAreLoggedProperlyWithNoHeaders() throws Exception {
final String startLogMessage = "Start Web-API PUT records Headers: {}";
final String endMessage = "End Web-API PUT records Headers: {} timeTaken:";
final String endMessage = "End Web-API PUT records Headers: {} status=200 time=";
when(servletRequest.getMethod()).thenReturn("PUT");
when(servletRequest.getServletPath()).thenReturn("records");
final ArgumentCaptor<String> logMessageCaptor = ArgumentCaptor.forClass(String.class);
doNothing().when(azureLogger).info(eq("TxnLogger"), logMessageCaptor.capture());
doNothing().when(jaxRsDpsLog).info(eq("TxnLogger"), logMessageCaptor.capture());
this.logFilter.doFilter(servletRequest, servletResponse, filterChain);
verify(servletRequest, times(2)).getMethod();
verify(servletRequest, times(2)).getServletPath();
verify(servletResponse, times(1)).getStatus();
assertEquals(2, logMessageCaptor.getAllValues().size());
assertEquals(startLogMessage, logMessageCaptor.getAllValues().get(0));
assertEquals(true, logMessageCaptor.getAllValues().get(1).startsWith(endMessage));
......
package org.opengroup.osdu.azure.logging;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import org.mockito.junit.jupiter.MockitoExtension;
import org.opengroup.osdu.core.common.logging.JaxRsDpsLog;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
/**
* Tests for {@link AzureLogger}
*/
@ExtendWith(MockitoExtension.class)
public class AzureLoggerTest {
private static final String LOGGER_NAME = AzureLoggerTest.class.getName();
private static final String LOG_MESSAGE = "Hello world";
private static final Exception EXCEPTION = new Exception();
@Mock
private JaxRsDpsLog jaxRsDpsLog;
@InjectMocks
private AzureLogger azureLogger;
@Test
public void testInfo() {
doNothing().when(jaxRsDpsLog).info(eq(LOG_MESSAGE));
azureLogger.info(LOGGER_NAME, LOG_MESSAGE);
verify(jaxRsDpsLog, times(1)).info(eq(LOG_MESSAGE));
}
@Test
public void testWarn() {
doNothing().when(jaxRsDpsLog).warning(eq(LOG_MESSAGE));
azureLogger.warn(LOGGER_NAME, LOG_MESSAGE);
verify(jaxRsDpsLog, times(1)).warning(eq(LOG_MESSAGE));
}
@Test
public void testWarnWithException() {
doNothing().when(jaxRsDpsLog).warning(eq(LOG_MESSAGE), eq(EXCEPTION));
azureLogger.warn(LOGGER_NAME, LOG_MESSAGE, EXCEPTION);
verify(jaxRsDpsLog, times(1)).warning(eq(LOG_MESSAGE), eq(EXCEPTION));
}
@Test
public void testError() {
doNothing().when(jaxRsDpsLog).error(eq(LOG_MESSAGE));
azureLogger.error(LOGGER_NAME, LOG_MESSAGE);
verify(jaxRsDpsLog, times(1)).error(eq(LOG_MESSAGE));
}
@Test
public void testErrorWithException() {
doNothing().when(jaxRsDpsLog).error(eq(LOG_MESSAGE), eq(EXCEPTION));
azureLogger.error(LOGGER_NAME, LOG_MESSAGE, EXCEPTION);
verify(jaxRsDpsLog, times(1)).error(eq(LOG_MESSAGE), eq(EXCEPTION));
}
}
package org.opengroup.osdu.azure.logging;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.junit.jupiter.MockitoExtension;
import org.slf4j.Logger;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertSame;
/**
* Contains tests for {@link Slf4jLoggerFactory}
*/
@ExtendWith(MockitoExtension.class)
public class Slf4JLoggerFactoryTest {
private static final String LOGGER_NAME1 = Slf4JLoggerFactoryTest.class.getName();
private static final String LOGGER_NAME2 = Slf4jLoggerFactory.class.getName();
@InjectMocks
private Slf4jLoggerFactory slf4jLoggerFactory;
@Test
public void testSameLoggerInstanceReturnedWhenCalledWithSameName() {
final Logger logger1 = slf4jLoggerFactory.getLogger(LOGGER_NAME1);
final Logger logger2 = slf4jLoggerFactory.getLogger(LOGGER_NAME1);
assertSame(logger1, logger2, "when called with same name, it should return same instance");
}
@Test
public void testDifferentLoggerInstanceReturnedWhenCalledWithDifferentName() {
final Logger logger1 = slf4jLoggerFactory.getLogger(LOGGER_NAME1);
final Logger logger2 = slf4jLoggerFactory.getLogger(LOGGER_NAME2);
assertNotEquals(logger1, logger2, "when called with different names, it should return different instances");
}
}
package org.opengroup.osdu.azure.logging;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.opengroup.osdu.core.common.logging.audit.AuditPayload;
import org.opengroup.osdu.core.common.model.http.HeadersToLog;
import org.opengroup.osdu.core.common.model.http.Request;
import org.slf4j.Logger;
import java.util.HashMap;
import java.util.Map;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
/**
* Contains tests for {@link Slf4JLogger}
*/
@ExtendWith(MockitoExtension.class)
public class Slf4JLoggerTest {
private static final String LOG_PREFIX = "services.app";
private static final String DEFAULT_LOGGER_NAME = Slf4JLogger.class.getName();
private static final String LOGGER_NAME = Slf4JLoggerTest.class.getName();
private static final String LOG_MESSAGE = "Hello world !";
@Mock
private HeadersToLog headersToLog;
@Mock
private AuditPayload auditPayload;
@Mock
private Slf4jLoggerFactory slf4jLoggerFactory;
@Mock
private Request request;
@Mock
private Logger logger;
@Mock
private Exception e;
private final Map<String, String> headers = new HashMap<>();
@InjectMocks
Slf4JLogger slf4JLogger;
@BeforeEach
public void setup() {
when(slf4jLoggerFactory.getLogger(any())).thenReturn(logger);
when(headersToLog.createStandardLabelsFromMap(eq(headers))).thenReturn(headers);
}
@Test
public void testAudit() {
doNothing().when(logger).info(eq("{} {} {}"), eq(LOG_PREFIX), eq(auditPayload), eq(headers));
slf4JLogger.audit(LOG_PREFIX, auditPayload, headers);
verify(logger, times(1)).info(eq("{} {} {}"), eq(LOG_PREFIX), eq(auditPayload), eq(headers));
verify(slf4jLoggerFactory, times(1)).getLogger(eq(DEFAULT_LOGGER_NAME));
verify(headersToLog, times(1)).createStandardLabelsFromMap(eq(headers));