Conform to Boreas recommended logging pattern 14/3814/2
authorLott, Christopher (cl778h) <cl778h@att.com>
Tue, 19 Feb 2019 22:43:56 +0000 (17:43 -0500)
committerLott, Christopher (cl778h) <cl778h@att.com>
Tue, 19 Feb 2019 22:55:43 +0000 (17:55 -0500)
Change-Id: I64f7b36692d02da9b19f7bd8433a46666fababc4
Issue-ID: ACUMOS-2329
Signed-off-by: Lott, Christopher (cl778h) <cl778h@att.com>
docs/release-notes.rst
gateway/src/main/java/org/acumos/federation/gateway/config/LoggingConfiguration.java [new file with mode: 0644]
gateway/src/main/java/org/acumos/federation/gateway/config/LoggingHandlerInterceptor.java [new file with mode: 0644]
gateway/src/main/resources/logback.xml

index f87d511..8feb3f9 100644 (file)
@@ -25,8 +25,8 @@ This server is available as a Docker image in a Docker registry at the Linux Fou
 --------------------------
 Version 2.0.0, 2019-02-20
 --------------------------
+* Use Boreas log pattern; remove EELF (`ACUMOS-2329 <https://jira.acumos.org/browse/ACUMOS-2329>`_)
 * Fix repeated update of metadata (`ACUMOS-2399 <https://jira.acumos.org/browse/ACUMOS-2399>`_)
-* Remove EELF
 * Update to CDS 2.x
 
 --------------------------
diff --git a/gateway/src/main/java/org/acumos/federation/gateway/config/LoggingConfiguration.java b/gateway/src/main/java/org/acumos/federation/gateway/config/LoggingConfiguration.java
new file mode 100644 (file)
index 0000000..404dd6e
--- /dev/null
@@ -0,0 +1,50 @@
+/*-
+ * ===============LICENSE_START=======================================================
+ * Acumos
+ * ===================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property & Tech Mahindra. All rights reserved.
+ * ===================================================================================
+ * This Acumos software file is distributed by AT&T and Tech Mahindra
+ * 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
+ *  
+ * This file 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.acumos.federation.gateway.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+/**
+ * Adds logging handler interceptor. <BR>
+ * http://www.devgrok.com/2017/04/adding-mdc-headers-to-every-spring-mvc.html
+ */
+@Configuration
+public class LoggingConfiguration {
+
+       @Bean
+       public LoggingHandlerInterceptor loggingHandlerInterceptor() {
+               return new LoggingHandlerInterceptor();
+       }
+
+       @Bean
+       public WebMvcConfigurer webConfigurer() {
+               return new WebMvcConfigurer() {
+                       @Override
+                       public void addInterceptors(InterceptorRegistry registry) {
+                               registry.addInterceptor(loggingHandlerInterceptor());
+                       }
+               };
+       }
+
+}
\ No newline at end of file
diff --git a/gateway/src/main/java/org/acumos/federation/gateway/config/LoggingHandlerInterceptor.java b/gateway/src/main/java/org/acumos/federation/gateway/config/LoggingHandlerInterceptor.java
new file mode 100644 (file)
index 0000000..5283ab3
--- /dev/null
@@ -0,0 +1,89 @@
+/*-
+ * ===============LICENSE_START=======================================================
+ * Acumos
+ * ===================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property & Tech Mahindra. All rights reserved.
+ * ===================================================================================
+ * This Acumos software file is distributed by AT&T and Tech Mahindra
+ * 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
+ *  
+ * This file 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.acumos.federation.gateway.config;
+
+import java.net.InetAddress;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.acumos.cds.logging.AcumosLogConstants;
+import org.slf4j.MDC;
+import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
+
+/**
+ * Adds request details to the mapped diagnostic context (MDC) so they can be
+ * logged. <BR>
+ * http://www.devgrok.com/2017/04/adding-mdc-headers-to-every-spring-mvc.html
+ */
+public class LoggingHandlerInterceptor extends HandlerInterceptorAdapter {
+
+       /**
+        * Tracks the set of keys added to MDC.
+        */
+       private ThreadLocal<Set<String>> storedKeys = ThreadLocal.withInitial(() -> new HashSet<>());
+
+       /**
+        * Copies key-value pairs from HTTP request to MDC context. Unfortunately they
+        * use different conventions for key naming.
+        */
+       @Override
+       public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
+                       throws Exception {
+               addKey(AcumosLogConstants.MDCs.SERVER_FQDN, InetAddress.getLocalHost().getCanonicalHostName());
+               addKey(AcumosLogConstants.MDCs.CLIENT_IP_ADDRESS, request.getRemoteAddr());
+               addKey(AcumosLogConstants.MDCs.SERVICE_NAME, request.getRequestURI());
+               String requestId = request.getHeader(AcumosLogConstants.Headers.REQUEST_ID);
+               // If missing, try this common value.
+               if (requestId == null)
+                       requestId = request.getHeader("X-Request-ID");
+               if (requestId != null)
+                       addKey(AcumosLogConstants.Headers.REQUEST_ID, requestId);
+               return true;
+       }
+
+       private void addKey(String key, String value) {
+               MDC.put(key, value);
+               storedKeys.get().add(key);
+       }
+
+       // request ended on current thread remove properties
+       @Override
+       public void afterConcurrentHandlingStarted(HttpServletRequest request, HttpServletResponse response, Object handler)
+                       throws Exception {
+               removeKeys();
+       }
+
+       @Override
+       public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
+                       throws Exception {
+               removeKeys();
+       }
+
+       private void removeKeys() {
+               for (String key : storedKeys.get())
+                       MDC.remove(key);
+
+               storedKeys.remove();
+       }
+}
\ No newline at end of file
index 50e96ae..3efa5e7 100644 (file)
@@ -3,14 +3,14 @@
   ===============LICENSE_START=======================================================
   Acumos
   ===================================================================================
