From 280f8015d06af1f41a3ef12e8300801c7a5e0d54 Mon Sep 17 00:00:00 2001 From: AviZi Date: Fri, 9 Jun 2017 02:39:56 +0300 Subject: [SDC-29] Amdocs OnBoard 1707 initial commit. Change-Id: Ie4d12a3f574008b792899b368a0902a8b46b5370 Signed-off-by: AviZi --- .../java/org/openecomp/core/logging/Markers.java | 21 ++ .../core/logging/Slf4JLoggerCreationService.java | 236 +++++++++++++++++++++ .../core/logging/aspects/MetricsAspect.java | 72 +++++++ .../logging/context/MdcPropagationService.java | 71 +++++++ .../core/logging/logback/DispatchingAppender.java | 142 +++++++++++++ .../logging/logback/EventTypeDiscriminator.java | 121 +++++++++++ .../core/logging/servlet/LoggingFilter.java | 135 ++++++++++++ ...penecomp.core.logging.api.LoggerCreationService | 1 + ...e.logging.api.context.ContextPropagationService | 1 + 9 files changed, 800 insertions(+) create mode 100644 common/openecomp-logging-lib/openecomp-logging-core/src/main/java/org/openecomp/core/logging/Markers.java create mode 100644 common/openecomp-logging-lib/openecomp-logging-core/src/main/java/org/openecomp/core/logging/Slf4JLoggerCreationService.java create mode 100644 common/openecomp-logging-lib/openecomp-logging-core/src/main/java/org/openecomp/core/logging/aspects/MetricsAspect.java create mode 100644 common/openecomp-logging-lib/openecomp-logging-core/src/main/java/org/openecomp/core/logging/context/MdcPropagationService.java create mode 100644 common/openecomp-logging-lib/openecomp-logging-core/src/main/java/org/openecomp/core/logging/logback/DispatchingAppender.java create mode 100644 common/openecomp-logging-lib/openecomp-logging-core/src/main/java/org/openecomp/core/logging/logback/EventTypeDiscriminator.java create mode 100644 common/openecomp-logging-lib/openecomp-logging-core/src/main/java/org/openecomp/core/logging/servlet/LoggingFilter.java create mode 100644 common/openecomp-logging-lib/openecomp-logging-core/src/main/resources/META-INF/services/org.openecomp.core.logging.api.LoggerCreationService create mode 100644 common/openecomp-logging-lib/openecomp-logging-core/src/main/resources/META-INF/services/org.openecomp.core.logging.api.context.ContextPropagationService (limited to 'common/openecomp-logging-lib/openecomp-logging-core/src/main') 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; + +/** + *

The list of markers that can be used for special logging such as metrics, audit, etc.

+ *

Although markers can be easily instantiated whenever needed, having constants for them helps + * eliminate mistakes - misspelling, using a marker that is not handled, etc.

Usage:

+ *
+ *     Logger log = LogFactory.getLogger(this.getClass());
+ *     log.info(Markers.AUDIT, "User '{}' logged out", user);
+ * 
+ * + * @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; + +/** + *

Wraps around any method annotated with {@link Metrics} to measure and log its execution time + * in milliseconds.

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.

See, for example, Aspect + * Oriented Programming with Spring.

+ * + * @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 SLF4J Mapped Diagnostic Context + * (MDC) 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 context; + + private MdcCopyingWrapper(Runnable task) { + this.task = task; + this.context = MDC.getCopyOfContextMap(); + } + + private static void replaceMdc(Map context) { + + if (context == null) { + MDC.clear(); + } else { + MDC.setContextMap(context); + } + } + + @Override + public void run() { + + Map 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; + +/** + *

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.

Changes that must be made + * in logback.xml supplied with EELF:

+ *
+ *     <appender name="DISPATCHER" class="DispatchingAppender">
+ *          <discriminator class="EventTypeDiscriminator"/>
+ *          <appenderNamePattern>asyncEELF%s</appenderNamePattern>
+ *     </appender>
+ *     <root level="INFO" additivity="false">
+ *          <appender-ref ref="DISPATCHER" />
+ *      </root>
+ * 
+ */ +public class DispatchingAppender extends AppenderBase { + + // "magic" appender to indicate a missing appender + private static final Appender NO_APPENDER = new DispatchingAppender(); + + private Map> appenders = new ConcurrentHashMap<>(); + + private Discriminator discriminator; + private String appenderNamePattern; + + public Discriminator getDiscriminator() { + return this.discriminator; + } + + @DefaultClass(MDCBasedDiscriminator.class) + public void setDiscriminator(Discriminator 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 appender = this.lookupAppender(appenderName); + if (appender == NO_APPENDER) { + this.addError(String.format("Appender %s does not exist", appenderName)); + } else { + appender.doAppend(event); + } + } + } + + private Appender lookupAppender(String key) { + + Appender appender = appenders.get(key); + if (appender != null) { + return appender; + } + + LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory(); + for (Logger log : context.getLoggerList()) { + + Iterator> iterator = log.iteratorForAppenders(); + while (iterator.hasNext()) { + + Appender 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, + *
+ *     <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>
+ * 
+ */ +public class EventTypeDiscriminator extends AbstractDiscriminator { + + 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; + +/** + *

Pushes information required by EELF onto MDC (Mapped Diagnostic Context).

This is + * servlet filter that should be configured in web.xml to be used. Example:

+ *
+ *  <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>
+ * 
+ */ +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 -- cgit 1.2.3-korg