1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102
//! Tracing subscriber for emitting logs into Cloudflare's syslog pipeline (queryable via Kibana).
//!
//! Follow [How To: Generate a WShim Token] to generate a logging token and put it in your worker
//! secrets:
//! ```ignore
//! wrangler secret put LOGGING_TOKEN
//! ```
//!
//! Usage in worker using workers-rs:
//! ```rust
//! use tracing::{debug, info, info_span, Instrument};
//! use worker::*;
//! use worker_cf_logging::initialize_tracing;
//!
//! #[event(fetch)]
//! pub async fn main(req: Request, env: Env, ctx: worker::Context) -> Result<Response> {
//! let logging_token = env.secret("LOGGING_TOKEN")?.to_string();
//!
//! let log_level = match env.var("LOG_LEVEL") {
//! Ok(var) => var.to_string(),
//! Err(_) => "info".to_string(),
//! };
//!
//! let logger = initialize_tracing(&log_level, logging_token, true);
//!
//! let res = handle(req).instrument(info_span!("handle")).await?;
//!
//! ctx.wait_until(async move {
//! _ = logger.flush().await;
//! });
//!
//! Ok(res)
//! }
//!
//! async fn handle(req: Request) -> Result<Response> {
//! info!(path = req.path(), req_method = ?req.method(), "incoming request");
//!
//! let req = worker::Fetch::Url(Url::parse("https://httpbin.org/ip")?);
//!
//! let ip = req.send().await?.text().await?;
//!
//! debug!(
//! ip_response = ?ip,
//! veg = "potato",
//! float = 0.12345,
//! signed = -12345,
//! unsigned = 12345u64,
//! flag = false,
//! "my favourites"
//! );
//!
//! Response::ok("bienvenue")
//! }
//!
//! ```
//!
//! You can then query your logs in Kibana, the service being the one you specified when generating
//! the logging token.
//!
//! [How To: Generate a WShim Token]: https://wiki.cfdata.org/display/OBS/How+To%3A+Generate+a+WShim+Token
//! [Tracing subscriber]: https://docs.rs/tracing-subscriber/latest/tracing_subscriber/
mod logger;
mod timing;
pub use logger::SyslogLogger;
use std::sync::Once;
use timing::WasmTimingLayer;
use tracing_subscriber::util::SubscriberInitExt;
use tracing_subscriber::{layer::SubscriberExt, EnvFilter};
use tracing_subscriber::registry;
static mut LOGGER: Option<SyslogLogger> = None;
static INITIALIZE_TRACING: Once = Once::new();
/// Initializes tracing subscriber.
///
/// Initialization is only performed once, meaning subsequent calls are ignored.
///
/// Enabling timings will attempt to time and log spans. NB. Time is only updated on IO in Workers.
///
/// Returns the underlying logger which **must** be called to flush to Kibana.
pub fn initialize_tracing(
filter_level: &str,
logging_token: String,
enable_timings: bool,
) -> SyslogLogger {
unsafe {
INITIALIZE_TRACING.call_once(|| {
let logger = SyslogLogger::new(&logging_token);
LOGGER = Some(logger.clone());
registry()
.with(enable_timings.then(WasmTimingLayer::new))
.with(logger)
.with(EnvFilter::new(filter_level))
.init();
});
LOGGER.as_ref().cloned().unwrap()
}
}