From 8eff104effad587c04a00cdd008935af38ee7dc9 Mon Sep 17 00:00:00 2001 From: vempo Date: Mon, 26 Mar 2018 20:37:06 +0300 Subject: Introduced metrics to logging API Metrics data can now be passed to logger. Also general cleanup, refactoring, simpler implementation, javadocs. Change-Id: I037101aa9626b3e011737ec2e3497ab348319e4c Issue-ID: SDC-772 Signed-off-by: vempo --- .../sdc/logging/GlobalLoggingContext.java | 123 ------------------- .../sdc/logging/aspects/MetricsAspect.java | 64 ---------- .../openecomp/sdc/logging/context/HostAddress.java | 89 ++++++++++++++ .../openecomp/sdc/logging/context/InstanceId.java | 52 ++++++++ .../openecomp/sdc/logging/slf4j/AuditField.java | 44 +++++++ .../openecomp/sdc/logging/slf4j/ContextField.java | 4 +- .../sdc/logging/slf4j/GlobalContextProvider.java | 9 +- .../org/openecomp/sdc/logging/slf4j/MDCField.java | 29 +++++ .../openecomp/sdc/logging/slf4j/MetricsField.java | 47 ++++++++ .../sdc/logging/slf4j/SLF4JLoggerWrapper.java | 134 ++++++++++----------- 10 files changed, 334 insertions(+), 261 deletions(-) delete mode 100644 openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/main/java/org/openecomp/sdc/logging/GlobalLoggingContext.java delete mode 100644 openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/main/java/org/openecomp/sdc/logging/aspects/MetricsAspect.java create mode 100644 openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/main/java/org/openecomp/sdc/logging/context/HostAddress.java create mode 100644 openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/main/java/org/openecomp/sdc/logging/context/InstanceId.java create mode 100644 openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/main/java/org/openecomp/sdc/logging/slf4j/AuditField.java create mode 100644 openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/main/java/org/openecomp/sdc/logging/slf4j/MDCField.java create mode 100644 openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/main/java/org/openecomp/sdc/logging/slf4j/MetricsField.java (limited to 'openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/main') diff --git a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/main/java/org/openecomp/sdc/logging/GlobalLoggingContext.java b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/main/java/org/openecomp/sdc/logging/GlobalLoggingContext.java deleted file mode 100644 index a708ed6715..0000000000 --- a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/main/java/org/openecomp/sdc/logging/GlobalLoggingContext.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright © 2016-2017 European Support Limited - * - * 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. - */ - -package org.openecomp.sdc.logging; - -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.util.UUID; -import java.util.concurrent.atomic.AtomicLong; -import java.util.prefs.BackingStoreException; -import java.util.prefs.Preferences; - -/** - * Collect information the is required for logging, but should not concern the business code of an application. For - * example, host name and IP address. - * - * @author evitaliy - * @since 04 Mar 2018 - */ -@SuppressWarnings({"UseOfSystemOutOrSystemErr", "CallToPrintStackTrace", "squid:S106", "squid:S1148"}) -public class GlobalLoggingContext { - - // 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_CACHE = new HostAddressCache(); - - @SuppressWarnings("squid:S1075") - private static final String INSTANCE_UUID_PREFERENCES_PATH = "/logging/instance/uuid"; - - private static final String INSTANCE_ID; - - static { - INSTANCE_ID = readInstanceId(); - } - - private GlobalLoggingContext() { - // prevent instantiation - } - - /** - * A unique ID of the logging entity. Is useful to distinguish between different nodes of the same application. It - * is assumed, that the node can be re-started, in which case the unique ID must be retained. - * - * @return unique logging entity ID - */ - public static String getInstanceId() { - return INSTANCE_ID; - } - - /** - * Local host address as returned by Java runtime. A value of host address will be cached for the interval specified - * in {@link HostAddressCache#REFRESH_TIME} - * - * @return local host address, may be null if could not be read for some reason - */ - public static InetAddress getHostAddress() { - return HOST_ADDRESS_CACHE.get(); - } - - private static String readInstanceId() { - - try { - - // On Linux, by default this will be ~/.java/.userPrefs/prefs.xml - final Preferences preferences = Preferences.userRoot(); - String existingId = preferences.get(INSTANCE_UUID_PREFERENCES_PATH, null); - if (existingId != null) { - return existingId; - } - - String newId = UUID.randomUUID().toString(); - preferences.put(INSTANCE_UUID_PREFERENCES_PATH, newId); - preferences.flush(); - return newId; - - } catch (BackingStoreException e) { - e.printStackTrace(); - // don't fail if there's a problem to use the store for some unexpected reason - return UUID.randomUUID().toString(); - } - } - - private static class HostAddressCache { - - private static final long REFRESH_TIME = 60000L; - - private final AtomicLong lastUpdated = new AtomicLong(0L); - private InetAddress hostAddress; - - InetAddress get() { - - long current = System.currentTimeMillis(); - if (current - lastUpdated.get() > REFRESH_TIME) { - - synchronized (this) { - - try { - // set now to register the attempt even if failed - lastUpdated.set(current); - hostAddress = InetAddress.getLocalHost(); - } catch (UnknownHostException e) { - e.printStackTrace(); // can't really use logging - hostAddress = null; - } - } - } - - return hostAddress; - } - } -} diff --git a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/main/java/org/openecomp/sdc/logging/aspects/MetricsAspect.java b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/main/java/org/openecomp/sdc/logging/aspects/MetricsAspect.java deleted file mode 100644 index a99a97d0a6..0000000000 --- a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/main/java/org/openecomp/sdc/logging/aspects/MetricsAspect.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright © 2016-2017 European Support Limited - * - * 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. - */ - -package org.openecomp.sdc.logging.aspects; - -import org.aspectj.lang.ProceedingJoinPoint; -import org.aspectj.lang.annotation.Around; -import org.aspectj.lang.annotation.Aspect; -import org.openecomp.sdc.logging.api.Logger; -import org.openecomp.sdc.logging.api.LoggerFactory; -import org.openecomp.sdc.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.

- * - * @author evitaliy - * @see Metrics - * @since 27/07/2016. - */ -@Aspect -public class MetricsAspect { - - private static final String MESSAGE_TEMPLATE = "'{}' took {} milliseconds"; - - @Around("@annotation(org.openecomp.sdc.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/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/main/java/org/openecomp/sdc/logging/context/HostAddress.java b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/main/java/org/openecomp/sdc/logging/context/HostAddress.java new file mode 100644 index 0000000000..bcfef6ca01 --- /dev/null +++ b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/main/java/org/openecomp/sdc/logging/context/HostAddress.java @@ -0,0 +1,89 @@ +/* + * Copyright © 2016-2018 European Support Limited + * + * 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. + */ + +package org.openecomp.sdc.logging.context; + +import java.net.InetAddress; +import java.net.UnknownHostException; + +/** + * Holds a reference to local host address as returned by Java runtime. A value of host address will be cached for the + * interval specified in the constructor or {@link #DEFAULT_REFRESH_INTERVAL}. The caching helps to avoid many low-level + * calls, but at the same time pick up any IP or FQDN changes. Although the underlying JDK implementation uses caching + * too, the refresh interval for logging may be much longer due to the nature of the use. + * + * @author evitaliy + * @since 26 Mar 2018 + */ +@SuppressWarnings({"UseOfSystemOutOrSystemErr", "CallToPrintStackTrace", "squid:S106", "squid:S1148"}) +public class HostAddress { + + private static final long DEFAULT_REFRESH_INTERVAL = 60000L; // 1 min + + private final long interval; + + private CacheEntry cachedAddress; + + public HostAddress() { + this(DEFAULT_REFRESH_INTERVAL); + } + + /** + * Creates a cache for host address with a custom refresh interval. + */ + public HostAddress(long refreshInterval) { + this.interval = refreshInterval; + this.cachedAddress = new CacheEntry(System.currentTimeMillis(), read()); + } + + /** + * Returns an address (host name and IP address) of the local system. + * + * @return local host address or null if it could not be read for some reason + */ + public synchronized InetAddress get() { + + long current = System.currentTimeMillis(); + if (current - cachedAddress.lastUpdated < interval) { + return cachedAddress.address; + } + + InetAddress address = read(); + cachedAddress = new CacheEntry(current, address); + return address; + } + + private InetAddress read() { + + try { + return InetAddress.getLocalHost(); + } catch (UnknownHostException e) { + e.printStackTrace(); // can't really use logging + return null; // let register the attempt even if failed + } + } + + private static class CacheEntry { + + private final long lastUpdated; + private final InetAddress address; + + private CacheEntry(long lastUpdated, InetAddress address) { + this.lastUpdated = lastUpdated; + this.address = address; + } + } +} diff --git a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/main/java/org/openecomp/sdc/logging/context/InstanceId.java b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/main/java/org/openecomp/sdc/logging/context/InstanceId.java new file mode 100644 index 0000000000..73544e1d9f --- /dev/null +++ b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/main/java/org/openecomp/sdc/logging/context/InstanceId.java @@ -0,0 +1,52 @@ +/* + * Copyright © 2016-2018 European Support Limited + * + * 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. + */ + +package org.openecomp.sdc.logging.context; + +import java.util.UUID; + +/** + * Holds a unique ID of the logging entity. Is useful to distinguish between different nodes of the same application. If + * it can be assumed, that the node can be re-started, then the unique ID must be retained on the disk. + * + * @author evitaliy + * @since 04 Mar 2018 + */ +@SuppressWarnings({"UseOfSystemOutOrSystemErr", "CallToPrintStackTrace", "squid:S106", "squid:S1148"}) +public class InstanceId { + + private static final String INSTANCE_ID; + + static { + // for some reason Java Preferences API + // https://docs.oracle.com/javase/8/docs/technotes/guides/preferences/overview.html + // didn't work in a Docker container, so for now just generate an ID every time + INSTANCE_ID = UUID.randomUUID().toString(); + } + + private InstanceId() { + // prevent instantiation + } + + /** + * A unique ID of the logging entity. + * + * @return unique logging entity ID + */ + public static String get() { + return INSTANCE_ID; + } +} diff --git a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/main/java/org/openecomp/sdc/logging/slf4j/AuditField.java b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/main/java/org/openecomp/sdc/logging/slf4j/AuditField.java new file mode 100644 index 0000000000..3e44a34722 --- /dev/null +++ b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/main/java/org/openecomp/sdc/logging/slf4j/AuditField.java @@ -0,0 +1,44 @@ +/* + * Copyright © 2016-2018 European Support Limited + * + * 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. + */ + +package org.openecomp.sdc.logging.slf4j; + +/** + * MDC fields that represent audit data. + * + * @author evitaliy + * @since 25 Mar 2018 + */ +enum AuditField implements MDCField { + + BEGIN_TIMESTAMP("BeginTimestamp"), + END_TIMESTAMP("EndTimestamp"), + ELAPSED_TIME("ElapsedTime"), + STATUS_CODE("StatusCode"), + RESPONSE_CODE("ResponseCode"), + RESPONSE_DESCRIPTION("ResponseDescription"), + CLIENT_IP_ADDRESS("ClientIpAddress"); + + private final String key; + + AuditField(String key) { + this.key = key; + } + + public String asKey() { + return key; + } +} diff --git a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/main/java/org/openecomp/sdc/logging/slf4j/ContextField.java b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/main/java/org/openecomp/sdc/logging/slf4j/ContextField.java index 6aa689bf21..cce5f44863 100644 --- a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/main/java/org/openecomp/sdc/logging/slf4j/ContextField.java +++ b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/main/java/org/openecomp/sdc/logging/slf4j/ContextField.java @@ -17,12 +17,12 @@ package org.openecomp.sdc.logging.slf4j; /** - * MDC fields to work with - populate, clear, copy. + * MDC fields that represent context data. * * @author evitaliy * @since 23 Mar 2018 */ -enum ContextField { +enum ContextField implements MDCField { REQUEST_ID("RequestId"), SERVICE_NAME("ServiceName"), diff --git a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/main/java/org/openecomp/sdc/logging/slf4j/GlobalContextProvider.java b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/main/java/org/openecomp/sdc/logging/slf4j/GlobalContextProvider.java index a415e22c63..5f2963ec40 100644 --- a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/main/java/org/openecomp/sdc/logging/slf4j/GlobalContextProvider.java +++ b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/main/java/org/openecomp/sdc/logging/slf4j/GlobalContextProvider.java @@ -19,7 +19,8 @@ package org.openecomp.sdc.logging.slf4j; import java.net.InetAddress; import java.util.EnumMap; import java.util.Map; -import org.openecomp.sdc.logging.GlobalLoggingContext; +import org.openecomp.sdc.logging.context.HostAddress; +import org.openecomp.sdc.logging.context.InstanceId; /** * Maps global logging context to corresponding MDC fields. @@ -29,13 +30,15 @@ import org.openecomp.sdc.logging.GlobalLoggingContext; */ class GlobalContextProvider implements ContextProvider { + private static final HostAddress HOST_ADDRESS_CACHE = new HostAddress(); + @Override public Map values() { Map values = new EnumMap<>(ContextField.class); - values.put(ContextField.INSTANCE_ID, GlobalLoggingContext.getInstanceId()); + values.put(ContextField.INSTANCE_ID, InstanceId.get()); - InetAddress hostAddress = GlobalLoggingContext.getHostAddress(); + InetAddress hostAddress = HOST_ADDRESS_CACHE.get(); if (hostAddress != null) { values.put(ContextField.SERVER, hostAddress.getHostName()); values.put(ContextField.SERVER_IP_ADDRESS, hostAddress.getHostAddress()); diff --git a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/main/java/org/openecomp/sdc/logging/slf4j/MDCField.java b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/main/java/org/openecomp/sdc/logging/slf4j/MDCField.java new file mode 100644 index 0000000000..1096face85 --- /dev/null +++ b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/main/java/org/openecomp/sdc/logging/slf4j/MDCField.java @@ -0,0 +1,29 @@ +/* + * Copyright © 2016-2018 European Support Limited + * + * 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. + */ + +package org.openecomp.sdc.logging.slf4j; + +/** + * Represents an MDC field. Maps a Java type to an MDC key that can be referred to in logger configuration. + * + * @author evitaliy + * @since 25 Mar 2018 + */ +interface MDCField { + + String asKey(); + +} diff --git a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/main/java/org/openecomp/sdc/logging/slf4j/MetricsField.java b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/main/java/org/openecomp/sdc/logging/slf4j/MetricsField.java new file mode 100644 index 0000000000..fda0c8b683 --- /dev/null +++ b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/main/java/org/openecomp/sdc/logging/slf4j/MetricsField.java @@ -0,0 +1,47 @@ +/* + * Copyright © 2016-2018 European Support Limited + * + * 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. + */ + +package org.openecomp.sdc.logging.slf4j; + +/** + * DC fields that represent metrics data. + * + * @author evitaliy + * @since 26 Mar 2018 + */ +public enum MetricsField implements MDCField { + + BEGIN_TIMESTAMP("BeginTimestamp"), + END_TIMESTAMP("EndTimestamp"), + ELAPSED_TIME("ElapsedTime"), + STATUS_CODE("StatusCode"), + RESPONSE_CODE("ResponseCode"), + RESPONSE_DESCRIPTION("ResponseDescription"), + CLIENT_IP_ADDRESS("ClientIpAddress"), + TARGET_VIRTUAL_ENTITY("TargetVirtualEntity"), + TARGET_ENTITY("TargetEntity"); + + private final String key; + + MetricsField(String key) { + this.key = key; + } + + public String asKey() { + return key; + } + +} diff --git a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/main/java/org/openecomp/sdc/logging/slf4j/SLF4JLoggerWrapper.java b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/main/java/org/openecomp/sdc/logging/slf4j/SLF4JLoggerWrapper.java index 783dac4ed4..fbb5fbf1f2 100644 --- a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/main/java/org/openecomp/sdc/logging/slf4j/SLF4JLoggerWrapper.java +++ b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/main/java/org/openecomp/sdc/logging/slf4j/SLF4JLoggerWrapper.java @@ -16,22 +16,16 @@ package org.openecomp.sdc.logging.slf4j; -import static org.openecomp.sdc.logging.slf4j.SLF4JLoggerWrapper.AuditField.BEGIN_TIMESTAMP; -import static org.openecomp.sdc.logging.slf4j.SLF4JLoggerWrapper.AuditField.CLIENT_IP_ADDRESS; -import static org.openecomp.sdc.logging.slf4j.SLF4JLoggerWrapper.AuditField.ELAPSED_TIME; -import static org.openecomp.sdc.logging.slf4j.SLF4JLoggerWrapper.AuditField.END_TIMESTAMP; -import static org.openecomp.sdc.logging.slf4j.SLF4JLoggerWrapper.AuditField.RESPONSE_CODE; -import static org.openecomp.sdc.logging.slf4j.SLF4JLoggerWrapper.AuditField.RESPONSE_DESCRIPTION; -import static org.openecomp.sdc.logging.slf4j.SLF4JLoggerWrapper.AuditField.STATUS_CODE; - -import java.text.Format; import java.text.SimpleDateFormat; import org.openecomp.sdc.logging.api.AuditData; import org.openecomp.sdc.logging.api.Logger; +import org.openecomp.sdc.logging.api.MetricsData; import org.slf4j.LoggerFactory; import org.slf4j.MDC; /** + * Delegates log calls to SLF4J API and MDC. + * * @author evitaliy * @since 08 Jan 18 */ @@ -40,40 +34,17 @@ class SLF4JLoggerWrapper implements Logger { //The specified format presents time in UTC formatted per ISO 8601, as required by ONAP logging guidelines private static final String DATE_TIME_PATTERN = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX"; - private static final String PREFIX = ""; - - enum AuditField { - - BEGIN_TIMESTAMP(PREFIX + "BeginTimestamp"), - END_TIMESTAMP(PREFIX + "EndTimestamp"), - ELAPSED_TIME(PREFIX + "ElapsedTime"), - STATUS_CODE(PREFIX + "StatusCode"), - RESPONSE_CODE(PREFIX + "ResponseCode"), - RESPONSE_DESCRIPTION(PREFIX + "ResponseDescription"), - CLIENT_IP_ADDRESS(PREFIX + "ClientIpAddress"); - - private final String key; - - AuditField(String key) { - this.key = key; - } - - public String asKey() { - return key; - } - } - private final org.slf4j.Logger logger; - SLF4JLoggerWrapper(org.slf4j.Logger delegate) { - this.logger = delegate; - } - // May cause http://www.slf4j.org/codes.html#loggerNameMismatch SLF4JLoggerWrapper(Class clazz) { this(LoggerFactory.getLogger(clazz)); } + SLF4JLoggerWrapper(org.slf4j.Logger delegate) { + this.logger = delegate; + } + SLF4JLoggerWrapper(String className) { this(LoggerFactory.getLogger(className)); } @@ -90,27 +61,55 @@ class SLF4JLoggerWrapper implements Logger { @Override public void metrics(String msg) { - logger.info(Markers.METRICS, msg); + // do nothing, left for backward compatibility } @Override - public void metrics(String msg, Object arg) { - logger.info(Markers.METRICS, msg, arg); + public void metrics(MetricsData data) { + + if (data == null) { + return; // not going to fail because of null + } + + try { + putMetricsOnMdc(data); + logger.info(Markers.METRICS, ""); + } finally { + clearMetricsFromMdc(); + } } - @Override - public void metrics(String msg, Object arg1, Object arg2) { - logger.info(Markers.METRICS, msg, arg1, arg2); + private void putMetricsOnMdc(MetricsData metrics) { + + SimpleDateFormat dateFormat = new SimpleDateFormat(DATE_TIME_PATTERN); + unsafePutOnMdc(MetricsField.BEGIN_TIMESTAMP, dateFormat.format(metrics.getStartTime())); + unsafePutOnMdc(MetricsField.END_TIMESTAMP, dateFormat.format(metrics.getEndTime())); + unsafePutOnMdc(MetricsField.ELAPSED_TIME, String.valueOf(metrics.getEndTime() - metrics.getStartTime())); + safePutOnMdc(MetricsField.RESPONSE_CODE, metrics.getResponseCode()); + safePutOnMdc(MetricsField.RESPONSE_DESCRIPTION, metrics.getResponseDescription()); + safePutOnMdc(MetricsField.CLIENT_IP_ADDRESS, metrics.getClientIpAddress()); + safePutOnMdc(MetricsField.TARGET_ENTITY, metrics.getTargetEntity()); + safePutOnMdc(MetricsField.TARGET_VIRTUAL_ENTITY, metrics.getTargetVirtualEntity()); + + if (metrics.getStatusCode() != null) { + unsafePutOnMdc(MetricsField.STATUS_CODE, metrics.getStatusCode().name()); + } } - @Override - public void metrics(String msg, Object... arguments) { - logger.info(Markers.METRICS, msg, arguments); + private void clearMetricsFromMdc() { + for (MetricsField f : MetricsField.values()) { + MDC.remove(f.asKey()); + } } - @Override - public void metrics(String msg, Throwable t) { - logger.info(Markers.METRICS, msg, t); + private static void unsafePutOnMdc(MDCField field, String value) { + MDC.put(field.asKey(), value); + } + + private static void safePutOnMdc(MDCField field, String value) { + if (value != null) { + unsafePutOnMdc(field, value); + } } @Override @@ -125,36 +124,33 @@ class SLF4JLoggerWrapper implements Logger { return; // not failing if null } - putTimes(data); - putIfNotNull(RESPONSE_CODE.key, data.getResponseCode()); - putIfNotNull(RESPONSE_DESCRIPTION.key, data.getResponseDescription()); - putIfNotNull(CLIENT_IP_ADDRESS.key, data.getClientIpAddress()); - - if (data.getStatusCode() != null) { - MDC.put(STATUS_CODE.key, data.getStatusCode().name()); - } - try { + putAuditOnMdc(data); logger.info(Markers.AUDIT, ""); } finally { - for (AuditField f : AuditField.values()) { - MDC.remove(f.key); - } + clearAuditFromMdc(); } } - private void putIfNotNull(String key, String value) { - if (value != null) { - MDC.put(key, value); + private void putAuditOnMdc(AuditData audit) { + + SimpleDateFormat dateFormat = new SimpleDateFormat(DATE_TIME_PATTERN); + unsafePutOnMdc(AuditField.BEGIN_TIMESTAMP, dateFormat.format(audit.getStartTime())); + unsafePutOnMdc(AuditField.END_TIMESTAMP, dateFormat.format(audit.getEndTime())); + unsafePutOnMdc(AuditField.ELAPSED_TIME, String.valueOf(audit.getEndTime() - audit.getStartTime())); + safePutOnMdc(AuditField.RESPONSE_CODE, audit.getResponseCode()); + safePutOnMdc(AuditField.RESPONSE_DESCRIPTION, audit.getResponseDescription()); + safePutOnMdc(AuditField.CLIENT_IP_ADDRESS, audit.getClientIpAddress()); + + if (audit.getStatusCode() != null) { + unsafePutOnMdc(AuditField.STATUS_CODE, audit.getStatusCode().name()); } } - private void putTimes(AuditData data) { - // SimpleDateFormat is not thread-safe and cannot be a constant - Format dateTimeFormat = new SimpleDateFormat(DATE_TIME_PATTERN); - MDC.put(BEGIN_TIMESTAMP.key, dateTimeFormat.format(data.getStartTime())); - MDC.put(END_TIMESTAMP.key, dateTimeFormat.format(data.getEndTime())); - MDC.put(ELAPSED_TIME.key, String.valueOf(data.getEndTime() - data.getStartTime())); + private void clearAuditFromMdc() { + for (AuditField f : AuditField.values()) { + MDC.remove(f.asKey()); + } } @Override -- cgit 1.2.3-korg