Datadog throws "unable to load class path" on Lucee, not on CF2018

The below datadog-related code is throwing an exception on Lucee.
It runs okay on CF2018 (we’ve been using it on production for years).

<cfcomponent name="datadog" displayname="Datadog Utility"><cfprocessingdirective pageEncoding="utf-8">

	<cffunction name="Init" output="false" returntype="any">
		<cfset this.javaOtelAttributeKey = createObject("java", "io.opentelemetry.api.common.AttributeKey")>
		<cfset this.javaOtelSpan = createObject("java", "io.opentelemetry.api.trace.Span")>
		<cfset this.javaStringClass = createObject("java", "java.lang.String").getClass()>

		<cfreturn this>
	</cffunction>

	<cffunction name="getCurrentSpan">
		<cfreturn this.javaOtelSpan.getClass().getMethod("current", javaCast("null", "")).invoke(javaCast("null", ""), javaCast("null", ""))>
	</cffunction>

	<cffunction name="setAttributeString">
		<cfargument name="key" type="string" required="true">
		<cfargument name="value" type="string" required="true">
		<cfset LOCAL.span = this.getCurrentSpan()>
		<cfset LOCAL.attributeKey = this.javaOtelAttributeKey.getClass().getMethod("stringKey", [this.javaStringClass]).invoke(javaCast("null", ""), [ARGUMENTS.key])>
		<cfset LOCAL.span.setAttribute( LOCAL.attributeKey, javaCast("string", ARGUMENTS.value) )>
	</cffunction>

</cfcomponent>

From what I recall, we’re using reflection to work around ambiguous function calls / it doesn’t work without using getMethod and invoke, on CF2018 at least.

Anyway, the Lucee bug (?) is, the setAttribute call is throwing the below:

lucee.runtime.exp.NativeException: unable to load class path [datadog
/opentelemetry/shim/trace/OtelSpan.class] at lucee.transformer.dynamic.
meta.dynamic.ClazzDynamic._getFunctionMembers(ClazzDynamic.java:514)
at lucee.transformer.dynamic.meta.dynamic.ClazzDynamic.
getFunctionMembers(ClazzDynamic.java:487) at lucee.transformer.dynamic.
meta.dynamic.ClazzDynamic.(ClazzDynamic.java:131) at lucee.
transformer.dynamic.meta.dynamic.ClazzDynamic.getInstance
(ClazzDynamic.java:88) at lucee.transformer.dynamic.DynamicInvoker.
toClazzDynamic(DynamicInvoker.java:165) at lucee.runtime.reflection.pairs.
MethodInstance.invoke(MethodInstance.java:94) at lucee.runtime.util.
VariableUtilImpl.callFunctionWithoutNamedValues(VariableUtilImpl.java:
824) at lucee.runtime.PageContextImpl.getFunction(PageContextImpl.java:
2075) at cfcs.utility.datadog_cfc$cf.udfCall(/cfcs/utility/datadog.cfc:27)

Any ideas?

Note, we have these JVM args set for both CF2018 and Lucee, setenv.sh:

-javaagent:/cfcustom/jars/dd-java-agent-1.49.0.jar -Ddd.trace.otel.enabled=true

Also, in ApplicationProxy.cfc we have:

<cfset this.javaSettings = { loadPaths = ["/cfcustom/jars/"] }>

These are in /cfcustom/jars, same jars for both CF2018 and Lucee:

  • dd-java-agent-1.49.0.jar
  • opentelemetry-api-1.50.0.jar
  • opentelemetry-context-1.50.0.jar

OS: Linux amd64 5.10.236-228.935.amzn2.x86_64
Java Version: 21.0.7 Eclipse Adoptium
Tomcat Version: Apache Tomcat/11.0.7
Lucee Version: 6.2.2.27-SNAPSHOT-light (docker)

EDIT: This can also be reproduced simply using the below, cfdump throws the same exception:

<cfdump var="#createObject("java", "io.opentelemetry.api.trace.Span").current()#" abort>

Though with that said, I can’t reproduce it using a minimal test :thinking:. Maybe the issue is specific to certain means of importing jars?

(unqualified answer)

CF2018 and Lucee 6.2 are using completely different jdk architectures from my understanding (up to 6.1x it was same)

(6.1 was on previous like CF2018), so perhaps roll back to lucee 6.1 for now until you can get this working in production on 6.2.

1 Like

I got hit with the same / similar issues with createObject("java", ...) in Lucee 6.2.x via CommandBox just yesterday.

After lots of debugging, I traced it down to -Djava.io.tmpdir=E:/CommandBox/temp. I assume different versions of lib’s needed by code were placed here and conflicting with CommandBox’s versions.

The reason for this setting for us was that, in the past, our code would complain about not being able to access the default temp directory.

By changing the temp dir to a different location, accessible by Lucee, seems to have solved the issue for us.

Perhaps something similar for you? Also, I believe someone from team posted recently about this issue (maybe in Slack?) being related to Java 21 changes.

1 Like

Thanks. For now, we’ll probably try using the opentracing jar instead.

For what it’s worth, the issue only happens if javaagent=dd-java-agent.jar is specified. I since moved dd-java-agent outside of /cfcustom/jars to rule that out as being a factor also.

When the agent is injected, I think it changes the behaviour of certain classes and Lucee throws “unable to load class path”. I think there is a Lucee bug somewhere here.

EDIT: For what it’s worth, tested, opentracing is also broken. We’re going to use dd-java-agent’s internal-only opentracing API in the meantime since we know it works.

Apparently a bug report was just created for this: Problem creating java obj in Lucee 6.2.2.35 and later - #4 by cfmitrah

Did/does this cf2018 code work with Lucee 6.1?

I finally have a minimal reproducible example: here. Or using our full code: here.
If you visit localhost:8888/test.cfm, it’ll throw the “unable to load class path” exception.

I can confirm it’s an issue on 6.2.1.122 as well.

nice, could you try using this approach of passing in the same array of jars to each createObject call?

return CreateObject( "java", "net.glxn.qrgen.javase.QRCode", _getLibPath() );

I’m seeing the same error when doing that.

Also, in answer to your earlier question, it doesn’t happen on Lucee 6.1.1.118.
So it was introduced somewhere between that and 6.2.1.122.

ok, excellent, last question, does it happen in 7?

Yes, it’s happening on 7.0.0.249-SNAPSHOT

excellent, thanks for checking all that

now we have the full picture, please go ahead and file a ticket!

1 Like

https://luceeserver.atlassian.net/browse/LDEV-5632

1 Like