From 06b25df3d4ddbd90c666d4db2e4a35623642746c Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Thu, 2 Jul 2026 21:23:10 -0400 Subject: [PATCH] log more in handlers --- .../generate/common/generation_debug_logs.rs | 62 ++++++++++++++++++ .../endpoints/generate/common/mod.rs | 3 +- ...eedance_1_0_lite_image_to_video_handler.rs | 44 ++++++++++--- ...seedance_1_0_pro_image_to_video_handler.rs | 44 ++++++++++--- ...p5_pro_multi_function_video_gen_handler.rs | 65 ++++++++++++++----- ...ce_2p0_multi_function_video_gen_handler.rs | 40 +++++++++++- 6 files changed, 221 insertions(+), 37 deletions(-) create mode 100644 crates/service/web/storyteller_web/src/http_server/endpoints/generate/common/generation_debug_logs.rs diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/generate/common/generation_debug_logs.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/generate/common/generation_debug_logs.rs new file mode 100644 index 0000000000..c59ab66f45 --- /dev/null +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/generate/common/generation_debug_logs.rs @@ -0,0 +1,62 @@ +use log::warn; +use sqlx::{Executor, MySql}; + +use enums::by_table::debug_logs::debug_log_level::DebugLogLevel; +use enums::by_table::debug_logs::debug_log_type::DebugLogType; +use mysql_queries::queries::debug_logs::insert_debug_log::{insert_debug_log, InsertDebugLogArgs}; +use tokens::tokens::non_unique::debug_logs_event_token::DebugLogEventToken; +use tokens::tokens::users::UserToken; + +/// Best-effort info-level debug log of an inbound generation HTTP request. +/// Never fails the request — insert errors are logged and swallowed. +pub async fn insert_generation_request_debug_log<'e, 'c: 'e, E>( + debug_log_event_token: &'e DebugLogEventToken, + user_token: &'e UserToken, + ip_address: &'e str, + request_url: &'e str, + request_json: &'e str, + mysql_executor: E, +) where + E: 'c + Executor<'c, Database = MySql>, +{ + if let Err(err) = insert_debug_log(InsertDebugLogArgs { + apriori_debug_log_event_token: Some(debug_log_event_token), + maybe_creator_user_token: Some(user_token), + debug_log_type: DebugLogType::HttpRequest, + maybe_log_level: Some(DebugLogLevel::Info), + maybe_ip_address: Some(ip_address), + maybe_url: Some(request_url), + message: request_json, + mysql_executor, + phantom: Default::default(), + }).await { + warn!("Failed to insert HTTP request debug log: {:?}", err); + } +} + +/// Best-effort error-level debug log of a generation backend failure. +/// Never fails the request — insert errors are logged and swallowed. +pub async fn insert_generation_failure_debug_log<'e, 'c: 'e, E>( + debug_log_event_token: &'e DebugLogEventToken, + user_token: &'e UserToken, + ip_address: &'e str, + request_url: &'e str, + error_message: &'e str, + mysql_executor: E, +) where + E: 'c + Executor<'c, Database = MySql>, +{ + if let Err(err) = insert_debug_log(InsertDebugLogArgs { + apriori_debug_log_event_token: Some(debug_log_event_token), + maybe_creator_user_token: Some(user_token), + debug_log_type: DebugLogType::BackendFailure, + maybe_log_level: Some(DebugLogLevel::Error), + maybe_ip_address: Some(ip_address), + maybe_url: Some(request_url), + message: error_message, + mysql_executor, + phantom: Default::default(), + }).await { + warn!("Failed to insert generation failure debug log: {:?}", err); + } +} diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/generate/common/mod.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/generate/common/mod.rs index fc99a874d5..f32dae75a9 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/generate/common/mod.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/generate/common/mod.rs @@ -1,4 +1,5 @@ +mod test_synthetic_failure_reason; +pub mod generation_debug_logs; pub mod job_failure_test; pub mod map_seedance2pro_web_errors; pub mod payments_error_test; -mod test_synthetic_failure_reason; \ No newline at end of file diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/generate/video/image/generate_seedance_1_0_lite_image_to_video_handler.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/generate/video/image/generate_seedance_1_0_lite_image_to_video_handler.rs index 996cb7b726..ecbf9896aa 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/generate/video/image/generate_seedance_1_0_lite_image_to_video_handler.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/generate/video/image/generate_seedance_1_0_lite_image_to_video_handler.rs @@ -3,6 +3,9 @@ use std::sync::Arc; use crate::billing::wallets::attempt_wallet_deduction::attempt_wallet_deduction_else_common_web_error; use crate::http_server::common_responses::common_web_error::CommonWebError; use crate::http_server::common_responses::media::media_links_builder::MediaLinksBuilder; +use crate::http_server::endpoints::generate::common::generation_debug_logs::{ + insert_generation_failure_debug_log, insert_generation_request_debug_log, +}; use crate::http_server::endpoints::generate::common::payments_error_test::payments_error_test; use crate::http_server::endpoints::media_files::helpers::get_media_domain::get_media_domain; use crate::http_server::validations::validate_idempotency_token_format::validate_idempotency_token_format; @@ -38,6 +41,7 @@ use mysql_queries::queries::media_files::get::get_media_file::{get_media_file, g use mysql_queries::queries::prompts::insert_prompt::{insert_prompt, InsertPromptArgs}; use sqlx::Acquire; use tokens::tokens::generic_inference_jobs::InferenceJobToken; +use tokens::tokens::non_unique::debug_logs_event_token::DebugLogEventToken; use utoipa::ToSchema; /// Seedance 1.0 Lite Image to Video @@ -84,6 +88,21 @@ pub async fn generate_seedance_1_0_lite_image_to_video_handler( } }; + // ==================== DEBUG LOG: HTTP REQUEST ==================== // + + let debug_log_event_token = DebugLogEventToken::generate(); + let ip_address = get_request_ip(&http_request); + let request_url = http_request.uri().to_string(); + + insert_generation_request_debug_log( + &debug_log_event_token, + user_token, + &ip_address, + &request_url, + &serde_json::to_string(&*request).unwrap_or_default(), + &mut *mysql_connection, + ).await; + let start_frame_media_file_token = match &request.media_file_token { Some(token) => token, None => { @@ -208,12 +227,21 @@ pub async fn generate_seedance_1_0_lite_image_to_video_handler( api_key: &server_state.inference_providers.fal.api_key, }; - let fal_result = enqueue_seedance_1_lite_image_to_video_webhook(args) - .await - .map_err(|err| { - warn!("Error calling enqueue_seedance_1_lite_image_to_video_webhook: {:?}", err); - CommonWebError::from_error(err) - })?; + let fal_result = match enqueue_seedance_1_lite_image_to_video_webhook(args).await { + Ok(result) => result, + Err(err) => { + warn!("Error calling enqueue_seedance_1_lite_image_to_video_webhook: {:?}", err); + insert_generation_failure_debug_log( + &debug_log_event_token, + user_token, + &ip_address, + &request_url, + &format!("Seedance 1.0 Lite generation failed: {:?}", err), + &mut *mysql_connection, + ).await; + return Err(CommonWebError::from_error(err)); + } + }; let external_job_id = fal_result.request_id .ok_or_else(|| { @@ -223,8 +251,6 @@ pub async fn generate_seedance_1_0_lite_image_to_video_handler( info!("Fal request_id: {}", external_job_id); - let ip_address = get_request_ip(&http_request); - let mut transaction = mysql_connection .begin() .await @@ -294,7 +320,7 @@ pub async fn generate_seedance_1_0_lite_image_to_video_handler( starting_job_status_override: None, maybe_frontend_failure_category: None, maybe_failure_reason: None, - maybe_debug_log_event_token: None, + maybe_debug_log_event_token: Some(&debug_log_event_token), phantom: Default::default(), }).await; diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/generate/video/image/generate_seedance_1_0_pro_image_to_video_handler.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/generate/video/image/generate_seedance_1_0_pro_image_to_video_handler.rs index 0e15c363c9..b9d1b04e89 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/generate/video/image/generate_seedance_1_0_pro_image_to_video_handler.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/generate/video/image/generate_seedance_1_0_pro_image_to_video_handler.rs @@ -3,6 +3,9 @@ use std::sync::Arc; use crate::billing::wallets::attempt_wallet_deduction::attempt_wallet_deduction_else_common_web_error; use crate::http_server::common_responses::common_web_error::CommonWebError; use crate::http_server::common_responses::media::media_links_builder::MediaLinksBuilder; +use crate::http_server::endpoints::generate::common::generation_debug_logs::{ + insert_generation_failure_debug_log, insert_generation_request_debug_log, +}; use crate::http_server::endpoints::generate::common::payments_error_test::payments_error_test; use crate::http_server::endpoints::media_files::helpers::get_media_domain::get_media_domain; use crate::http_server::validations::validate_idempotency_token_format::validate_idempotency_token_format; @@ -35,6 +38,7 @@ use mysql_queries::queries::media_files::get::get_media_file::{get_media_file, g use mysql_queries::queries::prompts::insert_prompt::{insert_prompt, InsertPromptArgs}; use sqlx::Acquire; use tokens::tokens::generic_inference_jobs::InferenceJobToken; +use tokens::tokens::non_unique::debug_logs_event_token::DebugLogEventToken; use utoipa::ToSchema; /// Seedance 1.0 Pro Image to Video @@ -81,6 +85,21 @@ pub async fn generate_seedance_1_0_pro_image_to_video_handler( } }; + // ==================== DEBUG LOG: HTTP REQUEST ==================== // + + let debug_log_event_token = DebugLogEventToken::generate(); + let ip_address = get_request_ip(&http_request); + let request_url = http_request.uri().to_string(); + + insert_generation_request_debug_log( + &debug_log_event_token, + user_token, + &ip_address, + &request_url, + &serde_json::to_string(&*request).unwrap_or_default(), + &mut *mysql_connection, + ).await; + let start_frame_media_file_token = match &request.media_file_token { Some(token) => token, None => { @@ -182,12 +201,21 @@ pub async fn generate_seedance_1_0_pro_image_to_video_handler( api_key: &server_state.inference_providers.fal.api_key, }; - let fal_result = enqueue_seedance_1_pro_image_to_video_webhook(args) - .await - .map_err(|err| { - warn!("Error calling enqueue_seedance_1_pro_image_to_video_webhook: {:?}", err); - CommonWebError::from_error(err) - })?; + let fal_result = match enqueue_seedance_1_pro_image_to_video_webhook(args).await { + Ok(result) => result, + Err(err) => { + warn!("Error calling enqueue_seedance_1_pro_image_to_video_webhook: {:?}", err); + insert_generation_failure_debug_log( + &debug_log_event_token, + user_token, + &ip_address, + &request_url, + &format!("Seedance 1.0 Pro generation failed: {:?}", err), + &mut *mysql_connection, + ).await; + return Err(CommonWebError::from_error(err)); + } + }; let external_job_id = fal_result.request_id .ok_or_else(|| { @@ -197,8 +225,6 @@ pub async fn generate_seedance_1_0_pro_image_to_video_handler( info!("Fal request_id: {}", external_job_id); - let ip_address = get_request_ip(&http_request); - let mut transaction = mysql_connection .begin() .await @@ -268,7 +294,7 @@ pub async fn generate_seedance_1_0_pro_image_to_video_handler( starting_job_status_override: None, maybe_frontend_failure_category: None, maybe_failure_reason: None, - maybe_debug_log_event_token: None, + maybe_debug_log_event_token: Some(&debug_log_event_token), phantom: Default::default(), }).await; diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/generate/video/multi_function/seedance_1p5_pro_multi_function_video_gen_handler.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/generate/video/multi_function/seedance_1p5_pro_multi_function_video_gen_handler.rs index 410eb0a671..ddc566f860 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/generate/video/multi_function/seedance_1p5_pro_multi_function_video_gen_handler.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/generate/video/multi_function/seedance_1p5_pro_multi_function_video_gen_handler.rs @@ -3,6 +3,9 @@ use std::sync::Arc; use crate::billing::wallets::attempt_wallet_deduction::attempt_wallet_deduction_else_common_web_error; use crate::http_server::common_responses::common_web_error::CommonWebError; +use crate::http_server::endpoints::generate::common::generation_debug_logs::{ + insert_generation_failure_debug_log, insert_generation_request_debug_log, +}; use crate::http_server::endpoints::generate::common::payments_error_test::payments_error_test; use crate::http_server::validations::validate_idempotency_token_format::validate_idempotency_token_format; use crate::http_server::web_utils::get_request_platform_type::get_request_platform_type; @@ -30,6 +33,7 @@ use mysql_queries::queries::prompt_context_items::insert_batch_prompt_context_it use mysql_queries::queries::prompts::insert_prompt::{insert_prompt, InsertPromptArgs}; use sqlx::Acquire; use tokens::tokens::generic_inference_jobs::InferenceJobToken; +use tokens::tokens::non_unique::debug_logs_event_token::DebugLogEventToken; /// Seedance 1.5 Pro Multi-Function (text and image to video) @@ -78,6 +82,21 @@ pub async fn seedance_1p5_pro_multi_function_video_gen_handler( } }; + // ==================== DEBUG LOG: HTTP REQUEST ==================== // + + let debug_log_event_token = DebugLogEventToken::generate(); + let ip_address = get_request_ip(&http_request); + let request_url = http_request.uri().to_string(); + + insert_generation_request_debug_log( + &debug_log_event_token, + user_token, + &ip_address, + &request_url, + &serde_json::to_string(&*request).unwrap_or_default(), + &mut *mysql_connection, + ).await; + if let Err(reason) = validate_idempotency_token_format(&request.uuid_idempotency_token) { return Err(CommonWebError::BadInputWithSimpleMessage(reason)); } @@ -177,12 +196,21 @@ pub async fn seedance_1p5_pro_multi_function_video_gen_handler( api_key: &server_state.inference_providers.fal.api_key, }; - fal_result = enqueue_seedance_1p5_pro_image_to_video_webhook(args) - .await - .map_err(|err| { - warn!("Error calling enqueue_seedance_1p5_pro_image_to_video_webhook: {:?}", err); - CommonWebError::from_error(err) - })?; + fal_result = match enqueue_seedance_1p5_pro_image_to_video_webhook(args).await { + Ok(result) => result, + Err(err) => { + warn!("Error calling enqueue_seedance_1p5_pro_image_to_video_webhook: {:?}", err); + insert_generation_failure_debug_log( + &debug_log_event_token, + user_token, + &ip_address, + &request_url, + &format!("Seedance 1.5 Pro generation failed: {:?}", err), + &mut *mysql_connection, + ).await; + return Err(CommonWebError::from_error(err)); + } + }; } else { info!("text-to-video case"); @@ -217,12 +245,21 @@ pub async fn seedance_1p5_pro_multi_function_video_gen_handler( &mut mysql_connection, ).await?; - fal_result = enqueue_seedance_1p5_pro_text_to_video_webhook(args) - .await - .map_err(|err| { - warn!("Error calling enqueue_seedance_1p5_pro_text_to_video_webhook: {:?}", err); - CommonWebError::from_error(err) - })?; + fal_result = match enqueue_seedance_1p5_pro_text_to_video_webhook(args).await { + Ok(result) => result, + Err(err) => { + warn!("Error calling enqueue_seedance_1p5_pro_text_to_video_webhook: {:?}", err); + insert_generation_failure_debug_log( + &debug_log_event_token, + user_token, + &ip_address, + &request_url, + &format!("Seedance 1.5 Pro generation failed: {:?}", err), + &mut *mysql_connection, + ).await; + return Err(CommonWebError::from_error(err)); + } + }; } let external_job_id = fal_result.request_id @@ -233,8 +270,6 @@ pub async fn seedance_1p5_pro_multi_function_video_gen_handler( info!("Fal request_id: {}", external_job_id); - let ip_address = get_request_ip(&http_request); - let mut transaction = mysql_connection .begin() .await @@ -342,7 +377,7 @@ pub async fn seedance_1p5_pro_multi_function_video_gen_handler( starting_job_status_override: None, maybe_frontend_failure_category: None, maybe_failure_reason: None, - maybe_debug_log_event_token: None, + maybe_debug_log_event_token: Some(&debug_log_event_token), phantom: Default::default(), }).await; diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/generate/video/multi_function/seedance_2p0_multi_function_video_gen_handler.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/generate/video/multi_function/seedance_2p0_multi_function_video_gen_handler.rs index 8eb8958b3a..2590368854 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/generate/video/multi_function/seedance_2p0_multi_function_video_gen_handler.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/generate/video/multi_function/seedance_2p0_multi_function_video_gen_handler.rs @@ -5,6 +5,9 @@ use crate::billing::wallets::attempt_wallet_deduction::attempt_wallet_deduction_ use crate::http_server::common_responses::common_web_error::CommonWebError; use crate::http_server::endpoint_helpers::refund_wallet_after_api_failure::refund_wallet_after_api_failure; use crate::http_server::endpoints::generate::common::map_seedance2pro_web_errors::map_seedance2pro_error_to_web_error; +use crate::http_server::endpoints::generate::common::generation_debug_logs::{ + insert_generation_failure_debug_log, insert_generation_request_debug_log, +}; use crate::http_server::endpoints::generate::common::payments_error_test::payments_error_test; use crate::http_server::user_lookup::user_session::session_utils::lookup::user_session_feature_flags::UserSessionFeatureFlags; use crate::http_server::validations::validate_idempotency_token_format::validate_idempotency_token_format; @@ -49,6 +52,8 @@ use sqlx::MySql; use tokens::tokens::characters::CharacterToken; use tokens::tokens::generic_inference_jobs::InferenceJobToken; use tokens::tokens::media_files::MediaFileToken; +use tokens::tokens::non_unique::debug_logs_event_token::DebugLogEventToken; + use url::Url; use url_utils::extension::extract_extension_from_url::{extract_extension_from_url, ExtractExtensions}; @@ -108,6 +113,21 @@ pub async fn seedance_2p0_multi_function_video_gen_handler( let user_token = &user_session.user_token; + // ==================== DEBUG LOG: HTTP REQUEST ==================== // + + let debug_log_event_token = DebugLogEventToken::generate(); + let ip_address = get_request_ip(&http_request); + let request_url = http_request.uri().to_string(); + + insert_generation_request_debug_log( + &debug_log_event_token, + user_token, + &ip_address, + &request_url, + &serde_json::to_string(&*request).unwrap_or_default(), + &mut *mysql_connection, + ).await; + if let Err(reason) = validate_idempotency_token_format(&request.uuid_idempotency_token) { return Err(CommonWebError::BadInputWithSimpleMessage(reason)); } @@ -248,6 +268,14 @@ pub async fn seedance_2p0_multi_function_video_gen_handler( } } + insert_generation_failure_debug_log( + &debug_log_event_token, + user_token, + &ip_address, + &request_url, + &format!("Seedance 2.0 generation failed: {:?}", err), + &mut *mysql_connection, + ).await; refund_wallet_after_api_failure(&deduction_result.ledger_entry_token, &mut mysql_connection).await?; return Err(err); } @@ -289,6 +317,14 @@ pub async fn seedance_2p0_multi_function_video_gen_handler( } } + insert_generation_failure_debug_log( + &debug_log_event_token, + user_token, + &ip_address, + &request_url, + &format!("Seedance 2.0 generation failed: {:?}", err), + &mut *mysql_connection, + ).await; refund_wallet_after_api_failure(&deduction_result.ledger_entry_token, &mut mysql_connection).await?; return Err(err); } @@ -305,8 +341,6 @@ pub async fn seedance_2p0_multi_function_video_gen_handler( // --- DB writes in a transaction --- - let ip_address = get_request_ip(&http_request); - let mut transaction = mysql_connection .begin() .await @@ -438,7 +472,7 @@ pub async fn seedance_2p0_multi_function_video_gen_handler( creator_set_visibility: Visibility::Public, maybe_platform_type: get_request_platform_type(&http_request), maybe_cost_estimates: None, - maybe_debug_log_event_token: None, + maybe_debug_log_event_token: Some(&debug_log_event_token), mysql_executor: &mut *transaction, phantom: Default::default(), }