Aharoni, Pavel (pa0916) | ca3cb01 | 2018-10-22 15:29:57 +0300 | [diff] [blame] | 1 | /*-
|
| 2 | * ============LICENSE_START=======================================================
|
| 3 | * OSAM
|
| 4 | * ================================================================================
|
| 5 | * Copyright (C) 2018 AT&T
|
| 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
|
| 10 | *
|
| 11 | * http://www.apache.org/licenses/LICENSE-2.0
|
| 12 | *
|
| 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=========================================================
|
| 19 | */
|
| 20 |
|
| 21 |
|
| 22 |
|
| 23 | package org.onap.osam.utils;
|
| 24 |
|
| 25 | import com.att.eelf.configuration.EELFLogger;
|
| 26 | import com.fasterxml.jackson.core.JsonProcessingException;
|
| 27 | import com.fasterxml.jackson.databind.ObjectMapper;
|
| 28 | import com.fasterxml.jackson.databind.SerializationFeature;
|
| 29 | import com.google.common.collect.ImmutableList;
|
| 30 | import io.joshworks.restclient.http.HttpResponse;
|
| 31 | import org.apache.commons.lang3.StringUtils;
|
| 32 | import org.onap.osam.exceptions.GenericUncheckedException;
|
| 33 | import org.onap.portalsdk.core.logging.logic.EELFLoggerDelegate;
|
| 34 | import org.onap.portalsdk.core.util.SystemProperties;
|
| 35 | import org.springframework.http.HttpMethod;
|
| 36 | import org.springframework.web.context.request.RequestContextHolder;
|
| 37 | import org.springframework.web.context.request.ServletRequestAttributes;
|
| 38 |
|
| 39 | import javax.servlet.http.HttpServletRequest;
|
| 40 | import javax.ws.rs.ProcessingException;
|
| 41 | import javax.ws.rs.core.Response;
|
| 42 | import java.util.Arrays;
|
| 43 | import java.util.Optional;
|
| 44 | import java.util.UUID;
|
| 45 |
|
| 46 | import static org.apache.commons.lang3.ObjectUtils.defaultIfNull;
|
| 47 | import static org.apache.commons.lang3.exception.ExceptionUtils.getRootCause;
|
| 48 | import static org.apache.commons.lang3.exception.ExceptionUtils.getThrowableList;
|
| 49 | import static org.onap.osam.utils.Streams.not;
|
| 50 |
|
| 51 | public class Logging {
|
| 52 |
|
| 53 | Logging() {
|
| 54 | }
|
| 55 |
|
| 56 | public static final String HTTP_REQUESTS_OUTGOING = "http.requests.outgoing.";
|
| 57 |
|
| 58 | public static final String REQUEST_ID_HEADER_KEY = SystemProperties.ECOMP_REQUEST_ID;
|
| 59 |
|
| 60 | private static ObjectMapper objectMapper = new ObjectMapper();
|
| 61 |
|
| 62 | public static String getMethodName() {
|
| 63 | return getMethodName(0);
|
| 64 | }
|
| 65 |
|
| 66 | public static String getMethodCallerName() {
|
| 67 | return getMethodName(1);
|
| 68 | }
|
| 69 |
|
| 70 | private static String getMethodName(int depth) {
|
| 71 | final StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
|
| 72 | String thisClassName = stackTrace[1].getClassName();
|
| 73 | final Optional<String> caller =
|
| 74 | Arrays.stream(stackTrace)
|
| 75 | .skip(1)
|
| 76 | .filter(not(frame -> frame.getClassName().equals(thisClassName)))
|
| 77 | .skip(depth)
|
| 78 | .map(StackTraceElement::getMethodName)
|
| 79 | .findFirst();
|
| 80 | return caller.orElse("<unknonwn method name>");
|
| 81 | }
|
| 82 |
|
| 83 | public static EELFLogger getRequestsLogger(String serverName) {
|
| 84 | return EELFLoggerDelegate.getLogger(HTTP_REQUESTS_OUTGOING +serverName);
|
| 85 | }
|
| 86 |
|
| 87 | public static void logRequest(final EELFLogger logger, final HttpMethod method, final String url, final Object body) {
|
| 88 | if (!logger.isDebugEnabled()) {
|
| 89 | return;
|
| 90 | }
|
| 91 |
|
| 92 | if (body == null) {
|
| 93 | logRequest(logger, method, url);
|
| 94 | return;
|
| 95 | }
|
| 96 |
|
| 97 | try {
|
| 98 | String bodyAsJson = objectMapper.writeValueAsString(body);
|
| 99 | logger.debug("Sending {} {} Body: {}", method.name(), url, bodyAsJson);
|
| 100 | } catch (JsonProcessingException e) {
|
| 101 | logRequest(logger, method, url);
|
| 102 | logger.debug("Failed to parse object in logRequest. {}", body);
|
| 103 | }
|
| 104 | }
|
| 105 |
|
| 106 | public static void logRequest(final EELFLogger logger, final HttpMethod method, final String url) {
|
| 107 | logger.debug("Sending {} {}", method.name(), url);
|
| 108 | }
|
| 109 |
|
| 110 | public static <T> void logResponse(final EELFLogger logger, final HttpMethod method, final String url, final Response response, final Class<T> entityClass) {
|
| 111 | if (!logger.isDebugEnabled()) {
|
| 112 | return;
|
| 113 | }
|
| 114 | if (response == null) {
|
| 115 | logger.debug("Received {} {} response: null", method.name(), url);
|
| 116 | return;
|
| 117 | }
|
| 118 | try {
|
| 119 | response.bufferEntity();
|
| 120 | logger.debug("Received {} {} Status: {} . Body: {}", method.name(), url, response.getStatus(), response.readEntity(entityClass));
|
| 121 | }
|
| 122 | catch (ProcessingException | IllegalStateException e) {
|
| 123 | logger.debug("Received {} {} Status: {} . Failed to read response as {}", method.name(), url, response.getStatus(), entityClass.getName());
|
| 124 | }
|
| 125 | }
|
| 126 |
|
| 127 | public static <T> void logResponse(final EELFLogger logger, final HttpMethod method, final String url, final HttpResponse<T> response) {
|
| 128 | try {
|
| 129 | logger.debug("Received {} {} Status: {} . Body: {}", method.name(), url, response.getStatus(), response.getBody());
|
| 130 | }
|
| 131 | catch (ProcessingException | IllegalStateException e) {
|
| 132 | logger.debug("Received {} {} Status: {} . Failed to read response", method.name(), url, response.getStatus());
|
| 133 | }
|
| 134 | }
|
| 135 |
|
| 136 | public static void logResponse(final EELFLogger logger, final HttpMethod method, final String url, final Response response) {
|
| 137 | logResponse(logger, method, url, response, String.class);
|
| 138 | }
|
| 139 |
|
| 140 | public static HttpServletRequest getHttpServletRequest(){
|
| 141 | return ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
|
| 142 | }
|
| 143 |
|
| 144 | public static String extractOrGenerateRequestId() {
|
| 145 | try {
|
| 146 | return getHttpServletRequest().getHeader(REQUEST_ID_HEADER_KEY);
|
| 147 | }
|
| 148 | catch (IllegalStateException e) {
|
| 149 | //in async jobs we don't have any HttpServletRequest
|
| 150 | return UUID.randomUUID().toString();
|
| 151 | }
|
| 152 | }
|
| 153 |
|
| 154 | public static void debugRequestDetails(Object requestDetails, final EELFLogger logger) {
|
| 155 | if (logger.isDebugEnabled()) {
|
| 156 | String requestDetailsAsString;
|
| 157 | try {
|
| 158 | requestDetailsAsString = new ObjectMapper().enable(SerializationFeature.INDENT_OUTPUT).writeValueAsString(requestDetails);
|
| 159 | } catch (JsonProcessingException e) {
|
| 160 | requestDetailsAsString = "error: cannot stringify RequestDetails";
|
| 161 | }
|
| 162 | logger.debug("requestDetailsAsString: {}", requestDetailsAsString);
|
| 163 | }
|
| 164 | }
|
| 165 |
|
| 166 | public static String exceptionToDescription(Throwable exceptionToDescribe) {
|
| 167 | // Ignore top-most GenericUnchecked or Runtime exceptions that has no added message
|
| 168 | final Throwable top = getThrowableList(exceptionToDescribe).stream()
|
| 169 | .filter(not(e -> ImmutableList.of(GenericUncheckedException.class, RuntimeException.class).contains(e.getClass())
|
| 170 | && StringUtils.equals(e.getMessage(), e.getCause() == null ? null : e.getCause().toString())))
|
| 171 | .findFirst().orElse(exceptionToDescribe);
|
| 172 |
|
| 173 | final Throwable root = defaultIfNull(getRootCause(top), top);
|
| 174 |
|
| 175 | String rootToString = root.toString();
|
| 176 |
|
| 177 | // nullPointer description will include some context
|
| 178 | if (root.getClass().equals(NullPointerException.class) && root.getStackTrace().length > 0) {
|
| 179 | rootToString = String.format("NullPointerException at %s:%d",
|
| 180 | root.getStackTrace()[0].getFileName(),
|
| 181 | root.getStackTrace()[0].getLineNumber());
|
| 182 | }
|
| 183 |
|
| 184 | // if input is a single exception, without cause: top.toString
|
| 185 | // else: return top.toString + root.toString
|
| 186 | // but not if root is already described in top.toString
|
| 187 | if (top.equals(root)) {
|
| 188 | return rootToString;
|
| 189 | } else {
|
| 190 | final String topToString = top.toString();
|
| 191 | if (topToString.contains(root.getClass().getName()) && topToString.contains(root.getLocalizedMessage())) {
|
| 192 | return topToString;
|
| 193 | } else {
|
| 194 | return topToString + ": " + rootToString;
|
| 195 | }
|
| 196 | }
|
| 197 | }
|
| 198 |
|
| 199 |
|
| 200 | }
|