diff --git a/.gitignore b/.gitignore index 4b234b6..9347201 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ .vscode Cargo.lock +.cargo/ \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 117a58e..4ec271f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -288,16 +288,6 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" -[[package]] -name = "clap_mangen" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3be86020147691e1d2ef58f75346a3d4d94807bfc473e377d52f09f0f7d77f7" -dependencies = [ - "clap", - "roff", -] - [[package]] name = "colorchoice" version = "1.0.0" @@ -797,9 +787,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.0.2" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8adf3ddd720272c6ea8bf59463c04e0f93d0bbf7c5439b691bca2987e0270897" +checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" dependencies = [ "equivalent", "hashbrown 0.14.2", @@ -1055,6 +1045,15 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" +[[package]] +name = "openssl-src" +version = "300.1.6+3.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439fac53e092cd7442a3660c85dde4643ab3b5bd39040912388dcdabf6b88085" +dependencies = [ + "cc", +] + [[package]] name = "openssl-sys" version = "0.9.93" @@ -1063,6 +1062,7 @@ checksum = "db4d56a4c0478783083cfafcc42493dd4a981d41669da64b4572a2a089b51b1d" dependencies = [ "cc", "libc", + "openssl-src", "pkg-config", "vcpkg", ] @@ -1258,12 +1258,6 @@ dependencies = [ "rand", ] -[[package]] -name = "roff" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" - [[package]] name = "rustc-demangle" version = "0.1.23" @@ -1353,18 +1347,18 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.189" +version = "1.0.190" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e422a44e74ad4001bdc8eede9a4570ab52f71190e9c076d14369f38b9200537" +checksum = "91d3c334ca1ee894a2c6f6ad698fe8c435b76d504b13d436f0685d648d6d96f7" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.189" +version = "1.0.190" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e48d1f918009ce3145511378cf68d613e3b3d9137d67272562080d68a2b32d5" +checksum = "67c5609f394e5c2bd7fc51efda478004ea80ef42fee983d5c67a65e34f32c0e3" dependencies = [ "proc-macro2", "quote", @@ -1373,9 +1367,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.107" +version = "1.0.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b420ce6e3d8bd882e9b243c6eed35dbc9a6110c9769e74b584e0d68d1f20c65" +checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" dependencies = [ "itoa", "ryu", @@ -1468,13 +1462,13 @@ dependencies = [ "chrono", "clap", "clap_complete", - "clap_mangen", "elasticsearch", "env_logger", "fs-tail", "hostname", "local-ip-address", "log", + "openssl", "regex", "retry", "serde", @@ -1689,7 +1683,7 @@ version = "0.20.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70f427fce4d84c72b5b732388bf4a9f4531b53f74e2887e3ecb2481f68f66d81" dependencies = [ - "indexmap 2.0.2", + "indexmap 2.1.0", "serde", "serde_spanned", "toml_datetime", diff --git a/Cargo.toml b/Cargo.toml index bd8c868..ae7e8fe 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,31 +23,4 @@ clap_complete = "4.4.4" regex = "1.10.2" serde = "1.0.189" cargo-deb = { version = "2.0.0" } - -[build-dependencies] -clap_mangen = "0.2.15" - - -[package.metadata.deb] -maintainer = "cargo-deb developers " -copyright = "2017, cargo-deb developers." -license-file = ["LICENSE", "2"] -extended-description = "example project for cargo-deb" -depends = "$auto" -section = "utils" -priority = "optional" -assets = [ - ["target/release/sql_normalizer", "usr/bin/", "755"], -] -default-features = false -features = ["example_debian_build"] - -[package.metadata.deb.variants.debug] -assets = [ - ["target/release/sql_normalizer", "usr/bin/", "755"], -] - -[features] -default = ["example_non_debian_build"] -example_non_debian_build = [] -example_debian_build = [] +openssl = { version = "0.10.35", features = ["vendored"] } \ No newline at end of file diff --git a/src/anonymize.rs b/src/anonymize.rs index 6a6cfac..c82542a 100644 --- a/src/anonymize.rs +++ b/src/anonymize.rs @@ -1,24 +1,22 @@ - -use sqlparser::ast::{Expr, Query, Select, SetExpr, Statement, Offset, Value, FunctionArg}; -use log::{debug}; -use sqlparser::ast::FunctionArgExpr::Expr as OtherExpr; use crate::parser::Command; - +use log::debug; +use sqlparser::ast::FunctionArgExpr::Expr as OtherExpr; +use sqlparser::ast::{Expr, FunctionArg, Offset, Query, Select, SetExpr, Statement, Value}; fn selection_changer(selection: &mut Expr) -> &mut Expr { debug!("Selection Changer: {:?}", selection); match selection { Expr::BinaryOp { left, right, .. } => { *left = Box::new(selection_changer(left).to_owned()); - *right= Box::new(selection_changer(right).to_owned()); - }, - Expr::Like { pattern, .. } => { + *right = Box::new(selection_changer(right).to_owned()); + } + Expr::Like { pattern, .. } => { *pattern = Box::new(selection_changer(pattern).to_owned()); } - Expr::Value(value) => { + Expr::Value(value) => { *value = Value::Placeholder("?".to_string()); } - Expr::InList { list , .. } => { + Expr::InList { list, .. } => { *list = vec![Expr::Value(Value::Placeholder("?".to_string()))]; } Expr::Between { low, high, .. } => { @@ -39,20 +37,23 @@ fn selection_changer(selection: &mut Expr) -> &mut Expr { for arg in function.args.iter_mut() { match arg { FunctionArg::Unnamed(ref mut f_arg) => { - let OtherExpr(f_arg_expr) = f_arg else { panic!("{}", f_arg) }; + let OtherExpr(f_arg_expr) = f_arg else { + panic!("{}", f_arg) + }; { *f_arg_expr = selection_changer(f_arg_expr).to_owned(); } - }, + } FunctionArg::Named { ref mut arg, .. } => { - let OtherExpr(f_arg_expr) = arg else { panic!("{}", arg) }; + let OtherExpr(f_arg_expr) = arg else { + panic!("{}", arg) + }; { *f_arg_expr = selection_changer(f_arg_expr).to_owned(); } } } } - } _ => {} }; @@ -68,8 +69,7 @@ fn matcher(query: &mut Query) -> &mut Query { for yy in xx.iter_mut() { *yy = selection_changer(yy).to_owned(); } - }; - + } } SetExpr::Select(select) => { let Select { selection, .. } = select.as_mut(); @@ -78,16 +78,14 @@ fn matcher(query: &mut Query) -> &mut Query { *selection = Some(selection_changer(selection.as_mut().unwrap()).to_owned()); } } - } - _ => () + _ => (), }; if query.offset.is_some() { let Offset { value, .. } = query.offset.as_mut().unwrap(); { *value = selection_changer(value).to_owned(); } - } for order_by in query.order_by.iter_mut() { @@ -104,28 +102,34 @@ fn matcher(query: &mut Query) -> &mut Query { #[derive(Debug, Clone)] pub struct Replaced { pub statement_type: Command, - pub statement: Statement + pub statement: Statement, } pub fn rec(statement: &mut Statement) -> Replaced { debug!("rec: {:?}", statement); - let typed ; + let typed; match statement { Statement::Query(query) => { *query = Box::new(matcher(query).to_owned()); typed = Command::Query; - }, - Statement::Explain { statement: explain_statement, .. } => { + } + Statement::Explain { + statement: explain_statement, + .. + } => { *explain_statement = Box::new(rec(explain_statement).statement.clone()); typed = Command::Explain; - }, - Statement::Insert { source,.. } => { + } + Statement::Insert { source, .. } => { *source = Box::new(matcher(source).to_owned()); typed = Command::Insert; - }, - Statement::Update { selection,assignments, .. } => { - + } + Statement::Update { + selection, + assignments, + .. + } => { *selection = Some(selection_changer(selection.as_mut().unwrap()).clone()); for assigment in assignments.iter_mut() { @@ -133,14 +137,16 @@ pub fn rec(statement: &mut Statement) -> Replaced { } typed = Command::Update; - }, - Statement::Delete { selection, limit, .. } => { - + } + Statement::Delete { + selection, limit, .. + } => { *selection = Some(selection_changer(selection.as_mut().unwrap()).clone()); - *limit = Some(selection_changer(limit.as_mut().unwrap()).clone()); + if limit.is_some() { + *limit = Some(selection_changer(limit.as_mut().unwrap()).clone()); + } typed = Command::Delete; - - }, + } _ => { typed = Command::Other; } diff --git a/src/cli.rs b/src/cli.rs index b3732af..27ffba9 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -3,23 +3,22 @@ use elasticsearch::http::Url; use log::LevelFilter; use std::path::PathBuf; -#[derive(Args,Debug)] +#[derive(Args, Debug)] pub struct AddArgs { - /// Elastic host. Env: ELASTIC_HOST #[arg(short, long, env = "ELASTIC_HOST", required_if_eq("output", "elastic"))] pub elastic_host: Option, /// Sets Elastic username. - #[arg(short='u', long, env = "ELASTIC_USER", requires = "elastic_password")] + #[arg(short = 'u', long, env = "ELASTIC_USER", requires = "elastic_password")] pub elastic_user: Option, /// Sets Elastic password. - #[arg(short='p', long, env = "ELASTIC_PASSWORD", requires = "elastic_user")] + #[arg(short = 'p', long, env = "ELASTIC_PASSWORD", requires = "elastic_user")] pub elastic_password: Option, /// Sets an output type - #[arg(short='t', long, default_value = "file")] + #[arg(short = 't', long, default_value = "file")] #[clap(value_enum)] pub output: Output, @@ -33,33 +32,37 @@ pub struct AddArgs { pub input_file: Option, /// Sets a output file path - #[arg(short = 'o', long, value_name = "FILE", required_if_eq("output", "file"), default_value="output.txt")] + #[arg( + short = 'o', + long, + value_name = "FILE", + required_if_eq("output", "file"), + default_value = "output.txt" + )] pub output_file: Option, /// Sets a push size - #[arg(short='s', long, default_value = "1000")] + #[arg(short = 's', long, default_value = "1000")] pub elastic_push_size: u16, /// Sets a push seconds - #[arg(short='c', long, default_value = "15")] + #[arg(short = 'c', long, default_value = "15")] pub elastic_push_seconds: u16, /// Sets Elastic password. - #[arg(short='n', long, default_value = "mysql_logs", env = "ELASTIC_INDEX")] + #[arg(short = 'n', long, default_value = "mysql_logs", env = "ELASTIC_INDEX")] pub elastic_index_name: Option, /// Log original query - #[arg(short='q', long, default_value = "false")] + #[arg(short = 'q', long, default_value = "false")] pub query: bool, - } - #[derive(Parser)] #[command(author, version, about, long_about = None)] pub struct Client { /// Turn debugging information on - #[arg(short, long, default_value="error", global=true)] + #[arg(short, long, default_value = "error", global = true)] pub log_level: LevelFilter, /// Commands @@ -75,16 +78,15 @@ pub enum Commands { #[derive(clap::ValueEnum, Clone, Debug)] pub enum Input { Slow, - General + General, } #[derive(clap::ValueEnum, Clone, Debug, PartialEq)] pub enum Output { File, - Elastic + Elastic, } - pub fn cli() -> Client { Client::parse() -} \ No newline at end of file +} diff --git a/src/elastic.rs b/src/elastic.rs index 88b5842..d355532 100644 --- a/src/elastic.rs +++ b/src/elastic.rs @@ -1,34 +1,38 @@ -use chrono::{DateTime, FixedOffset, Local}; -use crate::{cli}; +use crate::cli; use crate::cli::Commands::Send; -use elasticsearch::{BulkParts, Elasticsearch}; +use crate::parser::LogEntry; +use chrono::{DateTime, FixedOffset, Local}; use elasticsearch::auth::Credentials; use elasticsearch::http::request::JsonBody; use elasticsearch::http::response::Response; use elasticsearch::http::transport::{SingleNodeConnectionPool, TransportBuilder}; +use elasticsearch::{BulkParts, Elasticsearch}; use log::{error, info}; -use crate::parser::LogEntry; use serde_json::{json, Value}; use uuid::Uuid; - pub async fn collect(mut body: Vec, log_entry: &LogEntry) -> Vec { let _id = Uuid::new_v4(); let local_time: DateTime = Local::now(); let Send(client) = cli::cli().command; - let datetime_with_timezone = - DateTime::::from_naive_utc_and_offset(log_entry.timestamp, - *local_time.offset()); + let datetime_with_timezone = DateTime::::from_naive_utc_and_offset( + log_entry.timestamp, + *local_time.offset(), + ); body.push(json!({"index": {"_id": log_entry.id }})); body.push(json!(log_entry)); if body.len() > client.elastic_push_size as usize - || local_time.signed_duration_since(datetime_with_timezone).num_seconds() > client.elastic_push_seconds as i64 { + || local_time + .signed_duration_since(datetime_with_timezone) + .num_seconds() + > client.elastic_push_seconds as i64 + { match send(body.to_vec()).await { Ok(_) => {} - Err(e) => error!("{:?}", e) + Err(e) => error!("{:?}", e), } body.truncate(0); } @@ -42,39 +46,41 @@ async fn elastic_connect() -> Result> match &cli.command { Send(name) => { let conn_pool = SingleNodeConnectionPool::new(name.elastic_host.clone().unwrap()); - let mut transport = TransportBuilder::new(conn_pool) - .disable_proxy(); + let mut transport = TransportBuilder::new(conn_pool).disable_proxy(); if name.elastic_user.is_some() { - transport = transport.auth(Credentials::Basic(name.elastic_user.clone().unwrap(), name.elastic_password.clone().unwrap())); + transport = transport.auth(Credentials::Basic( + name.elastic_user.clone().unwrap(), + name.elastic_password.clone().unwrap(), + )); } Ok(Elasticsearch::new(transport.build()?)) } } - } async fn send(body: Vec) -> Result> { let mut request_body: Vec> = Vec::with_capacity(body.len()); - info!("Elastic send statistic - {}",body.len()); + info!("Elastic send statistic - {}", body.len()); for body_datum in body { request_body.push(body_datum.into()) } - let client = elastic_connect().await?; let cli = cli::cli(); let Send(options) = cli.command; let response = client - .bulk(BulkParts::Index(options.elastic_index_name.unwrap().as_str())) + .bulk(BulkParts::Index( + options.elastic_index_name.unwrap().as_str(), + )) .body(request_body) .send() .await?; if response.status_code() != 200 { - return Err(format!("{:?}",response).into()) + return Err(format!("{:?}", response).into()); } Ok(response) diff --git a/src/main.rs b/src/main.rs index 23c274a..b47dfec 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,17 +1,14 @@ -mod parser; -mod cli; mod anonymize; +mod cli; mod elastic; +mod parser; - +use log::error; use std::env; use std::fs::File; -use log::{ error}; -use std::io::{BufRead, Write}; use env_logger::{Builder, Target}; - - +use std::io::{BufRead, Write}; #[allow(unused_imports)] use std::io::{self, Read}; @@ -19,11 +16,11 @@ use std::io::{self, Read}; use fs_tail::TailedFile; use serde_json::Value; -use cli::Commands::Send; use crate::cli::Output; use crate::elastic::collect; -use crate::parser::{ MultiLine}; - +use crate::parser::MultiLine; +use cli::Commands::Send; +use std::{thread, time}; #[tokio::main] async fn main() -> Result<(), Box> { @@ -32,17 +29,15 @@ async fn main() -> Result<(), Box> { match env::var("RUST_LOG") { Err(_) => { Builder::new() - .target(Target::Stdout) - .filter_level(cli.log_level) - .init(); - - }, + .target(Target::Stdout) + .filter_level(cli.log_level) + .init(); + } _ => { env_logger::init(); - }, + } } - match &cli.command { Send(name) => { if let Some(config_path) = name.input_file.as_deref() { @@ -51,23 +46,29 @@ async fn main() -> Result<(), Box> { Ok(file) => { let file = TailedFile::new(file); let locked = file.lock(); - let mut file_write ; + let mut file_write; file_write = File::create(name.output_file.clone().unwrap()).unwrap(); - - - let mut collected_data: Vec = Vec::new(); - let mut log_entries: MultiLine = MultiLine {log_entries: Vec::new(), multi_line:false, sql: "".to_string(), temp_entry: None}; + let mut collected_data: Vec = Vec::new(); + let mut log_entries: MultiLine = MultiLine { + log_entries: Vec::new(), + multi_line: false, + sql: "".to_string(), + temp_entry: None, + }; for line in locked.lines() { match name.input { cli::Input::General => { - log_entries = parser::parse_mysql_log_entry(&line.unwrap(), log_entries); - }, + log_entries = + parser::parse_mysql_log_entry(&line.unwrap(), log_entries); + } cli::Input::Slow => { - log_entries = parser::parse_mysql_slow_log_entry(&line.unwrap(), log_entries); - + log_entries = parser::parse_mysql_slow_log_entry( + &line.unwrap(), + log_entries, + ); } } @@ -78,19 +79,23 @@ async fn main() -> Result<(), Box> { match name.output { Output::File => { if !log_entry.replaced_query.is_empty() { - let _ = File::write(&mut file_write,(serde_json::to_string(&log_entry).unwrap() + "\n").as_bytes()); + let _ = File::write( + &mut file_write, + (serde_json::to_string(&log_entry).unwrap() + "\n") + .as_bytes(), + ); log_entry.replaced_query = "".to_string(); } - }, + } Output::Elastic => { collected_data = collect(collected_data, log_entry).await; } } } let _ = File::flush(&mut file_write); + thread::sleep(time::Duration::from_millis(10)); } - - }, + } }; } } diff --git a/src/parser.rs b/src/parser.rs index ce1c1ae..f57c66a 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1,24 +1,23 @@ -use std::env; -use std::net::IpAddr; +use crate::{anonymize, cli}; use chrono::{NaiveDateTime, ParseError}; -use log::{error}; +use log::error; use regex::Regex; +use serde::Serialize; use sqlparser::dialect::MySqlDialect; use sqlparser::parser::{Parser, ParserError}; +use std::env; +use std::net::IpAddr; use uuid::Uuid; -use crate::{anonymize, cli}; -use serde::Serialize; #[derive(Debug, Serialize, Clone)] pub struct MultiLine { pub log_entries: Vec, pub temp_entry: Option, pub multi_line: bool, - pub sql: String + pub sql: String, } pub fn parse_mysql_log_entry(log_line: &str, mut multilines: MultiLine) -> MultiLine { - let mut parts: Vec<&str> = log_line.split_whitespace().collect(); let new_line = multilines.sql.clone(); @@ -26,33 +25,40 @@ pub fn parse_mysql_log_entry(log_line: &str, mut multilines: MultiLine) -> Multi match parse_timestamp(parts[0]) { Ok(_) => { parts = new_line.split_whitespace().collect(); - multilines = MultiLine {log_entries: Vec::new(), multi_line: false, sql: log_line.to_string(), temp_entry: None}; - }, + multilines = MultiLine { + log_entries: Vec::new(), + multi_line: false, + sql: log_line.to_string(), + temp_entry: None, + }; + } Err(_) => { multilines.multi_line = true; - multilines.sql += log_line; + multilines.sql += log_line; parts.truncate(0); } } let mut log_entries: Vec = Vec::new(); - if parts.len() >= 4 { + if parts.len() >= 4 { let timestamp = parts[0]; let _id = parts[1]; let _command = parts[1]; let sql_query = parts[3..].join(" "); match anonymize_sql(sql_query.to_string()) { - Ok(result) => for ast in result { - let mut entry = LogEntry::default(); - - entry.timestamp = parse_timestamp(timestamp).unwrap(); - entry.command = ast.statement_type; - entry.original_query = sql_query.to_string(); - entry.replaced_query = ast.statement.to_string(); - log_entries.push(entry); - }, + Ok(result) => { + for ast in result { + log_entries.push(LogEntry { + timestamp: parse_timestamp(timestamp).unwrap(), + command: ast.statement_type, + original_query: sql_query.to_string(), + replaced_query: ast.statement.to_string(), + ..LogEntry::default() + }); + } + } Err(_error) => { // error!("{} - {}", log_line.to_string(),error); } @@ -63,7 +69,10 @@ pub fn parse_mysql_log_entry(log_line: &str, mut multilines: MultiLine) -> Multi } pub fn parse_mysql_slow_log_entry(log_line: &str, mut multilines: MultiLine) -> MultiLine { - let re = Regex::new(r"^# Time: (.+)$|^# User@Host: (.+)Id:|^# Query_time: (.+)$|^SET timestamp=(.+);$").unwrap(); + let re = Regex::new( + r"^# Time: (.+)$|^# User@Host: (.+)Id:|^# Query_time: (.+)$|^SET timestamp=(.+);$", + ) + .unwrap(); let mut log_entries: Vec = Vec::new(); let mut log_entry = LogEntry::default(); if multilines.temp_entry.is_some() { @@ -74,7 +83,6 @@ pub fn parse_mysql_slow_log_entry(log_line: &str, mut multilines: MultiLine) -> if multilines.multi_line && log_entry.timestamp != NaiveDateTime::default() { // log_entry[0].original_query = log_line.to_string(); - match anonymize_sql(log_entry.original_query.clone()) { Ok(result) => { for ast in result { @@ -83,17 +91,13 @@ pub fn parse_mysql_slow_log_entry(log_line: &str, mut multilines: MultiLine) -> c_entry.command = ast.statement_type; log_entries.push(c_entry); } - }, - Err(_error) => { - } + Err(_error) => {} } - } multilines.multi_line = false; log_entry.original_query = "".to_string(); - log_entry = LogEntry::default(); log_entry.timestamp = parse_timestamp(match_time.as_str()).unwrap(); } @@ -101,12 +105,42 @@ pub fn parse_mysql_slow_log_entry(log_line: &str, mut multilines: MultiLine) -> log_entry.user = Some(match_time.as_str().trim().to_string()); } if let Some(match_time) = captures.get(3) { - let line_re = Regex::new(r"^(.+)Lock_time:(.+)Rows_sent:(.+)Rows_examined:\s(.+)").unwrap(); + let line_re = + Regex::new(r"^(.+)Lock_time:(.+)Rows_sent:(.+)Rows_examined:\s(.+)").unwrap(); let parse_info = line_re.captures(match_time.as_str()).unwrap(); - log_entry.query_time = Some(parse_info.get(1).unwrap().as_str().trim().parse::().unwrap()); - log_entry.lock_time = Some(parse_info.get(2).unwrap().as_str().trim().parse::().unwrap()); - log_entry.row_sent = Some(parse_info.get(3).unwrap().as_str().trim().parse::().unwrap()); - let last_part: Vec<&str> = parse_info.get(4).unwrap().as_str().split_whitespace().collect(); + log_entry.query_time = Some( + parse_info + .get(1) + .unwrap() + .as_str() + .trim() + .parse::() + .unwrap(), + ); + log_entry.lock_time = Some( + parse_info + .get(2) + .unwrap() + .as_str() + .trim() + .parse::() + .unwrap(), + ); + log_entry.row_sent = Some( + parse_info + .get(3) + .unwrap() + .as_str() + .trim() + .parse::() + .unwrap(), + ); + let last_part: Vec<&str> = parse_info + .get(4) + .unwrap() + .as_str() + .split_whitespace() + .collect(); log_entry.row_examined = Some(last_part.first().unwrap().parse::().unwrap()); } @@ -117,15 +151,13 @@ pub fn parse_mysql_slow_log_entry(log_line: &str, mut multilines: MultiLine) -> multilines.temp_entry = Some(log_entry); multilines.log_entries = log_entries; multilines - } else { - log_entry.original_query += log_line.replace("\t","").as_str(); + log_entry.original_query += log_line.replace('\t', "").as_str(); multilines.temp_entry = Some(log_entry); multilines } } - #[derive(Debug, Serialize, Clone)] pub struct LogEntry { pub timestamp: NaiveDateTime, @@ -140,29 +172,25 @@ pub struct LogEntry { pub lock_time: Option, pub row_sent: Option, pub row_examined: Option, - } -#[derive(Debug, Clone, Serialize,PartialEq)] +#[derive(Debug, Clone, Serialize, PartialEq)] pub enum Command { Query, Insert, Update, Other, Explain, - Delete + Delete, } - fn hostname() -> Option { match env::var("HOSTNAME") { Ok(val) => Some(val), - Err(_) => { - match hostname::get() { - Ok(host) => Some(host.to_string_lossy().into_owned()), - Err(_) => None, - } - } + Err(_) => match hostname::get() { + Ok(host) => Some(host.to_string_lossy().into_owned()), + Err(_) => None, + }, } } @@ -190,31 +218,29 @@ pub fn parse_timestamp(timestamp_str: &str) -> Result NaiveDateTime::parse_from_str(timestamp_str, format_str) } - -fn anonymize_sql(mut sql: String) -> Result, ParserError> { +fn anonymize_sql(sql: String) -> Result, ParserError> { let cli = cli::cli(); let dialect = MySqlDialect {}; let cli::Commands::Send(_name) = cli.command; - sql = sql.replace(" "," "); + // sql = sql.replace(" ", " "); if !sql.starts_with('#') { - return match Parser::parse_sql(&dialect, sql.as_str()) { Ok(mut ast) => { let mut replaced = Vec::new(); for statement in ast.iter_mut() { replaced.push(anonymize::rec(statement)); - }; + } Ok(replaced) } Err(err) => { - error!("Error parsing sql: {} - {}", err,sql); + error!("Error parsing sql: {} - {}", err, sql); Err(err) } - } + }; } Ok(Vec::new()) -} \ No newline at end of file +}