2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2017 - 2019 AT&T Intellectual Property. All rights reserved.
6 * ================================================================================
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 * ============LICENSE_END=========================================================
21 package org.onap.vid.logging;
23 import static com.att.eelf.configuration.Configuration.MDC_SERVER_FQDN;
24 import static org.apache.commons.lang3.StringUtils.defaultIfEmpty;
26 import java.net.InetAddress;
27 import java.net.UnknownHostException;
28 import java.util.Arrays;
29 import javax.servlet.http.HttpServletRequest;
30 import org.apache.commons.lang3.StringUtils;
31 import org.aspectj.lang.ProceedingJoinPoint;
32 import org.aspectj.lang.annotation.Around;
33 import org.aspectj.lang.annotation.Aspect;
34 import org.aspectj.lang.annotation.Pointcut;
35 import org.onap.portalsdk.core.logging.aspect.EELFLoggerAdvice;
36 import org.onap.portalsdk.core.logging.logic.EELFLoggerDelegate;
37 import org.onap.portalsdk.core.service.AppService;
38 import org.onap.portalsdk.core.util.SystemProperties;
39 import org.onap.portalsdk.core.web.support.UserUtils;
40 import org.onap.vid.controller.ControllersUtils;
41 import org.onap.vid.utils.SystemPropertiesWrapper;
42 import org.springframework.beans.factory.annotation.Autowired;
43 import org.springframework.web.context.request.RequestContextHolder;
44 import org.springframework.web.context.request.ServletRequestAttributes;
48 @org.springframework.context.annotation.Configuration
49 public class VidLoggerAspect {
51 private String canonicalHostName;
52 private final ControllersUtils controllersUtils;
53 private final String appName;
55 private final EELFLoggerAdvice advice;
58 public VidLoggerAspect(EELFLoggerAdvice advice, SystemPropertiesWrapper systemPropertiesWrapper,
59 AppService appService) {
61 final InetAddress localHost = InetAddress.getLocalHost();
62 canonicalHostName = localHost.getCanonicalHostName();
63 } catch (UnknownHostException e) {
65 canonicalHostName = null;
68 this.controllersUtils = new ControllersUtils(systemPropertiesWrapper);
70 this.appName = defaultIfEmpty(appService.getDefaultAppName(), SystemProperties.SDK_NAME);
73 @Pointcut("execution(public * org.onap.vid.controller..*Controller.*(..))")
74 public void vidControllers() {}
76 @Around("vidControllers() && (" +
77 " @within(org.onap.portalsdk.core.logging.aspect.AuditLog)" +
78 " || @annotation(org.onap.portalsdk.core.logging.aspect.AuditLog)" +
79 " || @annotation(org.springframework.web.bind.annotation.RequestMapping)" +
81 public Object logAuditMethodClassAround(ProceedingJoinPoint joinPoint) throws Throwable {
82 return logAroundMethod(joinPoint, SystemProperties.SecurityEventTypeEnum.INCOMING_REST_MESSAGE);
85 private Object logAroundMethod(ProceedingJoinPoint joinPoint, SystemProperties.SecurityEventTypeEnum securityEventType) throws Throwable {
87 Object[] passOnArgs = new Object[] {joinPoint.getSignature().getDeclaringType().getName(),joinPoint.getSignature().getName()};
88 Object[] returnArgs = advice.before(securityEventType, fabricateArgsWithNull(), passOnArgs);
90 fixSetRequestBasedDefaultsIntoGlobalLoggingContext(httpServletRequestOrNull(joinPoint),
91 joinPoint.getSignature().getDeclaringType().getName());
95 //Execute the actual method
97 String restStatus = "COMPLETE";
99 result = joinPoint.proceed();
100 } catch(Exception e) {
101 restStatus = "ERROR";
104 fixStatusCodeInMDC(restStatus);
105 advice.after(securityEventType, restStatus, joinPoint.getArgs(), returnArgs, passOnArgs);
111 // Set the status code into MDC *before* the metrics log is written by advice.after()
112 private void fixStatusCodeInMDC(String restStatus) {
113 EELFLoggerDelegate.mdcPut(SystemProperties.STATUS_CODE, restStatus);
117 * Returns an array with a single entry with a null value. This will stop org.onap.portalsdk.core.logging.aspect.EELFLoggerAdvice.before
118 * from throwing on ArrayIndexOutOfBound, and also prevent SessionExpiredException.
120 private Object[] fabricateArgsWithNull() {
121 return new Object[]{null};
125 * Finds the first joinPoint's param which is an HttpServletRequest. If not found, use Spring's RequestContextHolder
128 * @return null or the current httpServletRequest
130 private HttpServletRequest httpServletRequestOrNull(ProceedingJoinPoint joinPoint) {
131 final Object httpServletRequest = Arrays.stream(joinPoint.getArgs())
132 .filter(param -> param instanceof HttpServletRequest)
136 return ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
137 } catch (Exception e) { // ClassCast, IllegalState, etc.
142 return (HttpServletRequest) httpServletRequest;
146 * Mimics a part from org.onap.portalsdk.core.logging.aspect.EELFLoggerAdvice.before, but with much more carefulness
147 * of exceptions and defaults. Main difference is that if no session, function does not throw. It just fallback to
150 private void fixSetRequestBasedDefaultsIntoGlobalLoggingContext(HttpServletRequest httpServletRequest, String className) {
151 if (httpServletRequest != null) {
153 EELFLoggerDelegate logger = EELFLoggerDelegate.getLogger(className);
154 String requestId = UserUtils.getRequestId(httpServletRequest);
155 String loginId = controllersUtils.extractUserId(httpServletRequest);
157 logger.setRequestBasedDefaultsIntoGlobalLoggingContext(httpServletRequest, appName, requestId, loginId);
161 // Override the non-canonical hostname set by EELFLoggerDelegate::setGlobalLoggingContext()
162 // that was invoked by advice.before() (and some other SDK cases)
163 private void fixServerFqdnInMDC() {
164 if (!StringUtils.isBlank(canonicalHostName)) {
165 EELFLoggerDelegate.mdcPut(MDC_SERVER_FQDN, canonicalHostName);