#![warn(missing_docs)]
pub use postrust_auth;
pub use postrust_core;
pub use postrust_response;
pub use postrust_server;
pub use postrust_sql;
pub use lambda_http::Error;
pub fn init_tracing() {
let filter = std::env::var("RUST_LOG").unwrap_or_else(|_| {
let level = std::env::var("PGRST_LOG_LEVEL")
.ok()
.and_then(|v| postrust_core::LogLevel::parse_config(&v))
.unwrap_or_else(|| postrust_core::AppConfig::default().log_level);
format!("postrust={}", level.to_tracing())
});
let format = std::env::var("PGRST_LOG_FORMAT")
.ok()
.and_then(|v| postrust_core::LogFormat::parse_config(&v))
.unwrap_or_default();
#[cfg(feature = "otel")]
if let Some(otel) = postrust_server::otel::layer() {
use tracing_subscriber::layer::SubscriberExt as _;
use tracing_subscriber::util::SubscriberInitExt as _;
use tracing_subscriber::Layer as _;
let filter = match std::env::var_os("RUST_LOG") {
Some(_) => filter,
None => format!("{filter},opentelemetry=warn,opentelemetry_sdk=warn"),
};
let log = tracing_subscriber::fmt::layer()
.with_target(false)
.without_time();
let (text, json) = match format {
postrust_core::LogFormat::Text => (Some(log), None),
postrust_core::LogFormat::Json => (None, Some(log.json())),
};
tracing_subscriber::registry()
.with(
text.with_filter(tracing_subscriber::EnvFilter::new(&filter))
.and_then(json.with_filter(tracing_subscriber::EnvFilter::new(&filter))),
)
.with(otel)
.init();
postrust_server::otel::log_startup();
return;
}
let builder = tracing_subscriber::fmt()
.with_env_filter(tracing_subscriber::EnvFilter::new(filter))
.with_target(false)
.without_time();
match format {
postrust_core::LogFormat::Text => builder.init(),
postrust_core::LogFormat::Json => builder.json().init(),
}
#[cfg(feature = "otel")]
postrust_server::otel::log_startup();
}
pub fn config_from_env() -> Result<postrust_core::AppConfig, Error> {
let mut config = postrust_core::AppConfig::try_from_env()?;
if ["PGRST_DB_POOL", "PGRST_DB_POOL_SIZE"]
.iter()
.all(|var| std::env::var_os(var).is_none())
{
config.db_pool_size = 2;
}
Ok(config)
}
pub async fn run(app: postrust_server::App) -> Result<(), Error> {
#[cfg(feature = "otel")]
{
postrust_server::otel::init_metrics(false);
if postrust_server::otel::exporting() {
let router = app.router.layer(FlushLayer);
return lambda_http::run(router).await;
}
}
lambda_http::run(app.router).await
}
#[cfg(feature = "otel")]
#[derive(Clone, Copy, Debug, Default)]
pub struct FlushLayer;
#[cfg(feature = "otel")]
impl<S> tower::Layer<S> for FlushLayer {
type Service = FlushAfter<S>;
fn layer(&self, inner: S) -> Self::Service {
FlushAfter { inner }
}
}
#[cfg(feature = "otel")]
#[derive(Clone, Debug)]
pub struct FlushAfter<S> {
inner: S,
}
#[cfg(feature = "otel")]
impl<S, R> tower::Service<R> for FlushAfter<S>
where
S: tower::Service<R>,
S::Future: Send + 'static,
S::Response: Send + 'static,
S::Error: Send + 'static,
{
type Response = S::Response;
type Error = S::Error;
type Future =
std::pin::Pin<Box<dyn std::future::Future<Output = Result<S::Response, S::Error>> + Send>>;
fn poll_ready(
&mut self,
cx: &mut std::task::Context<'_>,
) -> std::task::Poll<Result<(), Self::Error>> {
self.inner.poll_ready(cx)
}
fn call(&mut self, request: R) -> Self::Future {
let answer = self.inner.call(request);
Box::pin(async move {
let response = answer.await;
postrust_server::otel::flush().await;
response
})
}
}
#[cfg(feature = "otel")]
pub fn flush_after_each_invocation() -> bool {
postrust_server::otel::exporting()
}