2 * Copyright © 2018-2019 AT&T Intellectual Property.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package org.onap.ccsdk.cds.blueprintsprocessor.core.service
19 import kotlinx.coroutines.AbstractCoroutine
20 import kotlinx.coroutines.InternalCoroutinesApi
21 import kotlinx.coroutines.handleCoroutineException
22 import org.onap.ccsdk.cds.controllerblueprints.core.logger
24 import org.springframework.http.server.reactive.ServerHttpRequest
25 import org.springframework.http.server.reactive.ServerHttpResponse
26 import reactor.core.Disposable
27 import reactor.core.publisher.MonoSink
28 import java.time.ZoneOffset
29 import java.time.ZonedDateTime
30 import java.time.format.DateTimeFormatter
32 import kotlin.coroutines.CoroutineContext
34 class LoggingService {
35 private val log = logger(LoggingService::class)
38 const val ONAP_REQUEST_ID = "X-ONAP-RequestID"
39 const val ONAP_INVOCATION_ID = "X-ONAP-InvocationID"
40 const val ONAP_PARTNER_NAME = "X-ONAP-PartnerName"
43 fun entering(request: ServerHttpRequest) {
44 val headers = request.headers
45 val requestID = defaultToUUID(headers.getFirst(ONAP_REQUEST_ID))
46 val invocationID = defaultToUUID(headers.getFirst(ONAP_INVOCATION_ID))
47 val partnerName = defaultToEmpty(headers.getFirst(ONAP_PARTNER_NAME))
48 MDC.put("InvokeTimestamp", ZonedDateTime.now(ZoneOffset.UTC).format(DateTimeFormatter.ISO_INSTANT))
49 MDC.put("RequestID", requestID)
50 MDC.put("InvocationID", invocationID)
51 MDC.put("PartnerName", partnerName)
52 MDC.put("ClientIPAddress", defaultToEmpty(request.remoteAddress?.address?.hostAddress))
53 MDC.put("ServerFQDN", defaultToEmpty(request.remoteAddress?.hostString))
54 if (MDC.get("ServiceName") == null || MDC.get("ServiceName").equals("", ignoreCase = true)) {
55 MDC.put("ServiceName", request.uri.path)
59 fun exiting(request: ServerHttpRequest, response: ServerHttpResponse) {
61 val reqHeaders = request.headers
62 val resHeaders = response.headers
63 resHeaders[ONAP_REQUEST_ID] = MDC.get("RequestID")
64 resHeaders[ONAP_INVOCATION_ID] = MDC.get("InvocationID")
65 } catch (e: Exception) {
66 log.warn("couldn't set response headers", e)
72 private fun defaultToEmpty(input: Any?): String {
73 return input?.toString() ?: ""
76 private fun defaultToUUID(input: String?): String {
77 return input ?: UUID.randomUUID().toString()
82 @InternalCoroutinesApi
83 class MonoMDCCoroutine<in T>(
84 parentContext: CoroutineContext,
85 private val sink: MonoSink<T>
86 ) : AbstractCoroutine<T>(parentContext, true), Disposable {
87 private var disposed = false
89 override fun onCompleted(value: T) {
91 if (value == null) sink.success() else sink.success(value)
95 override fun onCancelled(cause: Throwable, handled: Boolean) {
98 } else if (!handled) {
99 handleCoroutineException(context, cause)
103 override fun dispose() {
108 override fun isDisposed(): Boolean = disposed