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
355 changes: 263 additions & 92 deletions Cargo.lock

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,9 @@ public static class TracerInfo {
@JsonProperty("app_version")
public String serviceVersion;

@JsonProperty("process_tags")
public List<String> processTags;

@Override
public String toString() {
return new StringJoiner(", ", TracerInfo.class.getSimpleName() + "[", "]")
Expand All @@ -229,6 +232,7 @@ public String toString() {
.add("extraServices=" + extraServices)
.add("serviceEnv='" + serviceEnv + "'")
.add("serviceVersion='" + serviceVersion + "'")
.add("processTags=" + processTags)
.toString();
}
}
Expand Down
23 changes: 15 additions & 8 deletions components-rs/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -1388,6 +1388,14 @@ typedef struct ddog_crasht_Slice_CInt {
uintptr_t len;
} ddog_crasht_Slice_CInt;

/**
* Represents an object that should only be referred to by its handle.
* Do not access its member for any reason, only use the C API functions on this struct.
*/
typedef struct ddog_crasht_Handle_StackTrace {
struct ddog_crasht_StackTrace *inner;
} ddog_crasht_Handle_StackTrace;

/**
* A generic result type for when an operation may fail,
* or may return <T> in case of success.
Expand Down Expand Up @@ -1493,14 +1501,6 @@ typedef struct ddog_crasht_Span {
ddog_CharSlice thread_name;
} ddog_crasht_Span;

/**
* Represents an object that should only be referred to by its handle.
* Do not access its member for any reason, only use the C API functions on this struct.
*/
typedef struct ddog_crasht_Handle_StackTrace {
struct ddog_crasht_StackTrace *inner;
} ddog_crasht_Handle_StackTrace;

typedef struct ddog_crasht_ThreadData {
bool crashed;
ddog_CharSlice name;
Expand Down Expand Up @@ -1875,6 +1875,13 @@ void ddog_endpoint_set_timeout(struct ddog_Endpoint *endpoint, uint64_t millis);

void ddog_endpoint_set_test_token(struct ddog_Endpoint *endpoint, ddog_CharSlice token);

/**
* Set whether to use the system DNS resolver when building the reqwest client.
* If false, the default in-process resolver is used.
*/
void ddog_endpoint_set_use_system_resolver(struct ddog_Endpoint *endpoint,
bool use_system_resolver);

void ddog_endpoint_drop(struct ddog_Endpoint*);

struct ddog_Option_U32 ddog_Option_U32_some(uint32_t v);
Expand Down
46 changes: 45 additions & 1 deletion components-rs/crashtracker.h
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,45 @@ struct ddog_VoidResult ddog_crasht_init_without_receiver(struct ddog_crasht_Conf
*/
struct ddog_crasht_Slice_CInt ddog_crasht_default_signals(void);

/**
* Report an unhandled exception as a crash event.
*
* This function sends a crash report for an unhandled exception detected
* by the runtime. It is intended to be called when the process is in a
* terminal state due to an unhandled exception.
*
* # Parameters
* - `error_type`: Optional type/class of the exception (e.g. "NullPointerException"). Pass empty
* CharSlice for unknown.
* - `error_message`: Optional error message. Pass empty CharSlice for no message.
* - `runtime_stack`: Stack trace from the runtime. Consumed by this call.
*
* If the crash-tracker has not been initialized, this function is a no-op.
*
* # Side effects
* This function disables the signal-based crash handler before performing
* any work. This means that if the process receives a fatal signal (SIGSEGV)
* during or after this call, the crashtracker will not produce a
* second crash report. The previous signal handler (if any) will still be
* chained.
*
* # Failure mode
* If a fatal signal occurs while this function is in progress, the calling
* process is in an unrecoverable state; the crashtracker cannot report the
* secondary fault and the caller's own signal handler (if any) will execute
* in a potentially corrupted context. Callers should treat this function as a
* terminal operation and exit shortly after it returns.
*
* # Safety
* Crash-tracking functions are not reentrant.
* No other crash-handler functions should be called concurrently.
* The `runtime_stack` handle must be valid and will be consumed.
*/
DDOG_CHECK_RETURN
struct ddog_VoidResult ddog_crasht_report_unhandled_exception(ddog_CharSlice error_type,
ddog_CharSlice error_message,
struct ddog_crasht_Handle_StackTrace *runtime_stack);

/**
* Removes all existing additional tags
* Expected to be used after a fork, to reset the additional tags on the child
Expand Down Expand Up @@ -661,7 +700,12 @@ struct ddog_VoidResult ddog_crasht_CrashInfoBuilder_with_thread_name(struct ddog
* The `builder` can be null, but if non-null it must point to a Builder made by this module,
* which has not previously been dropped.
* All arguments must be valid.
* This method requires that the builder has a UUID and metadata set
* This method requires that the builder has `metadata` and `kind` set
* Applications can add `message` or `sig_info` to the builder to provide additional context.
* If set, the data will be used to derive the crash ping message in the order of
* - an explicit message set with `with_message`
* - sig_info set with `with_sig_info`
* - kind set with `with_kind`
*/
DDOG_CHECK_RETURN
struct ddog_VoidResult ddog_crasht_CrashInfoBuilder_upload_ping_to_endpoint(struct ddog_crasht_Handle_CrashInfoBuilder *builder,
Expand Down
3 changes: 2 additions & 1 deletion components-rs/ddtrace.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,8 @@ bool ddog_remote_configs_service_env_change(struct ddog_RemoteConfigState *remot
ddog_CharSlice service,
ddog_CharSlice env,
ddog_CharSlice version,
const struct ddog_Vec_Tag *tags);
const struct ddog_Vec_Tag *tags,
const struct ddog_Vec_Tag *process_tags);

bool ddog_remote_config_alter_dynamic_config(struct ddog_RemoteConfigState *remote_config,
ddog_CharSlice config,
Expand Down
2 changes: 2 additions & 0 deletions components-rs/remote_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -494,12 +494,14 @@ pub extern "C" fn ddog_remote_configs_service_env_change(
env: CharSlice,
version: CharSlice,
tags: &libdd_common_ffi::Vec<Tag>,
process_tags: &libdd_common_ffi::Vec<Tag>,
) -> bool {
let new_target = Target {
service: service.to_utf8_lossy().to_string(),
env: env.to_utf8_lossy().to_string(),
app_version: version.to_utf8_lossy().to_string(),
tags: tags.as_slice().to_vec(),
process_tags: process_tags.as_slice().to_vec(),
};

if let Some(target) = remote_config.manager.get_target() {
Expand Down
29 changes: 29 additions & 0 deletions ext/process_tags.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ typedef struct {
size_t count;
size_t capacity;
zend_string *serialized;
ddog_Vec_Tag vec;
} process_tags_t;

static process_tags_t process_tags = {0};
Expand Down Expand Up @@ -190,12 +191,35 @@ static void serialize_process_tags(void) {
}

smart_str_free(&buf);

process_tags.vec = ddog_Vec_Tag_new();
for (size_t i = 0; i < process_tags.count; i++) {
const char* key = process_tags.tag_list[i].key;
const char* value = process_tags.tag_list[i].value;

UNUSED(ddog_Vec_Tag_push(&process_tags.vec,
(ddog_CharSlice) {.ptr = key, .len = strlen(key)},
(ddog_CharSlice) {.ptr = value, .len = strlen(value)}
));
}
}

zend_string *ddtrace_process_tags_get_serialized(void) {
return (ddtrace_process_tags_enabled() && process_tags.serialized) ? process_tags.serialized : ZSTR_EMPTY_ALLOC();
}

const ddog_Vec_Tag *ddtrace_process_tags_get_vec(void) {
if (ddtrace_process_tags_enabled() && process_tags.vec.ptr) {
return &process_tags.vec;
}

static ddog_Vec_Tag empty_vec;
if (!empty_vec.ptr) {
empty_vec = ddog_Vec_Tag_new();
}
return &empty_vec;
}

bool ddtrace_process_tags_enabled(void){
return get_global_DD_EXPERIMENTAL_PROPAGATE_PROCESS_TAGS_ENABLED();
}
Expand Down Expand Up @@ -224,5 +248,10 @@ void ddtrace_process_tags_mshutdown(void) {
if (process_tags.serialized) {
zend_string_release(process_tags.serialized);
}

if (process_tags.vec.ptr) {
ddog_Vec_Tag_drop(process_tags.vec);
}

memset(&process_tags, 0, sizeof(process_tags));
}
6 changes: 6 additions & 0 deletions ext/process_tags.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
#include <stdbool.h>
#include "Zend/zend_types.h"
#include "ddtrace_export.h"
#include "components-rs/common.h"


// Called at first RINIT to collect process tags
void ddtrace_process_tags_first_rinit(void);
Expand All @@ -18,4 +20,8 @@ bool ddtrace_process_tags_enabled(void);
// Returns NULL if disabled or not yet collected
DDTRACE_PUBLIC zend_string *ddtrace_process_tags_get_serialized(void);

// Get a pointer to the process tags Vec<Tag>
// Returns a pointer to an empty Vec if disabled or not yet collected
const ddog_Vec_Tag *ddtrace_process_tags_get_vec(void);

#endif // DD_PROCESS_TAGS_H
4 changes: 3 additions & 1 deletion ext/sidecar.c
Original file line number Diff line number Diff line change
Expand Up @@ -528,9 +528,11 @@ void ddtrace_sidecar_submit_root_span_data_direct(ddog_SidecarTransport **transp
}
ddog_CharSlice version_slice = dd_zend_string_to_CharSlice(version_string);

const ddog_Vec_Tag *process_tags = ddtrace_process_tags_get_vec();

bool changed = true;
if (DDTRACE_G(remote_config_state)) {
changed = ddog_remote_configs_service_env_change(DDTRACE_G(remote_config_state), service_slice, env_slice, version_slice, &DDTRACE_G(active_global_tags));
changed = ddog_remote_configs_service_env_change(DDTRACE_G(remote_config_state), service_slice, env_slice, version_slice, &DDTRACE_G(active_global_tags), process_tags);
if (!changed && root) {
// ddog_remote_configs_service_env_change() generally only processes configs if they changed. However, upon request initialization it may be identical to the previous request.
// However, at request shutdown some configs are unloaded. Explicitly forcing a processing step ensures these are re-loaded.
Expand Down
2 changes: 1 addition & 1 deletion libdatadog
Submodule libdatadog updated 186 files
2 changes: 1 addition & 1 deletion tests/ext/crashtracker_segfault.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ $rr->waitForRequest(function ($request) {
if (!isset($payload["message"]["metadata"])) {
break;
}
if (($payload["message"]["kind"] ?? "") == "Crash ping") {
if (($payload["is_crash"] ?? false) !== true) {
continue;
}

Expand Down
29 changes: 29 additions & 0 deletions tests/ext/includes/request_replayer.inc
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,26 @@ class RequestReplayer
} while (true);
}

public function waitForRcRequest($matcher)
{
$i = 0;
do {
if ($i++ == $this->maxIteration) {
throw new Exception("wait for replay timeout");
}
usleep($this->flushInterval);

$requests = $this->replayAllRcRequests();
if (is_array($requests)) {
foreach ($requests as $request) {
if ($matcher($request)) {
return $request;
}
}
}
} while (true);
}

public function waitForDataAndReplay($ignoreTelemetry = true)
{
$i = 0;
Expand Down Expand Up @@ -104,6 +124,15 @@ class RequestReplayer
])), true);
}

public function replayAllRcRequests()
{
return json_decode(file_get_contents($this->endpoint . '/replay-rc-requests', false, stream_context_create([
"http" => [
"header" => "X-Datadog-Test-Session-Token: " . ini_get("datadog.trace.agent_test_session_token"),
],
])), true);
}

public function clearDumpedData()
{
file_get_contents($this->endpoint . '/clear-dumped-data', false, stream_context_create([
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ array(2) {
["_dd.di.ret.probe_id"]=>
string(1) "3"
}
string(%d) "/debugger/v1/input?ddtags=debugger_version:1.%s,env:none,version:,runtime_id:%s-%s-%s-%s-%s,host_name:%s"
string(%d) "/debugger/v1/diagnostics?ddtags=debugger_version:1.%s,env:none,version:,runtime_id:%s-%s-%s-%s-%s,host_name:%s"
array(1) {
[0]=>
array(6) {
Expand Down
68 changes: 68 additions & 0 deletions tests/ext/remote_config/rc_process_tags.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
--TEST--
Test remote config request payload
--SKIPIF--
<?php include __DIR__ . '/../includes/skipif_no_dev_env.inc'; ?>
--ENV--
DD_AGENT_HOST=request-replayer
DD_TRACE_AGENT_PORT=80
DD_TRACE_GENERATE_ROOT_SPAN=0
DD_REMOTE_CONFIG_POLL_INTERVAL_SECONDS=0.01
DD_EXPERIMENTAL_PROPAGATE_PROCESS_TAGS_ENABLED=1
--INI--
datadog.trace.agent_test_session_token=remote-config/check_payload
--FILE--
<?php

require __DIR__ . "/remote_config.inc";
include __DIR__ . '/../includes/request_replayer.inc';

reset_request_replayer();
$rr = new RequestReplayer();

// Start a span to trigger RC
\DDTrace\start_span();

$path = put_dynamic_config_file([
"log_injection_enabled" => true,
]);

try {
$request = $rr->waitForRcRequest(function($req) {
if (strpos($req["uri"], '/v0.7/config') === false) {
return false;
}

$body = json_decode($req["body"], true);
return isset($body["client"]["client_tracer"]["process_tags"])
&& !empty($body["client"]["client_tracer"]["process_tags"]);
});
$body = json_decode($request["body"], true);
} catch (Exception $e) {
echo "ERROR: No RC request found\n";
exit(1);
}

if (!isset($body["client"]["client_tracer"]["process_tags"])) {
echo "ERROR: Missing 'process_tags' field\n";
exit(1);
}

$process_tags = $body["client"]["client_tracer"]["process_tags"];
foreach ($process_tags as $tag) {
echo $tag . PHP_EOL;
}

del_rc_file($path);

?>
--CLEAN--
<?php
require __DIR__ . "/remote_config.inc";
reset_request_replayer();
?>
--EXPECTF--
entrypoint.basedir:remote_config
entrypoint.name:rc_process_tags
entrypoint.type:script
entrypoint.workdir:%s
runtime.sapi:cli
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ for ($i = 0; $i < 300; ++$i) {
?>
--EXPECTF--
Included
string(%d) "entrypoint.basedir:telemetry,entrypoint.name:process_tags,entrypoint.type:script,entrypoint.workdir:%s,runtime.sapi:cli"
string(%d) "entrypoint.basedir:telemetry,entrypoint.name:telemetry_process_tags,entrypoint.type:script,entrypoint.workdir:%s,runtime.sapi:cli"
--CLEAN--
<?php

Expand Down
Loading