feat: add events logger (#170)

* add common events

* log events in serve

* formatting

* extract serde_conv

* update

* update

* fix logging

* update
support-coreml
Meng Zhang 2023-05-30 15:44:29 -07:00 committed by GitHub
parent d8cee4adac
commit f3b37b253b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 348 additions and 33 deletions

207
Cargo.lock generated
View File

@ -46,6 +46,21 @@ dependencies = [
"memchr",
]
[[package]]
name = "android-tzdata"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
[[package]]
name = "android_system_properties"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
dependencies = [
"libc",
]
[[package]]
name = "anstream"
version = "0.3.2"
@ -285,6 +300,21 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "chrono"
version = "0.4.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec837a71355b28f6556dbd569b37b3f363091c0bd4b2e735674521b4c5fd9bc5"
dependencies = [
"android-tzdata",
"iana-time-zone",
"js-sys",
"num-traits",
"time 0.1.45",
"wasm-bindgen",
"winapi",
]
[[package]]
name = "cipher"
version = "0.4.4"
@ -845,7 +875,7 @@ checksum = "c85e1d9ab2eadba7e5040d4e09cbd6d072b76a557ad64e797c2cb9d4da21d7e4"
dependencies = [
"cfg-if",
"libc",
"wasi",
"wasi 0.11.0+wasi-snapshot-preview1",
]
[[package]]
@ -998,6 +1028,29 @@ dependencies = [
"tokio-native-tls",
]
[[package]]
name = "iana-time-zone"
version = "0.1.56"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0722cd7114b7de04316e7ea5456a0bbb20e4adb46fd27a3697adb812cff0f37c"
dependencies = [
"android_system_properties",
"core-foundation-sys",
"iana-time-zone-haiku",
"js-sys",
"wasm-bindgen",
"windows",
]
[[package]]
name = "iana-time-zone-haiku"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
dependencies = [
"cc",
]
[[package]]
name = "ident_case"
version = "1.0.1"
@ -1281,7 +1334,7 @@ checksum = "5b9d9a46eff5b4ff64b45a9e316a6d1e0bc719ef429cbec4dc630684212bfdf9"
dependencies = [
"libc",
"log",
"wasi",
"wasi 0.11.0+wasi-snapshot-preview1",
"windows-sys 0.45.0",
]
@ -1334,6 +1387,15 @@ dependencies = [
"minimal-lexical",
]
[[package]]
name = "num-traits"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
dependencies = [
"autocfg",
]
[[package]]
name = "num_cpus"
version = "1.15.0"
@ -1750,6 +1812,28 @@ dependencies = [
"winreg",
]
[[package]]
name = "rmp"
version = "0.8.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "44519172358fd6d58656c86ab8e7fbc9e1490c3e8f14d35ed78ca0dd07403c9f"
dependencies = [
"byteorder",
"num-traits",
"paste",
]
[[package]]
name = "rmp-serde"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c5b13be192e0220b8afb7222aa5813cb62cc269ebb5cac346ca6487681d2913e"
dependencies = [
"byteorder",
"rmp",
"serde",
]
[[package]]
name = "rust-cxx-cmake-bridge"
version = "0.1.0"
@ -1914,6 +1998,15 @@ dependencies = [
"serde",
]
[[package]]
name = "serde_spanned"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93107647184f6027e3b7dcb2e11034cf95ffa1e3a682c67951963ac69c1c007d"
dependencies = [
"serde",
]
[[package]]
name = "serde_urlencoded"
version = "0.7.1"
@ -1926,6 +2019,19 @@ dependencies = [
"serde",
]
[[package]]
name = "serdeconv"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8897696def1d25e554294b168e0e8e77c860483666eeb8d3d33ae58b06f47221"
dependencies = [
"rmp-serde",
"serde",
"serde_json",
"toml",
"trackable",
]
[[package]]
name = "sha1"
version = "0.10.5"
@ -2085,6 +2191,7 @@ dependencies = [
"rust-embed",
"serde",
"serde_json",
"serdeconv",
"strum",
"tabby-common",
"tokio",
@ -2098,6 +2205,12 @@ dependencies = [
[[package]]
name = "tabby-common"
version = "0.1.0"
dependencies = [
"chrono",
"lazy_static",
"serde",
"serdeconv",
]
[[package]]
name = "tar"
@ -2152,6 +2265,17 @@ dependencies = [
"syn 2.0.18",
]
[[package]]
name = "time"
version = "0.1.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a"
dependencies = [
"libc",
"wasi 0.10.0+wasi-snapshot-preview1",
"winapi",
]
[[package]]
name = "time"
version = "0.3.21"
@ -2273,6 +2397,40 @@ dependencies = [
"tracing",
]
[[package]]
name = "toml"
version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6135d499e69981f9ff0ef2167955a5333c35e36f6937d382974566b3d5b94ec"
dependencies = [
"serde",
"serde_spanned",
"toml_datetime",
"toml_edit",
]
[[package]]
name = "toml_datetime"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a76a9312f5ba4c2dec6b9161fdf25d87ad8a09256ccea5a556fef03c706a10f"
dependencies = [
"serde",
]
[[package]]
name = "toml_edit"
version = "0.19.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2380d56e8670370eee6566b0bfd4265f65b3f432e8c6d85623f728d4fa31f739"
dependencies = [
"indexmap",
"serde",
"serde_spanned",
"toml_datetime",
"winnow",
]
[[package]]
name = "tower"
version = "0.4.13"
@ -2340,6 +2498,25 @@ dependencies = [
"once_cell",
]
[[package]]
name = "trackable"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b15bd114abb99ef8cee977e517c8f37aee63f184f2d08e3e6ceca092373369ae"
dependencies = [
"trackable_derive",
]
[[package]]
name = "trackable_derive"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ebeb235c5847e2f82cfe0f07eb971d1e5f6804b18dac2ae16349cc604380f82f"
dependencies = [
"quote",
"syn 1.0.109",
]
[[package]]
name = "try-lock"
version = "0.2.4"
@ -2520,6 +2697,12 @@ dependencies = [
"try-lock",
]
[[package]]
name = "wasi"
version = "0.10.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
[[package]]
name = "wasi"
version = "0.11.0+wasi-snapshot-preview1"
@ -2646,6 +2829,15 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f"
dependencies = [
"windows-targets 0.48.0",
]
[[package]]
name = "windows-sys"
version = "0.42.0"
@ -2793,6 +2985,15 @@ version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
[[package]]
name = "winnow"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61de7bac303dc551fe038e2b3cef0f571087a47571ea6e79a87692ac99b99699"
dependencies = [
"memchr",
]
[[package]]
name = "winreg"
version = "0.10.1"
@ -2827,7 +3028,7 @@ dependencies = [
"hmac",
"pbkdf2",
"sha1",
"time",
"time 0.3.21",
"zstd",
]

View File

@ -11,3 +11,8 @@ version = "0.1.0"
edition = "2021"
authors = ["Meng Zhang"]
homepage = "https://github.com/TabbyML/tabby"
[workspace.dependencies]
lazy_static = "1.4.0"
serde = { version = "1.0", features = ["derive"] }
serdeconv = "0.4.1"

View File

@ -6,3 +6,7 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
chrono = "0.4.26"
lazy_static = { workspace = true }
serde = { workspace = true }
serdeconv = { workspace = true }

View File

@ -0,0 +1,82 @@
use chrono::Utc;
use lazy_static::lazy_static;
use serde::Serialize;
use std::fs;
use std::io::{BufWriter, Write};
use std::sync::Mutex;
lazy_static! {
static ref WRITER: Mutex<BufWriter<fs::File>> = {
let events_dir = &crate::path::EVENTS_DIR;
std::fs::create_dir_all(events_dir.as_path()).ok();
let now = Utc::now();
let fname = now.format("%Y-%m-%d.json");
let file = fs::OpenOptions::new()
.create(true)
.append(true)
.write(true)
.open(events_dir.join(fname.to_string()))
.ok()
.unwrap();
Mutex::new(BufWriter::new(file))
};
}
#[derive(Serialize)]
pub struct Choice<'a> {
pub index: u32,
pub text: &'a str,
}
#[derive(Serialize)]
#[serde(rename_all = "snake_case")]
pub enum Event<'a> {
View {
completion_id: &'a str,
choice_index: u32,
},
Selected {
completion_id: &'a str,
choice_index: u32,
},
Completion {
completion_id: &'a str,
language: &'a str,
prompt: &'a str,
choices: Vec<Choice<'a>>,
},
}
#[derive(Serialize)]
struct Log<'a> {
ts: u128,
event: &'a Event<'a>,
}
impl Event<'_> {
pub fn log(&self) {
let mut writer = WRITER.lock().unwrap();
serdeconv::to_json_writer(
&Log {
ts: timestamp(),
event: self,
},
writer.by_ref(),
)
.unwrap();
write!(writer, "\n").unwrap();
writer.flush().unwrap();
}
}
fn timestamp() -> u128 {
use std::time::{SystemTime, UNIX_EPOCH};
let start = SystemTime::now();
start
.duration_since(UNIX_EPOCH)
.expect("Time went backwards")
.as_millis()
}

