aboutsummaryrefslogtreecommitdiffstats
path: root/ms/blueprintsprocessor/modules/commons/rest-lib
diff options
context:
space:
mode:
authorDan Timoney <dtimoney@att.com>2019-10-31 12:57:09 +0000
committerGerrit Code Review <gerrit@onap.org>2019-10-31 12:57:09 +0000
commit987afaa51413b2b943deb2afdcdc92b89f16fc4c (patch)
tree04e0d3080d766a456b75b74bc999ab9f0b76a3b4 /ms/blueprintsprocessor/modules/commons/rest-lib
parente2619d958f8237f00467da8cacb0fb9fd210a323 (diff)
parent6fd8d3dbd0c6cdd27f9ef975e4a6a45403dfb298 (diff)
Merge "Add GRPC log tracing service."
Diffstat (limited to 'ms/blueprintsprocessor/modules/commons/rest-lib')
-rw-r--r--ms/blueprintsprocessor/modules/commons/rest-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/rest/service/RestLoggerService.kt124
1 files changed, 124 insertions, 0 deletions
diff --git a/ms/blueprintsprocessor/modules/commons/rest-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/rest/service/RestLoggerService.kt b/ms/blueprintsprocessor/modules/commons/rest-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/rest/service/RestLoggerService.kt
new file mode 100644
index 000000000..2ef5a31bc
--- /dev/null
+++ b/ms/blueprintsprocessor/modules/commons/rest-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/rest/service/RestLoggerService.kt
@@ -0,0 +1,124 @@
+/*
+ * Copyright © 2018-2019 AT&T Intellectual Property.
+ *
+ * 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.onap.ccsdk.cds.blueprintsprocessor.rest.service
+
+import kotlinx.coroutines.*
+import kotlinx.coroutines.reactor.ReactorContext
+import kotlinx.coroutines.reactor.asCoroutineContext
+import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintConstants.ONAP_INVOCATION_ID
+import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintConstants.ONAP_PARTNER_NAME
+import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintConstants.ONAP_REQUEST_ID
+import org.onap.ccsdk.cds.controllerblueprints.core.MDCContext
+import org.onap.ccsdk.cds.controllerblueprints.core.defaultToEmpty
+import org.onap.ccsdk.cds.controllerblueprints.core.defaultToUUID
+import org.onap.ccsdk.cds.controllerblueprints.core.logger
+import org.slf4j.MDC
+import org.springframework.http.server.reactive.ServerHttpRequest
+import org.springframework.http.server.reactive.ServerHttpResponse
+import reactor.core.Disposable
+import reactor.core.publisher.Mono
+import reactor.core.publisher.MonoSink
+import java.time.ZoneOffset
+import java.time.ZonedDateTime
+import java.time.format.DateTimeFormatter
+import kotlin.coroutines.CoroutineContext
+import kotlin.coroutines.EmptyCoroutineContext
+
+class RestLoggerService {
+ private val log = logger(RestLoggerService::class)
+
+
+ fun entering(request: ServerHttpRequest) {
+ val headers = request.headers
+ val requestID = headers.getFirst(ONAP_REQUEST_ID).defaultToUUID()
+ val invocationID = headers.getFirst(ONAP_INVOCATION_ID).defaultToUUID()
+ val partnerName = headers.getFirst(ONAP_PARTNER_NAME).defaultToEmpty()
+ MDC.put("InvokeTimestamp", ZonedDateTime.now(ZoneOffset.UTC).format(DateTimeFormatter.ISO_INSTANT))
+ MDC.put("RequestID", requestID)
+ MDC.put("InvocationID", invocationID)
+ MDC.put("PartnerName", partnerName)
+ MDC.put("ClientIPAddress", request.remoteAddress?.address?.hostAddress.defaultToEmpty())
+ MDC.put("ServerFQDN", request.remoteAddress?.hostString.defaultToEmpty())
+ if (MDC.get("ServiceName") == null || MDC.get("ServiceName").equals("", ignoreCase = true)) {
+ MDC.put("ServiceName", request.uri.path)
+ }
+ }
+
+ fun exiting(request: ServerHttpRequest, response: ServerHttpResponse) {
+ try {
+ val reqHeaders = request.headers
+ val resHeaders = response.headers
+ resHeaders[ONAP_REQUEST_ID] = MDC.get("RequestID")
+ resHeaders[ONAP_INVOCATION_ID] = MDC.get("InvocationID")
+ val partnerName = System.getProperty("APPNAME") ?: "BlueprintsProcessor"
+ resHeaders[ONAP_PARTNER_NAME] = partnerName
+ } catch (e: Exception) {
+ log.warn("couldn't set response headers", e)
+ } finally {
+ MDC.clear()
+ }
+ }
+}
+
+
+/** Used in Rest controller API methods to populate MDC context to nested coroutines from reactor web filter context. */
+@UseExperimental(InternalCoroutinesApi::class)
+fun <T> monoMdc(context: CoroutineContext = EmptyCoroutineContext,
+ block: suspend CoroutineScope.() -> T?): Mono<T> = Mono.create { sink ->
+
+ val reactorContext = (context[ReactorContext]?.context?.putAll(sink.currentContext())
+ ?: sink.currentContext()).asCoroutineContext()
+ /** Populate MDC context only if present in Reactor Context */
+ val newContext = if (!reactorContext.context.isEmpty
+ && reactorContext.context.hasKey(MDCContext)) {
+ val mdcContext = reactorContext.context.get<MDCContext>(MDCContext)
+ GlobalScope.newCoroutineContext(context + reactorContext + mdcContext)
+ } else GlobalScope.newCoroutineContext(context + reactorContext)
+
+ val coroutine = MonoMDCCoroutine(newContext, sink)
+ sink.onDispose(coroutine)
+ coroutine.start(CoroutineStart.DEFAULT, coroutine, block)
+}
+
+@InternalCoroutinesApi
+class MonoMDCCoroutine<in T>(
+ parentContext: CoroutineContext,
+ private val sink: MonoSink<T>
+) : AbstractCoroutine<T>(parentContext, true), Disposable {
+ private var disposed = false
+
+ override fun onCompleted(value: T) {
+ if (!disposed) {
+ if (value == null) sink.success() else sink.success(value)
+ }
+ }
+
+ override fun onCancelled(cause: Throwable, handled: Boolean) {
+ if (!disposed) {
+ sink.error(cause)
+ } else if (!handled) {
+ handleCoroutineException(context, cause)
+ }
+ }
+
+ override fun dispose() {
+ disposed = true
+ cancel()
+ }
+
+ override fun isDisposed(): Boolean = disposed
+}