diff options
author | vempo <vitaliy.emporopulo@amdocs.com> | 2018-03-26 20:37:06 +0300 |
---|---|---|
committer | Oren Kleks <orenkle@amdocs.com> | 2018-04-01 07:57:35 +0000 |
commit | 8eff104effad587c04a00cdd008935af38ee7dc9 (patch) | |
tree | 25d6307d7e90cb8d49d0a6cd1f94097747ce7eea /openecomp-be/lib | |
parent | 8d74513329f8b6c6783024de866784f32c4b0f2c (diff) |
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 <vitaliy.emporopulo@amdocs.com>
Diffstat (limited to 'openecomp-be/lib')
24 files changed, 953 insertions, 854 deletions
diff --git a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/api/AuditData.java b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/api/AuditData.java index ecf795b2d5..b7c4e0d78f 100644 --- a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/api/AuditData.java +++ b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/api/AuditData.java @@ -17,19 +17,15 @@ package org.openecomp.sdc.logging.api; /** - * Builder to populate audit data for logging according to - * <a href="https://wiki.onap.org/download/attachments/1015849/ONAP%20application%20logging%20guidelines.pdf?api=v2> - * ONAP application logging guidelines</a>. This includes only data known to an application, and not otherwise available - * to the logging framework. + * Builder to populate <i>audit</i> data. This includes only data known to an application, and not otherwise available + * to the logging framework. As opposed, for example, to local runtime, host address, etc. * * @author KATYR, evitaliy * @since February 15, 2018 */ public class AuditData { - // A concrete implementation interface was chosen over an interface to enable to gracefully add new fields without - // affecting client code. Also, the builder can be implemented differently if needed, without affecting client code. - // For instance, it may delegate the population and instantiation to a service provider. + // don't inherit from MetricsData because it has a very different meaning private final long startTime; private final long endTime; diff --git a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/api/ContextData.java b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/api/ContextData.java index ea777d5907..43f0143774 100644 --- a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/api/ContextData.java +++ b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/api/ContextData.java @@ -17,8 +17,9 @@ package org.openecomp.sdc.logging.api; /** - * Builder to populate logging context data. This includes only data known to an application, and not otherwise - * available to the logging framework. + * Builder to populate logging <i>context</i> data, i.e. data that should be available to any log writing event + * throughout an application. This includes only data known at some point to the application (e.g. at an API call), + * and not otherwise available to the logging framework (e.g. information about local runtime, machine, etc.). * * @author evitaliy * @since Mar 22, 2018 diff --git a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/api/Logger.java b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/api/Logger.java index d02e99f9a2..d100a2d7f9 100644 --- a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/api/Logger.java +++ b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/api/Logger.java @@ -31,16 +31,16 @@ public interface Logger { boolean isMetricsEnabled(); + void metrics(MetricsData data); + + /** + * Kept for backward compatibility. + * + * @deprecated will be removed soon, {@link #metrics(MetricsData)} must be used instead + */ + @Deprecated void metrics(String msg); - void metrics(String msg, Object arg); - - void metrics(String msg, Object arg1, Object arg2); - - void metrics(String msg, Object... arguments); - - void metrics(String msg, Throwable t); - boolean isAuditEnabled(); void audit(AuditData data); diff --git a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/api/LoggerFactory.java b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/api/LoggerFactory.java index 399fd3717e..1f3df8bcc0 100644 --- a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/api/LoggerFactory.java +++ b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/api/LoggerFactory.java @@ -16,9 +16,8 @@ package org.openecomp.sdc.logging.api; -import org.openecomp.sdc.logging.spi.LoggerCreationService; - import java.util.Objects; +import org.openecomp.sdc.logging.spi.LoggerCreationService; /** * <a>Factory to hide a concrete, framework-specific implementation of logger creation.</a> @@ -69,27 +68,12 @@ public class LoggerFactory { } @Override - public void metrics(String msg) { + public void metrics(MetricsData msg) { // no-op } @Override - public void metrics(String msg, Object arg) { - // no-op - } - - @Override - public void metrics(String msg, Object arg1, Object arg2) { - // no-op - } - - @Override - public void metrics(String msg, Object... arguments) { - // no-op - } - - @Override - public void metrics(String msg, Throwable t) { + public void metrics(String msg) { // no-op } diff --git a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/api/MetricsData.java b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/api/MetricsData.java new file mode 100644 index 0000000000..c44ab42efa --- /dev/null +++ b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/api/MetricsData.java @@ -0,0 +1,248 @@ +/* + * 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.api; + +/** + * Builder to populate <i>metrics</i> data. This includes only data known to an application, and not otherwise available + * to the logging framework. + * + * @author evitaliy + * @since 26 Mar 2018 + */ +public class MetricsData { + + // don't inherit from AuditData because it has a very different meaning + + private final long startTime; + private final long endTime; + private final StatusCode statusCode; + private final String responseCode; + private final String responseDescription; + private final String clientIpAddress; + private final String targetVirtualEntity; + private final String targetEntity; + + private MetricsData(final MetricsDataBuilder builder) { + this.startTime = builder.startTime; + this.endTime = builder.endTime; + this.statusCode = builder.statusCode; + this.responseCode = builder.responseCode; + this.responseDescription = builder.responseDescription; + this.clientIpAddress = builder.clientIpAddress; + this.targetEntity = builder.targetEntity; + this.targetVirtualEntity = builder.targetVirtualEntity; + } + + /** + * Begin timestamp of an API invocation. + * + * @return timestamp + */ + public long getStartTime() { + return startTime; + } + + /** + * End timestamp of an API invocation. + * + * @return timestamp + */ + public long getEndTime() { + return endTime; + } + + /** + * Result status of an API invocation. + * + * @return protocol and application agnostic status code + */ + public StatusCode getStatusCode() { + return statusCode; + } + + /** + * Application/protocol specific response status of an API invocation. + * + * @return response code + */ + public String getResponseCode() { + return responseCode; + } + + /** + * Application/protocol specific response in a human-friendly way. + * + * @return human-friendly response description + */ + public String getResponseDescription() { + return responseDescription; + } + + /** + * IP address of the invoking client when available. + * + * @return IP address + */ + public String getClientIpAddress() { + return clientIpAddress; + } + + /** + * External entity invoked by the local system. + * + * @return identifier of an external entity (system, component, sub-component) + */ + public String getTargetEntity() { + return targetEntity; + } + + /** + * External API invoked by the local system. + * + * @return name of an external API + */ + public String getTargetVirtualEntity() { + return targetVirtualEntity; + } + + @Override + public String toString() { + return "AuditData{startTime=" + startTime + ", endTime=" + endTime + ", statusCode=" + statusCode + + ", responseCode=" + responseCode + ", responseDescription=" + responseDescription + + ", clientIpAddress=" + clientIpAddress + '}'; + } + + public static MetricsDataBuilder builder() { + return new MetricsDataBuilder(); + } + + /** + * Fluent API for building metrics data. + */ + public static class MetricsDataBuilder { + + private long startTime; + private long endTime; + private StatusCode statusCode; + private String responseCode; + private String responseDescription; + private String clientIpAddress; + private String targetEntity; + private String targetVirtualEntity; + + MetricsDataBuilder() { /* package-private default constructor to hide the public one */ } + + /** + * Begin timestamp of an activity being audited. + * + * @param startTime local timestamp, usually received from {@link System#currentTimeMillis()} + * @return this builder for fluent API + */ + public MetricsDataBuilder startTime(final long startTime) { + this.startTime = startTime; + return this; + } + + /** + * End timestamp of an activity being audited. + * + * @param endTime local timestamp, usually received from {@link System#currentTimeMillis()} + * @return this builder for fluent API + */ + public MetricsDataBuilder endTime(final long endTime) { + this.endTime = endTime; + return this; + } + + /** + * Indicate whether an invocation was successful. It is up the the application to decide if a particular result + * must be treated as a success or a failure. + * + * @param statusCode invocation status success/failure + * @return this builder for fluent API + */ + public MetricsDataBuilder statusCode(final StatusCode statusCode) { + this.statusCode = statusCode; + return this; + } + + /** + * Application/protocol specific response code. For a Web API, it is likely a standard HTTP response code. + * + * @param responseCode response code that depends on application and invocation protocol + * @return this builder for fluent API + */ + public MetricsDataBuilder responseCode(final String responseCode) { + this.responseCode = responseCode; + return this; + } + + /** + * Response description that explains {@link #responseCode(String)} in a human-friendly way. For a Web API, it + * is likely to be a standard HTTP response phrase. + * + * @param responseDescription human-friendly response description + * @return this builder for fluent API + */ + public MetricsDataBuilder responseDescription(final String responseDescription) { + this.responseDescription = responseDescription; + return this; + } + + /** + * IP address of an invoking client. + * + * @param clientIpAddress IP address + * @return this builder for fluent API + */ + public MetricsDataBuilder clientIpAddress(final String clientIpAddress) { + this.clientIpAddress = clientIpAddress; + return this; + } + + /** + * External entity at which the operation is invoked. + * + * @param targetEntity external entity identifier + * @return this builder for fluent API + */ + public MetricsDataBuilder targetEntity(String targetEntity) { + this.targetEntity = targetEntity; + return this; + } + + /** + * Name of the API or operation activities invoked at the external entity. + * + * @param targetVirtualEntity invoked external API + * @return this builder for fluent API + */ + public MetricsDataBuilder targetVirtualEntity(String targetVirtualEntity) { + this.targetVirtualEntity = targetVirtualEntity; + return this; + } + + /** + * Create an instance of {@link MetricsData}. + * + * @return a populated instance of audit data + */ + public MetricsData build() { + return new MetricsData(this); + } + } +} diff --git a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/api/package-info.java b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/api/package-info.java new file mode 100644 index 0000000000..a8ecad0c55 --- /dev/null +++ b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/api/package-info.java @@ -0,0 +1,38 @@ +/* + * 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. + */ + +/** + * <p>Client-visible API for logging, implemented according to + * <a href="https://wiki.onap.org/download/attachments/1015849/ONAP%20application%20logging%20guidelines.pdf?api=v2"> + * ONAP application logging guidelines</a>. The actual implementation is delegated to a service provider bound through + * the <a href="https://docs.oracle.com/javase/tutorial/ext/basics/spi.html">Java SPI</a> mechanism. The provider must + * implement {@link org.openecomp.sdc.logging.spi.LoggingServiceProvider}.</p> + * <p>The logging API collects the following types of data:</p> + * <ol> + * <li>Context that must be propagated throughout the application, and available at any point for debug and error + * reporting.</li> + * <li>Audit data, reflecting the invocation of a local, usually REST, API.</li> + * <li>Metrics data, reflecting the invocation of a remote API by current system (component).</li> + * </ol> + * <p>The construction of all three types of data follows the same pattern for consistency. The builder pattern has + * been chosen over an interface to enable to gracefully add new fields without affecting the client code. Also, the + * builder can be implemented differently if needed, also without affecting client code. For instance, it may delegate + * the instantiation and population of a data object to the service provider.</p> + * + * @author evitaliy + * @since 26 Mar 2018 + */ +package org.openecomp.sdc.logging.api;
\ No newline at end of file diff --git a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/test/java/org/openecomp/sdc/logging/api/LoggerFactoryTest.java b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/test/java/org/openecomp/sdc/logging/api/LoggerFactoryTest.java index 1889f3e172..a1fe8c2b0f 100644 --- a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/test/java/org/openecomp/sdc/logging/api/LoggerFactoryTest.java +++ b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/test/java/org/openecomp/sdc/logging/api/LoggerFactoryTest.java @@ -16,14 +16,15 @@ package org.openecomp.sdc.logging.api; -import org.testng.annotations.Test; - -import java.lang.reflect.Field; - import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertNotNull; +import java.lang.reflect.Field; +import org.testng.annotations.Test; + /** + * Unit-test creation of a logger via factory, assuming not default binding. + * * @author evitaliy * @since 14/09/2016. */ @@ -71,6 +72,6 @@ public class LoggerFactoryTest { logger.info(""); logger.debug(""); logger.audit(null); - logger.metrics(""); + logger.metrics(MetricsData.builder().build()); } } diff --git a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/test/java/org/openecomp/sdc/logging/api/MetricsDataTest.java b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/test/java/org/openecomp/sdc/logging/api/MetricsDataTest.java new file mode 100644 index 0000000000..a3c8b1039a --- /dev/null +++ b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/test/java/org/openecomp/sdc/logging/api/MetricsDataTest.java @@ -0,0 +1,71 @@ +/* + * 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.api; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNull; + +import org.testng.annotations.Test; + +/** + * Unit-testing metrics builder and structure. + * + * @author evitaliy + * @since 04 Mar 18 + */ +public class MetricsDataTest { + + @Test + public void allMetricsPropertiesReadWhenPopulated() { + + final long start = System.currentTimeMillis(); + final long end = start + 1000; + final String responseCode = "Metrics-Response-Code"; + final String responseDescription = "Metrics-Response-Description"; + final String ipAddress = "10.56.20.72"; + final String targetEntity = "Metrics-Target-Entity"; + final String targetVirtualEntity = "Metrics-Target-Virtual-Entity"; + + MetricsData data = MetricsData.builder().startTime(start).endTime(end).statusCode(StatusCode.COMPLETE) + .responseCode(responseCode).responseDescription(responseDescription) + .clientIpAddress(ipAddress).targetEntity(targetEntity) + .targetVirtualEntity(targetVirtualEntity).build(); + + assertEquals(data.getClientIpAddress(), ipAddress); + assertEquals(data.getEndTime(), end); + assertEquals(data.getStartTime(), start); + assertEquals(data.getResponseCode(), responseCode); + assertEquals(data.getResponseDescription(), responseDescription); + assertEquals(data.getStatusCode(), StatusCode.COMPLETE); + assertEquals(data.getTargetEntity(), targetEntity); + assertEquals(data.getTargetVirtualEntity(), targetVirtualEntity); + + } + + @Test + public void allMetricsPropertiesEmptyWhenUnpopulated() { + MetricsData data = MetricsData.builder().build(); + assertEquals(data.getStartTime(), 0); + assertEquals(data.getEndTime(), 0); + assertNull(data.getClientIpAddress()); + assertNull(data.getResponseCode()); + assertNull(data.getResponseDescription()); + assertNull(data.getStatusCode()); + assertNull(data.getTargetEntity()); + assertNull(data.getTargetVirtualEntity()); + } +}
\ No newline at end of file diff --git a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/pom.xml b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/pom.xml index dbaef2ada6..e3fb79915e 100644 --- a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/pom.xml +++ b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/pom.xml @@ -19,12 +19,6 @@ <version>${project.version}</version> </dependency> <dependency> - <groupId>org.aspectj</groupId> - <artifactId>aspectjrt</artifactId> - <version>${aspectj.version}</version> - <scope>provided</scope> - </dependency> - <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>${slf4j-api.version}</version> 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; - -/** - * <p>Wraps around any method annotated with {@link Metrics} to measure and log its execution time - * in milliseconds.</p> - * <p>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.</p> - * <p>See, for example, <a href="http://docs.spring.io/spring/docs/current/spring-framework-reference/html/aop.html"> - * Aspect Oriented Programming with Spring</a>.</p> - * - * @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 <code>null</code> 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<ContextField, String> values() { Map<ContextField, String> 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-api/src/main/java/org/openecomp/sdc/logging/api/annotations/Metrics.java b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/main/java/org/openecomp/sdc/logging/slf4j/MDCField.java index 2be7eac01c..1096face85 100644 --- a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-api/src/main/java/org/openecomp/sdc/logging/api/annotations/Metrics.java +++ b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/main/java/org/openecomp/sdc/logging/slf4j/MDCField.java @@ -1,12 +1,12 @@ /* - * Copyright © 2016-2017 European Support Limited + * 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. @@ -14,14 +14,16 @@ * limitations under the License. */ -package org.openecomp.sdc.logging.api.annotations; +package org.openecomp.sdc.logging.slf4j; /** - * Indicates a method whose execution time should be measured and logged as required for Open OPENECOMP metrics. + * Represents an MDC field. Maps a Java type to an MDC key that can be referred to in logger configuration. * * @author evitaliy - * @since 27/07/2016. + * @since 25 Mar 2018 */ +interface MDCField { + + String asKey(); -public @interface Metrics { } 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 diff --git a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/test/java/org/openecomp/sdc/logging/LogFileCreationTest.java b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/test/java/org/openecomp/sdc/logging/LogFileCreationTest.java deleted file mode 100644 index 14dab13c9e..0000000000 --- a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/test/java/org/openecomp/sdc/logging/LogFileCreationTest.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * 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; - -import org.openecomp.sdc.logging.api.AuditData; -import org.openecomp.sdc.logging.api.Logger; -import org.openecomp.sdc.logging.api.LoggerFactory; -import org.testng.annotations.Test; - -/** - * This is only for manual testing to make sure that a log file is created as expected. - * To run change {@link #ENABLED} to 'true' - * - * @author evitaliy - * @since 13/09/2016. - */ -public class LogFileCreationTest { - - private static final boolean ENABLED = false; // for manual testing change to 'true' - - private static final Logger LOGGER = LoggerFactory.getLogger(LogFileCreationTest.class); - - @Test(enabled = ENABLED) - public void testMetrics() { - LOGGER.metrics("This is metrics"); - } - - @Test(enabled = ENABLED) - public void testAudit() { - LOGGER.audit(AuditData.builder().build()); - } - - @Test(enabled = ENABLED) - public void testDebug() { - LOGGER.debug("This is debug"); - } - - @Test(enabled = ENABLED) - public void testInfo() { - LOGGER.info("This is info"); - } - - @Test(enabled = ENABLED) - public void testWarn() { - LOGGER.warn("This is warning"); - } - - @Test(enabled = ENABLED) - public void testError() { - LOGGER.error("This is error"); - } -} diff --git a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/test/java/org/openecomp/sdc/logging/aspects/MetricsAspectTest.java b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/test/java/org/openecomp/sdc/logging/aspects/MetricsAspectTest.java deleted file mode 100644 index e4cd37995a..0000000000 --- a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/test/java/org/openecomp/sdc/logging/aspects/MetricsAspectTest.java +++ /dev/null @@ -1,429 +0,0 @@ -/* - * 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.aspects; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.UUID; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.function.Predicate; -import org.aspectj.lang.ProceedingJoinPoint; -import org.aspectj.lang.Signature; -import org.aspectj.lang.reflect.SourceLocation; -import org.aspectj.runtime.internal.AroundClosure; -import org.easymock.EasyMock; -import org.openecomp.sdc.logging.api.AuditData; -import org.openecomp.sdc.logging.api.Logger; -import org.openecomp.sdc.logging.api.LoggerFactory; -import org.powermock.api.easymock.PowerMock; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.modules.testng.PowerMockTestCase; -import org.testng.Assert; -import org.testng.annotations.Test; - -/** - * Unit-tests metrics aspect (AOP) behavior. - * - * @author evitaliy - * @since 17 Aug 2016 - */ -@PrepareForTest(LoggerFactory.class) -public class MetricsAspectTest extends PowerMockTestCase { - - private static final Object OBJ_TO_RETURN = new Object(); - private static final String EXPECTED_MESSAGE = "'{}' took {} milliseconds"; - - @Test - public void testLogExecutionTime() throws Throwable { - - String className = UUID.randomUUID().toString(); - String methodName = UUID.randomUUID().toString(); - - TestLogger logger = initLogging(className, true); - - MetricsAspect aspect = new MetricsAspect(); - MockProceedingJoinPoint pjp = new MockProceedingJoinPoint(className, methodName); - Object returned = aspect.logExecutionTime(pjp); - - Assert.assertEquals(OBJ_TO_RETURN, returned); - assertExecution(methodName, pjp, logger); - } - - private TestLogger initLogging(String className, boolean enabled) { - TestLogger logger = new TestLogger(enabled); - PowerMock.mockStatic(LoggerFactory.class); - EasyMock.expect(LoggerFactory.getLogger(className)).andReturn(logger); - PowerMock.replay(LoggerFactory.class); - return logger; - } - - private void assertExecution(String methodName, MockProceedingJoinPoint pjp, TestLogger logger) { - - Assert.assertEquals(1, pjp.getCount()); - Assert.assertTrue(logger.contains( - (event) -> (event != null) && (event.length == 3) && EXPECTED_MESSAGE.equals(event[0]) && methodName - .equals(event[1]) && (event[2] instanceof Long))); - } - - @Test - public void testMetricsDisabled() throws Throwable { - - String className = UUID.randomUUID().toString(); - String methodName = UUID.randomUUID().toString(); - - TestLogger logger = initLogging(className, false); - - MetricsAspect aspect = new MetricsAspect(); - MockProceedingJoinPoint pjp = new MockProceedingJoinPoint(className, methodName); - Object returned = aspect.logExecutionTime(pjp); - - Assert.assertEquals(OBJ_TO_RETURN, returned); - Assert.assertEquals(1, pjp.getCount()); - // return any event - must be empty - Assert.assertFalse(logger.contains((event) -> true)); - } - - @Test(expectedExceptions = IllegalArgumentException.class) - public void testThrowingError() throws Throwable { - - String className = UUID.randomUUID().toString(); - String methodName = UUID.randomUUID().toString(); - - final TestLogger logger = initLogging(className, true); - - MetricsAspect aspect = new MetricsAspect(); - MockProceedingJoinPoint pjp = new MockProceedingJoinPointWithException(className, methodName); - - try { - aspect.logExecutionTime(pjp); - } finally { - assertExecution(methodName, pjp, logger); - } - } - - private static class MockSignature implements Signature { - - private final String className; - private final String methodName; - - private MockSignature(String className, String methodName) { - this.className = className; - this.methodName = methodName; - } - - @Override - public String toShortString() { - return null; - } - - @Override - public String toLongString() { - return null; - } - - @Override - public String getName() { - return methodName; - } - - @Override - public int getModifiers() { - return 0; - } - - @Override - public Class getDeclaringType() { - return null; - } - - @Override - public String getDeclaringTypeName() { - return className; - } - } - - private static class MockProceedingJoinPoint implements ProceedingJoinPoint { - - private final AtomicInteger count = new AtomicInteger(0); - private final Signature signature; - - MockProceedingJoinPoint(String className, String methodName) { - this.signature = new MockSignature(className, methodName); - } - - int getCount() { - return count.get(); - } - - @Override - public void set$AroundClosure(AroundClosure aroundClosure) { - - } - - @Override - public Object proceed() throws Throwable { - count.incrementAndGet(); - return OBJ_TO_RETURN; - } - - @Override - public Object proceed(Object[] objects) { - return null; - } - - @Override - public String toShortString() { - return null; - } - - @Override - public String toLongString() { - return null; - } - - @Override - public Object getThis() { - return null; - } - - @Override - public Object getTarget() { - return null; - } - - @Override - public Object[] getArgs() { - return new Object[0]; - } - - @Override - public Signature getSignature() { - return this.signature; - } - - @Override - public SourceLocation getSourceLocation() { - return null; - } - - @Override - public String getKind() { - return null; - } - - @Override - public StaticPart getStaticPart() { - return null; - } - } - - private static class MockProceedingJoinPointWithException extends MockProceedingJoinPoint { - - MockProceedingJoinPointWithException(String className, String methodName) { - super(className, methodName); - } - - @Override - public Object proceed() throws Throwable { - super.proceed(); - throw new IllegalArgumentException(); - } - } - - private class TestLogger implements Logger { - - private final boolean enabled; - private final List<Object[]> events = Collections.synchronizedList(new ArrayList<>(10)); - - TestLogger(boolean enabled) { - this.enabled = enabled; - } - - @Override - public String getName() { - throw new RuntimeException("Not implemented"); - } - - @Override - public boolean isMetricsEnabled() { - return this.enabled; - } - - @Override - public void metrics(String var1) { - throw new RuntimeException("Not implemented"); - } - - @Override - public void metrics(String var1, Object var2) { - throw new RuntimeException("Not implemented"); - } - - @Override - public void metrics(String var1, Object var2, Object var3) { - - if (this.enabled) { - events.add(new Object[] {var1, var2, var3}); - } - } - - @Override - public void metrics(String var1, Object... var2) { - throw new RuntimeException("Not implemented"); - } - - @Override - public void metrics(String var1, Throwable throwable) { - throw new RuntimeException("Not implemented"); - } - - @Override - public boolean isAuditEnabled() { - throw new RuntimeException("Not implemented"); - } - - @Override - public void audit(AuditData var1) { - throw new RuntimeException("Not implemented"); - } - - @Override - public boolean isDebugEnabled() { - throw new RuntimeException("Not implemented"); - } - - @Override - public void debug(String var1) { - throw new RuntimeException("Not implemented"); - } - - @Override - public void debug(String var1, Object var2) { - throw new RuntimeException("Not implemented"); - } - - @Override - public void debug(String var1, Object var2, Object var3) { - throw new RuntimeException("Not implemented"); - } - - @Override - public void debug(String var1, Object... var2) { - throw new RuntimeException("Not implemented"); - } - - @Override - public void debug(String var1, Throwable throwable) { - throw new RuntimeException("Not implemented"); - } - - @Override - public boolean isInfoEnabled() { - throw new RuntimeException("Not implemented"); - } - - @Override - public void info(String var1) { - throw new RuntimeException("Not implemented"); - } - - @Override - public void info(String var1, Object var2) { - throw new RuntimeException("Not implemented"); - } - - @Override - public void info(String var1, Object var2, Object var3) { - throw new RuntimeException("Not implemented"); - } - - @Override - public void info(String var1, Object... var2) { - throw new RuntimeException("Not implemented"); - } - - @Override - public void info(String var1, Throwable throwable) { - throw new RuntimeException("Not implemented"); - } - - @Override - public boolean isWarnEnabled() { - throw new RuntimeException("Not implemented"); - } - - @Override - public void warn(String var1) { - throw new RuntimeException("Not implemented"); - } - - @Override - public void warn(String var1, Object var2) { - throw new RuntimeException("Not implemented"); - } - - @Override - public void warn(String var1, Object... var2) { - throw new RuntimeException("Not implemented"); - } - - @Override - public void warn(String var1, Object var2, Object var3) { - throw new RuntimeException("Not implemented"); - } - - @Override - public void warn(String var1, Throwable throwable) { - throw new RuntimeException("Not implemented"); - } - - @Override - public boolean isErrorEnabled() { - throw new RuntimeException("Not implemented"); - } - - @Override - public void error(String var1) { - throw new RuntimeException("Not implemented"); - } - - @Override - public void error(String var1, Object var2) { - throw new RuntimeException("Not implemented"); - } - - @Override - public void error(String var1, Object var2, Object var3) { - throw new RuntimeException("Not implemented"); - } - - @Override - public void error(String var1, Object... var2) { - throw new RuntimeException("Not implemented"); - } - - @Override - public void error(String var1, Throwable throwable) { - throw new RuntimeException("Not implemented"); - } - - boolean contains(Predicate<Object[]> predicate) { - return events.stream().anyMatch(predicate); - } - } -} diff --git a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/test/java/org/openecomp/sdc/logging/context/HostAddressTest.java b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/test/java/org/openecomp/sdc/logging/context/HostAddressTest.java new file mode 100644 index 0000000000..319bf19dcc --- /dev/null +++ b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/test/java/org/openecomp/sdc/logging/context/HostAddressTest.java @@ -0,0 +1,68 @@ +/* + * 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 static org.testng.Assert.assertNotNull; + +import java.net.InetAddress; +import java.net.UnknownHostException; +import org.easymock.EasyMock; +import org.powermock.api.easymock.PowerMock; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.testng.PowerMockTestCase; +import org.testng.annotations.Test; + +/** + * Retrieval and caching of host address. + * + * @author evitaliy + * @since 28 Mar 2018 + */ +@PrepareForTest(InetAddress.class) +public class HostAddressTest extends PowerMockTestCase { + + @Test + public void hostAddressIsAlwaysPopulated() { + assertNotNull(new HostAddress().get()); + } + + @Test + public void cachedAddressRemainsTheSameWhenGotWithingRefreshInterval() throws UnknownHostException { + mockInetAddress(1); + HostAddress addressCache = new HostAddress(1000); + addressCache.get(); + addressCache.get(); + } + + @Test + public void cachedAddressReplacedWhenGotAfterRefreshInterval() throws UnknownHostException { + mockInetAddress(2); + HostAddress addressCache = new HostAddress(-1); + addressCache.get(); + addressCache.get(); + } + + private void mockInetAddress(int times) throws UnknownHostException { + InetAddress inetAddress = EasyMock.mock(InetAddress.class); + EasyMock.replay(inetAddress); + PowerMock.mockStatic(InetAddress.class); + //noinspection ResultOfMethodCallIgnored + InetAddress.getLocalHost(); + PowerMock.expectLastCall().andReturn(inetAddress).times(times); + PowerMock.replay(InetAddress.class); + } +}
\ No newline at end of file diff --git a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/test/java/org/openecomp/sdc/logging/context/InstanceIdTest.java b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/test/java/org/openecomp/sdc/logging/context/InstanceIdTest.java new file mode 100644 index 0000000000..984cb3bade --- /dev/null +++ b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/test/java/org/openecomp/sdc/logging/context/InstanceIdTest.java @@ -0,0 +1,36 @@ +/* + * 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 static org.testng.Assert.assertNotNull; + +import org.testng.annotations.Test; + +/** + * Retrieval of instance ID. + * + * @author evitaliy + * @since 28 Mar 2018 + */ +public class InstanceIdTest { + + @Test + public void makeSureInstanceIdNotNull() { + assertNotNull(InstanceId.get()); + } + +}
\ No newline at end of file diff --git a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/test/java/org/openecomp/sdc/logging/slf4j/SLF4JLoggerWrapperTest.java b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/test/java/org/openecomp/sdc/logging/slf4j/SLF4JLoggerWrapperTest.java index 2c5233f9c9..f4a29efe8b 100644 --- a/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/test/java/org/openecomp/sdc/logging/slf4j/SLF4JLoggerWrapperTest.java +++ b/openecomp-be/lib/openecomp-sdc-logging-lib/openecomp-sdc-logging-core/src/test/java/org/openecomp/sdc/logging/slf4j/SLF4JLoggerWrapperTest.java @@ -16,13 +16,6 @@ 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 static org.testng.Assert.assertEquals; import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertNull; @@ -33,9 +26,11 @@ import java.lang.reflect.Proxy; import java.util.Arrays; import java.util.Map; import org.openecomp.sdc.logging.api.AuditData; +import org.openecomp.sdc.logging.api.MetricsData; import org.openecomp.sdc.logging.api.StatusCode; import org.slf4j.Logger; import org.slf4j.MDC; +import org.slf4j.Marker; import org.testng.annotations.Test; /** @@ -53,101 +48,209 @@ public class SLF4JLoggerWrapperTest { } @Test - public void beginTimeAvailableWhenPassed() { + public void metricsDoesNotFailWhenInputNull() { + new SLF4JLoggerWrapper(this.getClass()).metrics((MetricsData) null); + } + + @Test + public void auditBeginTimeAvailableWhenPassed() { SpyLogger spy = createSpy(); long start = System.currentTimeMillis(); new SLF4JLoggerWrapper(spy).audit(AuditData.builder().startTime(start).build()); - assertNotNull(spy.mdc().get(BEGIN_TIMESTAMP.asKey())); + assertNotNull(spy.mdc().get(AuditField.BEGIN_TIMESTAMP.asKey())); } @Test - public void entTimeAvailableWhenPassed() { + public void metricsBeginTimeAvailableWhenPassed() { + SpyLogger spy = createSpy(); + long start = System.currentTimeMillis(); + new SLF4JLoggerWrapper(spy).metrics(MetricsData.builder().startTime(start).build()); + assertNotNull(spy.mdc().get(MetricsField.BEGIN_TIMESTAMP.asKey())); + } + + @Test + public void auditEndTimeAvailableWhenPassed() { SpyLogger spy = createSpy(); long end = System.currentTimeMillis(); new SLF4JLoggerWrapper(spy).audit(AuditData.builder().endTime(end).build()); - assertNotNull(spy.mdc().get(END_TIMESTAMP.asKey())); + assertNotNull(spy.mdc().get(AuditField.END_TIMESTAMP.asKey())); } @Test - public void elapsedTimeAvailableWhenPassed() { + public void metricsEndTimeAvailableWhenPassed() { + SpyLogger spy = createSpy(); + long end = System.currentTimeMillis(); + new SLF4JLoggerWrapper(spy).metrics(MetricsData.builder().endTime(end).build()); + assertNotNull(spy.mdc().get(MetricsField.END_TIMESTAMP.asKey())); + } + + @Test + public void auditElapsedTimeAvailableWhenPassed() { SpyLogger spy = createSpy(); long start = System.currentTimeMillis(); new SLF4JLoggerWrapper(spy).audit(AuditData.builder() - .startTime(start).endTime(start).build()); - assertNotNull(spy.mdc().get(ELAPSED_TIME.asKey())); + .startTime(start).endTime(start + 777).build()); + assertEquals("777", spy.mdc().get(AuditField.ELAPSED_TIME.asKey())); + } + + @Test + public void metricsElapsedTimeAvailableWhenPassed() { + SpyLogger spy = createSpy(); + long start = System.currentTimeMillis(); + new SLF4JLoggerWrapper(spy).metrics(MetricsData.builder() + .startTime(start).endTime(start + 1024).build()); + assertEquals("1024", spy.mdc().get(MetricsField.ELAPSED_TIME.asKey())); } @Test - public void statusCodeAvailableWhenPassed() { + public void auditStatusCodeAvailableWhenPassed() { SpyLogger spy = createSpy(); new SLF4JLoggerWrapper(spy).audit(AuditData.builder().statusCode(StatusCode.COMPLETE).build()); - assertEquals(spy.mdc().get(STATUS_CODE.asKey()), StatusCode.COMPLETE.name()); + assertEquals(spy.mdc().get(AuditField.STATUS_CODE.asKey()), StatusCode.COMPLETE.name()); + } + + @Test + public void metricsStatusCodeAvailableWhenPassed() { + SpyLogger spy = createSpy(); + new SLF4JLoggerWrapper(spy).metrics(MetricsData.builder().statusCode(StatusCode.COMPLETE).build()); + assertEquals(spy.mdc().get(MetricsField.STATUS_CODE.asKey()), StatusCode.COMPLETE.name()); } @Test - public void statusCodeEmptyWhenNotPassed() { + public void auditStatusCodeEmptyWhenNotPassed() { SpyLogger spy = createSpy(); new SLF4JLoggerWrapper(spy).audit(AuditData.builder().build()); - assertNull(spy.mdc().get(STATUS_CODE.asKey())); + assertNull(spy.mdc().get(AuditField.STATUS_CODE.asKey())); + } + + @Test + public void metricsStatusCodeEmptyWhenNotPassed() { + SpyLogger spy = createSpy(); + new SLF4JLoggerWrapper(spy).metrics(MetricsData.builder().build()); + assertNull(spy.mdc().get(MetricsField.STATUS_CODE.asKey())); } @Test - public void responseCodeAvailableWhenPassed() { - final String responseCode = "SpyResponse"; + public void auditResponseCodeAvailableWhenPassed() { + final String responseCode = "AuditSpyResponse"; SpyLogger spy = createSpy(); new SLF4JLoggerWrapper(spy).audit(AuditData.builder().responseCode(responseCode).build()); - assertEquals(spy.mdc().get(RESPONSE_CODE.asKey()), responseCode); + assertEquals(spy.mdc().get(AuditField.RESPONSE_CODE.asKey()), responseCode); } @Test - public void responseCodeEmptyWhenNotPassed() { + public void metricsResponseCodeAvailableWhenPassed() { + final String responseCode = "MetricsSpyResponse"; + SpyLogger spy = createSpy(); + new SLF4JLoggerWrapper(spy).metrics(MetricsData.builder().responseCode(responseCode).build()); + assertEquals(spy.mdc().get(MetricsField.RESPONSE_CODE.asKey()), responseCode); + } + + @Test + public void auditResponseCodeEmptyWhenNotPassed() { SpyLogger spy = createSpy(); new SLF4JLoggerWrapper(spy).audit(AuditData.builder().build()); - assertNull(spy.mdc().get(RESPONSE_CODE.asKey())); + assertNull(spy.mdc().get(AuditField.RESPONSE_CODE.asKey())); + } + + @Test + public void metricsResponseCodeEmptyWhenNotPassed() { + SpyLogger spy = createSpy(); + new SLF4JLoggerWrapper(spy).metrics(MetricsData.builder().build()); + assertNull(spy.mdc().get(MetricsField.RESPONSE_CODE.asKey())); } @Test - public void responseDescriptionAvailableWhenPassed() { - final String responseDescription = "SpyDescription"; + public void auditResponseDescriptionAvailableWhenPassed() { + final String responseDescription = "AuditSpyDescription"; SpyLogger spy = createSpy(); new SLF4JLoggerWrapper(spy).audit(AuditData.builder().responseDescription(responseDescription).build()); - assertEquals(spy.mdc().get(RESPONSE_DESCRIPTION.asKey()), responseDescription); + assertEquals(spy.mdc().get(AuditField.RESPONSE_DESCRIPTION.asKey()), responseDescription); } @Test - public void responseDescriptionEmptyWhenNotPassed() { + public void metricsResponseDescriptionAvailableWhenPassed() { + final String responseDescription = "MetricsSpyDescription"; + SpyLogger spy = createSpy(); + new SLF4JLoggerWrapper(spy).metrics(MetricsData.builder().responseDescription(responseDescription).build()); + assertEquals(spy.mdc().get(MetricsField.RESPONSE_DESCRIPTION.asKey()), responseDescription); + } + + @Test + public void auditResponseDescriptionEmptyWhenNotPassed() { SpyLogger spy = createSpy(); new SLF4JLoggerWrapper(spy).audit(AuditData.builder().build()); - assertNull(spy.mdc().get(RESPONSE_DESCRIPTION.asKey())); + assertNull(spy.mdc().get(AuditField.RESPONSE_DESCRIPTION.asKey())); } @Test - public void clientIpAddressAvailableWhenPassed() { + public void metricsResponseDescriptionEmptyWhenNotPassed() { + SpyLogger spy = createSpy(); + new SLF4JLoggerWrapper(spy).metrics(MetricsData.builder().build()); + assertNull(spy.mdc().get(MetricsField.RESPONSE_DESCRIPTION.asKey())); + } + + @Test + public void auditClientIpAddressAvailableWhenPassed() { final String ipAddress = "10.56.20.20"; SpyLogger spy = createSpy(); new SLF4JLoggerWrapper(spy).audit(AuditData.builder().clientIpAddress(ipAddress).build()); - assertEquals(spy.mdc().get(CLIENT_IP_ADDRESS.asKey()), ipAddress); + assertEquals(spy.mdc().get(AuditField.CLIENT_IP_ADDRESS.asKey()), ipAddress); } @Test - public void clientIpAddressEmptyWhenNotPassed() { + public void metricsClientIpAddressAvailableWhenPassed() { + final String ipAddress = "10.56.20.22"; + SpyLogger spy = createSpy(); + new SLF4JLoggerWrapper(spy).metrics(MetricsData.builder().clientIpAddress(ipAddress).build()); + assertEquals(spy.mdc().get(MetricsField.CLIENT_IP_ADDRESS.asKey()), ipAddress); + } + + @Test + public void auditClientIpAddressEmptyWhenNotPassed() { SpyLogger spy = createSpy(); new SLF4JLoggerWrapper(spy).audit(AuditData.builder().build()); - assertNull(spy.mdc().get(CLIENT_IP_ADDRESS.asKey())); + assertNull(spy.mdc().get(AuditField.CLIENT_IP_ADDRESS.asKey())); } @Test - public void elapsedTimeEqualsDifferenceBetweenStartAndEnd() { + public void metricsClientIpAddressEmptyWhenNotPassed() { SpyLogger spy = createSpy(); - final long diff = 1024; - long start = System.currentTimeMillis(); - long end = start + diff; - new SLF4JLoggerWrapper(spy).audit(AuditData.builder().startTime(start).endTime(end).build()); - assertEquals(spy.mdc().get(ELAPSED_TIME.asKey()), Long.toString(diff)); + new SLF4JLoggerWrapper(spy).metrics(MetricsData.builder().build()); + assertNull(spy.mdc().get(MetricsField.CLIENT_IP_ADDRESS.asKey())); } - interface SpyLogger extends Logger { + @Test + public void metricsTargetEntityAvailableWhenPassed() { + final String targetEntity = "MetricsTargetEntity"; + SpyLogger spy = createSpy(); + new SLF4JLoggerWrapper(spy).metrics(MetricsData.builder().targetEntity(targetEntity).build()); + assertEquals(spy.mdc().get(MetricsField.TARGET_ENTITY.asKey()), targetEntity); + } + @Test + public void metricsTargetEntityEmptyWhenNotPassed() { + SpyLogger spy = createSpy(); + new SLF4JLoggerWrapper(spy).metrics(MetricsData.builder().build()); + assertNull(spy.mdc().get(MetricsField.TARGET_ENTITY.asKey())); + } + + @Test + public void metricsTargetVirtualEntityAvailableWhenPassed() { + final String targetEntity = "MetricsTargetVirtualEntity"; + SpyLogger spy = createSpy(); + new SLF4JLoggerWrapper(spy).metrics(MetricsData.builder().targetVirtualEntity(targetEntity).build()); + assertEquals(spy.mdc().get(MetricsField.TARGET_VIRTUAL_ENTITY.asKey()), targetEntity); + } + + @Test + public void metricsTargetVirtualEntityEmptyWhenNotPassed() { + SpyLogger spy = createSpy(); + new SLF4JLoggerWrapper(spy).metrics(MetricsData.builder().build()); + assertNull(spy.mdc().get(MetricsField.TARGET_VIRTUAL_ENTITY.asKey())); + } + + interface SpyLogger extends Logger { Map<String, String> mdc(); } @@ -168,16 +271,16 @@ public class SLF4JLoggerWrapperTest { private static class SpyingInvocationHandler implements InvocationHandler { - private Map<String, String> mdc; + private Map<String, String> lastMdc; @Override public Object invoke(Object proxy, Method method, Object[] args) { if (isReturnMdcMethod(method)) { - return mdc; + return lastMdc; } - if (!isAuditMethod(method, args)) { + if (!isAuditMethod(method, args) && !isMetricsMethod(method, args)) { throw new UnsupportedOperationException("Method " + method.getName() + " with arguments " + Arrays.toString(args) + " wasn't supposed to be called"); } @@ -186,12 +289,20 @@ public class SLF4JLoggerWrapperTest { return null; } + private boolean isMetricsMethod(Method method, Object[] args) { + return isSpecialLogMethod(method, args, Markers.METRICS); + } + private boolean isAuditMethod(Method method, Object[] args) { - return (method.getName().equals("info") && args.length > 0 && args[0].equals(Markers.AUDIT)); + return isSpecialLogMethod(method, args, Markers.AUDIT); + } + + private boolean isSpecialLogMethod(Method method, Object[] args, Marker marker) { + return method.getName().equals("info") && args.length > 0 && args[0].equals(marker); } private void storeEffectiveMdc() { - mdc = MDC.getCopyOfContextMap(); + lastMdc = MDC.getCopyOfContextMap(); } private boolean isReturnMdcMethod(Method method) { |