Skip to content

Added initial commit of camunda instrumentation #12830

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 33 commits into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
a631796
Added initial commit of camunda instrumentation
cb645j Dec 3, 2024
979c377
Add module to parent settings
cb645j Dec 5, 2024
4fbdbf8
Reorganized project structure and fixed gradle settings
cb645j Dec 9, 2024
7b268c0
fix the version reference in the build settings
cb645j Dec 9, 2024
c6aa4c2
Fixed the formatting for spotless
cb645j Dec 11, 2024
80b0e67
Fix formatting for lib folder also per spotless
cb645j Dec 11, 2024
b267316
fix bad import in span name extractor class
cb645j Dec 11, 2024
fb19def
Added dependencies to javaagent module, changed library instead of im…
cb645j Dec 11, 2024
b44bc9d
Fix import statements and remove dead code
cb645j Dec 12, 2024
26df3f1
Fix more errors on compile
cb645j Dec 12, 2024
9fb1aed
remove unused dependencies and supress warning
cb645j Dec 12, 2024
d7f179f
Add private constructor for singletons
cb645j Dec 12, 2024
308f6a8
Removed javadocs with no description and unused fields
cb645j Dec 12, 2024
fd44b57
remove print line and fix scope
cb645j Dec 12, 2024
bdd9ea1
Surpress unused warning in instrumentation
cb645j Dec 13, 2024
628d839
Surpress false warnings so build doesnt fail
cb645j Dec 13, 2024
75f3fdc
Combine supress warnings into one
cb645j Dec 16, 2024
0cd3185
remove empty if blocks from the code
cb645j Dec 16, 2024
3f9833a
Add extra dependency for muzzle check
cb645j Dec 16, 2024
38ff7f0
Consolidated similiar type instrumentations into single module
cb645j Dec 16, 2024
7fcfa7d
fix spotless java format
cb645j Dec 16, 2024
da9e851
Fix typos and compilation errors
cb645j Dec 16, 2024
4355c63
remove the label from method
cb645j Dec 16, 2024
c5718bc
Add a camunda test to test instrumentation all
cb645j Mar 26, 2025
193cd63
Remove unused imports
cb645j Mar 26, 2025
d60eaf3
remove print line from test class
cb645j Mar 26, 2025
cc90160
fix formatting and add required aliases
cb645j Mar 26, 2025
6e797eb
fix build errors and spotless
cb645j Mar 26, 2025
e484aa7
Add history time to live option
cb645j Mar 26, 2025
f938b85
Merge remote-tracking branch 'origin/main' into feature/camunda_instr…
cb645j Mar 26, 2025
2aa9616
add fossa
cb645j Mar 26, 2025
3277d7e
Trigger build
cb645j Mar 26, 2025
a3fd09c
Trigger build PR
cb645j Mar 27, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .fossa.yml
Original file line number Diff line number Diff line change
@@ -370,6 +370,12 @@ targets:
- type: gradle
path: ./
target: ':instrumentation:azure-core:azure-core-1.36:javaagent'
- type: gradle
path: ./
target: ':instrumentation:camunda:camunda-7.0:javaagent'
- type: gradle
path: ./
target: ':instrumentation:camunda:camunda-7.0:library'
- type: gradle
path: ./
target: ':instrumentation:cassandra:cassandra-3.0:javaagent'
26 changes: 26 additions & 0 deletions instrumentation/camunda/camunda-7.0/javaagent/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
plugins {
id("otel.javaagent-instrumentation")
}

muzzle {
pass {
group.set("org.camunda.bpm")
module.set("camunda-engine")

// have not tested with versions prior to 7.18.0
versions.set("[7.18.0,)")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Usually we also add assertInverse.set(true). This verifies that the instrumentation does not apply to versions outside the given range. If the instrumentation applies to earlier versions you have the choice of either expanding the supported version range or add a classLoaderMatcher method that checks for a class that was added in the first version you intend to support (this will make the instrumentation not apply to earlier versions). If the first supported version is 7.18 then the module should be named accordingly.

extraDependency("org.camunda.bpm:camunda-external-task-client:7.18.0")
}
}

