diff options
author | AviZi <avi.ziv@amdocs.com> | 2017-06-09 02:39:56 +0300 |
---|---|---|
committer | AviZi <avi.ziv@amdocs.com> | 2017-06-09 02:39:56 +0300 |
commit | 280f8015d06af1f41a3ef12e8300801c7a5e0d54 (patch) | |
tree | 9c1d3978c04cd28068f02073038c936bb49ca9e0 /common/openecomp-logging-lib/openecomp-logging-core | |
parent | fd3821dad11780d33c5373d74c957c442489945e (diff) |
[SDC-29] Amdocs OnBoard 1707 initial commit.
Change-Id: Ie4d12a3f574008b792899b368a0902a8b46b5370
Signed-off-by: AviZi <avi.ziv@amdocs.com>
Diffstat (limited to 'common/openecomp-logging-lib/openecomp-logging-core')
23 files changed, 2800 insertions, 0 deletions
diff --git a/common/openecomp-logging-lib/openecomp-logging-core/README b/common/openecomp-logging-lib/openecomp-logging-core/README new file mode 100644 index 0000000000..779c5d99df --- /dev/null +++ b/common/openecomp-logging-lib/openecomp-logging-core/README @@ -0,0 +1,29 @@ +The purpose of this module is to make a Web application meet the OPENECOMP logging requirements described in +OPENECOMP platform application logging guidelines. + +The default out-of-the box solution is based on SLF4J. + +It introduces three major areas of functionality as follows: + +1. Routing of logging messages for the Logback library, so that all logging events are written to separate files +according to their type. + +2. An AOP aspect for measuring execution time and logging it, so that the application code is not contaminated with +this type of logging. + +3. Collecting and populating the context of a Web API request and propagating it to every logging event. + +TODO: + +1. MetricsAspect + - Configurable metrics message + - Make sure there are no exceptions but applicative ones + +2. EventTypeDiscriminator + - Make event types configurable to make the names of log files easily customizable + +3. DispatchingAppender + - Read appenders from configuration, so that there is no need in EELF loggers + - Simpler use of discriminator or an entirely different mechanism + - Better appender name pattern, or mapping between a discriminating value and an appender name + - Discard the appenders cache on configuration changes diff --git a/common/openecomp-logging-lib/openecomp-logging-core/pom.xml b/common/openecomp-logging-lib/openecomp-logging-core/pom.xml new file mode 100644 index 0000000000..636595bc45 --- /dev/null +++ b/common/openecomp-logging-lib/openecomp-logging-core/pom.xml @@ -0,0 +1,72 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <name>openecomp-configuration-management-test</name> + <groupId>org.openecomp.sdc.common</groupId> + <artifactId>openecomp-logging-core</artifactId> + + <parent> + <artifactId>openecomp-logging-lib</artifactId> + <groupId>org.openecomp.sdc.common</groupId> + <version>1.1.0-SNAPSHOT</version> + <relativePath>..</relativePath> + </parent> + + <properties> + <logback.version>1.1.7</logback.version> + <powermock.version>1.6.5</powermock.version> + <easymock.version>3.4</easymock.version> + </properties> + + <dependencies> + <dependency> + <groupId>org.aspectj</groupId> + <artifactId>aspectjrt</artifactId> + </dependency> + <dependency> + <groupId>org.openecomp.sdc.common</groupId> + <artifactId>openecomp-logging-api</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>ch.qos.logback</groupId> + <artifactId>logback-classic</artifactId> + <version>${logback.version}</version> + </dependency> + <dependency> + <groupId>ch.qos.logback</groupId> + <artifactId>logback-core</artifactId> + <version>${logback.version}</version> + </dependency> + + <!-- for testing --> + <dependency> + <groupId>org.easymock</groupId> + <artifactId>easymock</artifactId> + <version>${easymock.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.powermock</groupId> + <artifactId>powermock-api-easymock</artifactId> + <version>${powermock.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.powermock</groupId> + <artifactId>powermock-core</artifactId> + <version>${powermock.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.powermock</groupId> + <artifactId>powermock-module-testng</artifactId> + <version>${powermock.version}</version> + <scope>test</scope> + </dependency> + </dependencies> + +</project> diff --git a/common/openecomp-logging-lib/openecomp-logging-core/src/main/java/org/openecomp/core/logging/Markers.java b/common/openecomp-logging-lib/openecomp-logging-core/src/main/java/org/openecomp/core/logging/Markers.java new file mode 100644 index 0000000000..dc2ae367b3 --- /dev/null +++ b/common/openecomp-logging-lib/openecomp-logging-core/src/main/java/org/openecomp/core/logging/Markers.java @@ -0,0 +1,21 @@ +package org.openecomp.core.logging; + +import org.slf4j.Marker; +import org.slf4j.MarkerFactory; + +/** + * <p>The list of markers that can be used for special logging such as metrics, audit, etc.</p> + * <p>Although markers can be easily instantiated whenever needed, having constants for them helps + * eliminate mistakes - misspelling, using a marker that is not handled, etc.</p> <p>Usage:</p> + * <pre> + * Logger log = LogFactory.getLogger(this.getClass()); + * log.info(Markers.AUDIT, "User '{}' logged out", user); + * </pre> + * + * @see org.slf4j.Marker + */ +public class Markers { + + public static final Marker AUDIT = MarkerFactory.getMarker("AUDIT"); + public static final Marker METRICS = MarkerFactory.getMarker("METRICS"); +} diff --git a/common/openecomp-logging-lib/openecomp-logging-core/src/main/java/org/openecomp/core/logging/Slf4JLoggerCreationService.java b/common/openecomp-logging-lib/openecomp-logging-core/src/main/java/org/openecomp/core/logging/Slf4JLoggerCreationService.java new file mode 100644 index 0000000000..3238e75f8e --- /dev/null +++ b/common/openecomp-logging-lib/openecomp-logging-core/src/main/java/org/openecomp/core/logging/Slf4JLoggerCreationService.java @@ -0,0 +1,236 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.core.logging; + +import org.openecomp.core.logging.api.Logger; +import org.openecomp.core.logging.api.LoggerCreationService; +import org.slf4j.LoggerFactory; + +public class Slf4JLoggerCreationService implements LoggerCreationService { + + @Override + public Logger getLogger(String className) { + return new Slf4JWrapper(className); + } + + @Override + public Logger getLogger(Class<?> clazz) { + return new Slf4JWrapper(clazz); + } + + private class Slf4JWrapper implements Logger { + + private final org.slf4j.Logger logger; + + public Slf4JWrapper(Class<?> clazz) { + logger = LoggerFactory.getLogger(clazz); + } + + public Slf4JWrapper(String className) { + logger = LoggerFactory.getLogger(className); + } + + @Override + public String getName() { + return logger.getName(); + } + + @Override + public boolean isMetricsEnabled() { + return logger.isInfoEnabled(Markers.METRICS); + } + + @Override + public void metrics(String msg) { + logger.info(Markers.METRICS, msg); + } + + @Override + public void metrics(String msg, Object arg) { + logger.info(Markers.METRICS, msg, arg); + } + + @Override + public void metrics(String msg, Object arg1, Object arg2) { + logger.info(Markers.METRICS, msg, arg1, arg2); + } + + @Override + public void metrics(String msg, Object... arguments) { + logger.info(Markers.METRICS, msg, arguments); + } + + @Override + public void metrics(String msg, Throwable throwable) { + logger.info(Markers.METRICS, msg, throwable); + } + + @Override + public boolean isAuditEnabled() { + return logger.isInfoEnabled(Markers.AUDIT); + } + + @Override + public void audit(String msg) { + logger.info(Markers.AUDIT, msg); + } + + @Override + public void audit(String msg, Object arg) { + logger.info(Markers.AUDIT, msg, arg); + } + + @Override + public void audit(String msg, Object arg1, Object arg2) { + logger.info(Markers.AUDIT, msg, arg1, arg2); + } + + @Override + public void audit(String msg, Object... arguments) { + logger.info(Markers.AUDIT, msg, arguments); + } + + @Override + public void audit(String msg, Throwable throwable) { + logger.info(Markers.AUDIT, msg, throwable); + } + + @Override + public boolean isDebugEnabled() { + return logger.isDebugEnabled(); + } + + @Override + public void debug(String msg) { + logger.debug(msg); + } + + @Override + public void debug(String format, Object arg) { + logger.debug(format, arg); + } + + @Override + public void debug(String format, Object arg1, Object arg2) { + logger.debug(format, arg1, arg2); + } + + @Override + public void debug(String format, Object... arguments) { + logger.debug(format, arguments); + } + + @Override + public void debug(String msg, Throwable throwable) { + logger.debug(msg, throwable); + } + + @Override + public boolean isInfoEnabled() { + return logger.isInfoEnabled(); + } + + @Override + public void info(String msg) { + logger.info(msg); + } + + @Override + public void info(String format, Object arg) { + logger.info(format, arg); + } + + @Override + public void info(String format, Object arg1, Object arg2) { + logger.info(format, arg1, arg2); + } + + @Override + public void info(String format, Object... arguments) { + logger.info(format, arguments); + } + + @Override + public void info(String msg, Throwable throwable) { + logger.info(msg, throwable); + } + + @Override + public boolean isWarnEnabled() { + return logger.isWarnEnabled(); + } + + @Override + public void warn(String msg) { + logger.warn(msg); + } + + @Override + public void warn(String format, Object arg) { + logger.warn(format, arg); + } + + @Override + public void warn(String format, Object... arguments) { + logger.warn(format, arguments); + } + + @Override + public void warn(String format, Object arg1, Object arg2) { + logger.warn(format, arg1, arg2); + } + + @Override + public void warn(String msg, Throwable throwable) { + logger.warn(msg, throwable); + } + + @Override + public boolean isErrorEnabled() { + return logger.isErrorEnabled(); + } + + @Override + public void error(String msg) { + logger.error(msg); + } + + @Override + public void error(String format, Object arg) { + logger.error(format, arg); + } + + @Override + public void error(String format, Object arg1, Object arg2) { + logger.error(format, arg1, arg2); + } + + @Override + public void error(String format, Object... arguments) { + logger.error(format, arguments); + } + + @Override + public void error(String msg, Throwable throwable) { + logger.error(msg, throwable); + } + } +} diff --git a/common/openecomp-logging-lib/openecomp-logging-core/src/main/java/org/openecomp/core/logging/aspects/MetricsAspect.java b/common/openecomp-logging-lib/openecomp-logging-core/src/main/java/org/openecomp/core/logging/aspects/MetricsAspect.java new file mode 100644 index 0000000000..9e8c7f0aa8 --- /dev/null +++ b/common/openecomp-logging-lib/openecomp-logging-core/src/main/java/org/openecomp/core/logging/aspects/MetricsAspect.java @@ -0,0 +1,72 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.core.logging.aspects; + +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.openecomp.core.logging.api.Logger; +import org.openecomp.core.logging.api.LoggerFactory; +import org.openecomp.core.logging.api.annotations.Metrics; + +/** + * <p>Wraps around any method annotated with {@link Metrics} to measure and log its execution time + * in milliseconds.</p> <p>In order for the aspect to be used, AspectJ annotation processing must be + * tuned on and this particular aspect enabled. Conversely, it can be disabled completely if the + * application does not need to log metrics.</p> <p>See, for example, <a + * href="http://docs.spring.io/spring/docs/current/spring-framework-reference/html/aop.html"> Aspect + * Oriented Programming with Spring</a>.</p> + * + * @see Metrics + */ +@Aspect +public class MetricsAspect { + + private static final String MESSAGE_TEMPLATE = "'{}' took {} milliseconds"; + + /** + * Log execution time object. + * + * @param pjp the pjp + * @return the object + * @throws Throwable the throwable + */ + @Around("@annotation(org.openecomp.core.logging.api.annotations.Metrics)") + public Object logExecutionTime(ProceedingJoinPoint pjp) throws Throwable { + + final Logger logger = LoggerFactory.getLogger(pjp.getSignature().getDeclaringTypeName()); + // measure and log only if the logger for this class is enabled + if (logger.isMetricsEnabled()) { + + final String method = pjp.getSignature().getName(); + final long start = System.currentTimeMillis(); + + try { + return pjp.proceed(); + } finally { + logger.metrics(MESSAGE_TEMPLATE, method, System.currentTimeMillis() - start); + } + + } else { + return pjp.proceed(); + } + } +} diff --git a/common/openecomp-logging-lib/openecomp-logging-core/src/main/java/org/openecomp/core/logging/context/MdcPropagationService.java b/common/openecomp-logging-lib/openecomp-logging-core/src/main/java/org/openecomp/core/logging/context/MdcPropagationService.java new file mode 100644 index 0000000000..94ad1b9717 --- /dev/null +++ b/common/openecomp-logging-lib/openecomp-logging-core/src/main/java/org/openecomp/core/logging/context/MdcPropagationService.java @@ -0,0 +1,71 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.core.logging.context; + +import org.openecomp.core.logging.api.context.ContextPropagationService; +import org.slf4j.MDC; + +import java.util.Map; + +/** + * Propagates the <a href="http://www.slf4j.org/manual.html#mdc">SLF4J Mapped Diagnostic Context + * (MDC)</a> of a thread onto a runnable created by that thread, so that the context is available + * when the runnable is executed in a new thread. + */ +public class MdcPropagationService implements ContextPropagationService { + + public Runnable create(Runnable task) { + return new MdcCopyingWrapper(task); + } + + private static class MdcCopyingWrapper implements Runnable { + + private final Runnable task; + private final Map<String, String> context; + + private MdcCopyingWrapper(Runnable task) { + this.task = task; + this.context = MDC.getCopyOfContextMap(); + } + + private static void replaceMdc(Map<String, String> context) { + + if (context == null) { + MDC.clear(); + } else { + MDC.setContextMap(context); + } + } + + @Override + public void run() { + + Map<String, String> oldContext = MDC.getCopyOfContextMap(); + replaceMdc(this.context); + + try { + task.run(); + } finally { + replaceMdc(oldContext); + } + } + } +} diff --git a/common/openecomp-logging-lib/openecomp-logging-core/src/main/java/org/openecomp/core/logging/logback/DispatchingAppender.java b/common/openecomp-logging-lib/openecomp-logging-core/src/main/java/org/openecomp/core/logging/logback/DispatchingAppender.java new file mode 100644 index 0000000000..6d5642e374 --- /dev/null +++ b/common/openecomp-logging-lib/openecomp-logging-core/src/main/java/org/openecomp/core/logging/logback/DispatchingAppender.java @@ -0,0 +1,142 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.core.logging.logback; + +import ch.qos.logback.classic.Logger; +import ch.qos.logback.classic.LoggerContext; +import ch.qos.logback.classic.sift.MDCBasedDiscriminator; +import ch.qos.logback.classic.spi.ILoggingEvent; +import ch.qos.logback.core.Appender; +import ch.qos.logback.core.AppenderBase; +import ch.qos.logback.core.joran.spi.DefaultClass; +import ch.qos.logback.core.sift.Discriminator; +import org.slf4j.LoggerFactory; + +import java.util.Iterator; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * <p>Allows to use EELF logging configuration almost as is, by using a custom routing function, but + * pre-configured appenders attached to the standard EELF loggers.</p> <p>Changes that must be made + * in <i>logback.xml</i> supplied with EELF:</p> + * <pre> + * <appender name="DISPATCHER" class="DispatchingAppender"> + * <discriminator class="EventTypeDiscriminator"/> + * <appenderNamePattern>asyncEELF%s</appenderNamePattern> + * </appender> + * <root level="INFO" additivity="false"> + * <appender-ref ref="DISPATCHER" /> + * </root> + * </pre> + */ +public class DispatchingAppender extends AppenderBase<ILoggingEvent> { + + // "magic" appender to indicate a missing appender + private static final Appender<ILoggingEvent> NO_APPENDER = new DispatchingAppender(); + + private Map<String, Appender<ILoggingEvent>> appenders = new ConcurrentHashMap<>(); + + private Discriminator<ILoggingEvent> discriminator; + private String appenderNamePattern; + + public Discriminator<ILoggingEvent> getDiscriminator() { + return this.discriminator; + } + + @DefaultClass(MDCBasedDiscriminator.class) + public void setDiscriminator(Discriminator<ILoggingEvent> discriminator) { + this.discriminator = discriminator; + } + + public String getAppenderNamePattern() { + return this.appenderNamePattern; + } + + public void setAppenderNamePattern(String pattern) { + this.appenderNamePattern = pattern; + } + + @Override + protected void append(ILoggingEvent event) { + + if (this.isStarted()) { + + String discriminatingValue = this.discriminator.getDiscriminatingValue(event); + String appenderName = String.format(this.appenderNamePattern, discriminatingValue); + Appender<ILoggingEvent> appender = this.lookupAppender(appenderName); + if (appender == NO_APPENDER) { + this.addError(String.format("Appender %s does not exist", appenderName)); + } else { + appender.doAppend(event); + } + } + } + + private Appender<ILoggingEvent> lookupAppender(String key) { + + Appender<ILoggingEvent> appender = appenders.get(key); + if (appender != null) { + return appender; + } + + LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory(); + for (Logger log : context.getLoggerList()) { + + Iterator<Appender<ILoggingEvent>> iterator = log.iteratorForAppenders(); + while (iterator.hasNext()) { + + Appender<ILoggingEvent> element = iterator.next(); + if (key.equals(element.getName())) { + this.appenders.putIfAbsent(key, element); + return element; + } + } + } + + // to avoid consecutive lookups if the required appender does not exist + this.appenders.putIfAbsent(key, NO_APPENDER); + return NO_APPENDER; + } + + @Override + public void start() { + + int errors = 0; + if (this.discriminator == null) { + this.addError("Missing discriminator. Aborting"); + } + + if (!this.discriminator.isStarted()) { + this.addError("Discriminator has not started successfully. Aborting"); + ++errors; + } + + if (this.appenderNamePattern == null) { + this.addError("Missing name pattern. Aborting"); + ++errors; + } + + if (errors == 0) { + super.start(); + } + } +} diff --git a/common/openecomp-logging-lib/openecomp-logging-core/src/main/java/org/openecomp/core/logging/logback/EventTypeDiscriminator.java b/common/openecomp-logging-lib/openecomp-logging-core/src/main/java/org/openecomp/core/logging/logback/EventTypeDiscriminator.java new file mode 100644 index 0000000000..107f6728d7 --- /dev/null +++ b/common/openecomp-logging-lib/openecomp-logging-core/src/main/java/org/openecomp/core/logging/logback/EventTypeDiscriminator.java @@ -0,0 +1,121 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.core.logging.logback; + +import ch.qos.logback.classic.Level; +import ch.qos.logback.classic.spi.ILoggingEvent; +import ch.qos.logback.core.sift.AbstractDiscriminator; +import org.openecomp.core.logging.Markers; +import org.slf4j.Marker; + +/** + * Can be used with {@link ch.qos.logback.classic.sift.SiftingAppender} to route events of different + * types to separate log files. For example, + * <pre> + * <configuration> + * <appender name="SIFT" class="ch.qos.logback.classic.sift.SiftingAppender"> + * <discriminator class="EventTypeDiscriminator"/> + * <sift> + * <appender name="{EventType}" + * class="ch.qos.logback.core.rolling.RollingFileAppender"> + * <file>${logDirectory}/${eventType}.log</file> + * <rollingPolicy class="ch. + * qos.logback.core.rolling.FixedWindowRollingPolicy"> + * <fileNamePattern> + * ${logDirectory}/${eventType}. + * %i.log.zip</fileNamePattern> + * <minIndex>1</minIndex> + * <maxIndex>9</maxIndex> + * </rollingPolicy> + * <triggeringPolicy + * class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy"> + * <maxFileSize>5MB</maxFileSize> + * </triggeringPolicy> + * <encoder> + * <pattern>${defaultPattern}</pattern> + * </encoder> + * </appender> + * </sift> + * </appender> + * <root level="INFO"> + * <appender-ref ref="SIFT" /> + * </root> + * </configuration> + * </pre> + */ +public class EventTypeDiscriminator extends AbstractDiscriminator<ILoggingEvent> { + + private static final String KEY = "eventType"; + + private static final String AUDIT = "Audit"; + private static final String METRICS = "Metrics"; + private static final String ERROR = "Error"; + private static final String DEBUG = "Debug"; + private static final String DEFAULT = DEBUG; + + private static final int MIN_ERROR_LEVEL = Level.WARN_INT; + private static final int MAX_ERROR_LEVEL = Level.ERROR_INT; + private static final int DEFAULT_LEVEL = Level.DEBUG_INT; + + @Override + public String getDiscriminatingValue(ILoggingEvent event) { + + Level level = event.getLevel(); + final int levelInt = level == null ? DEFAULT_LEVEL : level.toInt(); + if ((levelInt > MIN_ERROR_LEVEL - 1) && (levelInt < MAX_ERROR_LEVEL + 1)) { + return ERROR; + } + + if (levelInt == Level.DEBUG_INT) { + return DEBUG; + } + + /* + * After DEBUG, ERROR, and WARNING have been filtered out, + * only TRACE and INFO are left. TRACE is less than DEBUG + * and therefore cannot be used. So, INFO should be used for + * custom routing like AUDIT and METRICS + */ + if (levelInt == Level.INFO_INT) { + + final Marker marker = event.getMarker(); + if (marker != null) { + + if (marker.contains(Markers.AUDIT)) { + return AUDIT; + } + + if (marker.contains(Markers.METRICS)) { + return METRICS; + } + } + + return ERROR; + } + + return DEFAULT; + } + + @Override + public String getKey() { + return KEY; + } +} diff --git a/common/openecomp-logging-lib/openecomp-logging-core/src/main/java/org/openecomp/core/logging/servlet/LoggingFilter.java b/common/openecomp-logging-lib/openecomp-logging-core/src/main/java/org/openecomp/core/logging/servlet/LoggingFilter.java new file mode 100644 index 0000000000..53923d7784 --- /dev/null +++ b/common/openecomp-logging-lib/openecomp-logging-core/src/main/java/org/openecomp/core/logging/servlet/LoggingFilter.java @@ -0,0 +1,135 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.core.logging.servlet; + +import org.slf4j.MDC; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.UUID; +import java.util.concurrent.atomic.AtomicLong; +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; + +/** + * <p>Pushes information required by EELF onto MDC (Mapped Diagnostic Context).</p> <p>This is + * servlet filter that should be configured in <i>web.xml</i> to be used. Example:</p> + * <pre> + * <filter> + * <filter-name>LoggingServletFilter</filter-name> + * <filter-class>LoggingFilter</filter-class> + * </filter> + * <filter-mapping> + * <filter-name>LoggingServletFilter</filter-name> + * <url-pattern>/*</url-pattern> + * </filter-mapping> + * </pre> + */ +public class LoggingFilter implements Filter { + + // should be cashed to avoid low-level call, but with a timeout to account for IP or FQDN changes + private static final HostAddressCache HOST_ADDRESS = new HostAddressCache(); + private static final String UNKNOWN = "UNKNOWN"; + + public void destroy() { + } + + /** + * Do Filter. + * + * @param request the request + */ + public void doFilter(ServletRequest request, ServletResponse response, + FilterChain chain) throws IOException, ServletException { + + try { + + MDC.clear(); + + MDC.put("RequestId", UUID.randomUUID().toString()); + MDC.put("ServiceInstanceId", "N/A"); // not applicable + MDC.put("ServiceName", "SDC"); + MDC.put("InstanceUUID", "N/A"); + + // For some reason chooses IPv4 or IPv6 in a random way + MDC.put("RemoteHost", request.getRemoteHost()); + + InetAddress host = HOST_ADDRESS.get(); + + String ipAddress; + String hostName; + if (host == null) { + ipAddress = UNKNOWN; + hostName = UNKNOWN; + } else { + ipAddress = host.getHostAddress(); + hostName = host.getHostName(); + } + + MDC.put("ServerIPAddress", ipAddress); + MDC.put("ServerFQDN", hostName); + + // TODO: Clarify what these stand for + // MDC.put("AlertSeverity", ); + // MDC.put("Timer", ); + + chain.doFilter(request, response); + + } finally { + MDC.clear(); + } + } + + public void init(FilterConfig config) throws ServletException { + } + + private static class HostAddressCache { + + private static final long REFRESH_TIME = 1000L; + + private AtomicLong lastUpdated = new AtomicLong(0L); + private InetAddress hostAddress; + + public InetAddress get() { + + long current = System.currentTimeMillis(); + if (current - lastUpdated.get() > REFRESH_TIME) { + + synchronized (this) { + + try { + lastUpdated.set(current); // set now to register the attempt even if failed + hostAddress = InetAddress.getLocalHost(); + } catch (UnknownHostException unknownHostException) { + hostAddress = null; + } + } + } + + return hostAddress; + } + } +} diff --git a/common/openecomp-logging-lib/openecomp-logging-core/src/main/resources/META-INF/services/org.openecomp.core.logging.api.LoggerCreationService b/common/openecomp-logging-lib/openecomp-logging-core/src/main/resources/META-INF/services/org.openecomp.core.logging.api.LoggerCreationService new file mode 100644 index 0000000000..ecbf5e8fbe --- /dev/null +++ b/common/openecomp-logging-lib/openecomp-logging-core/src/main/resources/META-INF/services/org.openecomp.core.logging.api.LoggerCreationService @@ -0,0 +1 @@ +org.openecomp.core.logging.Slf4JLoggerCreationService
\ No newline at end of file diff --git a/common/openecomp-logging-lib/openecomp-logging-core/src/main/resources/META-INF/services/org.openecomp.core.logging.api.context.ContextPropagationService b/common/openecomp-logging-lib/openecomp-logging-core/src/main/resources/META-INF/services/org.openecomp.core.logging.api.context.ContextPropagationService new file mode 100644 index 0000000000..91297681ec --- /dev/null +++ b/common/openecomp-logging-lib/openecomp-logging-core/src/main/resources/META-INF/services/org.openecomp.core.logging.api.context.ContextPropagationService @@ -0,0 +1 @@ +org.openecomp.core.logging.context.MdcPropagationService
\ No newline at end of file diff --git a/common/openecomp-logging-lib/openecomp-logging-core/src/test/java/org/openecomp/core/logging/LoggerFactoryTest.java b/common/openecomp-logging-lib/openecomp-logging-core/src/test/java/org/openecomp/core/logging/LoggerFactoryTest.java new file mode 100644 index 0000000000..6fcc134957 --- /dev/null +++ b/common/openecomp-logging-lib/openecomp-logging-core/src/test/java/org/openecomp/core/logging/LoggerFactoryTest.java @@ -0,0 +1,25 @@ +package org.openecomp.core.logging; + +import org.openecomp.core.logging.api.LoggerFactory; +import org.testng.annotations.Test; + +import java.lang.reflect.Field; + +import static org.testng.Assert.assertEquals; + +/** + * @author evitaliy + * @since 12/09/2016. + */ +public class LoggerFactoryTest { + + @Test + public void testCreate() throws Exception { + // test that the service loader loads the right implementation + LoggerFactory.getLogger(LoggerFactoryTest.class); + Field factory = LoggerFactory.class.getDeclaredField("SERVICE"); + factory.setAccessible(true); + Object implementation = factory.get(null); + assertEquals(Slf4JLoggerCreationService.class, implementation.getClass()); + } +}
\ No newline at end of file diff --git a/common/openecomp-logging-lib/openecomp-logging-core/src/test/java/org/openecomp/core/logging/RoutingTest.java b/common/openecomp-logging-lib/openecomp-logging-core/src/test/java/org/openecomp/core/logging/RoutingTest.java new file mode 100644 index 0000000000..c0a418a31e --- /dev/null +++ b/common/openecomp-logging-lib/openecomp-logging-core/src/test/java/org/openecomp/core/logging/RoutingTest.java @@ -0,0 +1,155 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.core.logging; + +import ch.qos.logback.classic.Level; +import ch.qos.logback.classic.Logger; +import ch.qos.logback.classic.sift.SiftingAppender; +import ch.qos.logback.classic.spi.ILoggingEvent; +import ch.qos.logback.core.AppenderBase; +import org.openecomp.core.logging.logback.EventTypeDiscriminator; +import org.slf4j.LoggerFactory; +import org.testng.Assert; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Predicate; + +/** + * TODO: Add more negative tests + * + * @author EVITALIY + * @since 17/08/2016. + */ +public class RoutingTest { + + private static final String ERROR = "Error"; + private static final String DEBUG = "Debug"; + private static final String AUDIT = "Audit"; + private static final String METRICS = "Metrics"; + + private Logger logger; + private Map<String, TestAppender> result = new ConcurrentHashMap<>(); + + @BeforeClass + public void setUp() { + + SiftingAppender appender = new SiftingAppender(); + + EventTypeDiscriminator discriminator = new EventTypeDiscriminator(); + discriminator.start(); + + appender.setDiscriminator(discriminator); + appender.setAppenderFactory((context, discriminatingValue) -> + result.computeIfAbsent(discriminatingValue, f -> { + TestAppender tmp = new TestAppender(); + tmp.start(); + return tmp; + })); + + appender.start(); + + logger = (Logger) LoggerFactory.getLogger(RoutingTest.class.getName()); + // prevent from writing into appenders attached via parent loggers + logger.setAdditive(false); + logger.addAppender(appender); + logger.setLevel(Level.DEBUG); + } + + @Test + public void testWarning() { + String msg = "This is a test warning"; + logger.warn(msg); + TestAppender appender = result.get(ERROR); + Assert.assertTrue(appender.contains((event) -> + Level.WARN.equals(event.getLevel()) && msg.equals(event.getFormattedMessage()))); + } + + @Test + public void testError() { + String msg = "This is a test error"; + logger.error(msg); + TestAppender appender = result.get(ERROR); + Assert.assertTrue(appender.contains((event) -> + Level.ERROR.equals(event.getLevel()) && msg.equals(event.getFormattedMessage()))); + } + + @Test + public void testDebug() { + String msg = "This is a test debug"; + logger.debug(msg); + TestAppender appender = result.get(DEBUG); + Assert.assertTrue(appender.contains((event) -> + Level.DEBUG.equals(event.getLevel()) && msg.equals(event.getFormattedMessage()))); + } + + @Test + public void testInfo() { + String msg = "This is a test info"; + logger.info(msg); + TestAppender appender = result.get(ERROR); + Assert.assertTrue(appender.contains((event) -> + Level.INFO.equals(event.getLevel()) && msg.equals(event.getFormattedMessage()))); + } + + @Test + public void testAudit() { + String msg = "This is a test audit"; + logger.info(Markers.AUDIT, msg); + TestAppender appender = result.get(AUDIT); + Assert.assertTrue(appender.contains((event) -> + Level.INFO.equals(event.getLevel()) && msg.equals(event.getFormattedMessage()))); + } + + @Test + public void testMetrics() { + String msg = "This is a test metrics"; + logger.info(Markers.METRICS, msg); + TestAppender appender = result.get(METRICS); + Assert.assertTrue(appender.contains((event) -> + Level.INFO.equals(event.getLevel()) && msg.equals(event.getFormattedMessage()))); + } + + /** + * An appender that just accumulates messages in a list and enables to inspect them + * + * @author EVITALIY + * @since 17/08/2016. + */ + private static class TestAppender extends AppenderBase<ILoggingEvent> { + + private List<ILoggingEvent> events = Collections.synchronizedList(new ArrayList<>(10)); + + @Override + protected void append(ILoggingEvent event) { + this.events.add(event); + } + + public boolean contains(Predicate<ILoggingEvent> predicate) { + return events.stream().anyMatch(predicate); + } + } +} diff --git a/common/openecomp-logging-lib/openecomp-logging-core/src/test/java/org/openecomp/core/logging/api/LoggerTest.java b/common/openecomp-logging-lib/openecomp-logging-core/src/test/java/org/openecomp/core/logging/api/LoggerTest.java new file mode 100644 index 0000000000..b154f0d71c --- /dev/null +++ b/common/openecomp-logging-lib/openecomp-logging-core/src/test/java/org/openecomp/core/logging/api/LoggerTest.java @@ -0,0 +1,65 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.core.logging.api; + +import org.testng.annotations.Test; + +/** + * This is only for manual testing - change ENABLE to 'true' + * + * @author evitaliy + * @since 13/09/2016. + */ +public class LoggerTest { + + private static final boolean ENABLED = false; + private static final Logger LOGGER = LoggerFactory.getLogger(LoggerTest.class); + + @Test(enabled = ENABLED) + public void testMetrics() throws Exception { + LOGGER.metrics("This is metrics"); + } + + @Test(enabled = ENABLED) + public void testAudit() throws Exception { + LOGGER.audit("This is audit"); + } + + @Test(enabled = ENABLED) + public void testDebug() throws Exception { + LOGGER.debug("This is debug"); + } + + @Test(enabled = ENABLED) + public void testInfo() throws Exception { + LOGGER.info("This is info"); + } + + @Test(enabled = ENABLED) + public void testWarn() throws Exception { + LOGGER.warn("This is warning"); + } + + @Test(enabled = ENABLED) + public void testError() throws Exception { + LOGGER.error("This is error"); + } +} diff --git a/common/openecomp-logging-lib/openecomp-logging-core/src/test/java/org/openecomp/core/logging/aspects/MetricsAspectTest.java b/common/openecomp-logging-lib/openecomp-logging-core/src/test/java/org/openecomp/core/logging/aspects/MetricsAspectTest.java new file mode 100644 index 0000000000..68d255c9c3 --- /dev/null +++ b/common/openecomp-logging-lib/openecomp-logging-core/src/test/java/org/openecomp/core/logging/aspects/MetricsAspectTest.java @@ -0,0 +1,452 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.core.logging.aspects; + +import org.openecomp.core.logging.api.Logger; +import org.openecomp.core.logging.api.LoggerFactory; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.Signature; +import org.aspectj.lang.reflect.SourceLocation; +import org.aspectj.runtime.internal.AroundClosure; +import org.easymock.EasyMock; +import org.powermock.api.easymock.PowerMock; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.testng.PowerMockTestCase; +import org.testng.Assert; +import org.testng.annotations.Test; +import sun.reflect.generics.reflectiveObjects.NotImplementedException; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.UUID; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Predicate; + +/** + * @author EVITALIY + * @since 17/08/2016. + */ +@PrepareForTest(LoggerFactory.class) +public class MetricsAspectTest extends PowerMockTestCase { + + private static final Object OBJ_TO_RETURN = new Object(); + private static final String EXPECTED_MESSAGE = "'{}' took {} milliseconds"; + + @Test + public void testLogExecutionTime() throws Throwable { + + String className = UUID.randomUUID().toString(); + String methodName = UUID.randomUUID().toString(); + + TestLogger logger = initLogging(className, true); + + MetricsAspect aspect = new MetricsAspect(); + MockProceedingJoinPoint pjp = new MockProceedingJoinPoint(className, methodName); + Object returned = aspect.logExecutionTime(pjp); + + Assert.assertEquals(OBJ_TO_RETURN, returned); + assertExecution(methodName, pjp, logger); + } + + @Test + public void testMetricsDisabled() throws Throwable { + + String className = UUID.randomUUID().toString(); + String methodName = UUID.randomUUID().toString(); + + TestLogger logger = initLogging(className, false); + + MetricsAspect aspect = new MetricsAspect(); + MockProceedingJoinPoint pjp = new MockProceedingJoinPoint(className, methodName); + Object returned = aspect.logExecutionTime(pjp); + + Assert.assertEquals(OBJ_TO_RETURN, returned); + Assert.assertEquals(1, pjp.getCount()); + // return any event - must be empty + Assert.assertFalse(logger.contains((event) -> true)); + } + + @Test(expectedExceptions = IllegalArgumentException.class) + public void testThrowingError() throws Throwable { + + String className = UUID.randomUUID().toString(); + String methodName = UUID.randomUUID().toString(); + + final TestLogger logger = initLogging(className, true); + + MetricsAspect aspect = new MetricsAspect(); + MockProceedingJoinPoint pjp = new MockProceedingJoinPointWithException(className, methodName); + + try { + aspect.logExecutionTime(pjp); + } finally { + assertExecution(methodName, pjp, logger); + } + } + + private TestLogger initLogging(String className, boolean enabled) { + TestLogger logger = new TestLogger(enabled); + PowerMock.mockStatic(LoggerFactory.class); + EasyMock.expect(LoggerFactory.getLogger(className)).andReturn(logger); + PowerMock.replay(LoggerFactory.class); + return logger; + } + + private void assertExecution(String methodName, MockProceedingJoinPoint pjp, TestLogger logger) { + + Assert.assertEquals(1, pjp.getCount()); + Assert.assertTrue(logger.contains((event) -> + (event != null) && (event.length == 3) && EXPECTED_MESSAGE.equals(event[0]) + && methodName.equals(event[1]) && (event[2] instanceof Long))); + } + + private static class MockSignature implements Signature { + + private final String className; + private final String methodName; + + private MockSignature(String className, String methodName) { + this.className = className; + this.methodName = methodName; + } + + @Override + public String toShortString() { + return null; + } + + @Override + public String toLongString() { + return null; + } + + @Override + public String getName() { + return methodName; + } + + @Override + public int getModifiers() { + return 0; + } + + @Override + public Class getDeclaringType() { + return null; + } + + @Override + public String getDeclaringTypeName() { + return className; + } + } + + private static class MockProceedingJoinPoint implements ProceedingJoinPoint { + + private AtomicInteger count = new AtomicInteger(0); + private Signature signature; + + MockProceedingJoinPoint(String className, String methodName) { + this.signature = new MockSignature(className, methodName); + } + + int getCount() { + return count.get(); + } + + @Override + public Object proceed() throws Throwable { + count.incrementAndGet(); + return OBJ_TO_RETURN; + } + + @Override + public void set$AroundClosure(AroundClosure aroundClosure) { + + } + + @Override + public Object proceed(Object[] objects) throws Throwable { + return null; + } + + @Override + public String toShortString() { + return null; + } + + @Override + public String toLongString() { + return null; + } + + @Override + public Object getThis() { + return null; + } + + @Override + public Object getTarget() { + return null; + } + + @Override + public Object[] getArgs() { + return new Object[0]; + } + + @Override + public Signature getSignature() { + return this.signature; + } + + @Override + public SourceLocation getSourceLocation() { + return null; + } + + @Override + public String getKind() { + return null; + } + + @Override + public StaticPart getStaticPart() { + return null; + } + } + + private static class MockProceedingJoinPointWithException extends MockProceedingJoinPoint { + + MockProceedingJoinPointWithException(String className, String methodName) { + super(className, methodName); + } + + @Override + public Object proceed() throws Throwable { + super.proceed(); + throw new IllegalArgumentException(); + } + } + + private class TestLogger implements Logger { + + private final boolean enabled; + private List<Object[]> events = Collections.synchronizedList(new ArrayList<>(10)); + + public TestLogger(boolean enabled) { + this.enabled = enabled; + } + + @Override + public String getName() { + throw new NotImplementedException(); + } + + @Override + public boolean isMetricsEnabled() { + return this.enabled; + } + + @Override + public void metrics(String var1) { + throw new NotImplementedException(); + } + + @Override + public void metrics(String var1, Object var2) { + throw new NotImplementedException(); + } + + @Override + public void metrics(String var1, Object var2, Object var3) { + + if (this.enabled) { + events.add(new Object[]{var1, var2, var3}); + } + } + + @Override + public void metrics(String var1, Object... var2) { + throw new NotImplementedException(); + } + + @Override + public void metrics(String var1, Throwable throwable) { + throw new NotImplementedException(); + } + + @Override + public boolean isAuditEnabled() { + throw new NotImplementedException(); + } + + @Override + public void audit(String var1) { + throw new NotImplementedException(); + } + + @Override + public void audit(String var1, Object var2) { + throw new NotImplementedException(); + } + + @Override + public void audit(String var1, Object var2, Object var3) { + throw new NotImplementedException(); + } + + @Override + public void audit(String var1, Object... var2) { + throw new NotImplementedException(); + } + + @Override + public void audit(String var1, Throwable throwable) { + throw new NotImplementedException(); + } + + @Override + public boolean isDebugEnabled() { + throw new NotImplementedException(); + } + + @Override + public void debug(String var1) { + throw new NotImplementedException(); + } + + @Override + public void debug(String var1, Object var2) { + throw new NotImplementedException(); + } + + @Override + public void debug(String var1, Object var2, Object var3) { + throw new NotImplementedException(); + } + + @Override + public void debug(String var1, Object... var2) { + throw new NotImplementedException(); + } + + @Override + public void debug(String var1, Throwable throwable) { + throw new NotImplementedException(); + } + + @Override + public boolean isInfoEnabled() { + throw new NotImplementedException(); + } + + @Override + public void info(String var1) { + throw new NotImplementedException(); + } + + @Override + public void info(String var1, Object var2) { + throw new NotImplementedException(); + } + + @Override + public void info(String var1, Object var2, Object var3) { + throw new NotImplementedException(); + } + + @Override + public void info(String var1, Object... var2) { + throw new NotImplementedException(); + } + + @Override + public void info(String var1, Throwable throwable) { + throw new NotImplementedException(); + } + + @Override + public boolean isWarnEnabled() { + throw new NotImplementedException(); + } + + @Override + public void warn(String var1) { + throw new NotImplementedException(); + } + + @Override + public void warn(String var1, Object var2) { + throw new NotImplementedException(); + } + + @Override + public void warn(String var1, Object... var2) { + throw new NotImplementedException(); + } + + @Override + public void warn(String var1, Object var2, Object var3) { + throw new NotImplementedException(); + } + + @Override + public void warn(String var1, Throwable throwable) { + throw new NotImplementedException(); + } + + @Override + public boolean isErrorEnabled() { + throw new NotImplementedException(); + } + + @Override + public void error(String var1) { + throw new NotImplementedException(); + } + + @Override + public void error(String var1, Object var2) { + throw new NotImplementedException(); + } + + @Override + public void error(String var1, Object var2, Object var3) { + throw new NotImplementedException(); + } + + @Override + public void error(String var1, Object... var2) { + throw new NotImplementedException(); + } + + @Override + public void error(String var1, Throwable throwable) { + throw new NotImplementedException(); + } + + public boolean contains(Predicate<Object[]> predicate) { + return events.stream().anyMatch(predicate); + } + } +} diff --git a/common/openecomp-logging-lib/openecomp-logging-core/src/test/java/org/openecomp/core/logging/context/MDCPropagationFactoryTest.java b/common/openecomp-logging-lib/openecomp-logging-core/src/test/java/org/openecomp/core/logging/context/MDCPropagationFactoryTest.java new file mode 100644 index 0000000000..f2a6549a2a --- /dev/null +++ b/common/openecomp-logging-lib/openecomp-logging-core/src/test/java/org/openecomp/core/logging/context/MDCPropagationFactoryTest.java @@ -0,0 +1,216 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.core.logging.context; + +import org.slf4j.MDC; +import org.testng.annotations.Test; + +import java.util.UUID; +import java.util.concurrent.atomic.AtomicBoolean; + +import static org.testng.Assert.*; + +/** + * @author evitaliy + * @since 12/09/2016. + */ +public class MDCPropagationFactoryTest { + + @Test + public void testNoPropagation() throws InterruptedException { + + String uuid = UUID.randomUUID().toString(); + AtomicBoolean complete = new AtomicBoolean(false); + MDC.put("data", uuid); + + Runnable runnable = () -> { + assertNull(MDC.get("data")); + complete.set(true); + }; + + Thread thread = new Thread(runnable); + thread.start(); + thread.join(); + + assertEquals(MDC.get("data"), uuid); + assertTrue(complete.get()); + } + + @Test + public void testPropagation() throws InterruptedException { + + String uuid = UUID.randomUUID().toString(); + AtomicBoolean complete = new AtomicBoolean(false); + MDC.put("data", uuid); + + MdcPropagationService factory = new MdcPropagationService(); + Runnable runnable = factory.create(() -> { + assertEquals(MDC.get("data"), uuid); + complete.set(true); + }); + + Thread thread = new Thread(runnable); + thread.start(); + thread.join(); + + assertEquals(MDC.get("data"), uuid); + assertTrue(complete.get()); + } + + @Test + public void testReplacement() throws InterruptedException { + + String innerUuid = UUID.randomUUID().toString(); + AtomicBoolean innerComplete = new AtomicBoolean(false); + AtomicBoolean outerComplete = new AtomicBoolean(false); + + MDC.put("data", innerUuid); + + MdcPropagationService factory = new MdcPropagationService(); + + // should run with the context of main thread + Runnable inner = factory.create(() -> { + assertEquals(MDC.get("data"), innerUuid); + innerComplete.set(true); + }); + + // pushes its own context, but runs the inner runnable + Runnable outer = () -> { + String outerUuid = UUID.randomUUID().toString(); + MDC.put("data", outerUuid); + inner.run(); + assertEquals(MDC.get("data"), outerUuid); + outerComplete.set(true); + }; + + + Thread thread = new Thread(outer); + thread.start(); + thread.join(); + + assertEquals(MDC.get("data"), innerUuid); + assertTrue(outerComplete.get()); + assertTrue(innerComplete.get()); + } + + @Test + public void testEmpty() throws InterruptedException { + + final AtomicBoolean complete = new AtomicBoolean(false); + + MDC.remove("data"); + assertNull(MDC.get("data")); + + MdcPropagationService factory = new MdcPropagationService(); + Runnable runnable = factory.create(() -> { + assertNull(MDC.get("data")); + complete.set(true); + }); + + Thread thread = new Thread(runnable); + thread.start(); + thread.join(); + + assertNull(MDC.get("data")); + assertTrue(complete.get()); + } + + @Test + public void testCleanup() throws Exception { + + String innerUuid = UUID.randomUUID().toString(); + AtomicBoolean innerComplete = new AtomicBoolean(false); + AtomicBoolean outerComplete = new AtomicBoolean(false); + + MDC.put("data", innerUuid); + + MdcPropagationService factory = new MdcPropagationService(); + + // should run with the context of main thread + Runnable inner = factory.create(() -> { + assertEquals(MDC.get("data"), innerUuid); + innerComplete.set(true); + }); + + // pushes its own context, but runs the inner runnable + Runnable outer = () -> { + assertNull(MDC.get("data")); + inner.run(); + assertNull(MDC.get("data")); + outerComplete.set(true); + }; + + Thread thread = new Thread(outer); + thread.start(); + thread.join(); + + assertEquals(MDC.get("data"), innerUuid); + assertTrue(outerComplete.get()); + assertTrue(innerComplete.get()); + } + + @Test + public void testCleanupAfterError() throws Exception { + + String innerUuid = UUID.randomUUID().toString(); + AtomicBoolean innerComplete = new AtomicBoolean(false); + AtomicBoolean outerComplete = new AtomicBoolean(false); + AtomicBoolean exceptionThrown = new AtomicBoolean(false); + + MDC.put("data", innerUuid); + + MdcPropagationService factory = new MdcPropagationService(); + + // should run with the context of main thread + Runnable inner = factory.create(() -> { + assertEquals(MDC.get("data"), innerUuid); + innerComplete.set(true); + throw new RuntimeException(); + }); + + // pushes its own context, but runs the inner runnable + Runnable outer = () -> { + + String outerUuid = UUID.randomUUID().toString(); + MDC.put("data", outerUuid); + assertEquals(MDC.get("data"), outerUuid); + + try { + inner.run(); + } catch (RuntimeException e) { + exceptionThrown.set(true); + } finally { + assertEquals(MDC.get("data"), outerUuid); + outerComplete.set(true); + } + }; + + Thread thread = new Thread(outer); + thread.start(); + thread.join(); + + assertEquals(MDC.get("data"), innerUuid); + assertTrue(outerComplete.get()); + assertTrue(innerComplete.get()); + assertTrue(exceptionThrown.get()); + } + +} diff --git a/common/openecomp-logging-lib/openecomp-logging-core/src/test/java/org/openecomp/core/logging/context/TaskFactoryTest.java b/common/openecomp-logging-lib/openecomp-logging-core/src/test/java/org/openecomp/core/logging/context/TaskFactoryTest.java new file mode 100644 index 0000000000..1649302056 --- /dev/null +++ b/common/openecomp-logging-lib/openecomp-logging-core/src/test/java/org/openecomp/core/logging/context/TaskFactoryTest.java @@ -0,0 +1,26 @@ +package org.openecomp.core.logging.context; + +import org.openecomp.core.logging.api.context.TaskFactory; +import org.testng.annotations.Test; + +import java.lang.reflect.Field; + +import static org.testng.Assert.assertEquals; + +/** + * @author evitaliy + * @since 12/09/2016. + */ +public class TaskFactoryTest { + + @Test + public void testCreate() throws Exception { + // test that the service loader loads the right implementation + TaskFactory.create(() -> { + }); + Field factory = TaskFactory.class.getDeclaredField("SERVICE"); + factory.setAccessible(true); + Object implementation = factory.get(null); + assertEquals(MdcPropagationService.class, implementation.getClass()); + } +}
\ No newline at end of file diff --git a/common/openecomp-logging-lib/openecomp-logging-core/src/test/java/org/openecomp/core/logging/logback/EventTypeDiscriminatorTest.java b/common/openecomp-logging-lib/openecomp-logging-core/src/test/java/org/openecomp/core/logging/logback/EventTypeDiscriminatorTest.java new file mode 100644 index 0000000000..e2293b1761 --- /dev/null +++ b/common/openecomp-logging-lib/openecomp-logging-core/src/test/java/org/openecomp/core/logging/logback/EventTypeDiscriminatorTest.java @@ -0,0 +1,220 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.core.logging.logback; + +import ch.qos.logback.classic.Level; +import ch.qos.logback.classic.spi.LoggingEvent; +import org.openecomp.core.logging.Markers; +import org.slf4j.MarkerFactory; +import org.testng.annotations.Test; + +import static org.testng.Assert.assertEquals; + +/** + * @author EVITALIY + * @since 17/08/2016. + */ +public class EventTypeDiscriminatorTest { + + private static final String DEBUG = "Debug"; + private static final String ERROR = "Error"; + + @Test + public void testGetDefaultDiscriminatingValue() throws Exception { + EventTypeDiscriminator discriminator = new EventTypeDiscriminator(); + LoggingEvent event = new LoggingEvent(); + assertEquals(discriminator.getDiscriminatingValue(event), DEBUG); + } + + @Test + public void testGetErrorDiscriminatingValue() throws Exception { + EventTypeDiscriminator discriminator = new EventTypeDiscriminator(); + LoggingEvent event = new LoggingEvent(); + event.setLevel(Level.ERROR); + assertEquals(discriminator.getDiscriminatingValue(event), ERROR); + } + + @Test + public void testGetWarnDiscriminatingValue() throws Exception { + EventTypeDiscriminator discriminator = new EventTypeDiscriminator(); + LoggingEvent event = new LoggingEvent(); + event.setLevel(Level.WARN); + assertEquals(discriminator.getDiscriminatingValue(event), ERROR); + } + + @Test + public void testGetInfoDiscriminatingValue() throws Exception { + EventTypeDiscriminator discriminator = new EventTypeDiscriminator(); + LoggingEvent event = new LoggingEvent(); + event.setLevel(Level.INFO); + assertEquals(discriminator.getDiscriminatingValue(event), ERROR); + } + + @Test + public void testGetTraceDiscriminatingValue() throws Exception { + EventTypeDiscriminator discriminator = new EventTypeDiscriminator(); + LoggingEvent event = new LoggingEvent(); + event.setLevel(Level.TRACE); + assertEquals(discriminator.getDiscriminatingValue(event), DEBUG); + } + + @Test + public void testGetErrorWithAuditDiscriminatingValue() throws Exception { + EventTypeDiscriminator discriminator = new EventTypeDiscriminator(); + LoggingEvent event = new LoggingEvent(); + event.setLevel(Level.ERROR); + event.setMarker(Markers.AUDIT); + assertEquals(discriminator.getDiscriminatingValue(event), ERROR); + } + + @Test + public void testGetErrorWithMetricsDiscriminatingValue() throws Exception { + EventTypeDiscriminator discriminator = new EventTypeDiscriminator(); + LoggingEvent event = new LoggingEvent(); + event.setLevel(Level.ERROR); + event.setMarker(Markers.METRICS); + assertEquals(discriminator.getDiscriminatingValue(event), ERROR); + } + + @Test + public void testGetWarnWithAuditDiscriminatingValue() throws Exception { + EventTypeDiscriminator discriminator = new EventTypeDiscriminator(); + LoggingEvent event = new LoggingEvent(); + event.setLevel(Level.WARN); + event.setMarker(Markers.AUDIT); + assertEquals(discriminator.getDiscriminatingValue(event), ERROR); + } + + @Test + public void testGetWarnWithMetricsDiscriminatingValue() throws Exception { + EventTypeDiscriminator discriminator = new EventTypeDiscriminator(); + LoggingEvent event = new LoggingEvent(); + event.setLevel(Level.WARN); + event.setMarker(Markers.METRICS); + assertEquals(discriminator.getDiscriminatingValue(event), ERROR); + } + + @Test + public void testGetDebugWithAuditDiscriminatingValue() throws Exception { + EventTypeDiscriminator discriminator = new EventTypeDiscriminator(); + LoggingEvent event = new LoggingEvent(); + event.setLevel(Level.DEBUG); + event.setMarker(Markers.AUDIT); + assertEquals(discriminator.getDiscriminatingValue(event), DEBUG); + } + + @Test + public void testGetDebugWithMetricsDiscriminatingValue() throws Exception { + EventTypeDiscriminator discriminator = new EventTypeDiscriminator(); + LoggingEvent event = new LoggingEvent(); + event.setLevel(Level.DEBUG); + event.setMarker(Markers.METRICS); + assertEquals(discriminator.getDiscriminatingValue(event), DEBUG); + } + + @Test + public void testGetTraceWithAuditDiscriminatingValue() throws Exception { + EventTypeDiscriminator discriminator = new EventTypeDiscriminator(); + LoggingEvent event = new LoggingEvent(); + event.setLevel(Level.TRACE); + event.setMarker(Markers.AUDIT); + assertEquals(discriminator.getDiscriminatingValue(event), DEBUG); + } + + @Test + public void testGetTraceWithMetricsDiscriminatingValue() throws Exception { + EventTypeDiscriminator discriminator = new EventTypeDiscriminator(); + LoggingEvent event = new LoggingEvent(); + event.setLevel(Level.TRACE); + event.setMarker(Markers.METRICS); + assertEquals(discriminator.getDiscriminatingValue(event), DEBUG); + } + + @Test + public void testGetErrorWithMarkerDiscriminatingValue() throws Exception { + EventTypeDiscriminator discriminator = new EventTypeDiscriminator(); + LoggingEvent event = new LoggingEvent(); + event.setLevel(Level.ERROR); + event.setMarker(MarkerFactory.getMarker("Dummy")); + assertEquals(discriminator.getDiscriminatingValue(event), ERROR); + } + + @Test + public void testGetWarnWithMarkerDiscriminatingValue() throws Exception { + EventTypeDiscriminator discriminator = new EventTypeDiscriminator(); + LoggingEvent event = new LoggingEvent(); + event.setLevel(Level.WARN); + event.setMarker(MarkerFactory.getMarker("Dummy")); + assertEquals(discriminator.getDiscriminatingValue(event), ERROR); + } + + @Test + public void testGetDebugWithMarkerDiscriminatingValue() throws Exception { + EventTypeDiscriminator discriminator = new EventTypeDiscriminator(); + LoggingEvent event = new LoggingEvent(); + event.setLevel(Level.DEBUG); + event.setMarker(MarkerFactory.getMarker("Dummy")); + assertEquals(discriminator.getDiscriminatingValue(event), DEBUG); + } + + @Test + public void testGetTraceWithMarkerDiscriminatingValue() throws Exception { + EventTypeDiscriminator discriminator = new EventTypeDiscriminator(); + LoggingEvent event = new LoggingEvent(); + event.setLevel(Level.TRACE); + event.setMarker(MarkerFactory.getMarker("Dummy")); + assertEquals(discriminator.getDiscriminatingValue(event), DEBUG); + } + + @Test + public void testGetInfoWithMarkerDiscriminatingValue() throws Exception { + EventTypeDiscriminator discriminator = new EventTypeDiscriminator(); + LoggingEvent event = new LoggingEvent(); + event.setLevel(Level.INFO); + event.setMarker(MarkerFactory.getMarker("Dummy")); + assertEquals(discriminator.getDiscriminatingValue(event), ERROR); + } + + @Test + public void testGetAuditDiscriminatingValue() throws Exception { + EventTypeDiscriminator discriminator = new EventTypeDiscriminator(); + LoggingEvent event = new LoggingEvent(); + event.setLevel(Level.INFO); + event.setMarker(Markers.AUDIT); + assertEquals(discriminator.getDiscriminatingValue(event), "Audit"); + } + + @Test + public void testGetMetricsMarkerDiscriminatingValue() throws Exception { + EventTypeDiscriminator discriminator = new EventTypeDiscriminator(); + LoggingEvent event = new LoggingEvent(); + event.setLevel(Level.INFO); + event.setMarker(Markers.METRICS); + assertEquals(discriminator.getDiscriminatingValue(event), "Metrics"); + } + + @Test + public void testGetKey() throws Exception { + EventTypeDiscriminator discriminator = new EventTypeDiscriminator(); + assertEquals("eventType", discriminator.getKey()); + } + +} diff --git a/common/openecomp-logging-lib/openecomp-logging-core/src/test/java/org/openecomp/core/logging/servlet/LoggingFilterTest.java b/common/openecomp-logging-lib/openecomp-logging-core/src/test/java/org/openecomp/core/logging/servlet/LoggingFilterTest.java new file mode 100644 index 0000000000..f1d303b234 --- /dev/null +++ b/common/openecomp-logging-lib/openecomp-logging-core/src/test/java/org/openecomp/core/logging/servlet/LoggingFilterTest.java @@ -0,0 +1,314 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.core.logging.servlet; + +import org.slf4j.MDC; +import org.testng.Assert; +import org.testng.annotations.Test; + +import javax.servlet.*; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.PrintWriter; +import java.io.UnsupportedEncodingException; +import java.net.InetAddress; +import java.util.Enumeration; +import java.util.Locale; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.atomic.AtomicInteger; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNull; + +/** + * TODO: Add more tests + * + * @author EVITALIY + * @since 17/08/2016. + */ +public class LoggingFilterTest { + + private static final String REMOTE_HOST = UUID.randomUUID().toString(); + + @Test + public void testDoFilter() throws Exception { + LoggingFilter loggingFilter = new LoggingFilter(); + ServletRequest mockRequest = new TestServletRequest(); + ServletResponse mockResponse = new TestServletResponse(); + TestFilterChain mockChain = new TestFilterChain(); + loggingFilter.doFilter(mockRequest, mockResponse, mockChain); + assertEquals(1, mockChain.getCount()); + assertNull(MDC.getCopyOfContextMap()); + } + + private static class TestServletRequest implements ServletRequest { + + @Override + public Object getAttribute(String s) { + return null; + } + + @Override + public Enumeration getAttributeNames() { + return null; + } + + @Override + public String getCharacterEncoding() { + return null; + } + + @Override + public void setCharacterEncoding(String s) throws UnsupportedEncodingException { + + } + + @Override + public int getContentLength() { + return 0; + } + + @Override + public String getContentType() { + return null; + } + + @Override + public ServletInputStream getInputStream() throws IOException { + return null; + } + + @Override + public String getParameter(String s) { + return null; + } + + @Override + public Enumeration getParameterNames() { + return null; + } + + @Override + public String[] getParameterValues(String s) { + return new String[0]; + } + + @Override + public Map getParameterMap() { + return null; + } + + @Override + public String getProtocol() { + return null; + } + + @Override + public String getScheme() { + return null; + } + + @Override + public String getServerName() { + return null; + } + + @Override + public int getServerPort() { + return 0; + } + + @Override + public BufferedReader getReader() throws IOException { + return null; + } + + @Override + public String getRemoteAddr() { + return null; + } + + @Override + public String getRemoteHost() { + return REMOTE_HOST; + } + + @Override + public void setAttribute(String s, Object o) { + + } + + @Override + public void removeAttribute(String s) { + + } + + @Override + public Locale getLocale() { + return null; + } + + @Override + public Enumeration getLocales() { + return null; + } + + @Override + public boolean isSecure() { + return false; + } + + @Override + public RequestDispatcher getRequestDispatcher(String s) { + return null; + } + + @Override + public String getRealPath(String s) { + return null; + } + + @Override + public int getRemotePort() { + return 0; + } + + @Override + public String getLocalName() { + return null; + } + + @Override + public String getLocalAddr() { + return null; + } + + @Override + public int getLocalPort() { + return 0; + } + } + + private static class TestFilterChain implements FilterChain { + + private AtomicInteger count = new AtomicInteger(0); + + @Override + public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse) + throws IOException, ServletException { + + Assert.assertNotNull(MDC.get("RequestId")); + Assert.assertEquals(MDC.get("ServiceInstanceId"), "N/A"); + Assert.assertEquals(MDC.get("ServiceName"), "SDC"); + Assert.assertEquals(MDC.get("InstanceUUID"), "N/A"); + Assert.assertEquals(MDC.get("RemoteHost"), REMOTE_HOST); + + InetAddress host = InetAddress.getLocalHost(); + Assert.assertEquals(MDC.get("ServerIPAddress"), host.getHostAddress()); + Assert.assertEquals(MDC.get("ServerFQDN"), host.getHostName()); + + count.incrementAndGet(); + } + + public int getCount() { + return count.get(); + } + } + + private static class TestServletResponse implements ServletResponse { + + @Override + public String getCharacterEncoding() { + return null; + } + + @Override + public void setCharacterEncoding(String s) { + + } + + @Override + public String getContentType() { + return null; + } + + @Override + public void setContentType(String s) { + + } + + @Override + public ServletOutputStream getOutputStream() throws IOException { + return null; + } + + @Override + public PrintWriter getWriter() throws IOException { + return null; + } + + @Override + public void setContentLength(int i) { + + } + + @Override + public int getBufferSize() { + return 0; + } + + @Override + public void setBufferSize(int i) { + + } + + @Override + public void flushBuffer() throws IOException { + + } + + @Override + public void resetBuffer() { + + } + + @Override + public boolean isCommitted() { + return false; + } + + @Override + public void reset() { + + } + + @Override + public Locale getLocale() { + return null; + } + + @Override + public void setLocale(Locale locale) { + + } + } +} diff --git a/common/openecomp-logging-lib/openecomp-logging-core/src/test/resources/README b/common/openecomp-logging-lib/openecomp-logging-core/src/test/resources/README new file mode 100644 index 0000000000..430f36d760 --- /dev/null +++ b/common/openecomp-logging-lib/openecomp-logging-core/src/test/resources/README @@ -0,0 +1,8 @@ +Different routing/dispatching mechanisms can be tested using -Dlogback.configurationFile and a custom configuration +file, for example + +-Dlogback.configurationFile=<path>/dispatching-logback.xml + +or + +-Dlogback.configurationFile=<path>/sifting-logback.xml
\ No newline at end of file diff --git a/common/openecomp-logging-lib/openecomp-logging-core/src/test/resources/dispatching-logback.xml b/common/openecomp-logging-lib/openecomp-logging-core/src/test/resources/dispatching-logback.xml new file mode 100644 index 0000000000..d0aff70b8a --- /dev/null +++ b/common/openecomp-logging-lib/openecomp-logging-core/src/test/resources/dispatching-logback.xml @@ -0,0 +1,335 @@ +<configuration scan="true" scanPeriod="3 seconds"> + <!--<jmxConfigurator /> --> + <!-- directory path for all other type logs --> + <property name="logDir" value="logs" /> + + <!-- directory path for debugging type logs --> + <property name="debugDir" value="debug-logs" /> + + <!-- specify the component name --> + <property name="componentName" value="SDC" /> + + <!-- log file names --> + <property name="generalLogName" value="application" /> + <property name="securityLogName" value="security" /> + <property name="performanceLogName" value="performance" /> + <property name="serverLogName" value="server" /> + <property name="policyLogName" value="policy" /> + <property name="errorLogName" value="error" /> + <property name="metricsLogName" value="metrics" /> + <property name="auditLogName" value="audit" /> + <property name="debugLogName" value="debug" /> + + <property name="defaultPattern" value="%date{ISO8601,UTC}|%X{RequestId}|%X{ServiceInstanceId}|%thread|%X{VirtualServerName}|%X{ServiceName}|%X{InstanceUUID}|%.-5level|%X{AlertSeverity}|%X{ServerIPAddress}|%X{ServerFQDN}|%X{RemoteHost}|%X{ClassName}|%X{Timer}| %msg%n" /> + + <property name="debugLoggerPattern" value="%date{ISO8601,UTC}|%X{RequestId}|%X{ServiceInstanceId}|%thread|%X{VirtualServerName}|%X{ServiceName}|%X{InstanceUUID}|%.-5level|%X{AlertSeverity}|%X{ServerIPAddress}|%X{ServerFQDN}|%X{RemoteHost}|%X{ClassName}|%X{Timer}|[%caller{3}]| %msg%n" /> + + <property name="logDirectory" value="${logDir}/${componentName}" /> + <property name="debugLogDirectory" value="${debugDir}/${componentName}" /> + + + <!-- Example evaluator filter applied against console appender --> + <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> + <encoder> + <pattern>${defaultPattern}</pattern> + </encoder> + </appender> + + <!-- ============================================================================ --> + <!-- EELF Appenders --> + <!-- ============================================================================ --> + + <!-- The EELFAppender is used to record events to the general application + log --> + + + <appender name="EELF" + class="ch.qos.logback.core.rolling.RollingFileAppender"> + <file>${logDirectory}/${generalLogName}.log</file> + <rollingPolicy + class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy"> + <fileNamePattern>${logDirectory}/${generalLogName}.%i.log.zip + </fileNamePattern> + <minIndex>1</minIndex> + <maxIndex>9</maxIndex> + </rollingPolicy> + <triggeringPolicy + class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy"> + <maxFileSize>5MB</maxFileSize> + </triggeringPolicy> + <encoder> + <pattern>${defaultPattern}</pattern> + </encoder> + </appender> + + <appender name="asyncEELF" class="ch.qos.logback.classic.AsyncAppender"> + <queueSize>256</queueSize> + <appender-ref ref="EELF" /> + </appender> + + <!-- EELF Security Appender. This appender is used to record security events + to the security log file. Security events are separate from other loggers + in EELF so that security log records can be captured and managed in a secure + way separate from the other logs. This appender is set to never discard any + events. --> + <appender name="EELFSecurity" + class="ch.qos.logback.core.rolling.RollingFileAppender"> + <file>${logDirectory}/${securityLogName}.log</file> + <rollingPolicy + class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy"> + <fileNamePattern>${logDirectory}/${securityLogName}.%i.log.zip + </fileNamePattern> + <minIndex>1</minIndex> + <maxIndex>9</maxIndex> + </rollingPolicy> + <triggeringPolicy + class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy"> + <maxFileSize>5MB</maxFileSize> + </triggeringPolicy> + <encoder> + <pattern>${defaultPattern}</pattern> + </encoder> + </appender> + + <appender name="asyncEELFSecurity" class="ch.qos.logback.classic.AsyncAppender"> + <queueSize>256</queueSize> + <discardingThreshold>0</discardingThreshold> + <appender-ref ref="EELFSecurity" /> + </appender> + + <!-- EELF Performance Appender. This appender is used to record performance + records. --> + <appender name="EELFPerformance" + class="ch.qos.logback.core.rolling.RollingFileAppender"> + <file>${logDirectory}/${performanceLogName}.log</file> + <rollingPolicy + class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy"> + <fileNamePattern>${logDirectory}/${performanceLogName}.%i.log.zip + </fileNamePattern> + <minIndex>1</minIndex> + <maxIndex>9</maxIndex> + </rollingPolicy> + <triggeringPolicy + class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy"> + <maxFileSize>5MB</maxFileSize> + </triggeringPolicy> + <encoder> + <outputPatternAsHeader>true</outputPatternAsHeader> + <pattern>${defaultPattern}</pattern> + </encoder> + </appender> + <appender name="asyncEELFPerformance" class="ch.qos.logback.classic.AsyncAppender"> + <queueSize>256</queueSize> + <appender-ref ref="EELFPerformance" /> + </appender> + + <!-- EELF Server Appender. This appender is used to record Server related + logging events. The Server logger and appender are specializations of the + EELF application root logger and appender. This can be used to segregate Server + events from other components, or it can be eliminated to record these events + as part of the application root log. --> + <appender name="EELFServer" + class="ch.qos.logback.core.rolling.RollingFileAppender"> + <file>${logDirectory}/${serverLogName}.log</file> + <rollingPolicy + class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy"> + <fileNamePattern>${logDirectory}/${serverLogName}.%i.log.zip + </fileNamePattern> + <minIndex>1</minIndex> + <maxIndex>9</maxIndex> + </rollingPolicy> + <triggeringPolicy + class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy"> + <maxFileSize>5MB</maxFileSize> + </triggeringPolicy> + <encoder> + <pattern>${defaultPattern}</pattern> + </encoder> + </appender> + <appender name="asyncEELFServer" class="ch.qos.logback.classic.AsyncAppender"> + <queueSize>256</queueSize> + <appender-ref ref="EELFServer" /> + </appender> + + + <!-- EELF Policy Appender. This appender is used to record Policy engine + related logging events. The Policy logger and appender are specializations + of the EELF application root logger and appender. This can be used to segregate + Policy engine events from other components, or it can be eliminated to record + these events as part of the application root log. --> + <appender name="EELFPolicy" + class="ch.qos.logback.core.rolling.RollingFileAppender"> + <file>${logDirectory}/${policyLogName}.log</file> + <rollingPolicy + class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy"> + <fileNamePattern>${logDirectory}/${policyLogName}.%i.log.zip + </fileNamePattern> + <minIndex>1</minIndex> + <maxIndex>9</maxIndex> + </rollingPolicy> + <triggeringPolicy + class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy"> + <maxFileSize>5MB</maxFileSize> + </triggeringPolicy> + <encoder> + <pattern>${defaultPattern}</pattern> + </encoder> + </appender> + <appender name="asyncEELFPolicy" class="ch.qos.logback.classic.AsyncAppender"> + <queueSize>256</queueSize> + <appender-ref ref="EELFPolicy" /> + </appender> + + + <!-- EELF Audit Appender. This appender is used to record audit engine + related logging events. The audit logger and appender are specializations + of the EELF application root logger and appender. This can be used to segregate + Policy engine events from other components, or it can be eliminated to record + these events as part of the application root log. --> + + <appender name="EELFAudit" + class="ch.qos.logback.core.rolling.RollingFileAppender"> + <file>${logDirectory}/${auditLogName}.log</file> + <rollingPolicy + class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy"> + <fileNamePattern>${logDirectory}/${auditLogName}.%i.log.zip + </fileNamePattern> + <minIndex>1</minIndex> + <maxIndex>9</maxIndex> + </rollingPolicy> + <triggeringPolicy + class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy"> + <maxFileSize>5MB</maxFileSize> + </triggeringPolicy> + <encoder> + <pattern>${defaultPattern}</pattern> + </encoder> + </appender> + <appender name="asyncEELFAudit" class="ch.qos.logback.classic.AsyncAppender"> + <queueSize>256</queueSize> + <appender-ref ref="EELFAudit" /> + </appender> + +<appender name="EELFMetrics" + class="ch.qos.logback.core.rolling.RollingFileAppender"> + <file>${logDirectory}/${metricsLogName}.log</file> + <rollingPolicy + class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy"> + <fileNamePattern>${logDirectory}/${metricsLogName}.%i.log.zip + </fileNamePattern> + <minIndex>1</minIndex> + <maxIndex>9</maxIndex> + </rollingPolicy> + <triggeringPolicy + class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy"> + <maxFileSize>5MB</maxFileSize> + </triggeringPolicy> + <encoder> + <!-- <pattern>"%d{HH:mm:ss.SSS} [%thread] %-5level %logger{1024} - + %msg%n"</pattern> --> + <pattern>${defaultPattern}</pattern> + </encoder> + </appender> + + + <appender name="asyncEELFMetrics" class="ch.qos.logback.classic.AsyncAppender"> + <queueSize>256</queueSize> + <appender-ref ref="EELFMetrics"/> + </appender> + + <appender name="EELFError" + class="ch.qos.logback.core.rolling.RollingFileAppender"> + <file>${logDirectory}/${errorLogName}.log</file> + <rollingPolicy + class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy"> + <fileNamePattern>${logDirectory}/${errorLogName}.%i.log.zip + </fileNamePattern> + <minIndex>1</minIndex> + <maxIndex>9</maxIndex> + </rollingPolicy> + <triggeringPolicy + class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy"> + <maxFileSize>5MB</maxFileSize> + </triggeringPolicy> + <encoder> + <pattern>${defaultPattern}</pattern> + </encoder> + </appender> + + <appender name="asyncEELFError" class="ch.qos.logback.classic.AsyncAppender"> + <queueSize>256</queueSize> + <appender-ref ref="EELFError"/> + </appender> + + <appender name="EELFDebug" + class="ch.qos.logback.core.rolling.RollingFileAppender"> + <file>${debugLogDirectory}/${debugLogName}.log</file> + <rollingPolicy + class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy"> + <fileNamePattern>${debugLogDirectory}/${debugLogName}.%i.log.zip + </fileNamePattern> + <minIndex>1</minIndex> + <maxIndex>9</maxIndex> + </rollingPolicy> + <triggeringPolicy + class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy"> + <maxFileSize>5MB</maxFileSize> + </triggeringPolicy> + <encoder> + <pattern>${debugLoggerPattern}</pattern> + </encoder> + </appender> + + <appender name="asyncEELFDebug" class="ch.qos.logback.classic.AsyncAppender"> + <queueSize>256</queueSize> + <appender-ref ref="EELFDebug" /> + <includeCallerData>true</includeCallerData> + </appender> + + + <!-- ============================================================================ --> + <!-- EELF loggers --> + <!-- ============================================================================ --> + <logger name="org.openecomp.eelf" level="info" additivity="false"> + <appender-ref ref="asyncEELF" /> + </logger> + <logger name="org.openecomp.eelf.security" level="info" additivity="false"> + <appender-ref ref="asyncEELFSecurity" /> + </logger> + <logger name="org.openecomp.eelf.perf" level="info" additivity="false"> + <appender-ref ref="asyncEELFPerformance" /> + </logger> + <logger name="org.openecomp.eelf.server" level="info" additivity="false"> + <appender-ref ref="asyncEELFServer" /> + </logger> + <logger name="org.openecomp.eelf.policy" level="info" additivity="false"> + <appender-ref ref="asyncEELFPolicy" /> + </logger> + + <logger name="org.openecomp.eelf.audit" level="info" additivity="false"> + <appender-ref ref="asyncEELFAudit" /> + </logger> + + <logger name="org.openecomp.eelf.metrics" level="info" additivity="false"> + <appender-ref ref="asyncEELFMetrics" /> + </logger> + + + <logger name="org.openecomp.eelf.error" level="error" additivity="false"> + <appender-ref ref="asyncEELFError" /> + </logger> + + <logger name="org.openecomp.eelf.debug" level="debug" additivity="false"> + <appender-ref ref="asyncEELFDebug" /> + </logger> + + <appender name="DISPATCHER" class="org.openecomp.core.logging.logback.DispatchingAppender"> + <discriminator class="org.openecomp.core.logging.logback.EventTypeDiscriminator"/> + <appenderNamePattern>asyncEELF%s</appenderNamePattern> + </appender> + + <root level="DEBUG" additivity="false"> + <appender-ref ref="DISPATCHER" /> + </root> + +</configuration>
\ No newline at end of file diff --git a/common/openecomp-logging-lib/openecomp-logging-core/src/test/resources/logback.xml b/common/openecomp-logging-lib/openecomp-logging-core/src/test/resources/logback.xml new file mode 100644 index 0000000000..c79eca228b --- /dev/null +++ b/common/openecomp-logging-lib/openecomp-logging-core/src/test/resources/logback.xml @@ -0,0 +1,41 @@ +<configuration scan="true" scanPeriod="3 seconds"> + + <property name="logDir" value="logs" /> + <property name="componentName" value="SDC" /> + + <property name="defaultPattern" + value="%logger|%date{ISO8601,UTC}|%X{RequestId}|%X{ServiceInstanceId}|%thread|%X{VirtualServerName}|%X{ServiceName}|%X{InstanceUUID}|%.-5level|%X{AlertSeverity}|%X{ServerIPAddress}|%X{ServerFQDN}|%X{RemoteHost}|%X{ClassName}|%X{Timer}| %msg%n" /> + + <property name="logDirectory" value="${logDir}/${componentName}" /> + + <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> + <encoder> + <pattern>${defaultPattern}</pattern> + </encoder> + </appender> + + <appender name="DISPATCHER" class="ch.qos.logback.classic.sift.SiftingAppender"> + <discriminator class="org.openecomp.core.logging.logback.EventTypeDiscriminator"/> + <sift> + <appender name="${eventType}" class="ch.qos.logback.core.rolling.RollingFileAppender"> + <file>${logDirectory}/${eventType}.log</file> + <rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy"> + <fileNamePattern>${logDirectory}/${eventType}.%i.log.zip</fileNamePattern> + <minIndex>1</minIndex> + <maxIndex>9</maxIndex> + </rollingPolicy> + <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy"> + <maxFileSize>5MB</maxFileSize> + </triggeringPolicy> + <encoder> + <pattern>${defaultPattern}</pattern> + </encoder> + </appender> + </sift> + </appender> + + <root level="DEBUG"> + <appender-ref ref="DISPATCHER" /> + </root> + +</configuration>
\ No newline at end of file diff --git a/common/openecomp-logging-lib/openecomp-logging-core/src/test/resources/sifting-logback.xml b/common/openecomp-logging-lib/openecomp-logging-core/src/test/resources/sifting-logback.xml new file mode 100644 index 0000000000..1b50e10924 --- /dev/null +++ b/common/openecomp-logging-lib/openecomp-logging-core/src/test/resources/sifting-logback.xml @@ -0,0 +1,42 @@ +<configuration scan="true" scanPeriod="3 seconds" debug="true"> + + <property name="logDir" value="logs" /> + <property name="componentName" value="SDC" /> + + <property name="defaultPattern" value="%date{ISO8601,UTC}|%X{RequestId}|%X{ServiceInstanceId}|%thread|%X{VirtualServerName}|%X{ServiceName}|%X{InstanceUUID}|%.-5level|%X{AlertSeverity}|%X{ServerIPAddress}|%X{ServerFQDN}|%X{RemoteHost}|%X{ClassName}|%X{Timer}| %msg%n" /> + + <property name="debugPattern" value="%date{ISO8601,UTC}|%X{RequestId}|%X{ServiceInstanceId}|%thread|%X{VirtualServerName}|%X{ServiceName}|%X{InstanceUUID}|%.-5level|%X{AlertSeverity}|%X{ServerIPAddress}|%X{ServerFQDN}|%X{RemoteHost}|%X{ClassName}|%X{Timer}|[%caller{3}]| %msg%n" /> + + <property name="logDirectory" value="${logDir}/${componentName}" /> + + <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> + <encoder> + <pattern>${defaultPattern}</pattern> + </encoder> + </appender> + + <appender name="DISPATCHER" class="ch.qos.logback.classic.sift.SiftingAppender"> + <discriminator class="org.openecomp.core.logging.logback.EventTypeDiscriminator"/> + <sift> + <appender name="${eventType}" class="ch.qos.logback.core.rolling.RollingFileAppender"> + <file>${logDirectory}/${eventType}.log</file> + <rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy"> + <fileNamePattern>${logDirectory}/${eventType}.%i.log.zip</fileNamePattern> + <minIndex>1</minIndex> + <maxIndex>9</maxIndex> + </rollingPolicy> + <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy"> + <maxFileSize>5MB</maxFileSize> + </triggeringPolicy> + <encoder> + <pattern>${defaultPattern}</pattern> + </encoder> + </appender> + </sift> + </appender> + + <root level="DEBUG" additivity="false"> + <appender-ref ref="DISPATCHER" /> + </root> + +</configuration>
\ No newline at end of file |