From 7a724b15b5a1266b8517d56008becd336db6a1c5 Mon Sep 17 00:00:00 2001 From: Luke Parker Date: Tue, 22 May 2018 17:35:18 +1000 Subject: Rename slf4j ref impl, add constants Change-Id: Ib3f24c3aa4974ac8c87fa969613192e884674f00 Issue-ID: LOG-115 Signed-off-by: Luke Parker --- .../org/onap/logging/ref/slf4j/ONAPLogAdapter.java | 611 +++++++++++++++++++++ .../onap/logging/ref/slf4j/ONAPLogConstants.java | 253 +++++++++ .../org/onap/logging/ref/slf4j/package-info.java | 32 ++ 3 files changed, 896 insertions(+) create mode 100644 reference/logging-slf4j/src/main/java/org/onap/logging/ref/slf4j/ONAPLogAdapter.java create mode 100644 reference/logging-slf4j/src/main/java/org/onap/logging/ref/slf4j/ONAPLogConstants.java create mode 100644 reference/logging-slf4j/src/main/java/org/onap/logging/ref/slf4j/package-info.java (limited to 'reference/logging-slf4j/src/main/java/org') diff --git a/reference/logging-slf4j/src/main/java/org/onap/logging/ref/slf4j/ONAPLogAdapter.java b/reference/logging-slf4j/src/main/java/org/onap/logging/ref/slf4j/ONAPLogAdapter.java new file mode 100644 index 0000000..50693cb --- /dev/null +++ b/reference/logging-slf4j/src/main/java/org/onap/logging/ref/slf4j/ONAPLogAdapter.java @@ -0,0 +1,611 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.logging + * ================================================================================ + * Copyright © 2018 Amdocs + * All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.onap.logging.ref.slf4j; + +import java.time.LocalDateTime; +import java.util.UUID; + +import javax.servlet.http.HttpServletRequest; + +import org.slf4j.Logger; +import org.slf4j.MDC; +import org.slf4j.Marker; +import org.slf4j.event.Level; + +/** + * Extensible adapter for cheaply meeting ONAP logging obligations using + * an SLF4J facade. + * + *

This can be used with any SLF4J-compatible logging provider, with + * appropriate provider configuration.

+ * + *

The basics are that: + *

+ *

+ * + *

Minimal usage is: + *

    + *
  1. #entering(RequestAdapter)
  2. + *
  3. #invoke, #invoke, ...
  4. + *
  5. #getResponse + setters (or #setResponse)
  6. + *
  7. #exiting
  8. + *
+ *

+ * + *

... if you're happy for service information to be automatically derived as follows: + *

+ *

+ * + *

... and if those defaults don't suit, then you can override using properties on + * {@link #getServiceDescriptor()}, or by injecting your own adapter using + * {@link #setServiceDescriptor(ServiceDescriptor)}, or by overriding + * a protected methods like{@link #setEnteringMDCs}.

+ * + *

For everything else: + *

+ *

+ */ +public class ONAPLogAdapter { + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // + // Constants. + // + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + /** String constant for messages ENTERING, EXITING, etc. */ + private static final String EMPTY_MESSAGE = ""; + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // + // Fields. + // + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + /** Automatic UUID, overrideable per adapter or per invocation. */ + private static UUID sInstanceUUID = UUID.randomUUID(); + + /** Logger delegate. */ + private Logger mLogger; + + /** Overrideable descriptor for the service doing the logging. */ + private ServiceDescriptor mServiceDescriptor = new ServiceDescriptor(); + + /** Overrideable descriptor for the response returned by the service doing the logging. */ + private ResponseDescriptor mResponseDescriptor = new ResponseDescriptor(); + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // + // Constructors. + // + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Construct adapter. + * + * @param logger non-null logger. + */ + public ONAPLogAdapter(final Logger logger) { + this.mLogger = checkNotNull(logger); + } + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // + // Public methods. + // + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Get logger. + * + * @return unwrapped logger. + */ + public Logger unwrap() { + return this.mLogger; + } + + /** + * Report ENTERING marker. + * + * @param request non-null incoming request (wrapper). + * @return this. + */ + public ONAPLogAdapter entering(final RequestAdapter request) { + + checkNotNull(request); + + // Default the service name. + + this.setEnteringMDCs(request); + this.mLogger.info(ONAPLogConstants.Markers.ENTRY, EMPTY_MESSAGE); + + return this; + } + + /** + * Report ENTERING marker. + * + * @param request non-null incoming request. + * @return this. + */ + public ONAPLogAdapter entering(final HttpServletRequest request) { + return this.entering(new HttpServletRequestAdapter(checkNotNull(request))); + } + + /** + * Report EXITING marker. + * + * @return this. + */ + public ONAPLogAdapter exiting() { + try { + this.mResponseDescriptor.setMDCs(); + this.mLogger.info(ONAPLogConstants.Markers.EXIT, EMPTY_MESSAGE); + } + finally { + MDC.clear(); + } + return this; + } + + /** + * Report pending invocation with INVOKE marker. + * + *

If you call this variant, then YOU are assuming responsibility for + * setting the requisite ONAP headers.

+ * + * @param sync whether synchronous. + * @return invocation ID to be passed with invocation. + */ + public UUID invoke(final ONAPLogConstants.InvocationMode sync) { + + final UUID invocationID = UUID.randomUUID(); + + // Derive SYNC/ASYNC marker. + + final Marker marker = (sync == null) ? ONAPLogConstants.Markers.INVOKE : sync.getMarker(); + + // Log INVOKE*, with the invocationID as the message body. + // (We didn't really want this kind of behavior in the standard, + // but is it worse than new, single-message MDC?) + + this.mLogger.info(marker, "{}", invocationID); + return invocationID; + } + + /** + * Report pending invocation with INVOKE marker, + * setting standard ONAP logging headers automatically. + * + * @param builder request builder, for setting headers. + * @param sync whether synchronous, nullable. + * @return invocation ID to be passed with invocation. + */ + public UUID invoke(final RequestBuilder builder, + final ONAPLogConstants.InvocationMode sync) { + + // Sync can be defaulted. Builder cannot. + + checkNotNull(builder); + + // Log INVOKE, and retain invocation ID for header + return. + + final UUID invocationID = this.invoke(sync); + + // Set standard HTTP headers on (southbound request) builder. + + builder.setHeader(ONAPLogConstants.Headers.REQUEST_ID, + defaultToEmpty(MDC.get(ONAPLogConstants.MDCs.REQUEST_ID))); + builder.setHeader(ONAPLogConstants.Headers.INVOCATION_ID, + defaultToEmpty(invocationID)); + builder.setHeader(ONAPLogConstants.Headers.PARTNER_NAME, + defaultToEmpty(MDC.get(ONAPLogConstants.MDCs.PARTNER_NAME))); + + return invocationID; + } + + /** + * Report vanilla INVOKE marker. + * + * @param builder builder for downstream requests, if you want the + * standard ONAP headers to be added automatically. + * @return invocation ID to be passed with invocation. + */ + public UUID invoke(final RequestBuilder builder) { + return this.invoke(builder, (ONAPLogConstants.InvocationMode)null); + } + + /** + * Get descriptor, for overriding service details. + * @return non-null descriptor. + */ + public ServiceDescriptor getServiceDescriptor() { + return checkNotNull(this.mServiceDescriptor); + } + + /** + * Override {@link ServiceDescriptor}. + * @param d non-null override. + * @return this. + */ + public ONAPLogAdapter setServiceDescriptor(final ServiceDescriptor d) { + this.mServiceDescriptor = checkNotNull(d); + return this; + } + + /** + * Get descriptor, for setting response details. + * @return non-null descriptor. + */ + public ResponseDescriptor getResponseDescriptor() { + return checkNotNull(this.mResponseDescriptor); + } + + /** + * Override {@link ResponseDescriptor}. + * @param d non-null override. + * @return this. + */ + public ONAPLogAdapter setResponseDescriptor(final ResponseDescriptor d) { + this.mResponseDescriptor = checkNotNull(d); + return this; + } + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // + // Protected methods. + // + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Set MDCs that persist for the duration of an invocation. + * + *

It would be better to roll this into {@link #entering}, like + * with {@link #exiting}. Then it would be easier to do, but it + * would mean more work.

+ * + * @param request incoming HTTP request. + * @return this. + */ + protected ONAPLogAdapter setEnteringMDCs(final RequestAdapter request) { + + // Extract MDC values from standard HTTP headers. + + final String requestID = defaultToUUID(request.getHeader(ONAPLogConstants.Headers.REQUEST_ID)); + final String invocationID = defaultToUUID(request.getHeader(ONAPLogConstants.Headers.INVOCATION_ID)); + final String partnerName = defaultToEmpty(request.getHeader(ONAPLogConstants.Headers.PARTNER_NAME)); + + // Set standard MDCs. Override this entire method if you want to set + // others, OR set them BEFORE or AFTER the invocation of #entering, + // depending on where you need them to appear, OR extend the + // ServiceDescriptor to add them. + + MDC.put(ONAPLogConstants.MDCs.INVOKE_TIMESTAMP, LocalDateTime.now().toString()); + MDC.put(ONAPLogConstants.MDCs.REQUEST_ID, requestID); + MDC.put(ONAPLogConstants.MDCs.INVOCATION_ID, invocationID); + MDC.put(ONAPLogConstants.MDCs.PARTNER_NAME, partnerName); + MDC.put(ONAPLogConstants.MDCs.CLIENT_IP_ADDRESS, defaultToEmpty(request.getClientAddress())); + MDC.put(ONAPLogConstants.MDCs.SERVER_FQDN, defaultToEmpty(request.getServerAddress())); + + // Delegate to the service adapter, for service-related DMCs. + + this.mServiceDescriptor.setMDCs(); + + // Default the service name to the requestURI, in the event that + // no value has been provided. + + if (MDC.get(ONAPLogConstants.MDCs.SERVICE_NAME) == null) { + MDC.put(ONAPLogConstants.MDCs.SERVICE_NAME, request.getRequestURI()); + } + + return this; + } + + /** + * Dependency-free nullcheck. + * + * @param in to be checked. + * @param argument (and return) type. + * @return input arg. + */ + protected static T checkNotNull(final T in) { + if (in == null) { + throw new NullPointerException(); + } + return in; + } + + /** + * Dependency-free string default. + * + * @param in to be filtered. + * @return input string or null. + */ + protected static String defaultToEmpty(final Object in) { + if (in == null) { + return ""; + } + return in.toString(); + } + + /** + * Dependency-free string default. + * + * @param in to be filtered. + * @return input string or null. + */ + protected static String defaultToUUID(final String in) { + if (in == null) { + return UUID.randomUUID().toString(); + } + return in; + } + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // + // Inner classes. + // + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Extensible descriptor for reporting service details. + * + *

In most cases extension isn't required.

+ */ + public static class ServiceDescriptor { + + /** ServiceName. */ + protected String mName; + + /** InstanceUUID. */ + protected String mUUID = sInstanceUUID.toString(); + + /** + * Set name. + * @param name ServiceName. + * @return this. + */ + public ServiceDescriptor setServiceName(final String name) { + this.mName = name; + return this; + } + + /** + * Set name. + * @param uuid InstanceUUID. + * @return this. + */ + public ServiceDescriptor setServiceUUID(final String uuid) { + this.mUUID = uuid; + return this; + } + + /** + * Set MDCs. Once set they remain set until everything is cleared. + */ + protected void setMDCs() { + MDC.put(ONAPLogConstants.MDCs.SERVICE_NAME, defaultToEmpty(this.mName)); + MDC.put(ONAPLogConstants.MDCs.INSTANCE_UUID, defaultToEmpty(this.mUUID)); + } + } + + /** + * Response is different in that response MDCs are normally only + * reported once, for a single log message. (But there's no method + * for clearing them, because this is only expected to be called + * during #exiting.) + */ + public static class ResponseDescriptor { + + /** Response errorcode. */ + protected String mCode; + + /** Response description. */ + protected String mDescription; + + /** Response severity. */ + protected Level mSeverity; + + /** Response status, of {COMPLETED, ERROR}. */ + protected ONAPLogConstants.ResponseStatus mStatus; + + /** + * Setter. + * + * @param code response (error) code. + * @return this. + */ + public ResponseDescriptor setResponseCode(final String code) { + this.mCode = code; + return this; + } + + /** + * Setter. + * + * @param description response description. + * @return this. + */ + public ResponseDescriptor setResponseDescription(final String description) { + this.mDescription = description; + return this; + } + + /** + * Setter. + * + * @param severity response outcome severity. + * @return this. + */ + public ResponseDescriptor setResponseSeverity(final Level severity) { + this.mSeverity = severity; + return this; + } + + /** + * Setter. + * + * @param status response overall status. + * @return this. + */ + public ResponseDescriptor setResponseStatus(final ONAPLogConstants.ResponseStatus status) { + this.mStatus = status; + return this; + } + + /** + * Overrideable method to set MDCs based on property values. + */ + protected void setMDCs() { + MDC.put(ONAPLogConstants.MDCs.RESPONSE_CODE, defaultToEmpty(this.mCode)); + MDC.put(ONAPLogConstants.MDCs.RESPONSE_DESCRIPTION, defaultToEmpty(this.mDescription)); + MDC.put(ONAPLogConstants.MDCs.RESPONSE_SEVERITY, defaultToEmpty(this.mSeverity)); + MDC.put(ONAPLogConstants.MDCs.RESPONSE_STATUS_CODE, defaultToEmpty(this.mStatus)); + } + } + + /** + * Adapter for reading information from an incoming HTTP request. + * + *

Incoming is generally easy, because in most cases you'll be able to + * get your hands on the HttpServletRequest.

+ * + *

Perhaps should be generalized to refer to constants instead of + * requiring the implementation of specific methods.

+ * + * @param type, for chaining. + */ + public interface RequestAdapter { + + /** + * Get header by name. + * @param name header name. + * @return header value, or null. + */ + String getHeader(String name); + + /** + * Get client address. + * @return address, if available. + */ + String getClientAddress(); + + /** + * Get server address. + * @return address, if available. + */ + String getServerAddress(); + + /** + * Get default service name, from service URI. + * @return service name default. + */ + String getRequestURI(); + } + + /** + * Default {@link RequestBuilder} impl for {@link HttpServletRequest}, which + * will should available for most incoming REST requests. + */ + public static class HttpServletRequestAdapter implements RequestAdapter { + + /** Wrapped HTTP request. */ + private final HttpServletRequest mRequest; + + /** + * Construct adapter for HTTP request. + * @param request to be wrapped; + */ + public HttpServletRequestAdapter(final HttpServletRequest request) { + this.mRequest = checkNotNull(request); + } + + /** + * {@inheritDoc} + */ + @Override + public String getHeader(final String name) { + return this.mRequest.getHeader(name); + } + + /** + * {@inheritDoc} + */ + @Override + public String getClientAddress() { + return this.mRequest.getRemoteAddr(); + } + + /** + * {@inheritDoc} + */ + @Override + public String getServerAddress() { + return this.mRequest.getServerName(); + } + + /** + * {@inheritDoc} + */ + @Override + public String getRequestURI() { + return this.mRequest.getRequestURI(); + } + } + + /** + * Header builder, which (unlike {@link RequestAdapter} will tend to + * vary a lot from caller to caller, since they each get to choose their + * own REST (or HTTP, or whatever) client APIs. + * + *

No default implementation, because there's no HTTP client that's + * sufficiently ubiquitous to warrant incurring a mandatory dependency.

+ * + * @param type, for chaining. + */ + public interface RequestBuilder { + + /** + * Set HTTP header. + * @param name header name. + * @param value header value. + * @return this. + */ + T setHeader(String name, String value); + } +} diff --git a/reference/logging-slf4j/src/main/java/org/onap/logging/ref/slf4j/ONAPLogConstants.java b/reference/logging-slf4j/src/main/java/org/onap/logging/ref/slf4j/ONAPLogConstants.java new file mode 100644 index 0000000..744f99f --- /dev/null +++ b/reference/logging-slf4j/src/main/java/org/onap/logging/ref/slf4j/ONAPLogConstants.java @@ -0,0 +1,253 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.logging + * ================================================================================ + * Copyright © 2018 Amdocs + * All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.onap.logging.ref.slf4j; + +import org.slf4j.Marker; +import org.slf4j.MarkerFactory; + +/** + * Constants for standard ONAP headers, MDCs, etc. + * + *

See package-info.java.

+ */ +public final class ONAPLogConstants { + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // + // Constructors. + // + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Hide and forbid construction. + */ + private ONAPLogConstants() { + throw new UnsupportedOperationException(); + } + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // + // Inner classes. + // + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Marker constants. + */ + public static final class Markers { + + /** Marker reporting invocation. */ + public static final Marker INVOKE = MarkerFactory.getMarker("INVOKE"); + + /** Marker reporting synchronous invocation. */ + public static final Marker INVOKE_SYNCHRONOUS = build("INVOKE", "SYNCHRONOUS"); + + /** Marker reporting asynchronous invocation. */ + public static final Marker INVOKE_ASYNCHRONOUS = build("INVOKE", "ASYNCHRONOUS"); + + /** Marker reporting entry into a component. */ + public static final Marker ENTRY = MarkerFactory.getMarker("ENTRY"); + + /** Marker reporting exit from a component. */ + public static final Marker EXIT = MarkerFactory.getMarker("EXIT"); + + /** + * Build nested, detached marker. + * @param m1 top token. + * @param m2 sub-token. + * @return detached Marker. + */ + private static Marker build(final String m1, final String m2) { + final Marker marker = MarkerFactory.getDetachedMarker(m1); + marker.add(MarkerFactory.getDetachedMarker(m2)); + return marker; + } + + /** + * Hide and forbid construction. + */ + private Markers() { + throw new UnsupportedOperationException(); + } + } + + /** + * MDC name constants. + */ + public static final class MDCs { + + // Tracing. //////////////////////////////////////////////////////////// + + /** MDC correlating messages for an invocation. */ + public static final String INVOCATION_ID = "InvocationID"; + + /** MDC correlating messages for a logical transaction. */ + public static final String REQUEST_ID = "RequestID"; + + /** MDC recording calling service. */ + public static final String PARTNER_NAME = "PartnerName"; + + /** MDC recording current service. */ + public static final String SERVICE_NAME = "ServiceName"; + + /** MDC recording target service. */ + public static final String TARGET_SERVICE_NAME = "TargetServiceName"; + + /** MDC recording current service instance. */ + public static final String INSTANCE_UUID = "InstanceUUID"; + + // Network. //////////////////////////////////////////////////////////// + + /** MDC recording caller address. */ + public static final String CLIENT_IP_ADDRESS = "ClientIPAddress"; + + /** MDC recording server address. */ + public static final String SERVER_FQDN = "ServerFQDN"; + + /** + * MDC recording timestamp at the start of the current request, + * with the same scope as {@link #REQUEST_ID}. + * + *

Open issues: + *

    + *
      Easily confused with {@link #INVOKE_TIMESTAMP}.
    + *
      No mechanism for propagation between components, e.g. via HTTP headers.
    + *
      Whatever mechanism we define, it's going to be costly.
    + *
+ *

+ * */ + public static final String ENTRY_TIMESTAMP = "EntryTimestamp"; + + /** MDC recording timestamp at the start of the current invocation. */ + public static final String INVOKE_TIMESTAMP = "InvokeTimestamp"; + + // Outcomes. /////////////////////////////////////////////////////////// + + /** MDC reporting outcome code. */ + public static final String RESPONSE_CODE = "ResponseCode"; + + /** MDC reporting outcome description. */ + public static final String RESPONSE_DESCRIPTION = "ResponseDescription"; + + /** MDC reporting outcome error level. */ + public static final String RESPONSE_SEVERITY = "Severity"; + + /** MDC reporting outcome error level. */ + public static final String RESPONSE_STATUS_CODE = "StatusCode"; + + // Unsorted. /////////////////////////////////////////////////////////// + + /** + * Hide and forbid construction. + */ + private MDCs() { + throw new UnsupportedOperationException(); + } + } + + /** + * Header name constants. + */ + public static final class Headers { + + /** HTTP X-ONAP-RequestID header. */ + public static final String REQUEST_ID = "X-ONAP-RequestID"; + + /** HTTP X-ONAP-InvocationID header. */ + public static final String INVOCATION_ID = "X-ONAP-InvocationID"; + + /** HTTP X-ONAP-PartnerName header. */ + public static final String PARTNER_NAME = "X-ONAP-PartnerName"; + + /** + * Hide and forbid construction. + */ + private Headers() { + throw new UnsupportedOperationException(); + } + } + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // + // Enums. + // + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Response success or not, for setting StatusCode. + */ + public enum ResponseStatus { + + /** Success. */ + COMPLETED, + + /** Not. */ + ERROR, + } + + /** + * Synchronous or asynchronous execution, for setting invocation marker. + */ + public enum InvocationMode { + + /** Synchronous, blocking. */ + SYNCHRONOUS("SYNCHRONOUS", Markers.INVOKE_SYNCHRONOUS), + + /** Asynchronous, non-blocking. */ + ASYNCHRONOUS("ASYNCHRONOUS", Markers.INVOKE_ASYNCHRONOUS); + + /** Enum value. */ + private String mString; + + /** Corresponding marker. */ + private Marker mMarker; + + /** + * Construct enum. + * + * @param s enum value. + * @param m corresponding Marker. + */ + InvocationMode(final String s, final Marker m) { + this.mString = s; + this.mMarker = m; + } + + /** + * Get Marker for enum. + * + * @return Marker. + */ + public Marker getMarker() { + return this.mMarker; + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return this.mString; + } + } + +} diff --git a/reference/logging-slf4j/src/main/java/org/onap/logging/ref/slf4j/package-info.java b/reference/logging-slf4j/src/main/java/org/onap/logging/ref/slf4j/package-info.java new file mode 100644 index 0000000..d9a6247 --- /dev/null +++ b/reference/logging-slf4j/src/main/java/org/onap/logging/ref/slf4j/package-info.java @@ -0,0 +1,32 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.logging + * ================================================================================ + * Copyright © 2018 Amdocs + * All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.onap.logging.ref.slf4j; + +/** + *

Code in here has potential application outside this reference + * example, and accordingly: + *

    + *
  • Packaged in common.
  • + *
  • Has minimal dependencies.
  • + *
+ *

+ */ \ No newline at end of file -- cgit 1.2.3-korg