add a flag to log traces to stdout (#931)

### What

Add a flag `--export-traces-stdout` to log traces to stdout. Default is
disabled.

Command-line flag - `--export-traces-stdout`
Env var - `EXPORT_TRACES_STDOUT`

### How
Introduce a new command line flag. Make `initialize_tracing` accept a
`bool`, and setup the stdout exporter based on that.

<!-- How is it trying to accomplish it (what are the implementation
steps)? -->

V3_GIT_ORIGIN_REV_ID: f39d6f863fd2bca65ad89f1cef4b077aa9eabc5b
This commit is contained in:
Anon Ray 2024-08-05 13:31:38 +05:30 committed by hasura-bot
parent 12ed058661
commit 4d31c4b42e
8 changed files with 90 additions and 24 deletions

2
v3/Cargo.lock generated
View File

@ -1598,7 +1598,9 @@ version = "0.1.0"
dependencies = [
"anyhow",
"axum",
"clap",
"http 0.2.12",
"serde",
"serde_json",
"tokio",
"tower-http",

View File

@ -4,6 +4,10 @@
### Added
- A new CLI flag (`--export-traces-stdout`) and env var (`EXPORT_TRACES_STDOUT`)
is introduced to enable logging of traces to STDOUT. By default, logging is
disabled.
#### Remote Relationships Predicates
We have significantly enhanced our permission capabilities to support remote

View File

@ -14,7 +14,9 @@ tracing-util = { path = "../../utils/tracing-util" }
anyhow = { workspace = true }
axum = { workspace = true }
clap = { workspace = true, features = ["derive", "env"] }
http = { workspace = true }
serde = { workspace = true }
serde_json = { workspace = true }
tokio = { workspace = true, features = ["full"] }
tracing = { workspace = true }

View File

@ -3,21 +3,43 @@ use std::env;
use std::net;
use axum::{http::header::HeaderMap, response::Json, routing::post, Router};
use clap::Parser;
use serde::Serialize;
use serde_json::Value;
use tower_http::trace::TraceLayer;
use tracing::debug;
const DEFAULT_PORT: u16 = 3050;
#[derive(Parser, Serialize)]
struct ServerOptions {
/// The OpenTelemetry collector endpoint.
#[arg(long, value_name = "URL", env = "OTLP_ENDPOINT")]
otlp_endpoint: Option<String>,
/// Log traces to stdout.
#[arg(long, env = "EXPORT_TRACES_STDOUT")]
export_traces_stdout: bool,
}
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let otlp_endpoint_option = env::var("OTLP_ENDPOINT").ok();
tracing_util::initialize_tracing(
otlp_endpoint_option.as_deref(),
env!("CARGO_PKG_NAME"),
None,
true,
)?;
let server_options = ServerOptions::parse();
if let Some(otlp_endpoint) = server_options.otlp_endpoint {
let export_traces_stdout = if server_options.export_traces_stdout {
tracing_util::ExportTracesStdout::Enable
} else {
tracing_util::ExportTracesStdout::Disable
};
tracing_util::initialize_tracing(
Some(&otlp_endpoint),
env!("CARGO_PKG_NAME"),
None,
tracing_util::PropagateBaggage::Enable,
export_traces_stdout,
)?;
}
let app = Router::new()
.route("/validate-request", post(validate_request))

View File

@ -1058,7 +1058,13 @@ mod tests {
#[tokio::test]
// This test emulates scenarios where multiple JWKs are present and only the correct encoded JWT is used to decode the Hasura claims
async fn test_jwk() -> anyhow::Result<()> {
tracing_util::initialize_tracing(None, "test_jwk", None, false)?;
tracing_util::initialize_tracing(
None,
"test_jwk",
None,
tracing_util::PropagateBaggage::Disable,
tracing_util::ExportTracesStdout::Disable,
)?;
let mut server = mockito::Server::new_async().await;
let url = server.url();

View File

@ -53,7 +53,7 @@ const MB: usize = 1_048_576;
#[derive(Parser, Serialize)]
#[command(version = VERSION)]
struct ServerOptions {
/// The path to the metadata file, used to construct the schema.g
/// The path to the metadata file, used to construct the schema.
#[arg(long, value_name = "PATH", env = "METADATA_PATH")]
metadata_path: PathBuf,
/// An introspection metadata file, served over `/metadata` if provided.
@ -108,6 +108,10 @@ struct ServerOptions {
/// sensitve information.
#[arg(long, env = "EXPOSE_INTERNAL_ERRORS")]
expose_internal_errors: bool,
/// Log traces to stdout.
#[arg(long, env = "EXPORT_TRACES_STDOUT")]
export_traces_stdout: bool,
}
struct EngineState {
@ -122,13 +126,19 @@ struct EngineState {
#[tokio::main]
#[allow(clippy::print_stdout)]
async fn main() {
let server = ServerOptions::parse();
let server_options = ServerOptions::parse();
let export_traces_stdout = if server_options.export_traces_stdout {
tracing_util::ExportTracesStdout::Enable
} else {
tracing_util::ExportTracesStdout::Disable
};
tracing_util::initialize_tracing(
server.otlp_endpoint.as_deref(),
server_options.otlp_endpoint.as_deref(),
"graphql-engine",
Some(VERSION),
false,
tracing_util::PropagateBaggage::Disable,
export_traces_stdout,
)
.unwrap();
@ -137,7 +147,7 @@ async fn main() {
"app init",
"App initialization",
SpanVisibility::Internal,
|| Box::pin(start_engine(&server)),
|| Box::pin(start_engine(&server_options)),
)
.await
{

View File

@ -7,7 +7,7 @@ mod tracer;
// Avoid conflicts with `http` crate
pub use crate::http::TraceableHttpResponse;
pub use request::get_trace_headers;
pub use setup::{initialize_tracing, shutdown_tracer};
pub use setup::{initialize_tracing, shutdown_tracer, ExportTracesStdout, PropagateBaggage};
pub use traceable::{ErrorVisibility, Successful, Traceable, TraceableError};
pub use tracer::{
add_event_on_active_span, global_tracer, set_attribute_on_active_span,

View File

@ -10,6 +10,20 @@ use opentelemetry_sdk::propagation::{BaggagePropagator, TraceContextPropagator};
use opentelemetry_sdk::trace::{SpanProcessor, TracerProvider};
use opentelemetry_semantic_conventions as semcov;
/// A configuration type to enable/disable baggage propagation
#[derive(Debug, Copy, Clone)]
pub enum PropagateBaggage {
Enable,
Disable,
}
/// A configuration type to enable/disable exporting traces to stdout
#[derive(Debug, Copy, Clone)]
pub enum ExportTracesStdout {
Enable,
Disable,
}
/// Initialize the tracing setup.
///
/// This includes setting the global tracer and propagators:
@ -34,7 +48,8 @@ pub fn initialize_tracing(
endpoint: Option<&str>,
service_name: &'static str,
service_version: Option<&'static str>,
propagate_caller_baggage: bool,
propagate_caller_baggage: PropagateBaggage,
enable_stdout_export: ExportTracesStdout,
) -> Result<(), TraceError> {
// install global collector configured based on RUST_LOG env var.
tracing_subscriber::fmt::init();
@ -42,10 +57,11 @@ pub fn initialize_tracing(
global::set_text_map_propagator(TextMapCompositePropagator::new(vec![
Box::new(TraceContextPropagator::new()),
Box::new(opentelemetry_zipkin::Propagator::new()),
if propagate_caller_baggage {
Box::new(BaggagePropagator::new())
} else {
Box::new(InjectOnlyTextMapPropagator(BaggagePropagator::new()))
match propagate_caller_baggage {
PropagateBaggage::Enable => Box::new(BaggagePropagator::new()),
PropagateBaggage::Disable => {
Box::new(InjectOnlyTextMapPropagator(BaggagePropagator::new()))
}
},
Box::new(TraceContextResponsePropagator::new()),
]));
@ -67,13 +83,17 @@ pub fn initialize_tracing(
)
.build_span_exporter()?;
let stdout_exporter = opentelemetry_stdout::SpanExporter::default();
let tracer_provider = TracerProvider::builder()
.with_simple_exporter(stdout_exporter)
let mut tracer_provider_builder = TracerProvider::builder()
.with_batch_exporter(otlp_exporter, opentelemetry_sdk::runtime::Tokio)
.with_span_processor(BaggageSpanProcessor())
.with_config(config)
.build();
.with_config(config);
if let ExportTracesStdout::Enable = enable_stdout_export {
let stdout_exporter = opentelemetry_stdout::SpanExporter::default();
tracer_provider_builder = tracer_provider_builder.with_simple_exporter(stdout_exporter);
}
let tracer_provider = tracer_provider_builder.build();
// Set the global tracer provider so everyone gets this setup.
global::set_tracer_provider(tracer_provider);