A library for writing host-specific, single-binary configuration management and deployment tools
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

122 lines
2.8 KiB

2 years ago
8 years ago
2 years ago
8 years ago
3 years ago
3 years ago
3 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
4 years ago
8 years ago
2 years ago
4 years ago
2 years ago
2 years ago
8 years ago
5 years ago
  1. use std::cell::RefCell;
  2. use std::cmp::min;
  3. use std::io::{stderr, Write};
  4. use std::rc::Rc;
  5. // The log crate defines
  6. // 1 - Error, 2 - Warn, 3 - Info, 4 - Debug, 5 - Trace
  7. pub type Level = usize;
  8. #[derive(Clone, Debug, PartialEq, Eq)]
  9. pub struct Entry<S>(pub Level, pub S);
  10. pub trait Logger {
  11. fn write(&self, level: Level, msg: &str);
  12. fn writeln(&self, level: Level, msg: &str);
  13. fn info(&self, msg: &str) {
  14. self.writeln(3, msg);
  15. }
  16. fn debug(&self, msg: &str) {
  17. self.writeln(4, msg);
  18. }
  19. fn trace(&self, msg: &str) {
  20. self.writeln(5, msg);
  21. }
  22. fn put<'a>(&self, entries: impl IntoIterator<Item = Entry<&'a str>>) -> usize {
  23. let mut c = 0;
  24. for item in entries {
  25. self.writeln(item.0, item.1);
  26. c += 1;
  27. }
  28. c
  29. }
  30. }
  31. #[derive(Debug, Default)]
  32. pub struct StdErrLogger {
  33. line_started: RefCell<bool>,
  34. }
  35. impl Logger for StdErrLogger {
  36. fn write(&self, _level: Level, msg: &str) {
  37. *self.line_started.borrow_mut() = true;
  38. write!(&mut stderr(), "{msg}").expect("Could not write to stderr");
  39. }
  40. fn writeln(&self, _level: Level, msg: &str) {
  41. if self.line_started.replace(false) {
  42. writeln!(&mut stderr()).expect("Could not write to stderr");
  43. }
  44. writeln!(&mut stderr(), "{msg}").expect("Could not write to stderr");
  45. }
  46. }
  47. impl Drop for StdErrLogger {
  48. fn drop(&mut self) {
  49. if *self.line_started.borrow() {
  50. writeln!(&mut stderr()).expect("Could not write to stderr");
  51. }
  52. }
  53. }
  54. #[derive(Debug)]
  55. pub struct FilteringLogger<'a, L> {
  56. logger: &'a L,
  57. max_level: Level,
  58. }
  59. impl<'a, L> FilteringLogger<'a, L> {
  60. pub const fn new(logger: &'a L, max_level: Level) -> Self {
  61. Self { logger, max_level }
  62. }
  63. }
  64. impl<'a, L: Logger> Logger for FilteringLogger<'a, L> {
  65. fn write(&self, level: Level, msg: &str) {
  66. if level <= self.max_level {
  67. self.logger.write(level, msg);
  68. }
  69. }
  70. fn writeln(&self, level: Level, msg: &str) {
  71. if level <= self.max_level {
  72. self.logger.writeln(level, msg);
  73. }
  74. }
  75. }
  76. #[derive(Clone, Debug, Default)]
  77. pub struct StoringLogger {
  78. log: Rc<RefCell<(bool, Vec<Entry<String>>)>>,
  79. }
  80. impl StoringLogger {
  81. #[must_use]
  82. pub fn new() -> Self {
  83. Self::default()
  84. }
  85. #[must_use]
  86. pub fn release(self) -> Vec<Entry<String>> {
  87. Rc::try_unwrap(self.log).unwrap().into_inner().1
  88. }
  89. }
  90. impl Logger for StoringLogger {
  91. fn write(&self, level: Level, msg: &str) {
  92. let mut log = self.log.borrow_mut();
  93. let entry = if log.0 {
  94. log.1.pop().map(|e| Entry(min(e.0, level), e.1 + msg))
  95. } else {
  96. None
  97. }
  98. .unwrap_or_else(|| Entry(level, msg.to_string()));
  99. log.0 = true;
  100. log.1.push(entry);
  101. }
  102. fn writeln(&self, level: Level, msg: &str) {
  103. let mut log = self.log.borrow_mut();
  104. log.0 = false;
  105. log.1.push(Entry(level, msg.to_string()));
  106. }
  107. }
  108. #[cfg(test)]
  109. mod test {}