mysql_slowlog_parser/lib.rs
1//! # parse-mysql-slowlog streams a slow query and returns a stream of entries from slow logs
2//! from your `FramedReader` tokio input of choice.
3//!
4//!## Example:
5//!
6//!```rust
7//! use futures::StreamExt;
8//! use mysql_slowlog_parser::{CodecError, Entry, EntryCodec};
9//! use std::ops::AddAssign;
10//! use std::time::Instant;
11//! use tokio::fs::File;
12//! use tokio_util::codec::FramedRead;
13//!
14//! #[tokio::main]
15//! async fn main() {
16//! let start = Instant::now();
17//!
18//! let fr = FramedRead::with_capacity(
19//! File::open("assets/slow-test-queries.log")
20//! .await
21//! .unwrap(),
22//! EntryCodec::default(),
23//! 400000,
24//!);
25//!
26//! let mut i = 0;
27//!
28//! let future = fr.for_each(|re: Result<Entry, CodecError>| async move {
29//! let _ = re.unwrap();
30//!
31//! i.add_assign(1);
32//! });
33//!
34//! future.await;
35//! println!("parsed {} entries in: {}", i, start.elapsed().as_secs_f64());
36//!}
37//! ```
38
39#![deny(
40 missing_copy_implementations,
41 trivial_casts,
42 unsafe_code,
43 unused_import_braces,
44 unused_qualifications,
45 missing_docs
46)]
47
48extern crate core;
49
50use std::collections::HashMap;
51use std::default::Default;
52use std::fmt::{Debug, Formatter};
53use thiserror::Error;
54
55pub use crate::parser::{EntryAdminCommand, SessionLine, SqlStatementContext, StatsLine, TimeLine};
56
57use bytes::Bytes;
58
59pub use crate::codec::{CodecError, EntryCodec, EntryError};
60
61mod codec;
62mod parser;
63mod types;
64
65pub use types::{
66 Entry, EntryCall, EntryContext, EntrySession, EntrySqlAttributes, EntrySqlStatementObject,
67 EntrySqlType, EntryStatement, EntryStats,
68};
69
70/// Error covering problems reading or parsing a log
71#[derive(Error, Debug)]
72pub enum ReadError {
73 /// problem found where a Time:... line is expected
74 #[error("invalid time line: {0}")]
75 InvalidTimeLine(String),
76 /// problem found where a User:... line is expected
77 #[error("invalid user line: {0}")]
78 InvalidUserLine(String),
79 /// problem found where a Query_time:... line is expected
80 #[error("invalid stats line: {0}")]
81 InvalidStatsLine(String),
82 /// problem found at end of file with an incomplete SQL statement
83 #[error("invalid entry with invalid sql starting at end of file")]
84 IncompleteSql,
85 /// problem found at end of file somewhere in the middle of an entry
86 #[error("Invalid log format or format contains no entries")]
87 IncompleteLog,
88}
89
90/// types of masking to apply when parsing SQL statements
91/// * PlaceHolder - mask all sql values with a '?' placeholder
92/// * None - leave all values in place
93#[derive(Clone, Copy, Debug, PartialEq)]
94pub enum EntryMasking {
95 /// A placeholder `?` is used when a binding is found in a query
96 PlaceHolder,
97 /// No placeholder mask
98 None,
99}
100
101impl Default for EntryMasking {
102 fn default() -> Self {
103 Self::None
104 }
105}
106
107/// Struct to pass along configuration values to codec
108#[derive(Copy, Clone, Default)]
109pub struct EntryCodecConfig {
110 /// type of masking to use when parsing SQL
111 pub masking: EntryMasking,
112 /// mapping function in order to find specific key entries
113 pub map_comment_context: Option<fn(HashMap<Bytes, Bytes>) -> Option<SqlStatementContext>>,
114}
115
116impl Debug for EntryCodecConfig {
117 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
118 write!(f, "{:?}", self.masking)?;
119 write!(f, "map_comment_context: fn")
120 }
121}
122
123/// errors that occur when building a Reader
124#[derive(Error, Clone, Copy, Debug)]
125pub enum ReaderBuildError {
126 /// missing reader value
127 #[error("reader must be set to build Reader")]
128 MissingReader,
129}