Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
8 changes: 4 additions & 4 deletions .github/workflows/test_workflow.yml
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ jobs:
uses: actions/cache@v4
with:
path: ddprof-lib/build/async-profiler
key: async-profiler-${{ runner.os }}-${{ hashFiles('gradle/ap-lock.properties') }}
key: async-profiler-${{ runner.os }}-${{ hashFiles('gradle/lock.properties') }}
enableCrossOsArchive: true
restore-keys: |
async-profiler-${{ runner.os }}-
Expand Down Expand Up @@ -156,7 +156,7 @@ jobs:
uses: actions/cache@v4
with:
path: ddprof-lib/build/async-profiler
key: async-profiler-${{ runner.os }}-${{ hashFiles('gradle/ap-lock.properties') }}
key: async-profiler-${{ runner.os }}-${{ hashFiles('gradle/lock.properties') }}
enableCrossOsArchive: true
restore-keys: |
async-profiler-${{ runner.os }}-
Expand Down Expand Up @@ -276,7 +276,7 @@ jobs:
uses: actions/cache@v4
with:
path: ddprof-lib/build/async-profiler
key: async-profiler-${{ runner.os }}-${{ hashFiles('gradle/ap-lock.properties') }}
key: async-profiler-${{ runner.os }}-${{ hashFiles('gradle/lock.properties') }}
enableCrossOsArchive: true
restore-keys: |
async-profiler-${{ runner.os }}-
Expand Down Expand Up @@ -372,7 +372,7 @@ jobs:
uses: actions/cache@v4
with:
path: ddprof-lib/build/async-profiler
key: async-profiler-${{ runner.os }}-${{ hashFiles('gradle/ap-lock.properties') }}
key: async-profiler-${{ runner.os }}-${{ hashFiles('gradle/lock.properties') }}
enableCrossOsArchive: true
restore-keys: |
async-profiler-${{ runner.os }}-
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ The resulting artifact will be in `ddprof-lib/build/libs/ddprof-<version>.jar`
To smoothen the absorption of the upstream changes, we are using parts of the upstream codebase in (mostly) vanilla form.