-  Copyright (C) 2017 AT&T Intellectual Property & Tech Mahindra. All rights reserved.
+  Copyright (C) 2019 AT&T Intellectual Property & Tech Mahindra. All rights reserved.
   ===================================================================================
   This Acumos software file is distributed by AT&T and Tech Mahindra
   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
+          http://www.apache.org/licenses/LICENSE-2.0
    
   This file is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   ===============LICENSE_END=========================================================
   -->
 
-<configuration scan="true" scanPeriod="3 seconds" debug="false">
+<configuration scan="true" debug="false">
 
-  <!--  specify the component name -->
+       <!-- component name is log file basename -->
   <property name="componentName" value="federation-gateway"></property>
-  
-  <!--  specify the base path of the log directory -->
-  <property name="logDirPrefix" value="logs"></property>
-  
-  <!-- The directories where logs are written -->
-  <property name="logDirectory" value="${logDirPrefix}/${componentName}" />
-  <!-- Can easily relocate debug logs by modifying this path. -->
-  <property name="debugLogDirectory" value="${logDirPrefix}/${componentName}" />
-  
-  <!--  log file names -->
-  <property name="generalLogName" value="application" />
-  <property name="errorLogName" value="error" />
-  <property name="debugLogName" value="debug" />
-  
-  <property name="singleLineAthenaPattern"
-    value="%date{&quot;yyyy-MM-dd'T'HH:mm:ss.SSSXXX&quot;,UTC}|%X{EntryTimestamp}|%X{InvokeTimestamp}|%X{RequestID}|%X{InvocationID}|%X{InstanceUUID}|%X{ServiceInstanceID}|%X{Thread}|%X{ServiceName}|%X{PartnerName}|%X{StatusCode}|%X{ResponseCode}|%X{ResponseDescription}|%.-5level|%X{Severity}|%X{ServerIPAddress}|%X{Timer}|%X{ServerFQDN}|%X{ClientIPAddress}|%X{VirtualServerName}|%X{ContextName}|%X{TargetEntity}|%X{ClassName}|%X{TargetElement}|%X{User}|%logger|%X{DO_NOT_REPEAT_MDC}|%msg%n" />
 
