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.

140 lines
3.1 KiB

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