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}