Skip to content

Commit 9857057

Browse files
committed
Merge main into branch (forc-tracing update)
2 parents e9b7134 + 1a66135 commit 9857057

File tree

12 files changed

+1512
-1179
lines changed

12 files changed

+1512
-1179
lines changed

Cargo.lock

Lines changed: 1255 additions & 1125 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ repository = "https://github.com/FuelLabs/forc"
1717

1818
[workspace.dependencies]
1919
# Internal dependencies
20-
forc-tracing = { version = "0.71.1", path = "forc-tracing" }
20+
forc-tracing = { version = "0.72.0", path = "forc-tracing" }
2121
forc-wallet = { version = "0.16.2", path = "forc-wallet" }
2222

2323
# Sway dependencies (from crates.io)
@@ -41,6 +41,7 @@ fuel-core-client = { version = "0.47", default-features = false }
4141
fuel-core-storage = { version = "0.47", default-features = false }
4242
fuel-core-types = { version = "0.47", default-features = false }
4343
fuel-crypto = "0.65"
44+
fuel-telemetry = "0.1.1"
4445
fuel-tx = "0.65"
4546
fuel-vm = "0.65"
4647
fuels = "0.76"

forc-crypto/Cargo.toml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,15 @@ homepage.workspace = true
1212
license.workspace = true
1313
repository.workspace = true
1414

15+
[features]
16+
default = ["telemetry"]
17+
telemetry = ["forc-tracing/telemetry"]
18+
1519
[dependencies]
1620
anyhow.workspace = true
1721
async-trait.workspace = true
1822
clap = { workspace = true, features = ["derive", "env"] }
19-
forc-tracing = "0.70.2"
23+
forc-tracing.workspace = true
2024
forc-util.workspace = true
2125
fuel-core-types.workspace = true
2226
fuel-crypto = { version = "0.65", features = ["random"] }

forc-crypto/src/main.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,19 @@ use anyhow::Result;
44
use clap::Parser;
55
use forc_crypto::{address, keccak256, keys, sha256, Command};
66
use forc_tracing::{init_tracing_subscriber, println_error};
7+
78
use std::{
89
default::Default,
910
io::{stdin, stdout, IsTerminal, Read, Write},
1011
};
1112
use termion::screen::IntoAlternateScreen;
1213

1314
fn main() {
14-
init_tracing_subscriber(Default::default());
15+
let guard = init_tracing_subscriber(Default::default());
16+
1517
if let Err(err) = run() {
1618
println_error(&format!("{err}"));
19+
drop(guard);
1720
std::process::exit(1);
1821
}
1922
}

forc-node/Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@ path = "src/lib.rs"
1515
name = "forc-node"
1616
path = "src/main.rs"
1717

18+
[features]
19+
default = ["telemetry"]
20+
telemetry = ["forc-tracing/telemetry"]
21+
1822
[dependencies]
1923
anyhow.workspace = true
2024
clap = { workspace = true, features = ["derive", "string"] }

