mirror of
https://github.com/openai/codex.git
synced 2026-02-01 22:47:52 +00:00
chore: improve client (#10149)
<img width="883" height="84" alt="Screenshot 2026-01-29 at 11 13 12" src="https://github.com/user-attachments/assets/090a2fec-94ed-4c0f-aee5-1653ed8b1439" />
This commit is contained in:
1
codex-rs/Cargo.lock
generated
1
codex-rs/Cargo.lock
generated
@@ -1855,6 +1855,7 @@ dependencies = [
|
||||
"codex-otel",
|
||||
"codex-protocol",
|
||||
"dirs",
|
||||
"owo-colors",
|
||||
"pretty_assertions",
|
||||
"serde",
|
||||
"serde_json",
|
||||
|
||||
@@ -11,6 +11,7 @@ clap = { workspace = true, features = ["derive", "env"] }
|
||||
codex-otel = { workspace = true }
|
||||
codex-protocol = { workspace = true }
|
||||
dirs = { workspace = true }
|
||||
owo-colors = { workspace = true }
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
serde_json = { workspace = true }
|
||||
sqlx = { workspace = true }
|
||||
|
||||
@@ -5,7 +5,6 @@ CREATE TABLE logs (
|
||||
level TEXT NOT NULL,
|
||||
target TEXT NOT NULL,
|
||||
message TEXT,
|
||||
fields_json TEXT NOT NULL,
|
||||
module_path TEXT,
|
||||
file TEXT,
|
||||
line INTEGER
|
||||
|
||||
@@ -9,6 +9,7 @@ use chrono::Utc;
|
||||
use clap::Parser;
|
||||
use codex_state::STATE_DB_FILENAME;
|
||||
use dirs::home_dir;
|
||||
use owo_colors::OwoColorize;
|
||||
use sqlx::QueryBuilder;
|
||||
use sqlx::Row;
|
||||
use sqlx::Sqlite;
|
||||
@@ -64,8 +65,6 @@ struct LogRow {
|
||||
ts_nanos: i64,
|
||||
level: String,
|
||||
message: Option<String>,
|
||||
fields_json: String,
|
||||
module_path: Option<String>,
|
||||
file: Option<String>,
|
||||
line: Option<i64>,
|
||||
}
|
||||
@@ -237,7 +236,7 @@ async fn fetch_max_id(pool: &SqlitePool, filter: &LogFilter) -> anyhow::Result<i
|
||||
|
||||
fn base_select_builder<'a>() -> QueryBuilder<'a, Sqlite> {
|
||||
QueryBuilder::<Sqlite>::new(
|
||||
"SELECT id, ts, ts_nanos, level, message, fields_json, module_path, file, line FROM logs WHERE 1 = 1",
|
||||
"SELECT id, ts, ts_nanos, level, message, file, line FROM logs WHERE 1 = 1",
|
||||
)
|
||||
}
|
||||
|
||||
@@ -269,19 +268,38 @@ fn push_filters<'a>(builder: &mut QueryBuilder<'a, Sqlite>, filter: &'a LogFilte
|
||||
|
||||
fn format_row(row: &LogRow) -> String {
|
||||
let timestamp = format_timestamp(row.ts, row.ts_nanos);
|
||||
let level = row.level.as_str();
|
||||
let location = match (&row.file, row.line) {
|
||||
(Some(file), Some(line)) => format!("{file}:{line}"),
|
||||
(Some(file), None) => file.clone(),
|
||||
_ => "-".to_string(),
|
||||
};
|
||||
let module = row.module_path.as_deref().unwrap_or("-");
|
||||
let message = row.message.as_deref().unwrap_or("");
|
||||
let fields = row.fields_json.as_str();
|
||||
let level = row.level.as_str();
|
||||
if fields == "{}" || fields.is_empty() {
|
||||
return format!("{timestamp} {level:<5} [{module}] {location} - {message}");
|
||||
let level_colored = color_level(level);
|
||||
let timestamp_colored = timestamp.dimmed().to_string();
|
||||
let location_colored = location.dimmed().to_string();
|
||||
let message_colored = message.bold().to_string();
|
||||
format!("{timestamp_colored} {level_colored} {location_colored} - {message_colored}")
|
||||
}
|
||||
|
||||
fn color_level(level: &str) -> String {
|
||||
let padded = format!("{level:<5}");
|
||||
if level.eq_ignore_ascii_case("error") {
|
||||
return padded.red().bold().to_string();
|
||||
}
|
||||
format!("{timestamp} {level:<5} [{module}] {location} - {message} {fields}")
|
||||
if level.eq_ignore_ascii_case("warn") {
|
||||
return padded.yellow().bold().to_string();
|
||||
}
|
||||
if level.eq_ignore_ascii_case("info") {
|
||||
return padded.green().bold().to_string();
|
||||
}
|
||||
if level.eq_ignore_ascii_case("debug") {
|
||||
return padded.blue().bold().to_string();
|
||||
}
|
||||
if level.eq_ignore_ascii_case("trace") {
|
||||
return padded.magenta().bold().to_string();
|
||||
}
|
||||
padded.bold().to_string()
|
||||
}
|
||||
|
||||
fn format_timestamp(ts: i64, ts_nanos: i64) -> String {
|
||||
|
||||
@@ -22,7 +22,6 @@ use std::time::Duration;
|
||||
use std::time::SystemTime;
|
||||
use std::time::UNIX_EPOCH;
|
||||
|
||||
use serde_json::Value;
|
||||
use tokio::sync::mpsc;
|
||||
use tracing::Event;
|
||||
use tracing::field::Field;
|
||||
@@ -54,7 +53,7 @@ where
|
||||
{
|
||||
fn on_event(&self, event: &Event<'_>, _ctx: tracing_subscriber::layer::Context<'_, S>) {
|
||||
let metadata = event.metadata();
|
||||
let mut visitor = JsonVisitor::default();
|
||||
let mut visitor = MessageVisitor::default();
|
||||
event.record(&mut visitor);
|
||||
|
||||
let now = SystemTime::now()
|
||||
@@ -66,7 +65,6 @@ where
|
||||
level: metadata.level().as_str().to_string(),
|
||||
target: metadata.target().to_string(),
|
||||
message: visitor.message,
|
||||
fields_json: Value::Object(visitor.fields).to_string(),
|
||||
module_path: metadata.module_path().map(ToString::to_string),
|
||||
file: metadata.file().map(ToString::to_string),
|
||||
line: metadata.line().map(|line| line as i64),
|
||||
@@ -114,49 +112,44 @@ async fn flush(state_db: &std::sync::Arc<StateRuntime>, buffer: &mut Vec<LogEntr
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct JsonVisitor {
|
||||
fields: serde_json::Map<String, Value>,
|
||||
struct MessageVisitor {
|
||||
message: Option<String>,
|
||||
}
|
||||
|
||||
impl JsonVisitor {
|
||||
fn record_value(&mut self, field: &Field, value: Value) {
|
||||
impl MessageVisitor {
|
||||
fn record_message(&mut self, field: &Field, value: String) {
|
||||
if field.name() == "message" && self.message.is_none() {
|
||||
self.message = Some(match &value {
|
||||
Value::String(message) => message.clone(),
|
||||
_ => value.to_string(),
|
||||
});
|
||||
self.message = Some(value);
|
||||
}
|
||||
self.fields.insert(field.name().to_string(), value);
|
||||
}
|
||||
}
|
||||
|
||||
impl Visit for JsonVisitor {
|
||||
impl Visit for MessageVisitor {
|
||||
fn record_i64(&mut self, field: &Field, value: i64) {
|
||||
self.record_value(field, Value::from(value));
|
||||
self.record_message(field, value.to_string());
|
||||
}
|
||||
|
||||
fn record_u64(&mut self, field: &Field, value: u64) {
|
||||
self.record_value(field, Value::from(value));
|
||||
self.record_message(field, value.to_string());
|
||||
}
|
||||
|
||||
fn record_bool(&mut self, field: &Field, value: bool) {
|
||||
self.record_value(field, Value::from(value));
|
||||
self.record_message(field, value.to_string());
|
||||
}
|
||||
|
||||
fn record_f64(&mut self, field: &Field, value: f64) {
|
||||
self.record_value(field, Value::from(value));
|
||||
self.record_message(field, value.to_string());
|
||||
}
|
||||
|
||||
fn record_str(&mut self, field: &Field, value: &str) {
|
||||
self.record_value(field, Value::from(value));
|
||||
self.record_message(field, value.to_string());
|
||||
}
|
||||
|
||||
fn record_error(&mut self, field: &Field, value: &(dyn std::error::Error + 'static)) {
|
||||
self.record_value(field, Value::from(value.to_string()));
|
||||
self.record_message(field, value.to_string());
|
||||
}
|
||||
|
||||
fn record_debug(&mut self, field: &Field, value: &dyn std::fmt::Debug) {
|
||||
self.record_value(field, Value::from(format!("{value:?}")));
|
||||
self.record_message(field, format!("{value:?}"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@ pub struct LogEntry {
|
||||
pub level: String,
|
||||
pub target: String,
|
||||
pub message: Option<String>,
|
||||
pub fields_json: String,
|
||||
pub module_path: Option<String>,
|
||||
pub file: Option<String>,
|
||||
pub line: Option<i64>,
|
||||
|
||||
@@ -214,7 +214,7 @@ FROM threads
|
||||
}
|
||||
|
||||
let mut builder = QueryBuilder::<Sqlite>::new(
|
||||
"INSERT INTO logs (ts, ts_nanos, level, target, message, fields_json, module_path, file, line) ",
|
||||
"INSERT INTO logs (ts, ts_nanos, level, target, message, module_path, file, line) ",
|
||||
);
|
||||
builder.push_values(entries, |mut row, entry| {
|
||||
row.push_bind(entry.ts)
|
||||
@@ -222,7 +222,6 @@ FROM threads
|
||||
.push_bind(&entry.level)
|
||||
.push_bind(&entry.target)
|
||||
.push_bind(&entry.message)
|
||||
.push_bind(&entry.fields_json)
|
||||
.push_bind(&entry.module_path)
|
||||
.push_bind(&entry.file)
|
||||
.push_bind(entry.line);
|
||||
|
||||
Reference in New Issue
Block a user