MCPcopy Create free account
hub / github.com/clockworklabs/SpacetimeDB / logs

Function logs

crates/client-api/src/routes/database.rs:620–683  ·  view source on GitHub ↗
(
    State(worker_ctx): State<S>,
    Path(LogsParams { name_or_identity }): Path<LogsParams>,
    Query(LogsQuery { num_lines, follow }): Query<LogsQuery>,
    Extension(auth): Extension<SpacetimeAu

Source from the content-addressed store, hash-verified

618}
619
620pub async fn logs<S>(
621 State(worker_ctx): State<S>,
622 Path(LogsParams { name_or_identity }): Path<LogsParams>,
623 Query(LogsQuery { num_lines, follow }): Query<LogsQuery>,
624 Extension(auth): Extension<SpacetimeAuth>,
625) -> axum::response::Result<impl IntoResponse>
626where
627 S: ControlStateDelegate + NodeDelegate + Authorization,
628{
629 // You should not be able to read the logs from a database that you do not own
630 // so, unless you are the owner, this will fail.
631
632 let database_identity: Identity = name_or_identity.resolve(&worker_ctx).await?;
633 let database = worker_ctx_find_database(&worker_ctx, &database_identity)
634 .await?
635 .ok_or(NO_SUCH_DATABASE)?;
636
637 worker_ctx
638 .authorize_action(auth.claims.identity, database.database_identity, Action::ViewModuleLogs)
639 .await?;
640
641 fn log_err(database: Identity) -> impl Fn(&io::Error) {
642 move |e| warn!("error serving module logs for database {database}: {e:#}")
643 }
644
645 let body = match worker_ctx.leader(database.id).await {
646 Ok(host) => {
647 let module = host.module().await.map_err(log_and_500)?;
648 let logs = module.database_logger().tail(num_lines, follow).await.map_err(|e| {
649 warn!("database={database_identity} unable to tail logs: {e:#}");
650 (StatusCode::SERVICE_UNAVAILABLE, "Logs are temporarily not available")
651 })?;
652 Body::from_stream(logs.inspect_err(log_err(database_identity)))
653 }
654 Err(e) if e.is_misdirected() => return Err(MISDIRECTED.into()),
655 // If this is the right node for the current or last-known leader,
656 // we may still be able to serve logs from disk,
657 // even if we can't get hold of a running [ModuleHost].
658 Err(e) => {
659 warn!("could not obtain leader host for module logs: {e:#}");
660 let Some(replica) = worker_ctx.get_leader_replica_by_database(database.id).await else {
661 return Err(MISDIRECTED.into());
662 };
663 let logs_dir = worker_ctx.module_logs_dir(replica.id);
664 if !logs_dir.0.try_exists().map_err(log_and_500)? {
665 // Probably an in-memory database.
666 // Logs may become available at a later time.
667 return Err((
668 StatusCode::SERVICE_UNAVAILABLE,
669 "Database is not running and doesn't have persistent logs",
670 )
671 .into());
672 }
673 let logs = DatabaseLogger::read_latest_on_disk(logs_dir, num_lines);
674 Body::from_stream(logs.inspect_err(log_err(database_identity)))
675 }
676 };
677

Callers

nothing calls this directly

Calls 15

worker_ctx_find_databaseFunction · 0.85
log_errFunction · 0.85
mime_ndjsonFunction · 0.85
tailMethod · 0.80
database_loggerMethod · 0.80
ErrFunction · 0.50
OkFunction · 0.50
newFunction · 0.50
resolveMethod · 0.45
authorize_actionMethod · 0.45
leaderMethod · 0.45
moduleMethod · 0.45

Tested by

no test coverage detected

Used in the wild real call sites across dependent graphs

searching dependent graphs…