blob: 967b2f3c947725f53a9282dfe6f430dafbc70e43 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.apache.nlpcraft.common.opencensus
import io.opencensus.common.Scope
import io.opencensus.trace._
import org.apache.nlpcraft.common._
import scala.util.control.NonFatal
/**
* OpenCensus traces instrumentation.
*/
trait NCOpenCensusTrace {
/**
*
* @return
*/
def tracer(): Tracer = Tracing.getTracer
/**
*
* @return
*/
def currentSpan(): Span = tracer().getCurrentSpan
/**
*
* @param span Span to add tags to.
* @param tags Span tags to add to the given span.
*/
def addTags(
span: Span,
tags: (String, Any)*
): Unit = {
val attrs = new java.util.HashMap[String, AttributeValue]()
// Mandatory tags.
attrs.put("thread", AttributeValue.stringAttributeValue(Thread.currentThread().getName))
attrs.put("timestamp", AttributeValue.longAttributeValue(System.currentTimeMillis()))
for ((k, v) ← tags if v != null) v match {
case s: String ⇒ attrs.put(k, AttributeValue.stringAttributeValue(s))
case l: Long ⇒ attrs.put(k, AttributeValue.longAttributeValue(l))
case b: Boolean ⇒ attrs.put(k, AttributeValue.booleanAttributeValue(b))
case d: Double ⇒ attrs.put(k, AttributeValue.doubleAttributeValue(d))
case _ ⇒ attrs.put(k, AttributeValue.stringAttributeValue(if (v == null) "" else v.toString))
}
span.putAttributes(attrs)
}
/**
*
* @param name Span name. Will be prepended by the runtime class simple name.
* @return
*/
private def mkSpanName(name: String): String = U.cleanClassName(getClass) + '.' + name
/**
*
* @param name Span name. Will be prepended by the runtime class simple name.
* @param tags Span tags to add to the new span.
* @return
*/
def startSpan(name: String, tags: (String, Any)*): Span = {
val span = tracer().spanBuilder(mkSpanName(name)).startSpan()
addTags(span, tags: _*)
span
}
/**
*
* @param name Span name. Will be prepended by the runtime class simple name.
* @param parent An explicit parent span. If `null` - the default thread-local parent detection will be used.
* @param tags Span tags to add to the new span.
* @return
*/
def startSpan(name: String, parent: Span, tags: (String, Any)*): Span = {
val span = (
if (parent == null)
tracer().spanBuilder(mkSpanName(name))
else
tracer().spanBuilderWithExplicitParent(mkSpanName(name), parent)
)
.startSpan()
addTags(span, tags: _*)
span
}
/**
* Starts scoped span without a parent span.
*
* @param name Span name. Will be prepended by the runtime class simple name.
* @param tags Span tags to add to the new span.
* @param f
* @tparam V
* @return
*/
def startScopedSpan[V](name: String, tags: (String, Any)*)(f: Span ⇒ V): V =
startScopedSpan[V](name, null, tags:_*)(f)
/**
* Starts scoped span with an explicit parent span.
*
* @param name Span name. Will be prepended by the runtime class simple name.
* @param parent An explicit parent span. If `null` - the default thread-local parent detection will be used.
* @param tags Span tags to add to the new span.
* @param f
* @tparam V
* @return
*/
def startScopedSpan[V](name: String, parent: Span, tags: (String, Any)*)(f: Span ⇒ V): V = {
val t = tracer()
/**
*
*
* @param e
* @param scope
*/
def closeAndAddSuppressed(e: Throwable, scope: Scope): Unit = {
def span(): Span = t.getCurrentSpan
if (e != null)
try {
scope.close()
span().setStatus(Status.OK)
}
catch {
case NonFatal(suppressed)
span().setStatus(Status.INTERNAL.withDescription(suppressed.getMessage))
e.addSuppressed(suppressed)
case fatal: Throwable if NonFatal(e)
span().setStatus(Status.INTERNAL.withDescription(e.getMessage))
fatal.addSuppressed(e)
throw fatal
case fatal: InterruptedException
fatal.addSuppressed(e)
throw fatal
case fatal: Throwable
span().setStatus(Status.INTERNAL.withDescription(fatal.getMessage))
e.addSuppressed(fatal)
}
else
scope.close()
}
val scope = (
if (parent == null)
t.spanBuilder(mkSpanName(name))
else
t.spanBuilderWithExplicitParent(mkSpanName(name), parent)
)
.startScopedSpan()
var ex: Throwable = null
val span = t.getCurrentSpan
addTags(span, tags: _*)
try
f(span)
catch {
case e: Throwable
ex = e
throw e
}
finally
closeAndAddSuppressed(ex, scope)
}
}