Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

honeycomb tracing subscription #1083

Merged
merged 12 commits into from
Apr 5, 2023
1,639 changes: 1,156 additions & 483 deletions Cargo.lock

Large diffs are not rendered by default.

46 changes: 23 additions & 23 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -45,32 +45,32 @@ homepage = "https://fuel.network/"
keywords = ["blockchain", "cryptocurrencies", "fuel-vm", "vm"]
license = "BUSL-1.1"
repository = "https://github.com/FuelLabs/fuel-core"
version = "0.17.6"
version = "0.17.7"

[workspace.dependencies]
# Workspace members
fuel-core = { version = "0.17.6", path = "./crates/fuel-core", default-features = false }
fuel-core-client-bin = { version = "0.17.6", path = "./bin/client" }
fuel-core-bin = { version = "0.17.6", path = "./bin/fuel-core" }
fuel-core-keygen = { version = "0.17.6", path = "./bin/keygen" }
fuel-core-chain-config = { version = "0.17.6", path = "./crates/chain-config" }
fuel-core-client = { version = "0.17.6", path = "./crates/client" }
fuel-core-database = { version = "0.17.6", path = "./crates/database" }
fuel-core-metrics = { version = "0.17.6", path = "./crates/metrics" }
fuel-core-services = { version = "0.17.6", path = "./crates/services" }
fuel-core-consensus-module = { version = "0.17.6", path = "./crates/services/consensus_module" }
fuel-core-bft = { version = "0.17.6", path = "./crates/services/consensus_module/bft" }
fuel-core-poa = { version = "0.17.6", path = "./crates/services/consensus_module/poa" }
fuel-core-executor = { version = "0.17.6", path = "./crates/services/executor" }
fuel-core-importer = { version = "0.17.6", path = "./crates/services/importer" }
fuel-core-p2p = { version = "0.17.6", path = "./crates/services/p2p" }
fuel-core-producer = { version = "0.17.6", path = "./crates/services/producer" }
fuel-core-relayer = { version = "0.17.6", path = "./crates/services/relayer" }
fuel-core-sync = { version = "0.17.6", path = "./crates/services/sync" }
fuel-core-txpool = { version = "0.17.6", path = "./crates/services/txpool" }
fuel-core-storage = { version = "0.17.6", path = "./crates/storage" }
fuel-core-trace = { version = "0.17.6", path = "./crates/trace" }
fuel-core-types = { version = "0.17.6", path = "./crates/types", default-features = false }
fuel-core = { version = "0.17.7", path = "./crates/fuel-core", default-features = false }
fuel-core-client-bin = { version = "0.17.7", path = "./bin/client" }
fuel-core-bin = { version = "0.17.7", path = "./bin/fuel-core" }
fuel-core-keygen = { version = "0.17.7", path = "./bin/keygen" }
fuel-core-chain-config = { version = "0.17.7", path = "./crates/chain-config" }
fuel-core-client = { version = "0.17.7", path = "./crates/client" }
fuel-core-database = { version = "0.17.7", path = "./crates/database" }
fuel-core-metrics = { version = "0.17.7", path = "./crates/metrics" }
fuel-core-services = { version = "0.17.7", path = "./crates/services" }
fuel-core-consensus-module = { version = "0.17.7", path = "./crates/services/consensus_module" }
fuel-core-bft = { version = "0.17.7", path = "./crates/services/consensus_module/bft" }
fuel-core-poa = { version = "0.17.7", path = "./crates/services/consensus_module/poa" }
fuel-core-executor = { version = "0.17.7", path = "./crates/services/executor" }
fuel-core-importer = { version = "0.17.7", path = "./crates/services/importer" }
fuel-core-p2p = { version = "0.17.7", path = "./crates/services/p2p" }
fuel-core-producer = { version = "0.17.7", path = "./crates/services/producer" }
fuel-core-relayer = { version = "0.17.7", path = "./crates/services/relayer" }
fuel-core-sync = { version = "0.17.7", path = "./crates/services/sync" }
fuel-core-txpool = { version = "0.17.7", path = "./crates/services/txpool" }
fuel-core-storage = { version = "0.17.7", path = "./crates/storage" }
fuel-core-trace = { version = "0.17.7", path = "./crates/trace" }
fuel-core-types = { version = "0.17.7", path = "./crates/types", default-features = false }
fuel-core-tests = { version = "0.0.0", path = "./tests" }
fuel-core-xtask = { version = "0.0.0", path = "./xtask" }