-       <!-- Passes only events with level WARN or above -->
+       <!-- gather files in a subdirectory - usually a volume in docker -->
+       <property name="logDirPrefix" value="logs"/>
+
+       <!-- The directory where logs are written -->
+       <property name="logDirectory" value="${logDirPrefix}/${componentName}" />
+
+       <!-- Based on https://wiki.acumos.org/display/OAM/Log+Standards -->
+       <property name="p_tim" value="%d{&quot;yyyy-MM-dd'T'HH:mm:ss.SSSXXX&quot;, UTC}" />
+       <property name="p_thr" value="%thread" />
+       <property name="p_lvl" value="%.-5level" />
+       <!-- Logger yields original class name in SLF4J loggers -->
+       <property name="p_log" value="%logger" />
+       <property name="p_mrk" value="%replace(%replace(%marker){'\t', '\\\\t'}){'\n','\\\\n'}" />
+       <property name="p_mdc" value="%replace(%replace(%mdc){'\t','\\\\t'}){'\n', '\\\\n'}" />
+       <property name="p_msg" value="%replace(%replace(%msg){'\t', '\\\\t'}){'\n','\\\\n'}" />
+       <!--  Gather exception stack trace with no linebreaks -->
+       <property name="p_exc" value="%replace(%replace(%ex){'\t', '\\\\t'}){'\n','\\\\n'}" />
+       <!-- Use %nopexception to disable Logback default behavior of appending %ex -->
+       <property name="singleLineBoreasPattern" value="%nopexception${p_tim}\t${p_thr}\t${p_lvl}\t${p_log}\t${p_mrk}\t${p_mdc}\t${p_msg}\t${p_exc}%n" />
+       <property name="multiLineBoreasPattern" value="${p_tim}\t${p_thr}\t${p_lvl}\t${p_log}\t${p_mrk}\t${p_mdc}\t%msg\t%ex%n" />
+
+       <!-- Show events with level WARN or above on the console (docker log) -->
        <appender name="console-warn" class="ch.qos.logback.core.ConsoleAppender">
                <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
                        <level>WARN</level>
                </filter>
                <encoder>
-                       <pattern>${singleLineAthenaPattern}</pattern>
+                       <pattern>${multiLineBoreasPattern}</pattern>
                </encoder>
        </appender>
 
-  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
-    <encoder>
-      <pattern>${singleLineAthenaPattern}</pattern>
-    </encoder>
-  </appender>    
-    
-  <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>${singleLineAthenaPattern}</pattern>
-    </encoder>
-  </appender>
-  
-  <appender name="asyncEELF" class="ch.qos.logback.classic.AsyncAppender">
-    <queueSize>256</queueSize>
-    <appender-ref ref="EELF" />
-  </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>${singleLineAthenaPattern}</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>${singleLineAthenaPattern}</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="com.att.eelf" level="debug" additivity="false">
-    <appender-ref ref="asyncEELF" />
-  </logger>
-  
-  <logger name="com.att.eelf.error" level="debug" additivity="false">
-       <appender-ref ref="asyncEELFError" />
-  </logger>
-  
-   <logger name="com.att.eelf.debug" level="debug" additivity="false">
-        <appender-ref ref="asyncEELFDebug" />
-  </logger>
-  
-  <root level="info">
-               <appender-ref ref="asyncEELF" />
+       <!-- Show all events in the rolling log file -->
+       <appender name="file-rolling" class="ch.qos.logback.core.rolling.RollingFileAppender">
+               <file>${logDirectory}/${componentName}.log</file>
+               <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+                       <!-- daily rollover -->
+                       <fileNamePattern>${logDirectory}/${componentName}.%d{yyyy-MM-dd}.log.zip</fileNamePattern>
+                       <!-- keep 30 days' worth of history capped at 3GB total size -->
+                       <maxHistory>30</maxHistory>
+                       <totalSizeCap>3GB</totalSizeCap>
+               </rollingPolicy>
+               <encoder>
+                       <pattern>${singleLineBoreasPattern}</pattern>
+               </encoder>
+       </appender>
+
+       <appender name="file-async" class="ch.qos.logback.classic.AsyncAppender">
+               <queueSize>256</queueSize>
+               <appender-ref ref="file-rolling" />
+       </appender>
+
+       <!-- The root level is the default for all loggers, NOT a filter on any appender.
+                This level can be set with property logging.level.root=LEVEL. -->
+       <root level="INFO">
+               <appender-ref ref="file-async" />
                <appender-ref ref="console-warn" />
        </root>