dependencies {
implementation(project(":instrumentation:camunda:camunda-7.0:library"))

library("org.camunda.bpm:camunda-engine:7.18.0")
library("org.camunda.bpm:camunda-external-task-client:7.18.0")

annotationProcessor("com.google.auto.value:auto-value:1.6")

testImplementation(project(":instrumentation:camunda:camunda-7.0:testing"))
testImplementation("com.h2database:h2:2.2.224")
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.javaagent.instrumentation.camunda.v7_0.behavior;

import io.opentelemetry.api.GlobalOpenTelemetry;
import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
import io.opentelemetry.instrumentation.api.instrumenter.InstrumenterBuilder;
import io.opentelemetry.instrumentation.camunda.v7_0.behavior.CamundaBehaviorSpanNameExtractor;
import io.opentelemetry.instrumentation.camunda.v7_0.common.CamundaCommonRequest;
import io.opentelemetry.instrumentation.camunda.v7_0.common.CamundaVariableAttributeExtractor;

public class CamundaBehaviorSingletons {

private static final Instrumenter<CamundaCommonRequest, String> instrumenter;

private static final OpenTelemetry opentelemetry;

static {
opentelemetry = GlobalOpenTelemetry.get();

InstrumenterBuilder<CamundaCommonRequest, String> builder =
Instrumenter.<CamundaCommonRequest, String>builder(
opentelemetry,
"io.opentelemetry.camunda-behavior",
new CamundaBehaviorSpanNameExtractor())
.addAttributesExtractor(new CamundaVariableAttributeExtractor());

instrumenter = builder.buildInstrumenter();
}

public static OpenTelemetry getOpentelemetry() {
return opentelemetry;
}

public static Instrumenter<CamundaCommonRequest, String> getInstumenter() {
return instrumenter;
}

private CamundaBehaviorSingletons() {}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.javaagent.instrumentation.camunda.v7_0.behavior;

import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.hasClassesNamed;
import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.hasSuperType;
import static io.opentelemetry.javaagent.instrumentation.camunda.v7_0.behavior.CamundaBehaviorSingletons.getInstumenter;
import static io.opentelemetry.javaagent.instrumentation.camunda.v7_0.behavior.CamundaBehaviorSingletons.getOpentelemetry;
import static net.bytebuddy.matcher.ElementMatchers.named;

import io.opentelemetry.api.trace.SpanContext;
import io.opentelemetry.context.Context;
import io.opentelemetry.context.Scope;
import io.opentelemetry.instrumentation.camunda.v7_0.behavior.CamundaActivityExecutionGetter;
import io.opentelemetry.instrumentation.camunda.v7_0.behavior.CamundaVariableMapSetter;
import io.opentelemetry.instrumentation.camunda.v7_0.common.CamundaCommonRequest;
import io.opentelemetry.javaagent.bootstrap.Java8BytecodeBridge;
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
import java.util.Optional;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;
import net.bytebuddy.matcher.ElementMatchers;
import org.camunda.bpm.engine.impl.pvm.delegate.ActivityExecution;
import org.camunda.bpm.engine.variable.VariableMap;

public class CamundaCallableElementActivityBehaviorInstrumentation implements TypeInstrumentation {

@Override
public ElementMatcher<ClassLoader> classLoaderOptimization() {
return hasClassesNamed(
"org.camunda.bpm.engine.impl.bpmn.behavior.CallableElementActivityBehavior");
}

@Override
public ElementMatcher<TypeDescription> typeMatcher() {
return hasSuperType(
named("org.camunda.bpm.engine.impl.bpmn.behavior.CallableElementActivityBehavior"));
}

@Override
public void transform(TypeTransformer transformer) {
transformer.applyAdviceToMethod(
ElementMatchers.isMethod().and(ElementMatchers.named("startInstance")),
this.getClass().getName() + "$CamundaCallableElementActivityBehaviorAdvice");
}

@SuppressWarnings("unused")
public static class CamundaCallableElementActivityBehaviorAdvice {

@Advice.OnMethodEnter(suppress = Throwable.class)
public static void addTracingEnter(
@Advice.Argument(0) ActivityExecution execution,
@Advice.Argument(1) VariableMap variables,
@Advice.Local("request") CamundaCommonRequest request,
@Advice.Local("otelParentScope") Scope parentScope,
@Advice.Local("otelContext") Context context,
@Advice.Local("otelScope") Scope scope) {

if (execution == null) {
// log warning
return;
}

request = new CamundaCommonRequest();
request.setProcessDefinitionId(Optional.ofNullable(execution.getProcessDefinitionId()));
request.setProcessInstanceId(Optional.ofNullable(execution.getProcessInstanceId()));
request.setActivityId(Optional.ofNullable(execution.getCurrentActivityId()));
request.setActivityName(Optional.ofNullable(execution.getCurrentActivityName()));
request.setBusinessKey(Optional.ofNullable(execution.getProcessBusinessKey()));

if (Java8BytecodeBridge.currentContext() == Java8BytecodeBridge.rootContext()) {
// log
}
Comment on lines +76 to +78
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no-op


Context parentContext =
getOpentelemetry()
.getPropagators()
.getTextMapPropagator()
.extract(
Java8BytecodeBridge.currentContext(),
execution,
new CamundaActivityExecutionGetter());

parentScope = parentContext.makeCurrent();

if (getInstumenter().shouldStart(Java8BytecodeBridge.currentContext(), request)) {
context = getInstumenter().start(Java8BytecodeBridge.currentContext(), request);
scope = context.makeCurrent();

// Inject subflow trace context as pi variables so they are propagated and
// accessible

SpanContext currentSpanContext =
Java8BytecodeBridge.spanFromContext(context).getSpanContext();
if (currentSpanContext.isValid()) {
getOpentelemetry()
.getPropagators()
.getTextMapPropagator()
.inject(context, variables, new CamundaVariableMapSetter());
}
}
}

@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
public static void closeTrace(
@Advice.Argument(0) ActivityExecution execution,
@Advice.Local("request") CamundaCommonRequest request,
@Advice.Local("otelParentScope") Scope parentScope,
@Advice.Local("otelContext") Context context,
@Advice.Local("otelScope") Scope scope,
@Advice.Thrown Throwable throwable) {

if (context != null && scope != null) {
getInstumenter().end(context, request, "NA", throwable);
scope.close();
}

if (parentScope != null) {
parentScope.close();
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.javaagent.instrumentation.camunda.v7_0.behavior;

import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.hasClassesNamed;

import com.google.auto.service.AutoService;
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import net.bytebuddy.matcher.ElementMatcher;

@AutoService(InstrumentationModule.class)
public class CamundaCallableElementActivityBehaviorModule extends InstrumentationModule {

public CamundaCallableElementActivityBehaviorModule() {
super("camunda", "camunda-7.0", "camunda-behavior", "camunda-behavior-7_18");
}

@Override
public boolean defaultEnabled(ConfigProperties config) {
return config.getBoolean("otel.instrumentation.common.default-enabled", true);
}
Comment on lines +26 to +29
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this needed?


@Override
public List<TypeInstrumentation> typeInstrumentations() {
return Collections.singletonList(new CamundaCallableElementActivityBehaviorInstrumentation());
}

@Override
public ElementMatcher.Junction<ClassLoader> classLoaderMatcher() {
return hasClassesNamed(
"org.camunda.bpm.engine.impl.bpmn.behavior.CallableElementActivityBehavior");
}

String[] helperClassnames = {
"io.opentelemetry.javaagent.instrumentation.camunda.v7_0.behavior",
"io.opentelemetry.instrumentation.camunda.v7_0.behavior",
"io.opentelemetry.instrumentation.camunda.v7_0.common"
};

@Override
public boolean isHelperClass(String classname) {
return super.isHelperClass(classname)
|| Arrays.stream(helperClassnames).anyMatch(c -> classname.startsWith(c));
}
Comment on lines +42 to +52
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this needed?

}
Loading