forc-node/src/main.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ fn init_logging() {
6060

6161
/// Initialize common setup for testnet and ignition modes
6262
fn init_cli_setup() -> anyhow::Result<()> {
63-
init_tracing_subscriber(Default::default());
63+
let _ = init_tracing_subscriber(Default::default());
6464
let current_version = get_fuel_core_version()?;
6565
let supported_min_version = Version::parse(MIN_FUEL_CORE_VERSION)?;
6666
if current_version < supported_min_version {

forc-tracing/CHANGELOG.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,16 @@
1+
# 0.72.0 (January 26th, 2026)
2+
3+
### Added
4+
5+
- Initial telemetry integration via `fuel-telemetry` crate (enabled via `telemetry` feature)
6+
- Telemetry macros: `info_telemetry!`, `debug_telemetry!`, `warn_telemetry!`, `error_telemetry!`, `trace_telemetry!`, `span_telemetry!`
7+
- Support for `Stdout` tracing writer mode
8+
9+
### Changed
10+
11+
- `init_tracing_subscriber()` now returns `anyhow::Result<Option<WorkerGuard>>` instead of using global static storage
12+
- Log level filter now only applies when explicitly set via CLI flags (previously defaulted to `INFO`)
13+
114
# 0.71.1 (December 9th, 2025)
215

316
### Fixed

forc-tracing/Cargo.toml

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,23 @@ name = "forc-tracing"
33
# When releasing to crates.io:
44
# - Remove path dependencies
55
# - Update CHANGELOG.md.
6-
# - Create "forc-tracing-0.71.x" git tag.
7-
version = "0.71.1"
6+
# - Create "forc-tracing-0.72.x" git tag.
7+
version = "0.72.0"
88
description = "Tracing utility shared between forc crates."
99
edition = "2021"
1010
authors.workspace = true
1111
homepage.workspace = true
1212
license.workspace = true
1313
repository.workspace = true
1414

15+
[features]
16+
default = ["telemetry"]
17+
telemetry = ["dep:fuel-telemetry"]
18+
1519
[dependencies]
1620
ansiterm.workspace = true
21+
anyhow.workspace = true
22+
fuel-telemetry = { workspace = true, optional = true }
1723
regex.workspace = true
1824
tracing.workspace = true
1925
tracing-subscriber = { workspace = true, features = ["ansi", "env-filter", "json"] }

forc-tracing/src/lib.rs

Lines changed: 141 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,54 @@
11
//! Utility items shared between forc crates.
22
3+
#[cfg(feature = "telemetry")]
4+
pub mod telemetry;
5+
36
use ansiterm::Colour;
47
use std::str;
58
use std::sync::atomic::{AtomicBool, Ordering};
69
use std::{env, io};
710
use tracing::{Level, Metadata};
811
pub use tracing_subscriber::{
912
self,
10-
filter::{filter_fn, EnvFilter, LevelFilter},
13+
filter::{filter_fn, EnvFilter, FilterExt, LevelFilter},
1114
fmt::{format::FmtSpan, MakeWriter},
12-
layer::SubscriberExt,
15+
layer::{Layer, SubscriberExt},
16+
registry,
17+
util::SubscriberInitExt,
18+
Layer as LayerTrait,
1319
};
1420

21+
#[cfg(feature = "telemetry")]
22+
use fuel_telemetry::WorkerGuard;
23+
1524
const ACTION_COLUMN_WIDTH: usize = 12;
1625

26+
/// Filter to hide telemetry spans from regular application logs
27+
#[derive(Clone)]
28+
pub struct HideTelemetryFilter;
29+
30+
impl<S> tracing_subscriber::layer::Filter<S> for HideTelemetryFilter {
31+
fn enabled(
32+
&self,
33+
meta: &Metadata<'_>,
34+
_cx: &tracing_subscriber::layer::Context<'_, S>,
35+
) -> bool {
36+
// Hide spans that are created by telemetry macros
37+
!meta.target().starts_with("fuel_telemetry")
38+
}
39+
}
40+
1741
// Global flag to track if JSON output mode is active
1842
static JSON_MODE_ACTIVE: AtomicBool = AtomicBool::new(false);
1943

44+
// Global flag to track if telemetry is disabled
45+
static TELEMETRY_DISABLED: AtomicBool = AtomicBool::new(false);
46+
47+
/// Check if telemetry is disabled
48+
pub fn is_telemetry_disabled() -> bool {
49+
TELEMETRY_DISABLED.load(Ordering::SeqCst)
50+
}
51+
2052
/// Check if JSON mode is currently active
2153
fn is_json_mode_active() -> bool {
2254
JSON_MODE_ACTIVE.load(Ordering::SeqCst)
@@ -181,7 +213,7 @@ pub fn println_red_err(txt: &str) {
181213

182214
const LOG_FILTER: &str = "RUST_LOG";
183215

184-
#[derive(PartialEq, Eq)]
216+
#[derive(PartialEq, Eq, Clone)]
185217
pub enum TracingWriter {
186218
/// Write ERROR and WARN to stderr and everything else to stdout.
187219
Stdio,
@@ -193,13 +225,14 @@ pub enum TracingWriter {
193225
Json,
194226
}
195227

196-
#[derive(Default)]
228+
#[derive(Default, Clone)]
197229
pub struct TracingSubscriberOptions {
198230
pub verbosity: Option<u8>,
199231
pub silent: Option<bool>,
200232
pub log_level: Option<LevelFilter>,
201233
pub writer_mode: Option<TracingWriter>,
202234
pub regex_filter: Option<String>,
235+
pub disable_telemetry: Option<bool>,
203236
}
204237

205238
// This allows us to write ERROR and WARN level logs to stderr and everything else to stdout.
@@ -232,15 +265,34 @@ impl<'a> MakeWriter<'a> for TracingWriter {
232265
}
233266
}
234267

235-
/// A subscriber built from default `tracing_subscriber::fmt::SubscriberBuilder` such that it would match directly using `println!` throughout the repo.
268+
/// A subscriber built using tracing_subscriber::registry with optional telemetry layer.
236269
///
237270
/// `RUST_LOG` environment variable can be used to set different minimum level for the subscriber, default is `INFO`.
238-
pub fn init_tracing_subscriber(options: TracingSubscriberOptions) {
239-
let env_filter = match env::var_os(LOG_FILTER) {
240-
Some(_) => EnvFilter::try_from_default_env().expect("Invalid `RUST_LOG` provided"),
241-
None => EnvFilter::new("info"),
242-
};
243-
271+
///
272+
/// # Telemetry
273+
///
274+
/// When the `telemetry` feature is enabled (default), telemetry data is sent to InfluxDB.
275+
/// This can be disabled via:
276+
/// - The `--disable-telemetry` CLI flag
277+
/// - The `FORC_DISABLE_TELEMETRY` environment variable
278+
/// - Setting `disable_telemetry: Some(true)` in options
279+
///
280+
/// # Return Value
281+
///
282+
/// Returns `Ok(Some(WorkerGuard))` when telemetry is enabled, which must be kept alive
283+
/// for the duration of the program to ensure telemetry is properly collected.
284+
/// Returns `Ok(None)` when telemetry is disabled.
285+
///
286+
/// # Example
287+
///
288+
/// ```ignore
289+
/// let _guard = init_tracing_subscriber(Default::default())?;
290+
/// // Your program code here
291+
/// // The guard is dropped when main() exits, ensuring proper cleanup
292+
/// ```
293+
pub fn init_tracing_subscriber(
294+
options: TracingSubscriberOptions,
295+
) -> anyhow::Result<Option<WorkerGuard>> {
244296
let level_filter = options
245297
.log_level
246298
.or_else(|| {
@@ -262,47 +314,90 @@ pub fn init_tracing_subscriber(options: TracingSubscriberOptions) {
262314
TracingWriter::Json
263315
}
264316
Some(TracingWriter::Stderr) => TracingWriter::Stderr,
317+
Some(TracingWriter::Stdout) => TracingWriter::Stdout,
265318
_ => TracingWriter::Stdio,
266319
};
267320

268-
let builder = tracing_subscriber::fmt::Subscriber::builder()
269-
.with_env_filter(env_filter)
270-
.with_ansi(true)
271-
.with_level(false)
272-
.with_file(false)
273-
.with_line_number(false)
274-
.without_time()
275-
.with_target(false)
276-
.with_writer(writer_mode);
277-
278-
// Use regex to filter logs - if provided; otherwise allow all logs
279-
let filter = filter_fn(move |metadata| {
280-
if let Some(ref regex_filter) = options.regex_filter {
281-
let regex = regex::Regex::new(regex_filter).unwrap();
282-
regex.is_match(metadata.target())
283-
} else {
284-
true
285-
}
286-
});
321+
// Set the global telemetry disabled flag
322+
let disabled = is_telemetry_disabled_from_options(&options);
323+
TELEMETRY_DISABLED.store(disabled, Ordering::SeqCst);
324+
325+
// Build the fmt layer with proper filtering
326+
let hide_telemetry_filter = HideTelemetryFilter;
327+
let regex_filter = options.regex_filter.clone();
328+
329+
macro_rules! init_registry {
330+
($registry:expr) => {{
331+
let env_filter = match env::var_os(LOG_FILTER) {
332+
Some(_) => EnvFilter::try_from_default_env().expect("Invalid `RUST_LOG` provided"),
333+
None => EnvFilter::new("info"),
334+
};
335+
336+
let regex_filter_fn = filter_fn(move |metadata| {
337+
if let Some(ref regex_filter) = regex_filter {
338+
let regex = regex::Regex::new(regex_filter).unwrap();
339+
regex.is_match(metadata.target())
340+
} else {
341+
true
342+
}
343+
});
344+
345+
let composite_filter = env_filter.and(hide_telemetry_filter).and(regex_filter_fn);
346+
347+
// Only apply level_filter if user explicitly set it via CLI flags
348+
if is_json_mode_active() {
349+
let layer = tracing_subscriber::fmt::layer()
350+
.json()
351+
.with_ansi(true)
352+
.with_level(false)
353+
.with_file(false)
354+
.with_line_number(false)
355+
.without_time()
356+
.with_target(false)
357+
.with_writer(writer_mode)
358+
.with_filter(composite_filter);
359+
360+
match level_filter {
361+
Some(filter) => $registry.with(layer.with_filter(filter)).init(),
362+
None => $registry.with(layer).init(),
363+
}
364+
} else {
365+
let layer = tracing_subscriber::fmt::layer()
366+
.with_ansi(true)
367+
.with_level(false)
368+
.with_file(false)
369+
.with_line_number(false)
370+
.without_time()
371+
.with_target(false)
372+
.with_writer(writer_mode)
373+
.with_filter(composite_filter);
374+
375+
match level_filter {
376+
Some(filter) => $registry.with(layer.with_filter(filter)).init(),
377+
None => $registry.with(layer).init(),
378+
}
379+
}
380+
}};
381+
}
287382

288-
match (is_json_mode_active(), level_filter) {
289-
(true, Some(level)) => {
290-
let subscriber = builder.json().with_max_level(level).finish().with(filter);
291-
tracing::subscriber::set_global_default(subscriber).expect("setting subscriber failed");
292-
}
293-
(true, None) => {
294-
let subscriber = builder.json().finish().with(filter);
295-
tracing::subscriber::set_global_default(subscriber).expect("setting subscriber failed");
296-
}
297-
(false, Some(level)) => {
298-
let subscriber = builder.with_max_level(level).finish().with(filter);
299-
tracing::subscriber::set_global_default(subscriber).expect("setting subscriber failed");
300-
}
301-
(false, None) => {
302-
let subscriber = builder.finish().with(filter);
303-
tracing::subscriber::set_global_default(subscriber).expect("setting subscriber failed");
383+
// Initialize registry with explicit layer handling
384+
#[cfg(feature = "telemetry")]
385+
{
386+
if !disabled {
387+
if let Ok((telemetry_layer, guard)) = fuel_telemetry::new_with_watchers!() {
388+
init_registry!(registry().with(telemetry_layer));
389+
return Ok(Some(guard));
390+
}
304391
}
305392
}
393+
394+
// Fallback: no telemetry layer
395+
init_registry!(registry());
396+
Ok(None)
397+
}
398+
399+
fn is_telemetry_disabled_from_options(options: &TracingSubscriberOptions) -> bool {
400+
options.disable_telemetry.unwrap_or(false) || env::var("FORC_DISABLE_TELEMETRY").is_ok()
306401
}
307402

308403
#[cfg(test)]

0 commit comments

Comments
 (0)