1use crate::{EntryAdminCommand, SessionLine, SqlStatementContext, StatsLine};
2use bytes::{BufMut, Bytes, BytesMut};
3use sqlparser::ast::{visit_relations, Statement};
4use std::borrow::Cow;
5use std::collections::BTreeSet;
6use std::fmt::{Display, Formatter};
7use std::ops::ControlFlow;
8use winnow_datetime::DateTime;
9
10#[derive(Clone, Debug, PartialEq)]
12pub struct Entry {
13 pub call: EntryCall,
15 pub session: EntrySession,
17 pub stats: EntryStats,
19 pub sql_attributes: EntrySqlAttributes,
21}
22
23impl Entry {
24 pub fn log_time(&self) -> DateTime {
26 self.call.log_time
27 }
28
29 pub fn user_name(&self) -> Cow<str> {
31 String::from_utf8_lossy(&self.session.user_name)
32 }
33
34 pub fn user_name_bytes(&self) -> Bytes {
36 self.session.user_name.clone()
37 }
38
39 pub fn sys_user_name(&self) -> Cow<str> {
41 String::from_utf8_lossy(&self.session.sys_user_name)
42 }
43
44 pub fn sys_user_name_bytes(&self) -> Bytes {
46 self.session.sys_user_name.clone()
47 }
48
49 pub fn host_name(&self) -> Option<Cow<str>> {
51 if let Some(v) = &self.session.host_name {
52 Some(String::from_utf8_lossy(v.as_ref()))
53 } else {
54 None
55 }
56 }
57
58 pub fn host_name_bytes(&self) -> Option<Bytes> {
60 self.session.host_name_bytes()
61 }
62
63 pub fn ip_address(&self) -> Option<Cow<'_, str>> {
65 self.session.ip_address()
66 }
67
68 pub fn ip_address_bytes(&self) -> Option<Bytes> {
70 self.session.ip_address_bytes()
71 }
72
73 pub fn thread_id(&self) -> u32 {
75 self.session.thread_id()
76 }
77
78 pub fn stats(&self) -> &EntryStats {
80 &self.stats
81 }
82
83 pub fn query_time(&self) -> f64 {
85 self.stats.query_time()
86 }
87
88 pub fn lock_time(&self) -> f64 {
90 self.stats.lock_time()
91 }
92
93 pub fn rows_sent(&self) -> u32 {
95 self.stats.rows_sent()
96 }
97
98 pub fn rows_examined(&self) -> u32 {
100 self.stats.rows_examined()
101 }
102}
103
104#[derive(Clone, Debug, PartialEq)]
105pub struct EntrySqlStatement {
107 pub statement: Statement,
109 pub context: Option<SqlStatementContext>,
110}
111
112impl EntrySqlStatement {
113 pub fn sql_context(&self) -> Option<SqlStatementContext> {
114 self.context.clone()
115 }
116
117 pub fn objects(&self) -> Vec<EntrySqlStatementObject> {
118 let mut visited = BTreeSet::new();
119
120 visit_relations(&self.statement, |relation| {
121 let ident = &relation.0;
122
123 let _ = visited.insert(if ident.len() == 2 {
124 EntrySqlStatementObject {
125 schema_name: Some(ident[0].value.to_owned().into()),
126 object_name: ident[1].value.to_owned().into(),
127 }
128 } else {
129 EntrySqlStatementObject {
130 schema_name: None,
131 object_name: ident.last().unwrap().value.to_owned().into(),
132 }
133 });
134
135 ControlFlow::<()>::Continue(())
136 });
137 visited.into_iter().collect()
138 }
139
140 pub fn sql_type(&self) -> EntrySqlType {
141 match self.statement {
142 Statement::Query(_) => EntrySqlType::Query,
143 Statement::Insert { .. } => EntrySqlType::Insert,
144 Statement::Update { .. } => EntrySqlType::Update,
145 Statement::Delete { .. } => EntrySqlType::Delete,
146 Statement::CreateTable { .. } => EntrySqlType::CreateTable,
147 Statement::CreateIndex { .. } => EntrySqlType::CreateIndex,
148 Statement::CreateView { .. } => EntrySqlType::CreateView,
149 Statement::AlterTable { .. } => EntrySqlType::AlterTable,
150 Statement::AlterIndex { .. } => EntrySqlType::AlterIndex,
151 Statement::Drop { .. } => EntrySqlType::Drop,
152 Statement::DropFunction { .. } => EntrySqlType::DropFunction,
153 Statement::SetVariable { .. } => EntrySqlType::SetVariable,
154 Statement::SetNames { .. } => EntrySqlType::SetNames,
155 Statement::SetNamesDefault { .. } => EntrySqlType::SetNamesDefault,
156 Statement::ShowVariable { .. } => EntrySqlType::ShowVariable,
157 Statement::ShowVariables { .. } => EntrySqlType::ShowVariables,
158 Statement::ShowCreate { .. } => EntrySqlType::ShowCreate,
159 Statement::ShowColumns { .. } => EntrySqlType::ShowColumns,
160 Statement::ShowTables { .. } => EntrySqlType::ShowTables,
161 Statement::ShowCollation { .. } => EntrySqlType::ShowCollation,
162 Statement::Use { .. } => EntrySqlType::Use,
163 Statement::StartTransaction { .. } => EntrySqlType::StartTransaction,
164 Statement::SetTransaction { .. } => EntrySqlType::SetTransaction,
165 Statement::Commit { .. } => EntrySqlType::Commit,
166 Statement::Rollback { .. } => EntrySqlType::Rollback,
167 Statement::CreateSchema { .. } => EntrySqlType::CreateSchema,
168 Statement::CreateDatabase { .. } => EntrySqlType::CreateDatabase,
169 Statement::Grant { .. } => EntrySqlType::Grant,
170 Statement::Revoke { .. } => EntrySqlType::Revoke,
171 Statement::Kill { .. } => EntrySqlType::Kill,
172 Statement::ExplainTable { .. } => EntrySqlType::ExplainTable,
173 Statement::Explain { .. } => EntrySqlType::Explain,
174 Statement::Savepoint { .. } => EntrySqlType::Savepoint,
175 Statement::LockTables { .. } => EntrySqlType::LockTables,
176 Statement::UnlockTables { .. } => EntrySqlType::LockTables,
177 Statement::Flush { .. } => EntrySqlType::Flush,
178 _ => EntrySqlType::Unknown,
179 }
180 }
181}
182
183impl From<Statement> for EntrySqlStatement {
184 fn from(statement: Statement) -> Self {
185 EntrySqlStatement {
186 statement,
187 context: None,
188 }
189 }
190}
191
192#[derive(Clone, Debug, Ord, PartialOrd, PartialEq, Eq)]
194pub struct EntrySqlStatementObject {
195 pub schema_name: Option<Bytes>,
197 pub object_name: Bytes,
199}
200
201impl EntrySqlStatementObject {
202 pub fn schema_name(&self) -> Option<Cow<str>> {
204 if let Some(v) = &self.schema_name {
205 Some(String::from_utf8_lossy(v.as_ref()))
206 } else {
207 None
208 }
209 }
210
211 pub fn schema_name_bytes(&self) -> Option<Bytes> {
213 self.schema_name.clone()
214 }
215
216 pub fn object_name(&self) -> Cow<str> {
218 String::from_utf8_lossy(self.object_name.as_ref())
219 }
220
221 pub fn object_name_bytes(&self) -> Bytes {
223 self.object_name.clone()
224 }
225
226 pub fn full_object_name_bytes(&self) -> Bytes {
228 let mut s = if let Some(n) = self.schema_name.clone() {
229 let mut s = BytesMut::from(n.as_ref());
230 s.put_slice(b".");
231 s
232 } else {
233 BytesMut::new()
234 };
235
236 s.put_slice(self.object_name.as_ref());
237 s.freeze()
238 }
239
240 pub fn full_object_name(&self) -> Cow<'_, str> {
242 String::from_utf8_lossy(self.full_object_name_bytes().as_ref())
243 .to_string()
244 .into()
245 }
246}
247
248#[derive(Clone, Debug, PartialEq)]
253pub enum EntryStatement {
254 AdminCommand(EntryAdminCommand),
256 SqlStatement(EntrySqlStatement),
258 InvalidStatement(String),
260}
261
262impl EntryStatement {
263 pub fn objects(&self) -> Option<Vec<EntrySqlStatementObject>> {
265 match self {
266 Self::SqlStatement(s) => Some(s.objects().clone()),
267 _ => None,
268 }
269 }
270
271 pub fn sql_type(&self) -> Option<EntrySqlType> {
273 match self {
274 Self::SqlStatement(s) => Some(s.sql_type().clone()),
275 _ => None,
276 }
277 }
278
279 pub fn sql_context(&self) -> Option<SqlStatementContext> {
281 match self {
282 Self::SqlStatement(s) => s.sql_context().clone(),
283 _ => None,
284 }
285 }
286}
287
288#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
293pub enum EntrySqlType {
294 Query,
296 Insert,
298 Update,
300 Delete,
302 CreateTable,
304 CreateIndex,
306 CreateView,
308 AlterTable,
310 AlterIndex,
312 Drop,
314 DropFunction,
316 SetVariable,
318 SetNames,
320 SetNamesDefault,
322 ShowVariable,
324 ShowVariables,
326 ShowCreate,
328 ShowColumns,
330 ShowTables,
332 ShowCollation,
334 Use,
336 StartTransaction,
338 SetTransaction,
340 Commit,
342 Rollback,
344 CreateSchema,
346 CreateDatabase,
348 Grant,
350 Revoke,
352 Kill,
354 ExplainTable,
356 Explain,
358 Savepoint,
360 LockTables,
362 UnlockTables,
364 Flush,
366 Unknown,
368}
369
370impl Display for EntrySqlType {
371 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
372 let out = match self {
373 Self::Query => "SELECT",
374 Self::Insert => "INSERT",
375 Self::Update => "UPDATE",
376 Self::Delete => "DELETE",
377 Self::CreateTable => "CREATE TABLE",
378 Self::CreateIndex => "CREATE INDEX",
379 Self::CreateView => "CREATE VIEW",
380 Self::AlterTable => "ALTER TABLE",
381 Self::AlterIndex => "ALTER INDEX",
382 Self::Drop => "DROP TABLE",
383 Self::DropFunction => "DROP FUNCTION",
384 Self::SetVariable => "SET VARIABLE",
385 Self::SetNames => "SET NAMES",
386 Self::SetNamesDefault => "SET NAMES DEFAULT",
387 Self::ShowVariable => "SHOW VARIABLE",
388 Self::ShowVariables => "SHOW VARIABLES",
389 Self::ShowCreate => "SHOW CREATE TABLE",
390 Self::ShowColumns => "SHOW COLUMNS",
391 Self::ShowTables => "SHOW TABLES",
392 Self::ShowCollation => "SHOW COLLATION",
393 Self::Use => "USE",
394 Self::StartTransaction => "BEGIN TRANSACTION",
395 Self::SetTransaction => "SET TRANSACTION",
396 Self::Commit => "COMMIT TRANSACTION",
397 Self::Rollback => "ROLLBACK TRANSACTION",
398 Self::CreateSchema => "CREATE SCHEMA",
399 Self::CreateDatabase => "CREATE DATABASE",
400 Self::Grant => "GRANT",
401 Self::Revoke => "REVOKE",
402 Self::Kill => "KILL",
403 Self::ExplainTable => "EXPLAIN TABLE",
404 Self::Explain => "EXPLAIN",
405 Self::Savepoint => "SAVEPOINT",
406 Self::LockTables => "LOCK TABLES",
407 Self::UnlockTables => "UNLOCK TABLES",
408 Self::Flush => "FLUSH",
409 Self::Unknown => "NULL",
410 };
411
412 write!(f, "{}", out)
413 }
414}
415
416#[derive(Clone, Debug, PartialEq)]
418pub struct EntrySession {
419 pub user_name: Bytes,
421 pub sys_user_name: Bytes,
423 pub host_name: Option<Bytes>,
425 pub ip_address: Option<Bytes>,
427 pub thread_id: u32,
429}
430
431impl From<SessionLine> for EntrySession {
432 fn from(line: SessionLine) -> Self {
433 Self {
434 user_name: line.user,
435 sys_user_name: line.sys_user,
436 host_name: line.host,
437 ip_address: line.ip_address,
438 thread_id: line.thread_id,
439 }
440 }
441}
442
443impl EntrySession {
444 pub fn user_name(&self) -> Cow<str> {
446 String::from_utf8_lossy(&self.user_name)
447 }
448
449 pub fn user_name_bytes(&self) -> Bytes {
451 self.user_name.clone()
452 }
453
454 pub fn sys_user_name(&self) -> Cow<str> {
456 String::from_utf8_lossy(&self.sys_user_name)
457 }
458
459 pub fn sys_user_name_bytes(&self) -> Bytes {
461 self.sys_user_name.clone()
462 }
463
464 pub fn host_name(&self) -> Option<Cow<str>> {
466 if let Some(v) = &self.host_name {
467 Some(String::from_utf8_lossy(v.as_ref()))
468 } else {
469 None
470 }
471 }
472
473 pub fn host_name_bytes(&self) -> Option<Bytes> {
475 self.host_name.clone()
476 }
477
478 pub fn ip_address(&self) -> Option<Cow<'_, str>> {
480 if let Some(v) = &self.ip_address {
481 Some(String::from_utf8_lossy(v.as_ref()))
482 } else {
483 None
484 }
485 }
486
487 pub fn ip_address_bytes(&self) -> Option<Bytes> {
489 self.ip_address.clone()
490 }
491
492 pub fn thread_id(&self) -> u32 {
494 self.thread_id
495 }
496}
497
498#[derive(Clone, Debug, PartialEq)]
500pub struct EntrySqlAttributes {
501 pub sql: Bytes,
503 pub statement: EntryStatement,
505}
506
507impl EntrySqlAttributes {
508 pub fn sql_bytes(&self) -> Bytes {
510 self.sql.clone()
511 }
512
513 pub fn sql(&self) -> Cow<'_, str> {
515 String::from_utf8_lossy(self.sql.as_ref())
516 }
517
518 pub fn sql_type(&self) -> Option<EntrySqlType> {
520 self.statement.sql_type()
521 }
522
523 pub fn objects(&self) -> Option<Vec<EntrySqlStatementObject>> {
525 self.statement.objects()
526 }
527
528 pub fn statement(&self) -> &EntryStatement {
530 &self.statement
531 }
532}
533
534#[derive(Clone, Copy, Debug, PartialEq)]
536pub struct EntryCall {
537 pub log_time: DateTime,
539 pub set_timestamp: u32,
541}
542
543impl EntryCall {
544 pub fn new(log_time: DateTime, set_timestamp: u32) -> Self {
546 Self {
547 log_time,
548 set_timestamp,
549 }
550 }
551
552 pub fn log_time(&self) -> DateTime {
554 self.log_time
555 }
556
557 pub fn set_timestamp(&self) -> u32 {
559 self.set_timestamp
560 }
561}
562
563#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
565pub struct EntryStats {
566 pub query_time: f64,
568 pub lock_time: f64,
570 pub rows_sent: u32,
572 pub rows_examined: u32,
574}
575
576impl EntryStats {
577 pub fn query_time(&self) -> f64 {
579 self.query_time
580 }
581
582 pub fn lock_time(&self) -> f64 {
584 self.lock_time
585 }
586
587 pub fn rows_sent(&self) -> u32 {
589 self.rows_sent
590 }
591
592 pub fn rows_examined(&self) -> u32 {
594 self.rows_examined
595 }
596}
597
598impl From<StatsLine> for EntryStats {
599 fn from(line: StatsLine) -> Self {
600 Self {
601 query_time: line.query_time,
602 lock_time: line.lock_time,
603 rows_sent: line.rows_sent,
604 rows_examined: line.rows_examined,
605 }
606 }
607}
608
609#[derive(Clone, Debug, PartialEq)]
611pub struct EntryContext {
612 pub request_id: Option<Bytes>,
614 pub caller: Option<Bytes>,
616 pub function: Option<Bytes>,
618 pub line: Option<u32>,
620}
621
622impl EntryContext {
623 pub fn request_id(&self) -> Option<Cow<str>> {
625 if let Some(v) = &self.request_id {
626 Some(String::from_utf8_lossy(v.as_ref()))
627 } else {
628 None
629 }
630 }
631
632 pub fn request_id_bytes(&self) -> Option<Bytes> {
634 self.request_id.clone()
635 }
636
637 pub fn caller(&self) -> Option<Cow<str>> {
639 if let Some(v) = &self.caller {
640 Some(String::from_utf8_lossy(v.as_ref()))
641 } else {
642 None
643 }
644 }
645
646 pub fn caller_bytes(&self) -> Option<Bytes> {
648 self.caller.clone()
649 }
650
651 pub fn function(&self) -> Option<Cow<str>> {
653 if let Some(v) = &self.function {
654 Some(String::from_utf8_lossy(v.as_ref()))
655 } else {
656 None
657 }
658 }
659
660 pub fn function_bytes(&self) -> Option<Bytes> {
662 self.function.clone()
663 }
664
665 pub fn line(&self) -> Option<u32> {
667 self.line
668 }
669}