For this, we have four new gradle tasks in [ddprof-lib/build.gradle](ddprof-lib/build.gradle):
- `cloneAsyncProfiler` - clones the [DataDog/async-profiler](https://github.com/DataDog/async-profiler) repository into `ddprof-lib/build/async-profiler` using the commit lock specified in [gradle/ap-lock.properties](gradle/ap-lock.properties)
- `cloneAsyncProfiler` - clones the [DataDog/async-profiler](https://github.com/DataDog/async-profiler) repository into `ddprof-lib/build/async-profiler` using the commit lock specified in [gradle/ap-lock.properties](gradle/lock.properties)
- in that repository, we are maintainin a branch called `dd/master` where we keep the upstream code in sync with the 'safe' changes from the upstream `master` branch
- cherry-picks into that branch should be rare and only done for critical fixes that are needed in the project
- otherwise, we should wait for the next upstream release to avoid conflicts
Expand Down
26 changes: 13 additions & 13 deletions ddprof-lib/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -181,12 +181,12 @@ description = "Datadog Java Profiler Library"
def component_version = project.hasProperty("ddprof_version") ? project.ddprof_version : project.version

def props = new Properties()
file("${rootDir}/gradle/ap-lock.properties").withInputStream { stream ->
file("${rootDir}/gradle/lock.properties").withInputStream { stream ->
props.load(stream)
}

def branch_lock = props.getProperty("branch")
def commit_lock = props.getProperty("commit")
def ap_branch_lock = props.getProperty("ap.branch")
def ap_commit_lock = props.getProperty("ap.commit")

// this feels weird but it is the only way invoking `./gradlew :ddprof-lib:*` tasks will work
if (rootDir.toString().endsWith("ddprof-lib")) {
Expand Down Expand Up @@ -267,7 +267,7 @@ tasks.register('copyExternalLibs', Copy) {

def cloneAPTask = tasks.register('cloneAsyncProfiler') {
description = 'Clones async-profiler repo if directory is missing or updates it if commit hash differs'
inputs.file("${rootDir}/gradle/ap-lock.properties")
inputs.file("${rootDir}/gradle/lock.properties")
outputs.dir("${projectDir}/build/async-profiler")
outputs.upToDateWhen {
def targetDir = file("${projectDir}/build/async-profiler")
Expand All @@ -284,7 +284,7 @@ def cloneAPTask = tasks.register('cloneAsyncProfiler') {
}
currentCommit = os.toString().trim()
}
return currentCommit == commit_lock
return currentCommit == ap_commit_lock
} catch (Exception e) {
return false
}
Expand All @@ -300,11 +300,11 @@ def cloneAPTask = tasks.register('cloneAsyncProfiler') {
if (!targetDir.exists()) {
println "Cloning missing async-profiler git subdirectory..."
exec {
commandLine 'git', 'clone', '--branch', branch_lock, 'https://github.com/datadog/async-profiler.git', targetDir.absolutePath
commandLine 'git', 'clone', '--branch', ap_branch_lock, 'https://github.com/datadog/async-profiler.git', targetDir.absolutePath
}
exec {
workingDir targetDir.absolutePath
commandLine 'git', 'checkout', commit_lock
commandLine 'git', 'checkout', ap_commit_lock
}
} else {
// Also fix git ownership for existing directory
Expand All @@ -324,18 +324,18 @@ def cloneAPTask = tasks.register('cloneAsyncProfiler') {
currentCommit = os.toString().trim()
}

if (currentCommit != commit_lock) {
println "async-profiler commit hash differs (current: ${currentCommit}, expected: ${commit_lock}), updating..."
if (currentCommit != ap_commit_lock) {
println "async-profiler commit hash differs (current: ${currentCommit}, expected: ${ap_commit_lock}), updating..."
exec {
workingDir targetDir.absolutePath
commandLine 'rm', '-rf', targetDir.absolutePath
}
exec {
commandLine 'git', 'clone', '--branch', branch_lock, 'https://github.com/datadog/async-profiler.git', targetDir.absolutePath
commandLine 'git', 'clone', '--branch', ap_branch_lock, 'https://github.com/datadog/async-profiler.git', targetDir.absolutePath
}
exec {
workingDir targetDir.absolutePath
commandLine 'git', 'checkout', commit_lock
commandLine 'git', 'checkout', ap_commit_lock
}
} else {
println "async-profiler git subdirectory present with correct commit hash."
Expand Down Expand Up @@ -373,7 +373,7 @@ def patchStackFrame = tasks.register("patchStackFrame") {
configure {
dependsOn copyUpstreamFiles
}
inputs.files copyUpstreamFiles
inputs.file("${projectDir}/src/main/cpp-external/stackFrame_x64.cpp")
outputs.file("${projectDir}/src/main/cpp-external/stackFrame_x64.cpp")

doLast {
Expand Down Expand Up @@ -428,7 +428,7 @@ def patchStackWalker = tasks.register("patchStackWalker") {
configure {
dependsOn copyUpstreamFiles, patchStackFrame
}
inputs.files copyUpstreamFiles
inputs.file("${projectDir}/src/main/cpp-external/stackWalker.cpp")
outputs.file("${projectDir}/src/main/cpp-external/stackWalker.cpp")

doLast {
Expand Down
93 changes: 92 additions & 1 deletion ddprof-lib/src/main/cpp/javaApi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "engine.h"
#include "incbin.h"
#include "os.h"
#include "otel_process_ctx.h"
#include "profiler.h"
#include "thread.h"
#include "tsc.h"
Expand Down Expand Up @@ -110,7 +111,7 @@ Java_com_datadoghq_profiler_JavaProfiler_execute0(JNIEnv *env, jobject unused,
}

extern "C" DLLEXPORT jstring JNICALL
Java_com_datadoghq_profiler_JavaProfiler_getStatus0(JNIEnv* env,
Java_com_datadoghq_profiler_JavaProfiler_getStatus0(JNIEnv* env,
jobject unused) {
char msg[2048];
int ret = Profiler::instance()->status((char*)msg, sizeof(msg) - 1);
Expand Down Expand Up @@ -427,3 +428,93 @@ Java_com_datadoghq_profiler_ActiveBitmap_getActiveCountAddr0(JNIEnv *env,
jclass unused) {
return (jlong)Profiler::instance()->threadFilter()->addressOfSize();
}

// Static variable to track the current published context
static otel_process_ctx_result* current_published_context = nullptr;

extern "C" DLLEXPORT void JNICALL
Java_com_datadoghq_profiler_OTelContext_setProcessCtx0(JNIEnv *env,
jclass unused,
jstring env_data,
jstring hostname,
jstring runtime_id,
jstring service,
jstring version,
jstring tracer_version
) {
JniString env_str(env, env_data);
JniString hostname_str(env, hostname);
JniString runtime_id_str(env, runtime_id);
JniString service_str(env, service);
JniString version_str(env, version);
JniString tracer_version_str(env, tracer_version);

otel_process_ctx_data data = {
.deployment_environment_name = const_cast<char*>(env_str.c_str()),
.host_name = const_cast<char*>(hostname_str.c_str()),
.service_instance_id = const_cast<char*>(runtime_id_str.c_str()),
.service_name = const_cast<char*>(service_str.c_str()),
.service_version = const_cast<char*>(version_str.c_str()),
.telemetry_sdk_language = const_cast<char*>("java"),
.telemetry_sdk_version = const_cast<char*>(tracer_version_str.c_str()),
.telemetry_sdk_name = const_cast<char*>("dd-trace-java"),
.resources = NULL // TODO: Arbitrary tags not supported yet for Java
};

otel_process_ctx_result result = otel_process_ctx_publish(&data);
}

extern "C" DLLEXPORT jobject JNICALL
Java_com_datadoghq_profiler_OTelContext_readProcessCtx0(JNIEnv *env, jclass unused) {
#ifndef OTEL_PROCESS_CTX_NO_READ
otel_process_ctx_read_result result = otel_process_ctx_read();

if (!result.success) {
// Return null if reading failed
return nullptr;
}

// Convert C strings to Java strings
jstring jDeploymentEnvironmentName = result.data.deployment_environment_name ?
env->NewStringUTF(result.data.deployment_environment_name) : nullptr;
jstring jHostName = result.data.host_name ?
env->NewStringUTF(result.data.host_name) : nullptr;
jstring jServiceInstanceId = result.data.service_instance_id ?
env->NewStringUTF(result.data.service_instance_id) : nullptr;
jstring jServiceName = result.data.service_name ?
env->NewStringUTF(result.data.service_name) : nullptr;
jstring jServiceVersion = result.data.service_version ?
env->NewStringUTF(result.data.service_version) : nullptr;
jstring jTelemetrySdkLanguage = result.data.telemetry_sdk_language ?
env->NewStringUTF(result.data.telemetry_sdk_language) : nullptr;
jstring jTelemetrySdkVersion = result.data.telemetry_sdk_version ?
env->NewStringUTF(result.data.telemetry_sdk_version) : nullptr;
jstring jTelemetrySdkName = result.data.telemetry_sdk_name ?
env->NewStringUTF(result.data.telemetry_sdk_name) : nullptr;
// TODO: result.data.resources not supported yet for Java

otel_process_ctx_read_drop(&result);

// Find the ProcessContext class
jclass processContextClass = env->FindClass("com/datadoghq/profiler/OTelContext$ProcessContext");
if (!processContextClass) {
return nullptr;
}

// Find the constructor
jmethodID constructor = env->GetMethodID(processContextClass, "<init>",
"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
if (!constructor) {
return nullptr;
}

// Create the ProcessContext object
jobject processContext = env->NewObject(processContextClass, constructor,
jDeploymentEnvironmentName, jHostName, jServiceInstanceId, jServiceName, jServiceVersion, jTelemetrySdkLanguage, jTelemetrySdkVersion, jTelemetrySdkName);

return processContext;
#else
// If OTEL_PROCESS_CTX_NO_READ is defined, return null
return nullptr;
#endif
}
Loading
Loading