annotate rust/hg-core/src/logging.rs @ 52297:7be39c5110c9

hg-core: add a complete VFS This will be used from Python in a later change. More changes are needed in hg-core and rhg to properly clean up the APIs of the old VFS implementation but it can be done when the dust settles and we start adding more functionality to the pure Rust VFS.
author Rapha?l Gom?s <rgomes@octobus.net>
date Mon, 29 Jul 2024 20:47:43 +0200
parents db7dbe6f7bb2
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
46638
1f55cd5b292f rust: Add a log file rotation utility
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
1 use crate::errors::{HgError, HgResultExt, IoErrorContext, IoResultExt};
52297
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 51906
diff changeset
2 use crate::vfs::{Vfs, VfsImpl};
46638
1f55cd5b292f rust: Add a log file rotation utility
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
3 use std::io::Write;
52297
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 51906
diff changeset
4 use std::path::Path;
46638
1f55cd5b292f rust: Add a log file rotation utility
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
5
1f55cd5b292f rust: Add a log file rotation utility
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
6 /// An utility to append to a log file with the given name, and optionally
1f55cd5b292f rust: Add a log file rotation utility
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
7 /// rotate it after it reaches a certain maximum size.
1f55cd5b292f rust: Add a log file rotation utility
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
8 ///
1f55cd5b292f rust: Add a log file rotation utility
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
9 /// Rotation works by renaming "example.log" to "example.log.1", after renaming
1f55cd5b292f rust: Add a log file rotation utility
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
10 /// "example.log.1" to "example.log.2" etc up to the given maximum number of
1f55cd5b292f rust: Add a log file rotation utility
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
11 /// files.
1f55cd5b292f rust: Add a log file rotation utility
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
12 pub struct LogFile<'a> {
51906
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 47980
diff changeset
13 vfs: VfsImpl,
46638
1f55cd5b292f rust: Add a log file rotation utility
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
14 name: &'a str,
1f55cd5b292f rust: Add a log file rotation utility
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
15 max_size: Option<u64>,
1f55cd5b292f rust: Add a log file rotation utility
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
16 max_files: u32,
1f55cd5b292f rust: Add a log file rotation utility
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
17 }
1f55cd5b292f rust: Add a log file rotation utility
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
18
1f55cd5b292f rust: Add a log file rotation utility
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
19 impl<'a> LogFile<'a> {
51906
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 47980
diff changeset
20 pub fn new(vfs: VfsImpl, name: &'a str) -> Self {
46638
1f55cd5b292f rust: Add a log file rotation utility
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
21 Self {
1f55cd5b292f rust: Add a log file rotation utility
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
22 vfs,
1f55cd5b292f rust: Add a log file rotation utility
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
23 name,
1f55cd5b292f rust: Add a log file rotation utility
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
24 max_size: None,
1f55cd5b292f rust: Add a log file rotation utility
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
25 max_files: 0,
1f55cd5b292f rust: Add a log file rotation utility
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
26 }
1f55cd5b292f rust: Add a log file rotation utility
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
27 }
1f55cd5b292f rust: Add a log file rotation utility
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
28
1f55cd5b292f rust: Add a log file rotation utility
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
29 /// Rotate before writing to a log file that was already larger than the
1f55cd5b292f rust: Add a log file rotation utility
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
30 /// given size, in bytes. `None` disables rotation.
1f55cd5b292f rust: Add a log file rotation utility
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
31 pub fn max_size(mut self, value: Option<u64>) -> Self {
1f55cd5b292f rust: Add a log file rotation utility
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
32 self.max_size = value;
1f55cd5b292f rust: Add a log file rotation utility
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
33 self
1f55cd5b292f rust: Add a log file rotation utility
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
34 }
1f55cd5b292f rust: Add a log file rotation utility
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
35
1f55cd5b292f rust: Add a log file rotation utility
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
36 /// Keep this many rotated files `{name}.1` up to `{name}.{max}`, in
1f55cd5b292f rust: Add a log file rotation utility
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
37 /// addition to the original `{name}` file.
1f55cd5b292f rust: Add a log file rotation utility
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
38 pub fn max_files(mut self, value: u32) -> Self {
1f55cd5b292f rust: Add a log file rotation utility
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
39 self.max_files = value;
1f55cd5b292f rust: Add a log file rotation utility
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
40 self
1f55cd5b292f rust: Add a log file rotation utility
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
41 }
1f55cd5b292f rust: Add a log file rotation utility
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
42
1f55cd5b292f rust: Add a log file rotation utility
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
43 /// Append the given `bytes` as-is to the log file, after rotating if
1f55cd5b292f rust: Add a log file rotation utility
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
44 /// needed.
1f55cd5b292f rust: Add a log file rotation utility
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
45 ///
1f55cd5b292f rust: Add a log file rotation utility
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
46 /// No trailing newline is added. Make sure to include one in `bytes` if
1f55cd5b292f rust: Add a log file rotation utility
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
47 /// desired.
1f55cd5b292f rust: Add a log file rotation utility
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
48 pub fn write(&self, bytes: &[u8]) -> Result<(), HgError> {
1f55cd5b292f rust: Add a log file rotation utility
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
49 let path = self.vfs.join(self.name);
1f55cd5b292f rust: Add a log file rotation utility
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
50 let context = || IoErrorContext::WritingFile(path.clone());
1f55cd5b292f rust: Add a log file rotation utility
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
51 let open = || {
1f55cd5b292f rust: Add a log file rotation utility
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
52 std::fs::OpenOptions::new()
1f55cd5b292f rust: Add a log file rotation utility
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
53 .create(true)
1f55cd5b292f rust: Add a log file rotation utility
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
54 .append(true)
1f55cd5b292f rust: Add a log file rotation utility
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
55 .open(&path)
1f55cd5b292f rust: Add a log file rotation utility
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
56 .with_context(context)
1f55cd5b292f rust: Add a log file rotation utility
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
57 };
1f55cd5b292f rust: Add a log file rotation utility
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
58 let mut file = open()?;
1f55cd5b292f rust: Add a log file rotation utility
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
59 if let Some(max_size) = self.max_size {
1f55cd5b292f rust: Add a log file rotation utility
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
60 if file.metadata().with_context(context)?.len() >= max_size {
1f55cd5b292f rust: Add a log file rotation utility
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
61 // For example with `max_files == 5`, the first iteration of
1f55cd5b292f rust: Add a log file rotation utility
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
62 // this loop has `i == 4` and renames `{name}.4` to `{name}.5`.
1f55cd5b292f rust: Add a log file rotation utility
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
63 // The last iteration renames `{name}.1` to
1f55cd5b292f rust: Add a log file rotation utility
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
64 // `{name}.2`
1f55cd5b292f rust: Add a log file rotation utility
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
65 for i in (1..self.max_files).rev() {
1f55cd5b292f rust: Add a log file rotation utility
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
66 self.vfs
1f55cd5b292f rust: Add a log file rotation utility
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
67 .rename(
52297
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 51906
diff changeset
68 Path::new(&format!("{}.{}", self.name, i)),
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 51906
diff changeset
69 Path::new(&format!("{}.{}", self.name, i + 1)),
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 51906
diff changeset
70 false,
46638
1f55cd5b292f rust: Add a log file rotation utility
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
71 )
1f55cd5b292f rust: Add a log file rotation utility
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
72 .io_not_found_as_none()?;
1f55cd5b292f rust: Add a log file rotation utility
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
73 }
1f55cd5b292f rust: Add a log file rotation utility
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
74 // Then rename `{name}` to `{name}.1`. This is the
1f55cd5b292f rust: Add a log file rotation utility
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
75 // previously-opened `file`.
1f55cd5b292f rust: Add a log file rotation utility
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
76 self.vfs
52297
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 51906
diff changeset
77 .rename(
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 51906
diff changeset
78 Path::new(&self.name),
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 51906
diff changeset
79 Path::new(&format!("{}.1", self.name)),
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 51906
diff changeset
80 false,
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 51906
diff changeset
81 )
46638
1f55cd5b292f rust: Add a log file rotation utility
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
82 .io_not_found_as_none()?;
1f55cd5b292f rust: Add a log file rotation utility
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
83 // Finally, create a new `{name}` file and replace our `file`
1f55cd5b292f rust: Add a log file rotation utility
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
84 // handle.
1f55cd5b292f rust: Add a log file rotation utility
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
85 file = open()?;
1f55cd5b292f rust: Add a log file rotation utility
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
86 }
1f55cd5b292f rust: Add a log file rotation utility
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
87 }
1f55cd5b292f rust: Add a log file rotation utility
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
88 file.write_all(bytes).with_context(context)?;
1f55cd5b292f rust: Add a log file rotation utility
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
89 file.sync_all().with_context(context)
1f55cd5b292f rust: Add a log file rotation utility
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
90 }
1f55cd5b292f rust: Add a log file rotation utility
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
91 }
1f55cd5b292f rust: Add a log file rotation utility
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
92
1f55cd5b292f rust: Add a log file rotation utility
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
93 #[test]
1f55cd5b292f rust: Add a log file rotation utility
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
94 fn test_rotation() {
1f55cd5b292f rust: Add a log file rotation utility
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
95 let temp = tempfile::tempdir().unwrap();
52297
7be39c5110c9 hg-core: add a complete VFS
Rapha?l Gom?s <rgomes@octobus.net>
parents: 51906
diff changeset
96 let vfs = VfsImpl::new(temp.path().to_owned(), false);
51906
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 47980
diff changeset
97 let logger = LogFile::new(vfs.clone(), "log")
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 47980
diff changeset
98 .max_size(Some(3))
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 47980
diff changeset
99 .max_files(2);
46638
1f55cd5b292f rust: Add a log file rotation utility
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
100 logger.write(b"one\n").unwrap();
1f55cd5b292f rust: Add a log file rotation utility
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
101 logger.write(b"two\n").unwrap();
1f55cd5b292f rust: Add a log file rotation utility
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
102 logger.write(b"3\n").unwrap();
1f55cd5b292f rust: Add a log file rotation utility
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
103 logger.write(b"four\n").unwrap();
1f55cd5b292f rust: Add a log file rotation utility
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
104 logger.write(b"five\n").unwrap();
1f55cd5b292f rust: Add a log file rotation utility
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
105 assert_eq!(vfs.read("log").unwrap(), b"five\n");
1f55cd5b292f rust: Add a log file rotation utility
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
106 assert_eq!(vfs.read("log.1").unwrap(), b"3\nfour\n");
1f55cd5b292f rust: Add a log file rotation utility
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
107 assert_eq!(vfs.read("log.2").unwrap(), b"two\n");
1f55cd5b292f rust: Add a log file rotation utility
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
108 assert!(vfs.read("log.3").io_not_found_as_none().unwrap().is_none());
1f55cd5b292f rust: Add a log file rotation utility
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
109 }