Решение на Logging от Мария Божкова

Обратно към всички решения

Към профила на Мария Божкова

Резултати

  • 5 точки от тестове
  • 0 бонус точки
  • 5 точки общо
  • 4 успешни тест(а)
  • 11 неуспешни тест(а)

Код

use std::time::Instant;
use std::io;
use std::io::Write;
pub trait Logger {
fn push(&mut self, time: Instant, text: &str);
fn log(&mut self, text: &str);
fn try_flush(&mut self) -> io::Result<()>;
fn flush(&mut self);
}
pub struct LoggerEntity {
time: Instant,
message: String,
}
impl Clone for LoggerEntity {
fn clone(&self) -> LoggerEntity { LoggerEntity { time: self.time, message: self.message.clone() }}

Бих сложил декларацията на функцията и имплементацията на различни редове. LoggerEntity { LoggerEntity { ми отне известно време и объркване, докато схвана какво се случва.

}
pub struct BufferedLogger<W: Write> {
buffer: Vec<LoggerEntity>,
out: W,
buffer_size: usize,
}
impl<W: Write> BufferedLogger<W> {
pub fn new(out: W, buffer_size: usize) -> Self {
BufferedLogger {
buffer: Vec::new(),
buffer_size,
out,
}
}
pub fn buffered_entries(&self) -> Vec<String> {
self.buffer.clone().into_iter().map(|x| x.message).rev().collect()
}
}
impl<W: Write> Clone for BufferedLogger<W> {
// Ah, that buffer should be rc.
fn clone(&self) -> Self {
unimplemented!()
}
}
impl<W: Write> Logger for BufferedLogger<W> {
fn push(&mut self, time: Instant, text: &str) {
let el = LoggerEntity {
time,
message: text.to_string(),
};
self.buffer.push(el);
self.buffer.sort_by(|a, b| b.time.cmp(&a.time));
if self.buffer.len() == self.buffer_size {
self.flush();
}
}
fn log(&mut self, text: &str) {
self.push(Instant::now(), text)
}
fn try_flush(&mut self) -> io::Result<()> {
let flushed = self.buffered_entries().join("\n");
self.buffer.clear();
write!(self.out, "{}", flushed)
}
fn flush(&mut self) {
let flushed = self.buffered_entries().join("\n");
self.buffer.clear();
let _ = match write!(self.out, "{}", flushed) {
Ok(written) => written,
Err(err) => eprintln!("{}", err),
};
}

Можеше във flush да извикаш try_flush, и ако от него дойде грешка, да печаташ. Нещо повече, метода try_flush можеше да бъде имплементиран веднъж по този начин в trait-a.

}
pub struct MultiLogger {
// Box won't do the trick here
loggers: Vec<Box<dyn Logger>>,
}
impl MultiLogger {
pub fn new() -> Self {
MultiLogger {
loggers: Vec::new(),
}
}
pub fn log_to<L: Logger + 'static>(&mut self, logger: L) {
self.loggers.push(Box::new(logger));
}
}
impl Logger for MultiLogger {
fn push(&mut self, time: Instant, text: &str) {
unimplemented!()
}
fn log(&mut self, text: &str) {
self.push(Instant::now(), text)
}
fn try_flush(&mut self) -> io::Result<()> {
unimplemented!()
}
fn flush(&mut self) {
unimplemented!()
}
}
pub struct ScopedLogger<L: Logger> {
tag: String,
base_logger: Box<L>,
}
impl<L: Logger> ScopedLogger<L> {
pub fn new(tag: &str, base_logger: L) -> Self {
ScopedLogger {tag: tag.to_string(), base_logger: Box::new(base_logger)}
}
}
impl<L: Logger> Logger for ScopedLogger<L> {
fn push(&mut self, time: Instant, text: &str) {
let message = format!("[{}] {}", self.tag, text.to_string());
self.base_logger.push(time, message.as_str());
}
fn log(&mut self, text: &str) {
self.push(Instant::now(), text)
}
fn try_flush(&mut self) -> io::Result<()> {
self.base_logger.try_flush()
}
fn flush(&mut self) {
self.base_logger.flush()
}
}

Лог от изпълнението

Compiling solution v0.1.0 (/tmp/d20190123-22631-1ffem1c/solution)
warning: unused variable: `time`
   --> src/lib.rs:108:24
    |
108 |     fn push(&mut self, time: Instant, text: &str) {
    |                        ^^^^ help: consider using `_time` instead
    |
    = note: #[warn(unused_variables)] on by default

warning: unused variable: `text`
   --> src/lib.rs:108:39
    |
108 |     fn push(&mut self, time: Instant, text: &str) {
    |                                       ^^^^ help: consider using `_text` instead

warning: unused variable: `time`
   --> src/lib.rs:108:24
    |
108 |     fn push(&mut self, time: Instant, text: &str) {
    |                        ^^^^ help: consider using `_time` instead
    |
    = note: #[warn(unused_variables)] on by default

warning: unused variable: `text`
   --> src/lib.rs:108:39
    |
108 |     fn push(&mut self, time: Instant, text: &str) {
    |                                       ^^^^ help: consider using `_text` instead

    Finished dev [unoptimized + debuginfo] target(s) in 5.31s
     Running target/debug/deps/solution-2e785d603b538f71

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out

     Running target/debug/deps/solution_test-29808948fb50ed3a

running 15 tests
test solution_test::test_automatic_flushing_when_buffer_limit_is_reached ... FAILED
test solution_test::test_automatic_flushing_when_zero_buffer_limit ... FAILED
test solution_test::test_basic_log ... ok
test solution_test::test_basic_push ... ok
test solution_test::test_cloning_a_logger_shares_a_buffer ... FAILED
test solution_test::test_cloning_a_logger_shares_their_io ... FAILED
test solution_test::test_erroring_io ... ok
test solution_test::test_flushing_the_buffer ... FAILED
test solution_test::test_logger_combinations ... FAILED
test solution_test::test_multilogger_logs_and_flushes_when_needed ... FAILED
test solution_test::test_multilogger_logs_to_several_ios ... FAILED
test solution_test::test_reordering_logs_in_buffer ... ok
test solution_test::test_reordering_logs_in_io ... FAILED
test solution_test::test_scoped_logger ... FAILED
test solution_test::test_scoped_logger_with_a_string_tag ... FAILED

failures:

---- solution_test::test_automatic_flushing_when_buffer_limit_is_reached stdout ----
thread 'solution_test::test_automatic_flushing_when_buffer_limit_is_reached' panicked at 'assertion failed: `(left == right)`
  left: `"One\nTwo\nThree"`,
 right: `"One\nTwo\nThree\n"`', tests/solution_test.rs:200:5
note: Run with `RUST_BACKTRACE=1` for a backtrace.

---- solution_test::test_automatic_flushing_when_zero_buffer_limit stdout ----
thread 'solution_test::test_automatic_flushing_when_zero_buffer_limit' panicked at 'assertion failed: `(left == right)`
  left: `1`,
 right: `0`', tests/solution_test.rs:210:9

---- solution_test::test_cloning_a_logger_shares_a_buffer stdout ----
thread 'solution_test::test_cloning_a_logger_shares_a_buffer' panicked at 'not yet implemented', src/lib.rs:49:9

---- solution_test::test_cloning_a_logger_shares_their_io stdout ----
thread 'solution_test::test_cloning_a_logger_shares_their_io' panicked at 'not yet implemented', src/lib.rs:49:9

---- solution_test::test_flushing_the_buffer stdout ----
thread 'solution_test::test_flushing_the_buffer' panicked at 'assertion failed: `(left == right)`
  left: `"Some warning\nSome other warning"`,
 right: `"Some warning\nSome other warning\n"`', tests/solution_test.rs:95:5

---- solution_test::test_logger_combinations stdout ----
thread 'solution_test::test_logger_combinations' panicked at 'not yet implemented', src/lib.rs:49:9

---- solution_test::test_multilogger_logs_and_flushes_when_needed stdout ----
thread 'solution_test::test_multilogger_logs_and_flushes_when_needed' panicked at 'not yet implemented', src/lib.rs:49:9

---- solution_test::test_multilogger_logs_to_several_ios stdout ----
thread 'solution_test::test_multilogger_logs_to_several_ios' panicked at 'not yet implemented', src/lib.rs:109:9

---- solution_test::test_reordering_logs_in_io stdout ----
thread 'solution_test::test_reordering_logs_in_io' panicked at 'assertion failed: `(left == right)`
  left: `"First\nSecond\nThird\nFourth"`,
 right: `"First\nSecond\nThird\nFourth\n"`', tests/solution_test.rs:134:5

---- solution_test::test_scoped_logger stdout ----
thread 'solution_test::test_scoped_logger' panicked at 'not yet implemented', src/lib.rs:49:9

---- solution_test::test_scoped_logger_with_a_string_tag stdout ----
thread 'solution_test::test_scoped_logger_with_a_string_tag' panicked at 'not yet implemented', src/lib.rs:49:9


failures:
    solution_test::test_automatic_flushing_when_buffer_limit_is_reached
    solution_test::test_automatic_flushing_when_zero_buffer_limit
    solution_test::test_cloning_a_logger_shares_a_buffer
    solution_test::test_cloning_a_logger_shares_their_io
    solution_test::test_flushing_the_buffer
    solution_test::test_logger_combinations
    solution_test::test_multilogger_logs_and_flushes_when_needed
    solution_test::test_multilogger_logs_to_several_ios
    solution_test::test_reordering_logs_in_io
    solution_test::test_scoped_logger
    solution_test::test_scoped_logger_with_a_string_tag

test result: FAILED. 4 passed; 11 failed; 0 ignored; 0 measured; 0 filtered out

error: test failed, to rerun pass '--test solution_test'

История (1 версия и 4 коментара)

Мария обнови решението на 18.12.2018 09:19 (преди почти 2 години)

+use std::time::Instant;
+use std::io;
+use std::io::Write;
+
+pub trait Logger {
+ fn push(&mut self, time: Instant, text: &str);
+
+ fn log(&mut self, text: &str);
+
+ fn try_flush(&mut self) -> io::Result<()>;
+
+ fn flush(&mut self);
+}
+
+pub struct LoggerEntity {
+ time: Instant,
+ message: String,
+}
+
+impl Clone for LoggerEntity {
+ fn clone(&self) -> LoggerEntity { LoggerEntity { time: self.time, message: self.message.clone() }}

Бих сложил декларацията на функцията и имплементацията на различни редове. LoggerEntity { LoggerEntity { ми отне известно време и объркване, докато схвана какво се случва.

+}
+
+pub struct BufferedLogger<W: Write> {
+ buffer: Vec<LoggerEntity>,
+ out: W,
+ buffer_size: usize,
+}
+
+impl<W: Write> BufferedLogger<W> {
+ pub fn new(out: W, buffer_size: usize) -> Self {
+ BufferedLogger {
+ buffer: Vec::new(),
+ buffer_size,
+ out,
+ }
+ }
+
+
+ pub fn buffered_entries(&self) -> Vec<String> {
+ self.buffer.clone().into_iter().map(|x| x.message).rev().collect()
+ }
+}
+
+
+impl<W: Write> Clone for BufferedLogger<W> {
+ // Ah, that buffer should be rc.
+ fn clone(&self) -> Self {
+ unimplemented!()
+ }
+}
+
+impl<W: Write> Logger for BufferedLogger<W> {
+ fn push(&mut self, time: Instant, text: &str) {
+ let el = LoggerEntity {
+ time,
+ message: text.to_string(),
+ };
+
+ self.buffer.push(el);
+ self.buffer.sort_by(|a, b| b.time.cmp(&a.time));
+
+ if self.buffer.len() == self.buffer_size {
+ self.flush();
+ }
+ }
+
+ fn log(&mut self, text: &str) {
+ self.push(Instant::now(), text)
+ }
+
+ fn try_flush(&mut self) -> io::Result<()> {
+ let flushed = self.buffered_entries().join("\n");
+
+ self.buffer.clear();
+ write!(self.out, "{}", flushed)
+ }
+
+ fn flush(&mut self) {
+ let flushed = self.buffered_entries().join("\n");
+ self.buffer.clear();
+
+ let _ = match write!(self.out, "{}", flushed) {
+ Ok(written) => written,
+ Err(err) => eprintln!("{}", err),
+ };
+ }

Можеше във flush да извикаш try_flush, и ако от него дойде грешка, да печаташ. Нещо повече, метода try_flush можеше да бъде имплементиран веднъж по този начин в trait-a.

+}
+
+pub struct MultiLogger {
+ // Box won't do the trick here
+ loggers: Vec<Box<dyn Logger>>,
+}
+
+impl MultiLogger {
+ pub fn new() -> Self {
+ MultiLogger {
+ loggers: Vec::new(),
+ }
+ }
+
+ pub fn log_to<L: Logger + 'static>(&mut self, logger: L) {
+ self.loggers.push(Box::new(logger));
+ }
+}
+
+impl Logger for MultiLogger {
+ fn push(&mut self, time: Instant, text: &str) {
+ unimplemented!()
+ }
+
+ fn log(&mut self, text: &str) {
+ self.push(Instant::now(), text)
+ }
+
+ fn try_flush(&mut self) -> io::Result<()> {
+ unimplemented!()
+ }
+
+ fn flush(&mut self) {
+ unimplemented!()
+ }
+}
+
+pub struct ScopedLogger<L: Logger> {
+ tag: String,
+ base_logger: Box<L>,
+}
+
+impl<L: Logger> ScopedLogger<L> {
+ pub fn new(tag: &str, base_logger: L) -> Self {
+ ScopedLogger {tag: tag.to_string(), base_logger: Box::new(base_logger)}
+ }
+}
+
+impl<L: Logger> Logger for ScopedLogger<L> {
+ fn push(&mut self, time: Instant, text: &str) {
+ let message = format!("[{}] {}", self.tag, text.to_string());
+
+ self.base_logger.push(time, message.as_str());
+ }
+
+ fn log(&mut self, text: &str) {
+ self.push(Instant::now(), text)
+ }
+
+ fn try_flush(&mut self) -> io::Result<()> {
+ self.base_logger.try_flush()
+ }
+
+ fn flush(&mut self) {
+ self.base_logger.flush()
+ }
+}