View File

@ -1 +1,2 @@
pub mod events;
pub mod path;

View File

@ -1,18 +1,23 @@
use std::env;
use std::path::PathBuf;
fn get_root_dir() -> PathBuf {
match env::var("TABBY_ROOT") {
Ok(x) => PathBuf::from(x),
Err(_) => PathBuf::from(env::var("HOME").unwrap()).join(".tabby"),
}
use lazy_static::lazy_static;
lazy_static! {
pub static ref TABBY_ROOT: PathBuf = {
match env::var("TABBY_ROOT") {
Ok(x) => PathBuf::from(x),
Err(_) => PathBuf::from(env::var("HOME").unwrap()).join(".tabby"),
}
};
pub static ref EVENTS_DIR: PathBuf = TABBY_ROOT.join("events");
}
pub struct ModelDir(PathBuf);
impl ModelDir {
pub fn new(model: &str) -> Self {
Self(get_root_dir().join("models").join(model))
Self(TABBY_ROOT.join("models").join(model))
}
pub fn from(path: &str) -> Self {

View File

@ -10,7 +10,8 @@ tokio = { version = "1.17", features = ["full"] }
tower = "0.4"
utoipa = { version = "3.3", features = ["axum_extras", "preserve_order"] }
utoipa-swagger-ui = { version = "3.1", features = ["axum"] }
serde = { version = "1.0", features = ["derive"] }
serde = { workspace = true }
serdeconv = { workspace = true }
serde_json = "1.0"
env_logger = "0.10.0"
log = "0.4"
@ -18,7 +19,7 @@ ctranslate2-bindings = { path = "../ctranslate2-bindings" }
tower-http = { version = "0.4.0", features = ["cors"] }
clap = { version = "4.3.0", features = ["derive"] }
regex = "1.8.3"
lazy_static = "1.4.0"
lazy_static = { workspace = true }
rust-embed = "6.6.1"
mime_guess = "2.0.4"
strum = { version = "0.24", features = ["derive"] }

View File

@ -5,7 +5,7 @@ use ctranslate2_bindings::{
use serde::{Deserialize, Serialize};
use std::path::Path;
use std::sync::Arc;
use tabby_common::path::ModelDir;
use tabby_common::{events, path::ModelDir};
use utoipa::ToSchema;
mod languages;
@ -29,7 +29,6 @@ pub struct Choice {
#[derive(Serialize, Deserialize, ToSchema, Clone, Debug)]
pub struct CompletionResponse {
id: String,
created: u64,
choices: Vec<Choice>,
}
@ -51,15 +50,26 @@ pub async fn completion(
let language = request.language.unwrap_or("unknown".into());
let filtered_text = languages::remove_stop_words(&language, &text);
Json(CompletionResponse {
let response = CompletionResponse {
id: format!("cmpl-{}", uuid::Uuid::new_v4()),
created: timestamp(),
choices: [Choice {
choices: vec![Choice {
index: 0,
text: filtered_text.to_string(),
}]
.to_vec(),
})
}],
};
events::Event::Completion {
completion_id: &response.id,
language: &language,
prompt: &request.prompt,
choices: vec![events::Choice {
index: 0,
text: filtered_text,
}],
}
.log();
Json(response)
}
pub struct CompletionState {
@ -94,15 +104,6 @@ fn get_model_dir(model: &str) -> ModelDir {
}
}
fn timestamp() -> u64 {
use std::time::{SystemTime, UNIX_EPOCH};
let start = SystemTime::now();
start
.duration_since(UNIX_EPOCH)
.expect("Time went backwards")
.as_secs()
}
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
struct Metadata {
@ -115,7 +116,5 @@ struct TransformersInfo {
}
fn read_metadata(model_dir: &ModelDir) -> Metadata {
let file = std::fs::File::open(model_dir.metadata_file()).unwrap();
let reader = std::io::BufReader::new(file);
serde_json::from_reader(reader).unwrap()
serdeconv::from_json_file(model_dir.metadata_file()).unwrap()
}

View File

@ -1,10 +1,12 @@
use axum::Json;
use hyper::StatusCode;
use serde::{Deserialize, Serialize};
use tabby_common::events;
use utoipa::ToSchema;
#[derive(Serialize, Deserialize, ToSchema, Clone, Debug)]
pub struct LogEventRequest {
#[schema(example = "view")]
#[serde(rename = "type")]
event_type: String,
completion_id: String,
@ -17,6 +19,21 @@ pub struct LogEventRequest {
request_body = LogEventRequest,
)]
pub async fn log_event(Json(request): Json<LogEventRequest>) -> StatusCode {
println!("log_event: {:?}", request);
StatusCode::OK
if request.event_type == "view" {
events::Event::View {
completion_id: &request.completion_id,
choice_index: request.choice_index,
}
.log();
StatusCode::OK
} else if request.event_type == "selected" {
events::Event::Selected {
completion_id: &request.completion_id,
choice_index: request.choice_index,
}
.log();
StatusCode::OK
} else {
StatusCode::BAD_REQUEST
}
}