debug logs #2 (#1723)

This commit is contained in:
Brandon Thomas authored and GitHub committed 2026-07-02 19:36:48 -04:00
1 parent 82c0a7a4d9
commit 3a2e3b30ec
31 files changed
+462 -265

No files matched your search

@@ -1,12 +1,12 @@
{
"db_name": "MySQL",
"query": "\nINSERT INTO debug_logs\nSET\n event_token = ?,\n debug_log_type = ?,\n maybe_log_level = ?,\n maybe_creator_user_token = ?,\n message = ?\n ",
"query": "\nINSERT INTO debug_logs\nSET\n event_token = ?,\n debug_log_type = ?,\n maybe_log_level = ?,\n maybe_creator_user_token = ?,\n maybe_ip_address = ?,\n maybe_url = ?,\n message = ?\n ",
"describe": {
"columns": [],
"parameters": {
"Right": 5
"Right": 7
},
"nullable": []
},
"hash": "62995374005dc0553d007fb69e642d89a95cd5aaeeababd110c92c565023cfcf"
"hash": "32a8d1cfec89ba2056463a33ddc501a8a99283c7c00982a7fa79f7ff382c9b22"
}
@@ -1,6 +1,6 @@
{
"db_name": "MySQL",
"query": "\nSELECT\n d.id as `id: u64`,\n d.event_token as `event_token: tokens::tokens::non_unique::debug_logs_event_token::DebugLogEventToken`,\n d.debug_log_type as `debug_log_type: enums::by_table::debug_logs::debug_log_type::DebugLogType`,\n d.maybe_log_level as `maybe_log_level: enums::by_table::debug_logs::debug_log_level::DebugLogLevel`,\n d.maybe_creator_user_token as `maybe_creator_user_token: tokens::tokens::users::UserToken`,\n d.message,\n d.created_at,\n u.display_name as `maybe_user_display_name?`,\n u.username as `maybe_user_username?`,\n u.email_gravatar_hash as `maybe_user_gravatar_hash?`\nFROM debug_logs d\nLEFT OUTER JOIN users u\n ON u.token = d.maybe_creator_user_token\nWHERE d.maybe_creator_user_token = ?\n AND d.id < ?\nORDER BY d.id DESC\nLIMIT ?\n ",
"query": "\nSELECT\n d.id as `id: u64`,\n d.event_token as `event_token: tokens::tokens::non_unique::debug_logs_event_token::DebugLogEventToken`,\n d.debug_log_type as `debug_log_type: enums::by_table::debug_logs::debug_log_type::DebugLogType`,\n d.maybe_log_level as `maybe_log_level: enums::by_table::debug_logs::debug_log_level::DebugLogLevel`,\n d.maybe_creator_user_token as `maybe_creator_user_token: tokens::tokens::users::UserToken`,\n d.maybe_ip_address,\n d.maybe_url,\n d.message,\n d.created_at,\n u.display_name as `maybe_user_display_name?`,\n u.username as `maybe_user_username?`,\n u.email_gravatar_hash as `maybe_user_gravatar_hash?`\nFROM debug_logs d\nLEFT OUTER JOIN users u\n ON u.token = d.maybe_creator_user_token\nWHERE d.maybe_creator_user_token = ?\n AND d.id < ?\nORDER BY d.id DESC\nLIMIT ?\n ",
"describe": {
"columns": [
{
@@ -55,6 +55,26 @@
},
{
"ordinal": 5,
"name": "maybe_ip_address",
"type_info": {
"type": "VarString",
"flags": "BINARY",
"char_set": 224,
"max_size": 160
}
},
{
"ordinal": 6,
"name": "maybe_url",
"type_info": {
"type": "VarString",
"flags": "BINARY",
"char_set": 224,
"max_size": 1020
}
},
{
"ordinal": 7,
"name": "message",
"type_info": {
"type": "Blob",
@@ -64,7 +84,7 @@
}
},
{
"ordinal": 6,
"ordinal": 8,
"name": "created_at",
"type_info": {
"type": "Datetime",
@@ -74,7 +94,7 @@
}
},
{
"ordinal": 7,
"ordinal": 9,
"name": "maybe_user_display_name?",
"type_info": {
"type": "VarString",
@@ -84,7 +104,7 @@
}
},
{
"ordinal": 8,
"ordinal": 10,
"name": "maybe_user_username?",
"type_info": {
"type": "VarString",
@@ -94,7 +114,7 @@
}
},
{
"ordinal": 9,
"ordinal": 11,
"name": "maybe_user_gravatar_hash?",
"type_info": {
"type": "String",
@@ -113,6 +133,8 @@
false,
true,
true,
true,
true,
false,
false,
true,
@@ -120,5 +142,5 @@
true
]
},
"hash": "1197c08c8b390fb8bffbe10ad9f7d073a58b6c9124ee11573c6723d6d5471881"
"hash": "d1ade7fcfd3efac1cd3163c392110327bb73edb74fa0d9693fee5feddb8a3223"
}
@@ -1,6 +1,6 @@
{
"db_name": "MySQL",
"query": "\nSELECT\n d.id as `id: u64`,\n d.event_token as `event_token: tokens::tokens::non_unique::debug_logs_event_token::DebugLogEventToken`,\n d.debug_log_type as `debug_log_type: enums::by_table::debug_logs::debug_log_type::DebugLogType`,\n d.maybe_log_level as `maybe_log_level: enums::by_table::debug_logs::debug_log_level::DebugLogLevel`,\n d.maybe_creator_user_token as `maybe_creator_user_token: tokens::tokens::users::UserToken`,\n d.message,\n d.created_at,\n u.display_name as `maybe_user_display_name?`,\n u.username as `maybe_user_username?`,\n u.email_gravatar_hash as `maybe_user_gravatar_hash?`\nFROM debug_logs d\nLEFT OUTER JOIN users u\n ON u.token = d.maybe_creator_user_token\nWHERE d.event_token = ?\nORDER BY d.id ASC\nLIMIT ?\n ",
"query": "\nSELECT\n d.id as `id: u64`,\n d.event_token as `event_token: tokens::tokens::non_unique::debug_logs_event_token::DebugLogEventToken`,\n d.debug_log_type as `debug_log_type: enums::by_table::debug_logs::debug_log_type::DebugLogType`,\n d.maybe_log_level as `maybe_log_level: enums::by_table::debug_logs::debug_log_level::DebugLogLevel`,\n d.maybe_creator_user_token as `maybe_creator_user_token: tokens::tokens::users::UserToken`,\n d.maybe_ip_address,\n d.maybe_url,\n d.message,\n d.created_at,\n u.display_name as `maybe_user_display_name?`,\n u.username as `maybe_user_username?`,\n u.email_gravatar_hash as `maybe_user_gravatar_hash?`\nFROM debug_logs d\nLEFT OUTER JOIN users u\n ON u.token = d.maybe_creator_user_token\nWHERE d.event_token = ?\nORDER BY d.id ASC\nLIMIT ?\n ",
"describe": {
"columns": [
{
@@ -55,6 +55,26 @@
},
{
"ordinal": 5,
"name": "maybe_ip_address",
"type_info": {
"type": "VarString",
"flags": "BINARY",
"char_set": 224,
"max_size": 160
}
},
{
"ordinal": 6,
"name": "maybe_url",
"type_info": {
"type": "VarString",
"flags": "BINARY",
"char_set": 224,
"max_size": 1020
}
},
{
"ordinal": 7,
"name": "message",
"type_info": {
"type": "Blob",
@@ -64,7 +84,7 @@
}
},
{
"ordinal": 6,
"ordinal": 8,
"name": "created_at",
"type_info": {
"type": "Datetime",
@@ -74,7 +94,7 @@
}
},
{
"ordinal": 7,
"ordinal": 9,
"name": "maybe_user_display_name?",
"type_info": {
"type": "VarString",
@@ -84,7 +104,7 @@
}
},
{
"ordinal": 8,
"ordinal": 10,
"name": "maybe_user_username?",
"type_info": {
"type": "VarString",
@@ -94,7 +114,7 @@
}
},
{
"ordinal": 9,
"ordinal": 11,
"name": "maybe_user_gravatar_hash?",
"type_info": {
"type": "String",
@@ -113,6 +133,8 @@
false,
true,
true,
true,
true,
false,
false,
true,
@@ -120,5 +142,5 @@
true
]
},
"hash": "ae311f7fde7c73f166cd8c0a5c9965850e314936a401b24a3900585ab53a7db6"
"hash": "e9a149ffc963a59019fdd69bd53128fad946856d432108bf9b923dfeaf2442c5"
}
@@ -0,0 +1,6 @@
-- noinspection SqlDialectInspectionForFile
-- noinspection SqlNoDataSourceInspectionForFile
-- noinspection SqlResolveForFile
ALTER TABLE debug_logs
DROP COLUMN maybe_ip_address;
@@ -0,0 +1,6 @@
-- noinspection SqlDialectInspectionForFile
-- noinspection SqlNoDataSourceInspectionForFile
-- noinspection SqlResolveForFile
ALTER TABLE debug_logs
ADD COLUMN maybe_ip_address VARCHAR(40) DEFAULT NULL;
@@ -0,0 +1,6 @@
-- noinspection SqlDialectInspectionForFile
-- noinspection SqlNoDataSourceInspectionForFile
-- noinspection SqlResolveForFile
ALTER TABLE debug_logs
DROP COLUMN maybe_url;
@@ -0,0 +1,6 @@
-- noinspection SqlDialectInspectionForFile
-- noinspection SqlNoDataSourceInspectionForFile
-- noinspection SqlResolveForFile
ALTER TABLE debug_logs
ADD COLUMN maybe_url VARCHAR(255) DEFAULT NULL;
@@ -19,6 +19,12 @@ CREATE TABLE debug_logs (
-- The user who created the log entry (if any).
maybe_creator_user_token VARCHAR(32) DEFAULT NULL,
-- The client IP address of the request (if any). Wide enough for IPv6.
maybe_ip_address VARCHAR(40) DEFAULT NULL,
-- The request URL (if any). Truncated to 255 characters on insert.
maybe_url VARCHAR(255) DEFAULT NULL,
-- The log message body.
message MEDIUMTEXT NOT NULL,
@@ -16,6 +16,10 @@ pub struct ModerationDebugLogEntry {
pub debug_log_type: DebugLogType,
pub maybe_log_level: Option<DebugLogLevel>,
pub maybe_creator_user_token: Option<UserToken>,
/// The client IP address of the request (if recorded).
pub maybe_ip_address: Option<String>,
/// The request URL (if recorded; truncated to 255 chars).
pub maybe_url: Option<String>,
pub message: String,
pub created_at: DateTime<Utc>,
/// The creator user, joined in when the row has a user token.
@@ -66,6 +66,10 @@ pub struct ModerationListAllDebugLogsEntry {
pub debug_log_type: DebugLogType,
pub maybe_log_level: Option<DebugLogLevel>,
pub maybe_creator_user_token: Option<UserToken>,
/// The client IP address of the request (if recorded).
pub maybe_ip_address: Option<String>,
/// The request URL (if recorded; truncated to 255 chars).
pub maybe_url: Option<String>,
pub message: String,
pub created_at: DateTime<Utc>,
pub maybe_user: Option<ModerationDebugLogUser>,
@@ -19,6 +19,12 @@ where
/// The user associated with these debug log events (if any).
pub maybe_creator_user_token: Option<&'e UserToken>,
/// The client IP address of the request (if any). Truncated on insert.
pub maybe_ip_address: Option<&'e str>,
/// The request URL (if any). Truncated to 255 characters on insert.
pub maybe_url: Option<&'e str>,
/// The events to insert.
pub events: Vec<DebugLogEvent>,
@@ -56,9 +62,11 @@ where
}
let maybe_user_token_str = args.maybe_creator_user_token.map(|t| t.as_str().to_string());
let maybe_ip_address = args.maybe_ip_address.map(|ip| truncate_chars(ip, MAX_IP_ADDRESS_CHARS));
let maybe_url = args.maybe_url.map(|url| truncate_chars(url, MAX_URL_CHARS));
let mut query_builder = QueryBuilder::new(
"INSERT INTO debug_logs (event_token, debug_log_type, maybe_log_level, maybe_creator_user_token, message) VALUES "
"INSERT INTO debug_logs (event_token, debug_log_type, maybe_log_level, maybe_creator_user_token, maybe_ip_address, maybe_url, message) VALUES "
);
for (i, event) in args.events.iter().enumerate() {
@@ -71,6 +79,10 @@ where
query_builder.push(", ");
query_builder.push_bind(&maybe_user_token_str);
query_builder.push(", ");
query_builder.push_bind(maybe_ip_address);
query_builder.push(", ");
query_builder.push_bind(maybe_url);
query_builder.push(", ");
query_builder.push_bind(&event.message);
query_builder.push(")");
@@ -85,3 +97,17 @@ where
Ok(event_token)
}
/// Maximum stored length for `maybe_ip_address` (VARCHAR(40)).
const MAX_IP_ADDRESS_CHARS: usize = 40;
/// Maximum stored length for `maybe_url` (VARCHAR(255)).
const MAX_URL_CHARS: usize = 255;
/// Truncate to at most `max_chars` characters (UTF-8 safe).
fn truncate_chars(value: &str, max_chars: usize) -> &str {
match value.char_indices().nth(max_chars) {
Some((idx, _)) => &value[..idx],
None => value,
}
}
@@ -27,6 +27,12 @@ where
/// The log message body (pre-serialized JSON or any text).
pub message: &'e str,
/// The client IP address of the request (if any). Truncated on insert.
pub maybe_ip_address: Option<&'e str>,
/// The request URL (if any). Truncated to 255 characters on insert.
pub maybe_url: Option<&'e str>,
pub mysql_executor: E,
pub phantom: PhantomData<&'c E>,
}
@@ -53,12 +59,16 @@ SET
debug_log_type = ?,
maybe_log_level = ?,
maybe_creator_user_token = ?,
maybe_ip_address = ?,
maybe_url = ?,
message = ?
"#,
event_token.as_str(),
args.debug_log_type.to_str(),
args.maybe_log_level.map(|l| l.to_str()),
args.maybe_creator_user_token.map(|t| t.as_str()),
args.maybe_ip_address.map(|ip| truncate_chars(ip, MAX_IP_ADDRESS_CHARS)),
args.maybe_url.map(|url| truncate_chars(url, MAX_URL_CHARS)),
args.message,
)
.execute(args.mysql_executor)
@@ -66,3 +76,17 @@ SET
Ok(event_token)
}
/// Maximum stored length for `maybe_ip_address` (VARCHAR(40)).
const MAX_IP_ADDRESS_CHARS: usize = 40;
/// Maximum stored length for `maybe_url` (VARCHAR(255)).
const MAX_URL_CHARS: usize = 255;
/// Truncate to at most `max_chars` characters (UTF-8 safe).
fn truncate_chars(value: &str, max_chars: usize) -> &str {
match value.char_indices().nth(max_chars) {
Some((idx, _)) => &value[..idx],
None => value,
}
}
@@ -43,6 +43,8 @@ pub struct AllDebugLogRow {
pub debug_log_type: DebugLogType,
pub maybe_log_level: Option<DebugLogLevel>,
pub maybe_creator_user_token: Option<UserToken>,
pub maybe_ip_address: Option<String>,
pub maybe_url: Option<String>,
pub message: String,
pub created_at: DateTime<Utc>,
@@ -77,6 +79,8 @@ SELECT
d.debug_log_type,
d.maybe_log_level,
d.maybe_creator_user_token,
d.maybe_ip_address,
d.maybe_url,
d.message,
d.created_at,
u.display_name as maybe_user_display_name,
@@ -133,6 +137,8 @@ fn row_from_mysql_row(row: MySqlRow) -> Result<AllDebugLogRow, sqlx::Error> {
debug_log_type: row.try_get("debug_log_type")?,
maybe_log_level: row.try_get("maybe_log_level")?,
maybe_creator_user_token: row.try_get("maybe_creator_user_token")?,
maybe_ip_address: row.try_get("maybe_ip_address")?,
maybe_url: row.try_get("maybe_url")?,
message: row.try_get("message")?,
created_at,
maybe_user_display_name: row.try_get("maybe_user_display_name")?,
@@ -27,6 +27,8 @@ pub struct DebugLogRow {
pub debug_log_type: DebugLogType,
pub maybe_log_level: Option<DebugLogLevel>,
pub maybe_creator_user_token: Option<UserToken>,
pub maybe_ip_address: Option<String>,
pub maybe_url: Option<String>,
pub message: String,
pub created_at: DateTime<Utc>,
@@ -43,6 +45,8 @@ struct RawDebugLogRow {
debug_log_type: DebugLogType,
maybe_log_level: Option<DebugLogLevel>,
maybe_creator_user_token: Option<UserToken>,
maybe_ip_address: Option<String>,
maybe_url: Option<String>,
message: String,
created_at: NaiveDateTime,
maybe_user_display_name: Option<String>,
@@ -67,6 +71,8 @@ SELECT
d.debug_log_type as `debug_log_type: enums::by_table::debug_logs::debug_log_type::DebugLogType`,
d.maybe_log_level as `maybe_log_level: enums::by_table::debug_logs::debug_log_level::DebugLogLevel`,
d.maybe_creator_user_token as `maybe_creator_user_token: tokens::tokens::users::UserToken`,
d.maybe_ip_address,
d.maybe_url,
d.message,
d.created_at,
u.display_name as `maybe_user_display_name?`,
@@ -92,6 +98,8 @@ LIMIT ?
debug_log_type: row.debug_log_type,
maybe_log_level: row.maybe_log_level,
maybe_creator_user_token: row.maybe_creator_user_token,
maybe_ip_address: row.maybe_ip_address,
maybe_url: row.maybe_url,
message: row.message,
created_at: row.created_at.and_utc(),
maybe_user_display_name: row.maybe_user_display_name,
@@ -39,6 +39,8 @@ pub struct UserDebugLogRow {
pub debug_log_type: DebugLogType,
pub maybe_log_level: Option<DebugLogLevel>,
pub maybe_creator_user_token: Option<UserToken>,
pub maybe_ip_address: Option<String>,
pub maybe_url: Option<String>,
pub message: String,
pub created_at: DateTime<Utc>,
@@ -55,6 +57,8 @@ struct RawUserDebugLogRow {
debug_log_type: DebugLogType,
maybe_log_level: Option<DebugLogLevel>,
maybe_creator_user_token: Option<UserToken>,
maybe_ip_address: Option<String>,
maybe_url: Option<String>,
message: String,
created_at: NaiveDateTime,
maybe_user_display_name: Option<String>,
@@ -85,6 +89,8 @@ SELECT
d.debug_log_type as `debug_log_type: enums::by_table::debug_logs::debug_log_type::DebugLogType`,
d.maybe_log_level as `maybe_log_level: enums::by_table::debug_logs::debug_log_level::DebugLogLevel`,
d.maybe_creator_user_token as `maybe_creator_user_token: tokens::tokens::users::UserToken`,
d.maybe_ip_address,
d.maybe_url,
d.message,
d.created_at,
u.display_name as `maybe_user_display_name?`,
@@ -112,6 +118,8 @@ LIMIT ?
debug_log_type: row.debug_log_type,
maybe_log_level: row.maybe_log_level,
maybe_creator_user_token: row.maybe_creator_user_token,
maybe_ip_address: row.maybe_ip_address,
maybe_url: row.maybe_url,
message: row.message,
created_at: row.created_at.and_utc(),
maybe_user_display_name: row.maybe_user_display_name,
@@ -75,6 +75,8 @@ pub async fn moderation_list_all_debug_logs_handler(
debug_log_type: row.debug_log_type,
maybe_log_level: row.maybe_log_level,
maybe_creator_user_token: row.maybe_creator_user_token,
maybe_ip_address: row.maybe_ip_address,
maybe_url: row.maybe_url,
message: row.message,
created_at: row.created_at,
maybe_user,
@@ -71,6 +71,8 @@ pub async fn moderation_list_debug_logs_for_token_handler(
debug_log_type: row.debug_log_type,
maybe_log_level: row.maybe_log_level,
maybe_creator_user_token: row.maybe_creator_user_token,
maybe_ip_address: row.maybe_ip_address,
maybe_url: row.maybe_url,
message: row.message,
created_at: row.created_at,
maybe_user,
@@ -72,6 +72,8 @@ pub async fn moderation_list_debug_logs_for_user_handler(
debug_log_type: row.debug_log_type,
maybe_log_level: row.maybe_log_level,
maybe_creator_user_token: row.maybe_creator_user_token,
maybe_ip_address: row.maybe_ip_address,
maybe_url: row.maybe_url,
message: row.message,
created_at: row.created_at,
maybe_user,
@@ -106,6 +106,7 @@ pub async fn omni_api_image_generate_handler(
})?;
let ip_address = get_request_ip(&http_request);
let request_url = http_request.uri().to_string();
// ==================== INGEST URL INPUTS ==================== //
@@ -139,6 +140,8 @@ pub async fn omni_api_image_generate_handler(
maybe_creator_user_token: Some(user_token),
debug_log_type: DebugLogType::HttpRequest,
maybe_log_level: None,
maybe_ip_address: Some(&ip_address),
maybe_url: Some(&request_url),
message: &serde_json::to_string(&*request).unwrap_or_default(),
mysql_executor: &mut *mysql_connection,
phantom: Default::default(),
@@ -171,6 +174,8 @@ pub async fn omni_api_image_generate_handler(
maybe_creator_user_token: Some(user_token),
debug_log_type: DebugLogType::FalRequest,
maybe_log_level: None,
maybe_ip_address: Some(&ip_address),
maybe_url: Some(&request_url),
message: &format!("{:#?}", outbound_request),
mysql_executor: &mut *mysql_connection,
phantom: Default::default(),
@@ -119,6 +119,7 @@ pub async fn omni_api_video_generate_handler(
})?;
let ip_address = get_request_ip(&http_request);
let request_url = http_request.uri().to_string();
// ==================== INGEST URL INPUTS ==================== //
@@ -206,6 +207,8 @@ pub async fn omni_api_video_generate_handler(
maybe_creator_user_token: Some(user_token),
debug_log_type: DebugLogType::HttpRequest,
maybe_log_level: None,
maybe_ip_address: Some(&ip_address),
maybe_url: Some(&request_url),
message: &serde_json::to_string(&*request).unwrap_or_default(),
mysql_executor: &mut *mysql_connection,
phantom: Default::default(),
@@ -238,6 +241,8 @@ pub async fn omni_api_video_generate_handler(
maybe_creator_user_token: Some(user_token),
debug_log_type: DebugLogType::FalRequest,
maybe_log_level: None,
maybe_ip_address: Some(&ip_address),
maybe_url: Some(&request_url),
message: &format!("{:#?}", outbound_request),
mysql_executor: &mut *mysql_connection,
phantom: Default::default(),
@@ -256,6 +261,8 @@ pub async fn omni_api_video_generate_handler(
maybe_creator_user_token: Some(user_token),
debug_log_type: DebugLogType::GrokApiRequest,
maybe_log_level: None,
maybe_ip_address: Some(&ip_address),
maybe_url: Some(&request_url),
message: &format!("{:#?}", outbound_request),
mysql_executor: &mut *mysql_connection,
phantom: Default::default(),
@@ -130,11 +130,16 @@ pub async fn omni_gen_image_generate_handler(
// ==================== DEBUG LOG: HTTP REQUEST ==================== //
let ip_address = get_request_ip(&http_request);
let request_url = http_request.uri().to_string();
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: None,
maybe_ip_address: Some(&ip_address),
maybe_url: Some(&request_url),
message: &serde_json::to_string(&*request).unwrap_or_default(),
mysql_executor: &mut *mysql_connection,
phantom: Default::default(),
@@ -167,6 +172,8 @@ pub async fn omni_gen_image_generate_handler(
maybe_creator_user_token: Some(user_token),
debug_log_type: DebugLogType::FalRequest,
maybe_log_level: None,
maybe_ip_address: Some(&ip_address),
maybe_url: Some(&request_url),
message: &format!("{:#?}", outbound_request),
mysql_executor: &mut *mysql_connection,
phantom: Default::default(),
@@ -178,7 +185,6 @@ pub async fn omni_gen_image_generate_handler(
// ==================== WRITE RESULT ==================== //
let ip_address = get_request_ip(&http_request);
let maybe_platform_type = get_request_platform_type(&http_request);
let mut transaction = mysql_connection
@@ -191,11 +191,16 @@ pub async fn omni_gen_video_generate_handler(
// ==================== DEBUG LOG: HTTP REQUEST ==================== //
let ip_address = get_request_ip(&http_request);
let request_url = http_request.uri().to_string();
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: None,
maybe_ip_address: Some(&ip_address),
maybe_url: Some(&request_url),
message: &serde_json::to_string(&*request).unwrap_or_default(),
mysql_executor: &mut *mysql_connection,
phantom: Default::default(),
@@ -228,6 +233,8 @@ pub async fn omni_gen_video_generate_handler(
maybe_creator_user_token: Some(user_token),
debug_log_type: DebugLogType::FalRequest,
maybe_log_level: None,
maybe_ip_address: Some(&ip_address),
maybe_url: Some(&request_url),
message: &format!("{:#?}", outbound_request),
mysql_executor: &mut *mysql_connection,
phantom: Default::default(),
@@ -246,6 +253,8 @@ pub async fn omni_gen_video_generate_handler(
maybe_creator_user_token: Some(user_token),
debug_log_type: DebugLogType::GrokApiRequest,
maybe_log_level: None,
maybe_ip_address: Some(&ip_address),
maybe_url: Some(&request_url),
message: &format!("{:#?}", outbound_request),
mysql_executor: &mut *mysql_connection,
phantom: Default::default(),
@@ -257,7 +266,6 @@ pub async fn omni_gen_video_generate_handler(
// ==================== WRITE RESULT ==================== //
let ip_address = get_request_ip(&http_request);
let maybe_platform_type = get_request_platform_type(&http_request);
let mut transaction = mysql_connection.begin().await.map_err(|err| {
@@ -102,6 +102,8 @@ pub async fn beeble_webhook_handler(
maybe_creator_user_token: job.maybe_creator_user_token.as_ref(),
debug_log_type: DebugLogType::BeebleWebhook,
maybe_log_level: None,
maybe_ip_address: None,
maybe_url: None,
message: &raw_body,
mysql_executor: &mut *mysql_connection,
phantom: Default::default(),
@@ -53,6 +53,8 @@ pub async fn handle_failed_fal_webhook(
maybe_creator_user_token: job.maybe_creator_user_token.as_ref(),
debug_log_type: DebugLogType::FalWebhook,
maybe_log_level: None,
maybe_ip_address: None,
maybe_url: None,
message: raw_body,
mysql_executor: &mut **mysql_connection,
phantom: Default::default(),
@@ -53,6 +53,8 @@ pub async fn handle_successful_fal_webhook(
maybe_creator_user_token: job.maybe_creator_user_token.as_ref(),
debug_log_type: DebugLogType::FalWebhook,
maybe_log_level: None,
maybe_ip_address: None,
maybe_url: None,
message: raw_body,
mysql_executor: &mut **mysql_connection,
phantom: Default::default(),
@@ -13,6 +13,18 @@ import {
IconUser,
} from "@tabler/icons-react";
/** Compact form for the header row, eg. "Jul 2, 18:02:47". */
export function formatDebugLogDateTimeCompact(iso: string): string {
return new Date(iso).toLocaleString("en-US", {
month: "short",
day: "numeric",
hour: "2-digit",
minute: "2-digit",
second: "2-digit",
hour12: false,
});
}
export function formatDebugLogDateTime(iso: string): string {
return new Date(iso).toLocaleString("en-US", {
month: "short",
@@ -86,8 +98,6 @@ export interface DebugLogCardProps {
log: DebugLog;
copiedId: string | null;
onCopy: (value: string, id: string) => void;
/** Show a direct link to the event's debug-logs page in the header row. */
showEventLink?: boolean;
/** Start expanded (defaults to true). */
defaultExpanded?: boolean;
/** Expand/collapse-all broadcast from the page. */
@@ -98,7 +108,6 @@ export function DebugLogCard({
log,
copiedId,
onCopy,
showEventLink = false,
defaultExpanded = true,
expandAll,
}: DebugLogCardProps) {
@@ -135,48 +144,54 @@ export function DebugLogCard({
{log.maybe_log_level.toUpperCase()}
</Badge>
)}
{showEventLink && (
<span className="text-xs text-muted-foreground tabular-nums whitespace-nowrap">
{formatDebugLogDateTimeCompact(log.created_at)}
</span>
{log.maybe_url && (
<span
className="font-mono text-xs text-muted-foreground truncate max-w-[18rem]"
title={log.maybe_url}
>
{log.maybe_url}
</span>
)}
{maybeUser && (
<span
className="inline-flex items-center min-w-0"
onClick={(e) => e.stopPropagation()}
>
<Link
to={`/debug_logs/${encodeURIComponent(log.event_token)}`}
className="font-mono text-xs text-muted-foreground hover:text-foreground hover:underline truncate"
title={`View event ${log.event_token}`}
>
{log.event_token}
</Link>
</span>
)}
{maybeUser && (
<span
className="inline-flex items-center gap-1 text-xs text-muted-foreground min-w-0"
onClick={(e) => e.stopPropagation()}
>
<Link
to={`/user/profile/${encodeURIComponent(maybeUser.username)}`}
className="inline-flex items-center gap-1 hover:underline text-foreground/80 min-w-0"
className="inline-flex items-center gap-1 hover:underline text-foreground/80 text-xs min-w-0"
title={maybeUser.username}
>
<IconUser className="size-3.5 shrink-0" />
<span className="truncate">{maybeUser.display_name}</span>
</Link>
<Link
to={`/debug_logs/user/${encodeURIComponent(maybeUser.user_token)}`}
className="inline-flex items-center gap-1 text-muted-foreground hover:text-foreground shrink-0 hover:underline"
title="View this user's debug logs"
>
<IconListSearch className="size-3.5" />
logs
</Link>
</span>
)}
<span className="text-xs text-muted-foreground tabular-nums whitespace-nowrap">
{formatDebugLogDateTime(log.created_at)}
</span>
<span className="text-xs text-muted-foreground/60 font-mono ml-auto">
#{log.id}
{log.maybe_ip_address && (
<span
className="font-mono text-xs text-muted-foreground truncate min-w-0 max-w-[10rem]"
title={log.maybe_ip_address}
>
{log.maybe_ip_address}
</span>
)}
<span
className="ml-auto inline-flex items-center gap-1.5 min-w-0"
onClick={(e) => e.stopPropagation()}
>
<Link
to={`/debug_logs/${encodeURIComponent(log.event_token)}`}
className="font-mono text-xs text-muted-foreground hover:text-foreground hover:underline truncate"
title={`View event ${log.event_token}`}
>
{log.event_token}
</Link>
<span className="text-xs text-muted-foreground/60 font-mono whitespace-nowrap">
(#{log.id})
</span>
</span>
<span
className="ml-2 inline-flex items-center"
@@ -202,40 +217,53 @@ export function DebugLogCard({
{expanded && (
<div className="border-t border-border/50 p-4 flex flex-col gap-3">
<div className="flex flex-wrap gap-x-6 gap-y-1 text-xs text-muted-foreground">
<div>
<span className="uppercase tracking-wider font-medium">
Event:
</span>{" "}
<Link
to={`/debug_logs/${encodeURIComponent(log.event_token)}`}
className="font-mono text-foreground/80 hover:underline"
>
{log.event_token}
</Link>
</div>
{log.maybe_creator_user_token && (
<span className="inline-flex items-center gap-3 min-w-0">
<button
type="button"
onClick={() =>
onCopy(log.maybe_creator_user_token!, `user_token_${log.id}`)
}
className="inline-flex items-center gap-1 text-muted-foreground hover:text-foreground cursor-pointer min-w-0"
title="Copy user token"
>
<span className="whitespace-nowrap">user token:</span>
<span className="font-mono truncate">
{log.maybe_creator_user_token}
</span>
{copiedId === `user_token_${log.id}` ? (
<IconCheck className="size-3 shrink-0 text-emerald-400" />
) : (
<IconCopy className="size-3 shrink-0 opacity-60" />
)}
</button>
<span className="text-muted-foreground/40">|</span>
{maybeUser && (
{/* Line 1: timestamp, path, ip, event token — all click-to-copy. */}
<div className="flex flex-wrap items-center gap-x-6 gap-y-1 text-xs text-muted-foreground">
<span className="tabular-nums whitespace-nowrap">
{formatDebugLogDateTime(log.created_at)}
</span>
{log.maybe_url && (
<CopyText
label="Path:"
value={log.maybe_url}
display={log.maybe_url}
copyKey={`url_${log.id}`}
copiedId={copiedId}
onCopy={onCopy}
title="Copy URL"
className="font-mono truncate max-w-[32rem]"
/>
)}
{log.maybe_ip_address && (
<CopyText
label="IP:"
value={log.maybe_ip_address}
display={log.maybe_ip_address}
copyKey={`ip_${log.id}`}
copiedId={copiedId}
onCopy={onCopy}
title="Copy IP address"
className="font-mono truncate max-w-[16rem]"
/>
)}
<CopyText
label="Event Token:"
value={log.event_token}
display={log.event_token}
copyKey={`event_${log.id}`}
copiedId={copiedId}
onCopy={onCopy}
title="Copy event token"
className="font-mono truncate"
/>
</div>
{/* Line 2: the user and their event logs. */}
{log.maybe_creator_user_token && (
<div className="flex flex-wrap items-center gap-x-6 gap-y-1 text-xs text-muted-foreground">
<span className="inline-flex items-center gap-1.5 min-w-0">
<span className="whitespace-nowrap">User:</span>
{maybeUser ? (
<Link
to={`/user/profile/${encodeURIComponent(maybeUser.username)}`}
className="inline-flex items-center gap-1.5 text-foreground/80 hover:text-foreground hover:underline min-w-0"
@@ -244,18 +272,29 @@ export function DebugLogCard({
<IconUser className="size-3.5 shrink-0" />
<span className="truncate">{maybeUser.display_name}</span>
</Link>
) : (
<CopyText
value={log.maybe_creator_user_token}
display={log.maybe_creator_user_token}
copyKey={`user_token_${log.id}`}
copiedId={copiedId}
onCopy={onCopy}
title="Copy user token"
className="font-mono truncate"
icon={<IconUser className="size-3.5 shrink-0" />}
/>
)}
<Link
to={`/debug_logs/user/${encodeURIComponent(log.maybe_creator_user_token)}`}
className="inline-flex items-center gap-1 text-muted-foreground hover:text-foreground hover:underline shrink-0"
title="View this user's debug logs"
>
<IconListSearch className="size-3.5" />
logs
</Link>
</span>
)}
</div>
<Link
to={`/debug_logs/user/${encodeURIComponent(log.maybe_creator_user_token)}`}
className="inline-flex items-center gap-1 hover:text-foreground hover:underline shrink-0"
title="View this user's debug logs"
>
<IconListSearch className="size-3.5" />
user event logs
</Link>
</div>
)}
<PrettyPayload raw={log.message} />
</div>
)}
@@ -263,6 +302,52 @@ export function DebugLogCard({
);
}
interface CopyTextProps {
/** Optional label rendered before the value, eg. "Path:". */
label?: string;
/** The raw value copied to the clipboard. */
value: string;
/** The rendered text (may differ from the copied value). */
display: string;
copyKey: string;
copiedId: string | null;
onCopy: (value: string, id: string) => void;
title: string;
className?: string;
icon?: React.ReactNode;
}
function CopyText({
label,
value,
display,
copyKey,
copiedId,
onCopy,
title,
className,
icon,
}: CopyTextProps) {
return (
<button
type="button"
onClick={() => onCopy(value, copyKey)}
className="inline-flex items-center gap-1 hover:text-foreground cursor-pointer min-w-0"
title={title}
>
{label && <span className="whitespace-nowrap">{label}</span>}
{icon}
<span className={className}>{display}</span>
{copiedId === copyKey ? (
<IconCheck className="size-3 shrink-0 text-emerald-400" />
) : (
<IconCopy className="size-3 shrink-0 opacity-60" />
)}
</button>
);
}
function tryParseJson(raw: string): unknown | undefined {
const trimmed = raw.trim();
if (
@@ -269,7 +269,6 @@ export function DebugLogsAll() {
log={log}
copiedId={copiedId}
onCopy={copy}
showEventLink
defaultExpanded={false}
expandAll={expandAll}
/>
@@ -254,7 +254,6 @@ export function UserDebugLogs() {
log={log}
copiedId={copiedId}
onCopy={copy}
showEventLink
defaultExpanded={false}
expandAll={expandAll}
/>
@@ -126,6 +126,8 @@ export interface DebugLog {
id: number;
maybe_log_level: DebugLogLevel | null;
maybe_creator_user_token: string | null;
maybe_ip_address: string | null;
maybe_url: string | null;
message: string;
maybe_user: DebugLogUser | null;
}
+1 -1
View File
@@ -24,7 +24,7 @@ if (import.meta.env.DEV) {
// (disabled — it overrides the origin above and points at localhost:12345,
// which breaks dev unless a local backend is running. Re-enable only when
// testing against a local storyteller-web.)
//StorytellerApiHostStore.getInstance().setDevelopment();
StorytellerApiHostStore.getInstance().setDevelopment();
} catch (e) {
console.warn("Failed to set dev API host override", e);
}
+88 -168
View File
File diff suppressed because it is too large. Load diff