1use log::log;
35pub use log::Level;
36use std::io::{Error, Read, Seek, SeekFrom};
37use std::result::Result;
38
39pub struct ReadStatsLogger {
41 tag: String,
42 level: Level,
43 pub read_count: usize,
44 pub bytes_total: usize,
45}
46
47impl ReadStatsLogger {
48 pub fn new(level: Level, tag: &str) -> Self {
49 log!(
50 level,
51 "Initialize Read logger `{tag}`,tag,begin,end,length,request_length,count,bytes_total"
52 );
53 ReadStatsLogger {
54 tag: tag.to_string(),
55 level,
56 read_count: 0,
57 bytes_total: 0,
58 }
59 }
60 pub fn log(&mut self, begin: usize, length: usize, request_length: usize) {
62 self.read_count += 1;
64 self.bytes_total += length;
65 let end = (begin + length).saturating_sub(1);
66 log!(
67 self.level,
68 "Read {begin}-{end} ({length} bytes). Total requests: {} ({} bytes),{},{begin},{end},{length},{request_length},{},{}",
69 self.read_count,
70 self.bytes_total,
71 self.tag,
72 self.read_count,
73 self.bytes_total,
74 );
75 }
76}
77
78pub struct ReadLogger<T: Read> {
80 inner: T,
81 offset: usize,
82 logger: ReadStatsLogger,
83}
84
85impl<T: Read> ReadLogger<T> {
86 pub fn new(read: T, level: Level, tag: &str) -> Self {
87 ReadLogger {
88 inner: read,
89 offset: 0,
90 logger: ReadStatsLogger::new(level, tag),
91 }
92 }
93 pub fn stats(&self) -> &ReadStatsLogger {
94 &self.logger
95 }
96}
97
98impl<T: Read> Read for ReadLogger<T> {
99 fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
100 let length = self.inner.read(buf)?;
101 self.logger.log(self.offset, length, buf.len());
102 self.offset += length;
103 Ok(length)
104 }
105}
106
107impl<T: Read + Seek> Seek for ReadLogger<T> {
108 fn seek(&mut self, pos: SeekFrom) -> Result<u64, Error> {
109 let offset = self.inner.seek(pos)?;
110 self.offset = offset as usize;
111 Ok(offset)
112 }
113}
114
115#[cfg(test)]
116mod tests {
117 use super::*;
118 use std::fs::File;
119 use std::io::{BufReader, Cursor};
120
121 fn init_logger() {
122 let _ = env_logger::builder().is_test(true).try_init();
123 }
124
125 #[test]
126 fn check_stats() {
127 init_logger();
128 let mut stats = ReadStatsLogger::new(Level::Info, "READ");
129 stats.log(0, 4, 4);
130 stats.log(4, 4, 4);
131 assert_eq!(stats.read_count, 2);
132 assert_eq!(stats.bytes_total, 8);
133 }
134
135 #[test]
136 fn read_cursor() {
137 init_logger();
138 let text = "0123456789";
139 let mut reader = ReadLogger::new(Cursor::new(text), Level::Info, "READ");
140
141 let mut bytes = [0; 4];
142 reader.read_exact(&mut bytes).unwrap();
143 reader.read_exact(&mut bytes).unwrap();
144 assert_eq!(&bytes, b"4567");
145 assert_eq!(reader.stats().read_count, 2);
146 assert_eq!(reader.stats().bytes_total, 8);
147
148 let n = reader.read(&mut bytes).unwrap();
149 assert_eq!(n, 2);
150 assert_eq!(reader.stats().bytes_total, 10);
152 }
153
154 #[test]
155 fn seek() {
156 init_logger();
157 let text = "0123456789";
158 let mut reader = ReadLogger::new(Cursor::new(text), Level::Info, "READ");
159
160 let mut bytes = [0; 4];
161 reader.seek(SeekFrom::Start(4)).unwrap();
162 reader.read_exact(&mut bytes).unwrap();
163 assert_eq!(&bytes, b"4567");
164 assert_eq!(reader.stats().read_count, 1);
165 assert_eq!(reader.stats().bytes_total, 4);
166 }
167
168 #[test]
169 fn buf_reader() {
170 init_logger();
171 let text = "0123456789";
172 let mut cursor = ReadLogger::new(Cursor::new(text), Level::Debug, "READ");
173 let mut buffer = ReadLogger::new(BufReader::new(&mut cursor), Level::Info, "BUFFER");
175
176 let mut bytes = [0; 4];
177 buffer.read_exact(&mut bytes).unwrap();
178 buffer.read_exact(&mut bytes).unwrap();
179 assert_eq!(&bytes, b"4567");
180 assert_eq!(buffer.stats().read_count, 2);
181 assert_eq!(buffer.stats().bytes_total, 8);
182 assert_eq!(cursor.stats().read_count, 1);
183 assert_eq!(cursor.stats().bytes_total, 10);
184 }
185
186 #[test]
187 fn file() {
188 init_logger();
189 let f = File::open("Cargo.toml").unwrap();
190 let mut read_logger = ReadLogger::new(f, Level::Debug, "READ");
191 let mut reader = BufReader::new(&mut read_logger);
192 let mut bytes = [0; 4];
193 reader.read_exact(&mut bytes).unwrap();
194 reader.read_exact(&mut bytes).unwrap();
195 assert_eq!(read_logger.stats().read_count, 1);
196 assert!(read_logger.stats().bytes_total > 200);
197 }
198}