diff --git a/spring-boot/README.md b/spring-boot/README.md
index 20ed3cc..791511c 100644
--- a/spring-boot/README.md
+++ b/spring-boot/README.md
@@ -136,6 +136,13 @@ vanillabp:
task-timeout: PT3S # overrides vanillabp.workflow-modules.Demo.workflows.DemoWorkflow.adapters.camunda8.task-timeout
```
+### Logging
+
+These attributes are set in addition to the [default logging context](https://github.com/vanillabp/spring-boot-support#logging)
+(defined in class `io.vanillabp.camunda8.LoggingContext`):
+
+* Tenant-ID - The tenant ID used accessing Camunda 8 cluster.
+
## Multi-instance
Since Camunda 8 is a remote engine the workflow is processed in a different runtime environment. Due to this fact the Blueprint adapter cannot do the entire binding of multi-instance context information under the hood. In the BPMN the multi-instance aspects like the input element, the element's index and the total number of elements have to be defined according to a certain naming convention:
diff --git a/spring-boot/pom.xml b/spring-boot/pom.xml
index a990186..07d9bf9 100644
--- a/spring-boot/pom.xml
+++ b/spring-boot/pom.xml
@@ -35,7 +35,7 @@
io.vanillabp
spring-boot-support
- 1.1.1
+ 1.1.2-SNAPSHOT
io.camunda.spring
diff --git a/spring-boot/src/main/java/io/vanillabp/camunda8/Camunda8AdapterConfiguration.java b/spring-boot/src/main/java/io/vanillabp/camunda8/Camunda8AdapterConfiguration.java
index c947d8d..9a698d1 100644
--- a/spring-boot/src/main/java/io/vanillabp/camunda8/Camunda8AdapterConfiguration.java
+++ b/spring-boot/src/main/java/io/vanillabp/camunda8/Camunda8AdapterConfiguration.java
@@ -155,7 +155,10 @@ public Camunda8TaskHandler camunda8TaskHandler(
final Object bean,
final Method method,
final List parameters,
- final String idPropertyName) {
+ final String idPropertyName,
+ final String tenantId,
+ final String workflowModuleId,
+ final String bpmnProcessId) {
return new Camunda8TaskHandler(
taskType,
@@ -163,7 +166,10 @@ public Camunda8TaskHandler camunda8TaskHandler(
bean,
method,
parameters,
- idPropertyName);
+ idPropertyName,
+ tenantId,
+ workflowModuleId,
+ bpmnProcessId);
}
diff --git a/spring-boot/src/main/java/io/vanillabp/camunda8/LoggingContext.java b/spring-boot/src/main/java/io/vanillabp/camunda8/LoggingContext.java
new file mode 100644
index 0000000..0a292ce
--- /dev/null
+++ b/spring-boot/src/main/java/io/vanillabp/camunda8/LoggingContext.java
@@ -0,0 +1,65 @@
+package io.vanillabp.camunda8;
+
+import org.slf4j.MDC;
+
+public class LoggingContext extends io.vanillabp.springboot.adapter.LoggingContext {
+
+ /**
+ * The current workflow's tenant. Per default the same value as the workflow module's ID
+ * but may be overwritten by using Spring Boot properties.
+ *
+ * see Multi-tenancy
+ */
+ public static final String WORKFLOW_TENANT_ID = "workflowTenantId";
+
+ public static void clearContext() {
+
+ io.vanillabp.springboot.adapter.LoggingContext.clearContext();
+
+ MDC.remove(WORKFLOW_ADAPTER_ID);
+ MDC.remove(WORKFLOW_AGGREGATE_ID);
+ MDC.remove(WORKFLOW_BPM_ID);
+ MDC.remove(WORKFLOW_BPMN_ID);
+ MDC.remove(WORKFLOW_TASK_NODE);
+ MDC.remove(WORKFLOW_TASK_ID);
+ MDC.remove(WORKFLOW_TASK_NODE_ID);
+ MDC.remove(WORKFLOW_MODULE_ID);
+ MDC.remove(WORKFLOW_TENANT_ID);
+
+ }
+
+ public static void setLoggingContext(
+ final String adapterId,
+ final String tenantId,
+ final String workflowModuleId,
+ final String aggregateId,
+ final String bpmnId,
+ final String taskId,
+ final String bpmId,
+ final String taskNode,
+ final String taskNodeId) {
+
+ MDC.put(WORKFLOW_ADAPTER_ID, adapterId);
+ MDC.put(WORKFLOW_AGGREGATE_ID, aggregateId);
+ MDC.put(WORKFLOW_BPM_ID, bpmId);
+ MDC.put(WORKFLOW_BPMN_ID, bpmnId);
+ MDC.put(WORKFLOW_TASK_NODE, taskNode);
+ MDC.put(WORKFLOW_TASK_ID, taskId);
+ MDC.put(WORKFLOW_TASK_NODE_ID, taskNodeId);
+ MDC.put(WORKFLOW_MODULE_ID, workflowModuleId);
+ MDC.put(WORKFLOW_TENANT_ID, tenantId);
+
+ final var context = io.vanillabp.springboot.adapter.LoggingContext.getWriteableContext();
+ context.put(WORKFLOW_TENANT_ID, tenantId);
+ context.put(WORKFLOW_ADAPTER_ID, adapterId);
+ context.put(WORKFLOW_AGGREGATE_ID, aggregateId);
+ context.put(WORKFLOW_BPM_ID, bpmId);
+ context.put(WORKFLOW_BPMN_ID, bpmnId);
+ context.put(WORKFLOW_TASK_NODE, taskNode);
+ context.put(WORKFLOW_TASK_ID, taskId);
+ context.put(WORKFLOW_TASK_NODE_ID, taskNodeId);
+ context.put(WORKFLOW_MODULE_ID, workflowModuleId);
+
+ }
+
+}
diff --git a/spring-boot/src/main/java/io/vanillabp/camunda8/service/Camunda8ProcessService.java b/spring-boot/src/main/java/io/vanillabp/camunda8/service/Camunda8ProcessService.java
index 0c7eda7..c773042 100644
--- a/spring-boot/src/main/java/io/vanillabp/camunda8/service/Camunda8ProcessService.java
+++ b/spring-boot/src/main/java/io/vanillabp/camunda8/service/Camunda8ProcessService.java
@@ -3,6 +3,7 @@
import io.camunda.zeebe.client.ZeebeClient;
import io.vanillabp.camunda8.Camunda8AdapterConfiguration;
import io.vanillabp.camunda8.Camunda8VanillaBpProperties;
+import io.vanillabp.camunda8.LoggingContext;
import io.vanillabp.springboot.adapter.AdapterAwareProcessService;
import io.vanillabp.springboot.adapter.ProcessServiceImplementation;
import java.time.Duration;
@@ -102,6 +103,11 @@ public CrudRepository getWorkflowAggregateRepository() {
}
+ @Override
+ public String getPrimaryBpmnProcessId() {
+ return parent.getPrimaryBpmnProcessId();
+ }
+
@Override
public DE startWorkflow(
final DE workflowAggregate) throws Exception {
@@ -322,34 +328,53 @@ private DE runInTransaction(
final Consumer runnable,
final String methodSignature) {
- // persist to get ID in case of @Id @GeneratedValue
- // or force optimistic locking exceptions before running
- // the workflow if aggregate was already persisted before
- final var attachedAggregate = workflowAggregateRepository
- .save(workflowAggregate);
-
- if (TransactionSynchronizationManager.isActualTransactionActive()) {
- if (taskIdToTestForAlreadyCompletedOrCancelled != null) {
+ try {
+
+ // persist to get ID in case of @Id @GeneratedValue
+ // or force optimistic locking exceptions before running
+ // the workflow if aggregate was already persisted before
+ final var attachedAggregate = workflowAggregateRepository
+ .save(workflowAggregate);
+
+ final var aggregateId = getWorkflowAggregateId.apply(attachedAggregate);
+ final var bpmnProcessId = parent.getPrimaryBpmnProcessId();
+ LoggingContext.setLoggingContext(
+ Camunda8AdapterConfiguration.ADAPTER_ID,
+ camunda8Properties.getTenantId(parent.getWorkflowModuleId()),
+ parent.getWorkflowModuleId(),
+ aggregateId == null ? null : aggregateId.toString(),
+ bpmnProcessId,
+ taskIdToTestForAlreadyCompletedOrCancelled,
+ null,
+ null,
+ null);
+
+ if (TransactionSynchronizationManager.isActualTransactionActive()) {
+ if (taskIdToTestForAlreadyCompletedOrCancelled != null) {
+ publisher.publishEvent(
+ new Camunda8TransactionProcessor.Camunda8TestForTaskAlreadyCompletedOrCancelled(
+ methodSignature,
+ () -> client
+ .newUpdateTimeoutCommand(Long.parseUnsignedLong(taskIdToTestForAlreadyCompletedOrCancelled, 16))
+ .timeout(Duration.ofMinutes(10))
+ .send()
+ .join(5, TimeUnit.MINUTES), // needs to run synchronously
+ () -> "aggregate: " + aggregateId + "; bpmn-process-id: " + bpmnProcessId));
+ }
publisher.publishEvent(
- new Camunda8TransactionProcessor.Camunda8TestForTaskAlreadyCompletedOrCancelled(
+ new Camunda8TransactionProcessor.Camunda8CommandAfterTx(
methodSignature,
- () -> client
- .newUpdateTimeoutCommand(Long.parseUnsignedLong(taskIdToTestForAlreadyCompletedOrCancelled, 16))
- .timeout(Duration.ofMinutes(10))
- .send()
- .join(5, TimeUnit.MINUTES), // needs to run synchronously
- () -> "aggregate: " + getWorkflowAggregateId.apply(attachedAggregate) + "; bpmn-process-id: " + parent.getPrimaryBpmnProcessId()));
+ () -> runnable.accept(attachedAggregate),
+ () -> "aggregate: " + aggregateId + "; bpmn-process-id: " + bpmnProcessId));
+ } else {
+ runnable.accept(attachedAggregate);
}
- publisher.publishEvent(
- new Camunda8TransactionProcessor.Camunda8CommandAfterTx(
- methodSignature,
- () -> runnable.accept(attachedAggregate),
- () -> "aggregate: " + getWorkflowAggregateId.apply(attachedAggregate) + "; bpmn-process-id: " + parent.getPrimaryBpmnProcessId()));
- } else {
- runnable.accept(attachedAggregate);
- }
- return attachedAggregate;
+ return attachedAggregate;
+
+ } finally {
+ LoggingContext.clearContext();
+ }
}
diff --git a/spring-boot/src/main/java/io/vanillabp/camunda8/wiring/Camunda8TaskHandler.java b/spring-boot/src/main/java/io/vanillabp/camunda8/wiring/Camunda8TaskHandler.java
index 57f7b1c..4b13060 100644
--- a/spring-boot/src/main/java/io/vanillabp/camunda8/wiring/Camunda8TaskHandler.java
+++ b/spring-boot/src/main/java/io/vanillabp/camunda8/wiring/Camunda8TaskHandler.java
@@ -4,6 +4,8 @@
import io.camunda.zeebe.client.api.response.ActivatedJob;
import io.camunda.zeebe.client.api.worker.JobClient;
import io.camunda.zeebe.client.api.worker.JobHandler;
+import io.vanillabp.camunda8.Camunda8AdapterConfiguration;
+import io.vanillabp.camunda8.LoggingContext;
import io.vanillabp.camunda8.service.Camunda8TransactionAspect;
import io.vanillabp.camunda8.service.Camunda8TransactionProcessor;
import io.vanillabp.camunda8.wiring.Camunda8Connectable.Type;
@@ -40,6 +42,12 @@ public class Camunda8TaskHandler extends TaskHandlerBase implements JobHandler,
private final String idPropertyName;
+ private final String tenantId;
+
+ private final String workflowModuleId;
+
+ private final String bpmnProcessId;
+
private ZeebeClient zeebeClient;
public Camunda8TaskHandler(
@@ -48,11 +56,17 @@ public Camunda8TaskHandler(
final Object bean,
final Method method,
final List parameters,
- final String idPropertyName) {
+ final String idPropertyName,
+ final String tenantId,
+ final String workflowModuleId,
+ final String bpmnProcessId) {
super(workflowAggregateRepository, bean, method, parameters);
this.taskType = taskType;
this.idPropertyName = idPropertyName;
+ this.tenantId = tenantId;
+ this.workflowModuleId = workflowModuleId;
+ this.bpmnProcessId = bpmnProcessId;
}
@@ -79,6 +93,18 @@ public void handle(
try {
final var businessKey = getVariable(job, idPropertyName);
+ final var taskId = Long.toHexString(job.getKey());
+
+ LoggingContext.setLoggingContext(
+ Camunda8AdapterConfiguration.ADAPTER_ID,
+ tenantId,
+ workflowModuleId,
+ businessKey == null ? null : businessKey.toString(),
+ bpmnProcessId,
+ taskId,
+ Long.toString(job.getProcessInstanceKey()),
+ job.getBpmnProcessId() + "#" + job.getElementId(),
+ Long.toString(job.getElementInstanceKey()));
logger.trace("Will handle task '{}' (task-definition '{}‘) of workflow '{}' (instance-id '{}') as job '{}'",
job.getElementId(),
@@ -134,7 +160,7 @@ public void handle(
param,
() -> {
taskIdRetrieved.set(true);
- return Long.toHexString(job.getKey());
+ return taskId;
}),
(args, param) -> processTaskEventParameter(
args,
@@ -167,6 +193,7 @@ public void handle(
} finally {
Camunda8TransactionProcessor.unregisterCallbacks();
Camunda8TransactionAspect.unregisterDeferredInTransaction();
+ LoggingContext.clearContext();
}
}
diff --git a/spring-boot/src/main/java/io/vanillabp/camunda8/wiring/Camunda8TaskWiring.java b/spring-boot/src/main/java/io/vanillabp/camunda8/wiring/Camunda8TaskWiring.java
index c346cee..9a73652 100644
--- a/spring-boot/src/main/java/io/vanillabp/camunda8/wiring/Camunda8TaskWiring.java
+++ b/spring-boot/src/main/java/io/vanillabp/camunda8/wiring/Camunda8TaskWiring.java
@@ -22,10 +22,6 @@
import io.vanillabp.springboot.adapter.TaskWiringBase;
import io.vanillabp.springboot.parameters.MethodParameter;
import jakarta.persistence.Id;
-import org.camunda.bpm.model.xml.instance.ModelElementInstance;
-import org.springframework.beans.factory.ObjectProvider;
-import org.springframework.context.ApplicationContext;
-
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
@@ -37,6 +33,9 @@
import java.util.Set;
import java.util.function.Consumer;
import java.util.stream.Stream;
+import org.camunda.bpm.model.xml.instance.ModelElementInstance;
+import org.springframework.beans.factory.ObjectProvider;
+import org.springframework.context.ApplicationContext;
public class Camunda8TaskWiring extends TaskWiringBase, Camunda8MethodParameterFactory>
implements Consumer {
@@ -241,7 +240,10 @@ protected void connectToBpms(
bean,
method,
parameters,
- idPropertyName);
+ idPropertyName,
+ tenantId,
+ workflowModuleId,
+ processService.getPrimaryBpmnProcessId());
if (this.client != null) {
taskHandler.accept(this.client);
} else {