fix: nativets http tracing (#7716)

* fix: nativets http tracing

Signed-off-by: pyranota <pyra@duck.com>

* ee repo

Signed-off-by: pyranota <pyra@duck.com>

* nit

Signed-off-by: pyranota <pyra@duck.com>

* ee ref

Signed-off-by: pyranota <pyra@duck.com>

* ee repo

Signed-off-by: pyranota <pyra@duck.com>

* ee repo

Signed-off-by: pyranota <pyra@duck.com>

* fix

Signed-off-by: pyranota <pyra@duck.com>

* fix

Signed-off-by: pyranota <pyra@duck.com>

* fix v2

Signed-off-by: pyranota <pyra@duck.com>

* ee repo

Signed-off-by: pyranota <pyra@duck.com>

* chore: update ee-repo-ref to 5d841b358dd32130c9f34b54f59b96b5c322f213

This commit updates the EE repository reference after PR #396 was merged in windmill-ee-private.

Previous ee-repo-ref: 250723c698fceccbc66ae9a6c6c7c09e33465819

New ee-repo-ref: 5d841b358dd32130c9f34b54f59b96b5c322f213

Automated by sync-ee-ref workflow.

---------

Signed-off-by: pyranota <pyra@duck.com>
Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>
This commit is contained in:
Pyra
2026-01-28 18:19:19 +00:00
committed by GitHub
co-authored by windmill-internal-app[bot]
parent d3d35d4cd8
commit f50a866430
7 changed files with 54 additions and 65 deletions
+1 -1
View File
@@ -1 +1 @@
371efb2d7307f588c5ce00d63fd036751cc068f2
5d841b358dd32130c9f34b54f59b96b5c322f213
+12 -28
View File
@@ -668,10 +668,11 @@ async fn windmill_main() -> anyhow::Result<()> {
// Load OTEL tracing proxy settings and initialize deno_telemetry if nativets tracing is enabled
// This must happen before any Deno runtime is created
#[cfg(all(feature = "private", feature = "enterprise", feature = "deno_core"))]
#[cfg(all(feature = "private", feature = "enterprise"))]
{
reload_otel_tracing_proxy_setting(&Connection::Sql(db.clone())).await;
#[cfg(feature = "deno_core")]
if windmill_worker::is_otel_tracing_proxy_enabled_for_lang(&ScriptLang::Nativets).await {
match windmill_worker::load_internal_otel_exporter().await {
Ok(()) => {
@@ -1572,34 +1573,17 @@ Windmill Community Edition {GIT_VERSION}
let otel_tracing_proxy_f = async {
#[cfg(all(feature = "private", feature = "enterprise"))]
{
// Start OTEL tracing proxy for HTTP request interception
// Only enabled when: setting is on, worker mode (not server), and single worker (to avoid race conditions)
if worker_mode
&& num_workers == 1
&& windmill_worker::OTEL_TRACING_PROXY_SETTINGS
.read()
.await
.enabled
{
if let Some(db) = conn.as_sql() {
tracing::info!(
"Starting jobs OTEL tracing (ports will be dynamically assigned)"
);
if let Err(e) =
windmill_worker::start_jobs_otel_tracing(db.clone(), otel_killpill_rx)
.await
{
tracing::error!("Jobs OTEL tracing error: {}", e);
}
}
} else if windmill_worker::OTEL_TRACING_PROXY_SETTINGS
.read()
if worker_mode {
if let Some(db) = conn.as_sql() {
if let Err(e) = windmill_worker::start_jobs_otel_tracing(
db.clone(),
otel_killpill_rx,
num_workers,
)
.await
.enabled
&& num_workers > 1
{
tracing::warn!("OTEL tracing proxy is enabled but num_workers > 1. Disabling to avoid race conditions. Set NUM_WORKERS=1 to enable.");
{
tracing::error!("Jobs OTEL tracing error: {}", e);
}
}
}
@@ -1328,22 +1328,6 @@ try {{
let stream_notifier = StreamNotifier::new(conn, job);
// Set job context for OTEL tracing (EE only)
#[cfg(all(feature = "private", feature = "enterprise"))]
{
let tracing_enabled =
crate::worker::is_otel_tracing_proxy_enabled_for_lang(&ScriptLang::Nativets)
.await;
tracing::debug!(
"nativets job {}: OTEL tracing enabled={}",
job.id,
tracing_enabled
);
if tracing_enabled {
crate::otel_tracing_proxy_ee::set_current_job_context(job.id).await;
}
}
let result = crate::js_eval::eval_fetch_timeout(
env_code,
inner_content.clone(),
+27 -3
View File
@@ -1135,7 +1135,9 @@ pub async fn eval_fetch_timeout(
// We call the function exposed by runtime.js since we can't dynamically import ext: modules.
#[cfg(all(feature = "private", feature = "enterprise"))]
if crate::DENO_OTEL_INITIALIZED.load(std::sync::atomic::Ordering::SeqCst) {
if let Err(e) = js_runtime.execute_script("<otel_bootstrap>", "globalThis.__bootstrapOtel()") {
if let Err(e) =
js_runtime.execute_script("<otel_bootstrap>", "globalThis.__bootstrapOtel()")
{
tracing::warn!("Failed to bootstrap OTEL telemetry: {}", e);
}
}
@@ -1331,6 +1333,26 @@ async fn eval_fetch(
.context("failed to load module")?;
let main_override = script_entrypoint_override.unwrap_or("main".to_string());
// Inject parent trace context using enterSpan with a duck-typed span object.
// Uses job_id as trace_id so all spans are linked to the job.
// span_id is a placeholder - it gets overwritten by the OTLP handler with the real parent span_id.
#[cfg(all(feature = "private", feature = "enterprise"))]
let otel_context_inject = if crate::DENO_OTEL_INITIALIZED.load(std::sync::atomic::Ordering::SeqCst) {
let trace_id = job_id.as_simple().to_string();
format!(
r#"globalThis.__enterSpan?.({{
isRecording: () => true,
spanContext: () => ({{ traceId: "{trace_id}", spanId: "ffffffffffffffff", traceFlags: 1 }})
}});"#
)
} else {
String::new()
};
#[cfg(not(all(feature = "private", feature = "enterprise")))]
let otel_context_inject = "";
let script = js_runtime
.execute_script(
"<anon>",
@@ -1343,7 +1365,7 @@ function isAsyncIterable(obj) {{
function processStreamIterative(res) {{
const iterator = res[Symbol.asyncIterator]();
function processLoop() {{
return new Promise(function(resolve) {{
function step() {{
@@ -1363,10 +1385,12 @@ function processStreamIterative(res) {{
step();
}});
}}
return processLoop();
}}
{otel_context_inject}
let args = Deno.core.ops.op_get_static_args().map(JSON.parse)
import("file:///eval.ts").then((module) => module.{main_override}(...args))
.then(res => {{
+1 -1
View File
@@ -86,7 +86,7 @@ pub use otel_tracing_proxy_ee::{
set_current_job_context, start_jobs_otel_tracing, TRACING_PROXY_PORT,
};
#[cfg(all(feature = "private", feature = "enterprise", feature = "deno_core"))]
pub use otel_tracing_proxy_ee::{load_internal_otel_exporter, DENO_OTEL_INITIALIZED};
pub use otel_tracing_proxy_ee::{load_internal_otel_exporter, DENO_OTEL_INITIALIZED, OTLP_COLLECTOR_PORT};
pub use result_processor::handle_job_error;
+5 -2
View File
@@ -52,9 +52,12 @@ Object.assign(globalThis, {
// Expose bootstrapOtel globally so it can be called from Rust after runtime creation.
// We use dynamic import so deno_telemetry isn't loaded during snapshot creation.
// Config: [tracingEnabled, metricsEnabled, consoleConfig, deterministic]
// consoleConfig: 0=ignore, 1=capture, 2=replace
globalThis.__bootstrapOtel = () => {
import("ext:deno_telemetry/telemetry.ts").then(({ bootstrap }) => {
bootstrap([1, 0, 0, 0]);
import("ext:deno_telemetry/telemetry.ts").then(({ bootstrap, enterSpan }) => {
bootstrap([1, 0, 1, 0]);
// Expose enterSpan for setting parent trace context
globalThis.__enterSpan = enterSpan;
});
};
+8 -14
View File
@@ -675,7 +675,6 @@ async fn get_otel_tracing_proxy_envs() -> anyhow::Result<Vec<(&'static str, Stri
])
}
#[cfg(windows)]
lazy_static::lazy_static! {
pub static ref SYSTEM_ROOT: String = std::env::var("SystemRoot").unwrap_or_else(|_| "C:\\Windows".to_string());
@@ -2704,19 +2703,6 @@ async fn do_nativets(
let stream_notifier = StreamNotifier::new(conn, job);
// Set job context for OTEL tracing (EE only)
#[cfg(all(feature = "private", feature = "enterprise"))]
{
let tracing_enabled = is_otel_tracing_proxy_enabled_for_lang(&ScriptLang::Nativets).await;
tracing::debug!(
"nativets job {}: OTEL tracing enabled={}",
job.id, tracing_enabled
);
if tracing_enabled {
crate::otel_tracing_proxy_ee::set_current_job_context(job.id).await;
}
}
Ok(eval_fetch_timeout(
env_code,
code.clone(),
@@ -3133,6 +3119,14 @@ pub async fn handle_queued_job(
_ => None,
});
// Set job context for OTEL tracing before entering handle_code_execution_job's span
#[cfg(all(feature = "private", feature = "enterprise"))]
if matches!(job.script_lang, Some(ScriptLang::Nativets) | Some(ScriptLang::Bunnative))
&& is_otel_tracing_proxy_enabled_for_lang(&ScriptLang::Nativets).await
{
crate::otel_tracing_proxy_ee::set_current_job_context(job.id).await;
}
// Box::pin to move large future to heap
let r = Box::pin(handle_code_execution_job(
job.as_ref(),