diff --git a/OpacityCore/src/main/cpp/OpacityCore.cpp b/OpacityCore/src/main/cpp/OpacityCore.cpp index e695d79..8a4a0e3 100644 --- a/OpacityCore/src/main/cpp/OpacityCore.cpp +++ b/OpacityCore/src/main/cpp/OpacityCore.cpp @@ -558,12 +558,29 @@ extern "C" JNIEXPORT jobject JNICALL Java_com_opacitylabs_opacitycore_OpacityCore_getNative(JNIEnv *env, jobject thiz, jstring name, - jstring params) { + jstring params, + jstring traceparent, + jstring tracestate) { char *res, *err; const char *name_str = env->GetStringUTFChars(name, nullptr); const char *params_str = params != nullptr ? env->GetStringUTFChars(params, nullptr) : nullptr; - int status = opacity_core::opacity_get(name_str, params_str, &res, &err); + // Optional W3C trace context. A null traceparent runs the plain + // `opacity_get` (standalone per-flow trace); a non-null one runs + // `opacity_get_with_context` to join the caller's trace. + const char *traceparent_str = + traceparent != nullptr ? env->GetStringUTFChars(traceparent, nullptr) + : nullptr; + const char *tracestate_str = + tracestate != nullptr ? env->GetStringUTFChars(tracestate, nullptr) + : nullptr; + int status; + if (traceparent_str != nullptr) { + status = opacity_core::opacity_get_with_context( + name_str, params_str, traceparent_str, tracestate_str, &res, &err); + } else { + status = opacity_core::opacity_get(name_str, params_str, &res, &err); + } return createOpacityResponse(env, status, res, err); } diff --git a/OpacityCore/src/main/jni/include/sdk.h b/OpacityCore/src/main/jni/include/sdk.h index 88820dc..4062793 100644 --- a/OpacityCore/src/main/jni/include/sdk.h +++ b/OpacityCore/src/main/jni/include/sdk.h @@ -178,6 +178,17 @@ int32_t opacity_init(const char *api_key_str, int32_t opacity_get(const char *name, const char *params, char **res_ptr, char **err_ptr); +/** + * Like [`opacity_get`], but joins the caller's W3C trace: the flow's root span + * is parented to the supplied `traceparent`. `tracestate` is optional + */ +int32_t opacity_get_with_context(const char *name, + const char *params, + const char *traceparent, + const char *tracestate, + char **res_ptr, + char **err_ptr); + void opacity_free_string(char *ptr); void emit_webview_event(const char *payload); diff --git a/OpacityCore/src/main/kotlin/com/opacitylabs/opacitycore/OpacityCore.kt b/OpacityCore/src/main/kotlin/com/opacitylabs/opacitycore/OpacityCore.kt index 0234a99..c309935 100644 --- a/OpacityCore/src/main/kotlin/com/opacitylabs/opacitycore/OpacityCore.kt +++ b/OpacityCore/src/main/kotlin/com/opacitylabs/opacitycore/OpacityCore.kt @@ -275,14 +275,40 @@ object OpacityCore { } @JvmStatic - suspend fun get(name: String, params: Map?): Result> { + suspend fun get( + name: String, + params: Map? + ): Result> { + return runGet(name, params, null, null) + } + + /** + * Runs the flow joined to the caller's W3C trace. [traceparent] is required; + * [tracestate] is optional (W3C allows it to be absent). + */ + @JvmStatic + suspend fun getWithContext( + name: String, + params: Map?, + traceparent: String, + tracestate: String? = null + ): Result> { + return runGet(name, params, traceparent, tracestate) + } + + private suspend fun runGet( + name: String, + params: Map?, + traceparent: String?, + tracestate: String? + ): Result> { return withContext(Dispatchers.IO) { val paramsString = params?.let { val jsonElement = mapToJsonElement(it) Json.encodeToString(jsonElement) } - val res = getNative(name, paramsString) + val res = getNative(name, paramsString, traceparent, tracestate) if (res.status != 0) { return@withContext Result.failure(parseOpacityError(res.err)) } @@ -305,7 +331,12 @@ object OpacityCore { private external fun nativeInitializeOpenTelemetry(openTelemetryEndpoint: String, grafanaInstanceId: String, grafanaApiToken: String): Int - private external fun getNative(name: String, params: String?): OpacityResponse + private external fun getNative( + name: String, + params: String?, + traceparent: String?, + tracestate: String? + ): OpacityResponse external fun getSdkVersions(): String external fun emitWebviewEvent(eventJson: String) external fun isBrowserOverlayEnabled(): Boolean