Expand Down
2 changes: 2 additions & 0 deletions bin/fuel-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,11 @@ dirs = "4.0"
fuel-core = { workspace = true }
humantime = "2.1"
lazy_static = { workspace = true }
libhoney-rust = { version = "0.1.6" }
serde_json = { workspace = true, features = ["raw_value"], optional = true }
tokio = { workspace = true, features = ["macros", "rt-multi-thread"] }
tracing = { workspace = true }
tracing-honeycomb = { version = "0.4", features = ["use_parking_lot"] }
tracing-subscriber = { workspace = true, features = [
"ansi",
"env-filter",
Expand Down
58 changes: 45 additions & 13 deletions bin/fuel-core/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,16 @@ use std::{
str::FromStr,
};
use tracing::log::warn;
use tracing_subscriber::filter::EnvFilter;
use tracing_honeycomb::{
self,
new_honeycomb_telemetry_layer,
};
use tracing_subscriber::{
filter::EnvFilter,
layer::SubscriberExt,
registry,
Layer,
};

lazy_static::lazy_static! {
pub static ref DEFAULT_DB_PATH: PathBuf = dirs::home_dir().unwrap().join(".fuel").join("db");
Expand Down Expand Up @@ -36,7 +45,11 @@ pub enum Fuel {
pub const LOG_FILTER: &str = "RUST_LOG";
pub const HUMAN_LOGGING: &str = "HUMAN_LOGGING";

pub async fn init_logging() -> anyhow::Result<()> {
pub async fn init_logging(
service_name: String,
network_name: String,
honeycomb_key: Option<String>,
) -> anyhow::Result<()> {
let filter = match env::var_os(LOG_FILTER) {
Some(_) => {
EnvFilter::try_from_default_env().expect("Invalid `RUST_LOG` provided")
Expand All @@ -51,33 +64,52 @@ pub async fn init_logging() -> anyhow::Result<()> {
})
.unwrap_or(true);

let sub = tracing_subscriber::fmt::Subscriber::builder()
.with_writer(std::io::stderr)
.with_env_filter(filter);
let layer = tracing_subscriber::fmt::Layer::default().with_writer(std::io::stderr);

if human_logging {
let telemetry_layer: Option<Box<dyn Layer<_> + Send + Sync>> =
honeycomb_key.map(|honeycomb_key| {
let service_name = format!("node-{}-{}", service_name, network_name);
let honeycomb_config = libhoney::Config {
options: libhoney::client::Options {
api_key: honeycomb_key,
dataset: service_name,
..libhoney::client::Options::default()
},
transmission_options: libhoney::transmission::Options::default(),
};
new_honeycomb_telemetry_layer("fuel-core", honeycomb_config).boxed()
});

let fmt = if human_logging {
// use pretty logs
sub.with_ansi(true)
layer
.with_ansi(true)
.with_level(true)
.with_line_number(true)
.init();
.boxed()
} else {
// use machine parseable structured logs
sub
layer
// disable terminal colors
.with_ansi(false)
.with_level(true)
.with_line_number(true)
// use json
.json()
.init();
}
.boxed()
};

let subscriber = registry::Registry::default() // provide underlying span data store
.with(filter) // filter out low-level debug tracing (eg tokio executor)
.with(fmt) // log to stdout
.with(telemetry_layer); // publish to honeycomb backend

tracing::subscriber::set_global_default(subscriber)
.expect("setting global default failed");
Ok(())
}

pub async fn run_cli() -> anyhow::Result<()> {
init_logging().await?;

let opt = Opt::try_parse();
if opt.is_err() {
let command = run::Command::try_parse();
Expand Down
28 changes: 27 additions & 1 deletion bin/fuel-core/src/cli/run.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#![allow(unused_variables)]
use crate::{
cli::{
init_logging,
run::consensus::PoATriggerArgs,
DEFAULT_DB_PATH,
},
Expand Down Expand Up @@ -67,6 +68,10 @@ pub struct Command {
#[clap(long = "port", default_value = "4000", env)]
pub port: u16,

/// Vanity name for node, used in telemetry
#[clap(long = "service-name", default_value = "fuel-core", value_parser, env)]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to propagate it in the helm chart? Or do we plan to set it via the env variables?

Copy link
Member Author

@Voxelot Voxelot Mar 31, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We already have a setting on helm for this but it needs to be linked to the cli here

pub service_name: String,

#[clap(
name = "DB_PATH",
long = "db-path",
Expand Down Expand Up @@ -153,13 +158,17 @@ pub struct Command {

#[clap(long = "tx-pool-ttl", default_value = "5m", env)]
pub tx_pool_ttl: humantime::Duration,

#[clap(long = "honeycomb-api-key", env)]
pub honeycomb_key: Option<String>,
}

impl Command {
pub fn get_config(self) -> anyhow::Result<Config> {
let Command {
ip,
port,
service_name: name,
database_path,
database_type,
chain_config,
Expand All @@ -181,6 +190,7 @@ impl Command {
max_da_lag,
max_wait_time,
tx_pool_ttl,
honeycomb_key,
} = self;

let addr = net::SocketAddr::new(ip, port);
Expand Down Expand Up @@ -267,14 +277,30 @@ impl Command {
#[cfg(feature = "p2p")]
sync: sync_args.into(),
consensus_key,
name: String::default(),
name,
verifier,
honeycomb_api_key: honeycomb_key,
})
}
}

pub async fn exec(command: Command) -> anyhow::Result<()> {
let config = command.get_config()?;
let network_name = {
#[cfg(feature = "p2p")]
{
let config = config.p2p.as_ref().unwrap();
config.network_name.clone()
}
#[cfg(not(feature = "p2p"))]
"default_network".to_string()
};
init_logging(
config.name.clone(),
network_name,
config.honeycomb_api_key.clone(),
)
.await?;
// log fuel-core version
info!("Fuel Core version v{}", env!("CARGO_PKG_VERSION"));
trace!("Initializing in TRACE mode.");
Expand Down
7 changes: 5 additions & 2 deletions bin/fuel-core/src/cli/snapshot.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use crate::cli::DEFAULT_DB_PATH;
use crate::cli::{
init_logging,
DEFAULT_DB_PATH,
};
use clap::Parser;
use std::path::PathBuf;

Expand Down Expand Up @@ -36,7 +39,7 @@ pub async fn exec(command: Command) -> anyhow::Result<()> {
},
database::Database,
};

init_logging("snapshot".to_string(), "local".to_string(), None).await?;
let path = command.database_path;
let config: ChainConfig = command.chain_config.parse()?;
let db = Database::open(&path).context(format!(
Expand Down
1 change: 1 addition & 0 deletions crates/fuel-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ tokio = { workspace = true, features = ["macros", "rt-multi-thread"] }
tokio-stream = { workspace = true, features = ["sync"] }
tower-http = { version = "0.3", features = ["set-header", "trace"] }
tracing = { workspace = true }
tracing-honeycomb = { version = "0.4", features = ["use_parking_lot"] }
uuid = { version = "1.1", features = ["v4"] }

[dev-dependencies]
Expand Down
2 changes: 2 additions & 0 deletions crates/fuel-core/src/graphql_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use fuel_core_types::{
};
use std::net::SocketAddr;

mod honeycomb;
pub mod ports;
pub mod service;

Expand All @@ -23,6 +24,7 @@ pub struct Config {
pub max_depth: usize,
pub transaction_parameters: ConsensusParameters,
pub consensus_key: Option<Secret<SecretKeyWrapper>>,
pub honeycomb_enabled: bool,
}

pub trait IntoApiResult<T> {
Expand Down
117 changes: 117 additions & 0 deletions crates/fuel-core/src/graphql_api/honeycomb.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
use async_graphql::{
extensions::{
Extension,
ExtensionContext,
ExtensionFactory,
NextExecute,
NextParseQuery,
NextRequest,
NextResolve,
NextSubscribe,
NextValidation,
ResolveInfo,
Tracing,
},
parser::types::ExecutableDocument,
Response,
ServerError,
ServerResult,
ValidationResult,
Value,
Variables,
};
use futures::stream::BoxStream;
use std::sync::Arc;
use tracing::instrument;
use tracing_honeycomb::{
register_dist_tracing_root,
TraceId,
};

pub(crate) struct HoneyTrace;

impl ExtensionFactory for HoneyTrace {
fn create(&self) -> Arc<dyn Extension> {
Arc::new(InternalHoneyTrace {
inner_trace: Tracing::create(&Tracing),
})
}
}

struct InternalHoneyTrace {
inner_trace: Arc<dyn Extension>,
}

#[async_trait::async_trait]
impl Extension for InternalHoneyTrace {
#[instrument(skip(self, ctx, next))]
async fn request(
&self,
ctx: &ExtensionContext<'_>,
next: NextRequest<'_>,
) -> Response {
let response = self.inner_trace.request(ctx, next);
let _ = register_dist_tracing_root(TraceId::new(), None);
response.await
}

#[instrument(skip(self, ctx, stream, next))]
fn subscribe<'s>(
&self,
ctx: &ExtensionContext<'_>,
stream: BoxStream<'s, Response>,
next: NextSubscribe<'_>,
) -> BoxStream<'s, Response> {
let response = self.inner_trace.subscribe(ctx, stream, next);
let _ = register_dist_tracing_root(TraceId::new(), None);
response
}

#[instrument(skip(self, ctx, query, variables, next))]
async fn parse_query(
&self,
ctx: &ExtensionContext<'_>,
query: &str,
variables: &Variables,
next: NextParseQuery<'_>,
) -> ServerResult<ExecutableDocument> {
let response = self.inner_trace.parse_query(ctx, query, variables, next);
let _ = register_dist_tracing_root(TraceId::new(), None);
response.await
}

#[instrument(skip(self, ctx, next))]
async fn validation(
&self,
ctx: &ExtensionContext<'_>,
next: NextValidation<'_>,
) -> Result<ValidationResult, Vec<ServerError>> {
let response = self.inner_trace.validation(ctx, next);
let _ = register_dist_tracing_root(TraceId::new(), None);
response.await
}

#[instrument(skip(self, ctx, operation_name, next))]
async fn execute(
&self,
ctx: &ExtensionContext<'_>,
operation_name: Option<&str>,
next: NextExecute<'_>,
) -> Response {
let response = self.inner_trace.execute(ctx, operation_name, next);
let _ = register_dist_tracing_root(TraceId::new(), None);
response.await
}

#[instrument(skip(self, ctx, info, next))]
async fn resolve(
&self,
ctx: &ExtensionContext<'_>,
info: ResolveInfo<'_>,
next: NextResolve<'_>,
) -> ServerResult<Option<Value>> {
let response = self.inner_trace.resolve(ctx, info, next);
let _ = register_dist_tracing_root(TraceId::new(), None);
response.await
}
}
Loading