rabbah closed pull request #2413: Integration with OpenTracing api
URL: https://github.com/apache/incubator-openwhisk/pull/2413
This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:
As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):
diff --git a/.gitignore b/.gitignore
index 3cad311608..759a5b5a4c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -42,6 +42,7 @@ node_modules
# IntelliJ
.idea
*.class
+*.iml
# Ansible
ansible/environments/docker-machine/hosts
@@ -59,4 +60,4 @@ ansible/roles/nginx/files/*cert.pem
!tests/dat/actions/python3_virtualenv.zip
!tests/dat/actions/python_virtualenv_dir.zip
!tests/dat/actions/python_virtualenv_name.zip
-!tests/dat/actions/zippedaction.zip
\ No newline at end of file
+!tests/dat/actions/zippedaction.zip
diff --git a/ansible/environments/local/hosts b/ansible/environments/local/hosts
index 0cbc0d59bc..b2f1f2dcf3 100644
--- a/ansible/environments/local/hosts
+++ b/ansible/environments/local/hosts
@@ -31,3 +31,6 @@ ansible ansible_connection=local
[apigateway]
172.17.0.1 ansible_connection=local
+[jaeger_agent]
+172.17.0.1 ansible_connection=local
+
diff --git a/ansible/roles/controller/tasks/deploy.yml
b/ansible/roles/controller/tasks/deploy.yml
index e9b91cab5e..b103da7eee 100644
--- a/ansible/roles/controller/tasks/deploy.yml
+++ b/ansible/roles/controller/tasks/deploy.yml
@@ -34,6 +34,11 @@
"SERVICE_CHECK_HTTP": "/ping"
"SERVICE_CHECK_TIMEOUT": "2s"
"SERVICE_CHECK_INTERVAL": "15s"
+ "JAEGER_AGENT_HOST": "{{ groups['jaeger_agent'] | first }}"
+ "JAEGER_SERVICE_NAME": "openwhisk"
+ "JAEGER_REPORTER_LOG_SPANS": "true"
+ "JAEGER_SAMPLER_TYPE": "const"
+ "JAEGER_SAMPLER_PARAM": "1"
"JAVA_OPTS": "-Xmx{{ controller.heap }}"
"CONTROLLER_OPTS": "{{ controller.arguments }}"
volumes:
diff --git a/ansible/roles/invoker/tasks/deploy.yml
b/ansible/roles/invoker/tasks/deploy.yml
index 157f0add0d..d178e4b722 100644
--- a/ansible/roles/invoker/tasks/deploy.yml
+++ b/ansible/roles/invoker/tasks/deploy.yml
@@ -71,6 +71,11 @@
-e SERVICE_CHECK_HTTP=/ping
-e SERVICE_CHECK_TIMEOUT=2s
-e SERVICE_CHECK_INTERVAL=15s
+ -e JAEGER_AGENT_HOST={{ groups['jaeger_agent'] | first }}
+ -e JAEGER_SERVICE_NAME=openwhisk
+ -e JAEGER_REPORTER_LOG_SPANS=true
+ -e JAEGER_SAMPLER_TYPE=const
+ -e JAEGER_SAMPLER_PARAM=1
-e JAVA_OPTS=-Xmx{{ invoker.heap }}
-e INVOKER_OPTS='{{ invoker.arguments }}'
-v /sys/fs/cgroup:/sys/fs/cgroup
diff --git a/common/scala/build.gradle b/common/scala/build.gradle
index 3cf8fd55ce..259d89ad1e 100644
--- a/common/scala/build.gradle
+++ b/common/scala/build.gradle
@@ -34,6 +34,14 @@ dependencies {
compile 'org.apache.httpcomponents:httpclient:4.4.1'
compile 'com.github.ben-manes.caffeine:caffeine:2.4.0'
compile 'com.google.code.findbugs:jsr305:3.0.2'
+
+ compile 'io.opentracing:opentracing-api:0.30.0'
+ compile 'io.opentracing:opentracing-noop:0.30.0'
+ compile 'io.opentracing:opentracing-util:0.30.0'
+ compile 'io.opentracing.contrib:opentracing-globaltracer:0.1.2'
+ compile 'io.opentracing.contrib:opentracing-tracerresolver:0.1.0'
+ compile 'com.uber.jaeger:jaeger-core:0.20.0'
+ compile 'com.uber.jaeger:jaeger-tracerresolver:0.20.0'
}
tasks.withType(ScalaCompile) {
diff --git a/common/scala/src/main/scala/whisk/common/Tracing.scala
b/common/scala/src/main/scala/whisk/common/Tracing.scala
new file mode 100644
index 0000000000..b13d1e80c8
--- /dev/null
+++ b/common/scala/src/main/scala/whisk/common/Tracing.scala
@@ -0,0 +1,135 @@
+/*
+ * 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 whisk.common
+
+import scala.collection.JavaConversions._
+
+import io.opentracing.contrib.tracerresolver.TracerResolver
+import io.opentracing.tag.Tags
+import io.opentracing.util.GlobalTracer
+import io.opentracing.Span
+import io.opentracing.Tracer
+import io.opentracing.propagation.Format
+import io.opentracing.propagation.TextMapExtractAdapter
+import io.opentracing.propagation.TextMapInjectAdapter
+
+object Tracing {
+
+ val tracerOption: Option[Tracer] = initTracer()
+ val LOGGING_ENABLED = false
+
+ /**
+ * There is no need to call this method explicitly, using Tracing.startSpan
and Tracing.endSpan
+ * directly will just work.
+ *
+ * @return the tracer implementation that is the entry point to the
open-tracing api
+ */
+ def initTracer(): Option[Tracer] = {
+ // get and register the tracer if the global tracer hasn't been registered
+ val existingTracerOption = Option(!GlobalTracer.isRegistered)
+ .filter(identity)
+ .flatMap(_ => Option(TracerResolver.resolveTracer))
+ existingTracerOption foreach GlobalTracer.register
+
+ // if the previous option is empty, get the global tracer as fallback
method
+ Option(existingTracerOption.getOrElse(GlobalTracer.get))
+ }
+
+ /**
+ * Metadata used for the span creation.
+ *
+ * @param action name of the span (most prominent piece of information)
+ * @param path path of the package
+ * @param user name of the current user who invokes the action
+ * @param revision revision of the action
+ * @param version version of the action
+ */
+ case class SpanMetadata(action: String, path: String, user: String,
revision: String, version: String) {
+ override def toString: String = {
+ s"SPAN[action=$action, path=$path, user=$user, revision=$revision,
version=$version]"
+ }
+ }
+
+ /**
+ * Starts the tracing and returns the span that can be later on closed by
Tracing.endSpan(spanOption).
+ *
+ * Semantics is as follows:
+ * 1. when starting a primitive action/span don't care about
parentOption and carrierOption
+ * 2. when starting a primitive action/span that is child of
another action/span, pass the parentOption
+ * with the hash map of ids and the implementation will make
the child-parent relationship
+ * 3. when starting an action/span that can have children, pass
the empty mutable Map [String, String]
+ * in the carrierOption argument and later on continue with
point (2), but use this map as a parentOption
+ * 4. combination of (2) and (3) i.e. starting a sequence that is
itself part of another sequence. In this case
+ * pass both parentOption (as reference for the parent) and
carrierOption (for the future use by children)
+ *
+ * NOTE: make sure, you end the span with the endSpan method once the
encapsulating action is done
+ *
+ * @param spanMetadata metadata needed for creating the span, they will be
used as tags on that new span
+ * @param parentOption if the parent option is not empty the new span will
be started as a child span of the parent one
+ * @param carrierOption if the carrier option is not empty, but it contains
the empty mutable map, the tracer implementation
+ * fills (Tracer.inject) the set of specific ids using
text map method so that later on it can be extracted.
+ * @return the created span
+ */
+ def startSpan(spanMetadata: SpanMetadata,
+ parentOption: Option[Map[String, String]] = None,
+ carrierOption: Option[scala.collection.mutable.HashMap[String,
String]] = None)(implicit logging: Logging): Option[Span] = {
+
+ if (LOGGING_ENABLED) {
+ logging.info(this, s"newSpan: $spanMetadata")
+ logging.info(this, s"parentSpan: $parentOption")
+ logging.info(this, s"carrierForNewSpan: $carrierOption")
+ }
+
+ tracerOption.map(tracer => {
+ val spanBuilder = tracer.buildSpan(spanMetadata.action)
+
+ // add reference to parrent if there is any and start the span
+ val span = parentOption.map(parent => {
+ val parentSpan = tracer.extract(Format.Builtin.TEXT_MAP, new
TextMapExtractAdapter(parent))
+ spanBuilder.asChildOf(parentSpan)
+ }).getOrElse(spanBuilder).startManual
+
+ // inject the context in case it's the child of high-lvl action
(sequence)
+ carrierOption.map(carrier => {
+ tracer.inject(span.context, Format.Builtin.TEXT_MAP, new
TextMapInjectAdapter(carrier))
+ })
+
+ Tags.COMPONENT.set(span, "openwhisk")
+
+ // general message data
+ span.setTag("user", spanMetadata.user)
+ span.setTag("revision", spanMetadata.revision)
+
+ // action data
+ span.setTag("action", spanMetadata.action)
+ span.setTag("version", spanMetadata.version)
+ span.setTag("path", spanMetadata.path)
+ span
+ });
+ }
+
+ /**
+ * Closes the passed span, this method is basically dual to the startSpan
method
+ *
+ * @param spanOption span that is to be ended/finished
+ */
+ def endSpan(spanOption: Option[Span]): Unit = {
+ spanOption.foreach(_.finish)
+ }
+
+}
diff --git a/common/scala/src/main/scala/whisk/core/connector/Message.scala
b/common/scala/src/main/scala/whisk/core/connector/Message.scala
index 3491c21123..78004a4feb 100644
--- a/common/scala/src/main/scala/whisk/core/connector/Message.scala
+++ b/common/scala/src/main/scala/whisk/core/connector/Message.scala
@@ -56,7 +56,8 @@ case class ActivationMessage(
activationNamespace: EntityPath,
rootControllerIndex: InstanceId,
content: Option[JsObject],
- cause: Option[ActivationId] = None)
+ cause: Option[ActivationId] = None,
+ tracingMetadata: Option[Map[String, String]] = None)
extends Message {
def meta = JsObject("meta" -> {
@@ -82,7 +83,7 @@ object ActivationMessage extends DefaultJsonProtocol {
def parse(msg: String) = Try(serdes.read(msg.parseJson))
private implicit val fqnSerdes = FullyQualifiedEntityName.serdes
- implicit val serdes = jsonFormat9(ActivationMessage.apply)
+ implicit val serdes = jsonFormat10(ActivationMessage.apply)
}
/**
diff --git
a/core/controller/src/main/scala/whisk/core/controller/actions/PostActionActivation.scala
b/core/controller/src/main/scala/whisk/core/controller/actions/PostActionActivation.scala
index abd294ac16..cf99fff77d 100644
---
a/core/controller/src/main/scala/whisk/core/controller/actions/PostActionActivation.scala
+++
b/core/controller/src/main/scala/whisk/core/controller/actions/PostActionActivation.scala
@@ -28,6 +28,7 @@ import whisk.core.controller.WhiskServices
import whisk.core.entity._
import whisk.http.Messages
+
protected[core] trait PostActionActivation extends PrimitiveActions with
SequenceActions {
/** The core collections require backend services to be injected in this
trait. */
services: WhiskServices =>
@@ -47,16 +48,18 @@ protected[core] trait PostActionActivation extends
PrimitiveActions with Sequenc
action: WhiskAction,
payload: Option[JsObject],
waitForResponse: Option[FiniteDuration],
- cause: Option[ActivationId])(
+ cause: Option[ActivationId],
+ tracingMetadata: Option[Map[String, String]] = None)(
implicit transid: TransactionId): Future[Either[ActivationId,
WhiskActivation]] = {
action.toExecutableWhiskAction match {
// this is a topmost sequence
case None =>
val SequenceExec(components) = action.exec
- invokeSequence(user, action, components, payload,
waitForResponse, cause, topmost = true, 0).map(r => r._1)
+ invokeSequence(user, action, components, payload,
waitForResponse, cause, topmost = true, atomicActionsCount = 0,
parentSpanMetadata = None)
+ .map(r => r._1)
// a non-deprecated ExecutableWhiskAction
case Some(executable) if !executable.exec.deprecated =>
- invokeSingleAction(user, executable, payload, waitForResponse,
cause)
+ invokeSingleAction(user, executable, payload, waitForResponse,
cause, tracingMetadata = None)
// a deprecated exec
case _ =>
Future.failed(RejectRequest(BadRequest,
Messages.runtimeDeprecated(action.exec)))
diff --git
a/core/controller/src/main/scala/whisk/core/controller/actions/PrimitiveActions.scala
b/core/controller/src/main/scala/whisk/core/controller/actions/PrimitiveActions.scala
index f07347a6f1..7d9bf56521 100644
---
a/core/controller/src/main/scala/whisk/core/controller/actions/PrimitiveActions.scala
+++
b/core/controller/src/main/scala/whisk/core/controller/actions/PrimitiveActions.scala
@@ -18,6 +18,7 @@
package whisk.core.controller.actions
import scala.collection.mutable.Buffer
+import scala.collection.immutable.Map
import scala.concurrent.ExecutionContext
import scala.concurrent.Future
import scala.concurrent.Promise
@@ -96,7 +97,8 @@ protected[actions] trait PrimitiveActions {
action: ExecutableWhiskAction,
payload: Option[JsObject],
waitForResponse: Option[FiniteDuration],
- cause: Option[ActivationId])(
+ cause: Option[ActivationId],
+ tracingMetadata: Option[Map[String, String]])(
implicit transid: TransactionId): Future[Either[ActivationId,
WhiskActivation]] = {
// merge package parameters with action (action parameters supersede),
then merge in payload
@@ -110,7 +112,8 @@ protected[actions] trait PrimitiveActions {
activationNamespace = user.namespace.toPath,
activeAckTopicIndex,
args,
- cause = cause)
+ cause = cause,
+ tracingMetadata = tracingMetadata)
val startActivation = transid.started(this, waitForResponse.map(_ =>
LoggingMarkers.CONTROLLER_ACTIVATION_BLOCKING).getOrElse(LoggingMarkers.CONTROLLER_ACTIVATION))
val startLoadbalancer = transid.started(this,
LoggingMarkers.CONTROLLER_LOADBALANCER, s"action activation id:
${message.activationId}")
diff --git
a/core/controller/src/main/scala/whisk/core/controller/actions/SequenceActions.scala
b/core/controller/src/main/scala/whisk/core/controller/actions/SequenceActions.scala
index 9efaf172fd..d4c710a68b 100644
---
a/core/controller/src/main/scala/whisk/core/controller/actions/SequenceActions.scala
+++
b/core/controller/src/main/scala/whisk/core/controller/actions/SequenceActions.scala
@@ -21,6 +21,7 @@ import java.time.Clock
import java.time.Instant
import java.util.concurrent.atomic.AtomicReference
+import scala.collection.immutable.Map
import scala.collection._
import scala.concurrent.ExecutionContext
import scala.concurrent.Future
@@ -33,6 +34,7 @@ import akka.actor.ActorSystem
import spray.json._
import whisk.common.Logging
+import whisk.common.Tracing
import whisk.common.TransactionId
import whisk.core.controller.WhiskServices
import whisk.core.entity._
@@ -65,7 +67,8 @@ protected[actions] trait SequenceActions {
action: WhiskAction,
payload: Option[JsObject],
waitForResponse: Option[FiniteDuration],
- cause: Option[ActivationId])(
+ cause: Option[ActivationId],
+ tracingMetadata: Option[Map[String, String]] = None)(
implicit transid: TransactionId): Future[Either[ActivationId,
WhiskActivation]]
/**
@@ -90,7 +93,8 @@ protected[actions] trait SequenceActions {
waitForOutermostResponse: Option[FiniteDuration],
cause: Option[ActivationId],
topmost: Boolean,
- atomicActionsCount: Int)(
+ atomicActionsCount: Int,
+ parentSpanMetadata: Option[Map[String, String]] = None)(
implicit transid: TransactionId): Future[(Either[ActivationId,
WhiskActivation], Int)] = {
require(action.exec.kind == Exec.SEQUENCE, "this method requires an
action sequence")
@@ -106,7 +110,7 @@ protected[actions] trait SequenceActions {
completeSequenceActivation(
seqActivationId,
// the cause for the component activations is the current
sequence
- invokeSequenceComponents(user, action, seqActivationId,
payload, components, cause = Some(seqActivationId), atomicActionsCount),
+ invokeSequenceComponents(user, action, seqActivationId,
payload, components, cause = Some(seqActivationId), atomicActionsCount,
parentSpanMetadata),
user, action, topmost, start, cause)
}
@@ -237,7 +241,8 @@ protected[actions] trait SequenceActions {
inputPayload: Option[JsObject],
components: Vector[FullyQualifiedEntityName],
cause: Option[ActivationId],
- atomicActionCnt: Int)(
+ atomicActionCnt: Int,
+ parentSpanMetadata: Option[Map[String, String]] = None)(
implicit transid: TransactionId): Future[SequenceAccounting] = {
// For each action in the sequence, fetch any of its associated
parameters (including package or binding).
@@ -257,12 +262,15 @@ protected[actions] trait SequenceActions {
SequenceAccounting(atomicActionCnt,
ActivationResponse.payloadPlaceholder(inputPayload))
}
+ // start tracing span for sequence (there might be already a span that
is needed to be set as parrent -> nesting)
+ val (spanOption, newTracingMetadata) = startTracingHelper(cause,
seqAction, user, parentSpanMetadata)
+
// execute the actions in sequential blocking fashion
resolvedFutureActions.foldLeft(initialAccounting) {
(accountingFuture, futureAction) =>
accountingFuture.flatMap { accounting =>
if (accounting.atomicActionCnt < actionSequenceLimit) {
- invokeNextAction(user, futureAction, accounting,
cause).flatMap { accounting =>
+ invokeNextAction(user, futureAction, accounting,
cause, newTracingMetadata.map(_.toMap)).flatMap { accounting =>
if (!accounting.shortcircuit) {
Future.successful(accounting)
} else {
@@ -275,11 +283,17 @@ protected[actions] trait SequenceActions {
Future.failed(FailedSequenceActivation(updatedAccount)) // terminates the fold
}
}
- }.recoverWith {
+ }.andThen{case result => {
+ Tracing.endSpan(spanOption)
+ result
+ }}.recoverWith {
// turn the failed accounting back to success; this is the only
possible failure
// since all throwables are recovered with a failed accounting
instance and this is
// in turned boxed to FailedSequenceActivation
- case FailedSequenceActivation(accounting) =>
Future.successful(accounting)
+ case FailedSequenceActivation(accounting) => {
+ Tracing.endSpan(spanOption)
+ Future.successful(accounting)
+ }
}
}
@@ -294,13 +308,15 @@ protected[actions] trait SequenceActions {
* @param futureAction the future which fetches the action to be invoked
from the db
* @param accounting the state of the sequence activation, contains the
dynamic activation count, logs and payload for the next action
* @param cause the activation id of the first sequence containing this
activations
+ * @param tracingMetadata hash map of ids into which specific tracer puts
its own ids (@see
http://opentracing.io/documentation/pages/supported-tracers.html)
* @return a future which resolves with updated accounting for a sequence,
including the last result, duration, and activation ids
*/
private def invokeNextAction(
user: Identity,
futureAction: Future[WhiskAction],
accounting: SequenceAccounting,
- cause: Option[ActivationId])(
+ cause: Option[ActivationId],
+ tracingMetadata: Option[Map[String, String]] = None)(
implicit transid: TransactionId): Future[SequenceAccounting] = {
futureAction.flatMap { action =>
// the previous response becomes input for the next action in the
sequence;
@@ -315,12 +331,12 @@ protected[actions] trait SequenceActions {
val SequenceExec(components) = action.exec
logging.info(this, s"sequence invoking an enclosed
sequence $action")
// call invokeSequence to invoke the inner sequence; this
is a blocking activation by definition
- invokeSequence(user, action, components, inputPayload,
None, cause, topmost = false, accounting.atomicActionCnt)
+ invokeSequence(user, action, components, inputPayload,
None, cause, topmost = false, accounting.atomicActionCnt, tracingMetadata)
case Some(executable) =>
// this is an invoke for an atomic action
logging.info(this, s"sequence invoking an enclosed atomic
action $action")
val timeout = action.limits.timeout.duration + 1.minute
- invokeAction(user, action, inputPayload, waitForResponse =
Some(timeout), cause) map {
+ invokeAction(user, action, inputPayload, waitForResponse =
Some(timeout), cause, tracingMetadata) map {
case res => (res, accounting.atomicActionCnt + 1)
}
}
@@ -353,6 +369,24 @@ protected[actions] trait SequenceActions {
/** Max atomic action count allowed for sequences */
private lazy val actionSequenceLimit =
whiskConfig.actionSequenceLimit.toInt
+
+ /** Starts the tracing for the sequence action and creates the tracing
metadata hash map into which
+ * the tracer implementation inserts its own ids, these ids are then
propagated via the ActivationMessage into
+ * invoker that can add the reference from the primitive action to the
parent sequence action
+ */
+ private def startTracingHelper(cause: Option[ActivationId],
+ seqAction: WhiskAction,
+ user: Identity,
+ parentSpanMetadata: Option[Map[String,
String]]) = {
+ val newTracingMetadata = cause.map(_ =>
scala.collection.mutable.HashMap.empty[String, String])
+ val spanMetadata = Tracing.SpanMetadata(seqAction.name.asString,
+ seqAction.namespace.asString,
+ user.subject.asString,
+ seqAction.rev.asString,
+ seqAction.version.toString)
+ val spanOption = Tracing.startSpan(spanMetadata, parentSpanMetadata,
newTracingMetadata)
+ (spanOption, newTracingMetadata)
+ }
}
/**
diff --git
a/core/invoker/src/main/scala/whisk/core/container/WhiskContainer.scala
b/core/invoker/src/main/scala/whisk/core/container/WhiskContainer.scala
index 468569384f..84efcb43f3 100644
--- a/core/invoker/src/main/scala/whisk/core/container/WhiskContainer.scala
+++ b/core/invoker/src/main/scala/whisk/core/container/WhiskContainer.scala
@@ -23,10 +23,12 @@ import java.util.concurrent.atomic.AtomicInteger
import scala.concurrent.duration.DurationInt
import scala.concurrent.duration.FiniteDuration
+
import akka.actor.ActorSystem
import spray.json._
import whisk.common.Logging
import whisk.common.LoggingMarkers
+import whisk.common.Tracing
import whisk.common.TransactionId
import whisk.core.connector.ActivationMessage
import whisk.core.entity._
@@ -85,16 +87,26 @@ class WhiskContainer(
/**
* Sends a run command to action container to run once.
- *
- * @param state the value of the status to compare the actual state against
- * @return triple of start time, end time, response for user action.
*/
def run(msg: ActivationMessage, args: JsObject, timeout:
FiniteDuration)(implicit system: ActorSystem, transid: TransactionId):
RunResult = {
val startMarker = transid.started("Invoker",
LoggingMarkers.INVOKER_ACTIVATION_RUN, s"sending arguments to ${msg.action}
$details")
+
+ // start the span
+ val spanMetadata = Tracing.SpanMetadata(msg.action.asString,
+ msg.action.path.asString,
+ msg.user.subject.asString,
+ msg.revision.asString,
+
msg.action.version.getOrElse(SemVer()).toString)
+ val spanOption = Tracing.startSpan(spanMetadata, msg.tracingMetadata)
val result = sendPayload("/run", constructActivationMetadata(msg,
args, timeout), timeout, retry = false)
+
// Use start and end time of the activation
val RunResult(Interval(startActivation, endActivation), _) = result
transid.finished("Invoker", startMarker.copy(startActivation),
s"running result: ${result.toBriefString}", endTime = endActivation)
+
+ // finish the span
+ Tracing.endSpan(spanOption)
+
result
}
diff --git a/gradle/wrapper/gradle-wrapper.jar
b/gradle/wrapper/gradle-wrapper.jar
index 1c7c90c27c..f82b0dc688 100644
Binary files a/gradle/wrapper/gradle-wrapper.jar and
b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties
b/gradle/wrapper/gradle-wrapper.properties
index 117efd1502..3b2c3d6910 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,4 +1,4 @@
-#Tue Apr 25 07:35:34 CEST 2017
+#Wed Jun 21 07:23:46 CEST 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
diff --git
a/tests/src/test/scala/whisk/core/controller/test/WebActionsApiTests.scala
b/tests/src/test/scala/whisk/core/controller/test/WebActionsApiTests.scala
index 9a4dc921cd..e2a0ab78f5 100644
--- a/tests/src/test/scala/whisk/core/controller/test/WebActionsApiTests.scala
+++ b/tests/src/test/scala/whisk/core/controller/test/WebActionsApiTests.scala
@@ -265,7 +265,8 @@ trait WebActionsApiTests extends ControllerTestCommon with
BeforeAndAfterEach wi
action: WhiskAction,
payload: Option[JsObject],
waitForResponse: Option[FiniteDuration],
- cause: Option[ActivationId])(
+ cause: Option[ActivationId],
+ tracingMetadata: Option[Map[String, String]] = None)(
implicit transid: TransactionId): Future[Either[ActivationId,
WhiskActivation]] = {
invocationCount = invocationCount + 1
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
[email protected]
With regards,
Apache Git Services