1use std::fmt::{Display, Formatter};
4
5use serde::{Deserialize, Serialize};
6use serde_json::Value;
7
8#[derive(Deserialize, Serialize, Debug, Clone, PartialEq)]
10#[serde(tag = "type")]
11pub enum LoggingMessage {
12 #[serde(rename = "log_message")]
15 LogMessage {
16 time: f64,
18 #[serde(rename = "levelname")]
20 level_name: LevelName,
21 name: String,
23 message: String,
25 #[serde(rename = "msgid")]
29 msg_id: Option<MessageId>,
30 },
31 #[serde(rename = "file_status")]
34 FileStatus {
35 status: String,
37 path: String,
39 },
40 #[serde(rename = "progress_percent")]
42 ProgressPercent {
43 operation: u64,
45 #[serde(rename = "msgid")]
47 msg_id: Option<MessageId>,
48 time: f64,
50 finished: bool,
53 current: Option<u64>,
57 total: Option<u64>,
61 info: Option<Vec<Value>>,
65 },
66 #[serde(rename = "progress_message")]
69 ProgressMessage {
70 operation: u64,
72 #[serde(rename = "msgid")]
74 msg_id: Option<MessageId>,
75 finished: bool,
78 message: Option<String>,
80 time: f64,
82 },
83 #[serde(rename = "archive_progress")]
85 ArchiveProgress {
86 original_size: Option<u64>,
89 compressed_size: Option<u64>,
91 deduplicated_size: Option<u64>,
93 nfiles: Option<u64>,
95 path: Option<String>,
97 time: f64,
99 finished: bool,
102 },
103 UMountError(String),
106}
107
108impl LoggingMessage {
109 pub(crate) fn from_str(log_message: &str) -> Result<Self, serde_json::Error> {
111 if log_message.starts_with("fusermount: entry for") {
114 Ok(LoggingMessage::UMountError(log_message.to_string()))
115 } else {
116 serde_json::from_str(log_message)
117 }
118 }
119}
120#[derive(Deserialize, Serialize, Debug, Clone, Copy, PartialEq)]
122#[serde(rename_all = "UPPERCASE")]
123pub enum LevelName {
124 Debug,
126 Info,
128 Warning,
130 Error,
132 Critical,
134}
135
136#[derive(Deserialize, Serialize, Debug, Clone, Copy, PartialEq)]
141pub enum MessageId {
142 #[serde(rename = "Archive.AlreadyExists")]
144 ArchiveAlreadyExists,
145 #[serde(rename = "Archive.DoesNotExist")]
147 ArchiveDoesNotExist,
148 #[serde(rename = "Archive.IncompatibleFilesystemEncodingError")]
151 ArchiveIncompatibleFilesystemEncodingError,
152 BackupFileNotFoundError,
154 #[serde(rename = "Cache.CacheInitAbortedError")]
156 CacheCacheInitAbortedError,
157 #[serde(rename = "Cache.EncryptionMethodMismatch")]
159 CacheEncryptionMethodMismatch,
160 #[serde(rename = "Cache.RepositoryAccessAborted")]
162 CacheRepositoryAccessAborted,
163 #[serde(rename = "Cache.RepositoryIDNotUnique")]
166 CacheRepositoryIDNotUnique,
167 #[serde(rename = "Cache.RepositoryReplay")]
170 CacheRepositoryReplay,
171 #[serde(rename = "Buffer.MemoryLimitExceeded")]
173 BufferMemoryLimitExceeded,
174 ExtensionModuleError,
176 IntegrityError,
178 NoManifestError,
180 PlaceholderError,
182 KeyfileInvalidError,
184 KeyfileMismatchError,
186 KeyfileNotFoundError,
188 PassphraseWrong,
190 PasswordRetriesExceeded,
192 RepoKeyNotFoundError,
194 UnsupportedManifestError,
196 UnsupportedPayloadError,
198 NotABorgKeyFile,
200 RepoIdMismatch,
202 UnencryptedRepo,
204 UnknownKeyType,
206 LockError,
208 LockErrorT,
210 ConnectionClosed,
212 InvalidRPCMethod,
214 PathNotAllowed,
216 NoPassphraseFailure,
218 #[serde(rename = "RemoteRepository.RPCServerOutdated")]
220 RemoteRepositoryRPCServerOutdated,
221 UnexpectedRPCDataFormatFromClient,
223 UnexpectedRPCDataFormatFromServer,
225 #[serde(rename = "Repository.AlreadyExists")]
227 RepositoryAlreadyExists,
228 #[serde(rename = "Repository.CheckNeeded")]
230 RepositoryCheckNeeded,
231 #[serde(rename = "Repository.DoesNotExist")]
233 RepositoryDoesNotExist,
234 #[serde(rename = "Repository.InsufficientFreeSpaceError")]
236 RepositoryInsufficientFreeSpaceError,
237 #[serde(rename = "Repository.InvalidRepository")]
239 RepositoryInvalidRepository,
240 #[serde(rename = "Repository.AtticRepository")]
242 RepositoryAtticRepository,
243 #[serde(rename = "Repository.ObjectNotFound")]
245 RepositoryObjectNotFound,
246 #[serde(rename = "cache.begin_transaction")]
248 CacheBeginTransaction,
249 #[serde(rename = "cache.download_chunks")]
251 CacheDownloadChunks,
252 #[serde(rename = "cache.commit")]
254 CacheCommit,
255 #[serde(rename = "cache.sync")]
257 CacheSync,
258 #[serde(rename = "repository.compact_segments")]
260 RepositoryCompactSegments,
261 #[serde(rename = "repository.replay_segments")]
263 RepositoryReplaySegments,
264 #[serde(rename = "repository.check")]
266 RepositoryCheck,
267 #[serde(rename = "check.verify_data")]
269 CheckVerifyData,
270 #[serde(rename = "check.rebuild_manifest")]
272 CheckRebuildManifest,
273 #[serde(rename = "extract")]
275 Extract,
276 #[serde(rename = "extract.permissions")]
278 ExtractPermissions,
279 #[serde(rename = "archive.delete")]
281 ArchiveDelete,
282 #[serde(rename = "archive.calc_stats")]
284 ArchiveCalcStats,
285 #[serde(rename = "prune")]
287 Prune,
288 #[serde(rename = "upgrade.convert_segments")]
290 UpgradeConvertSegments,
291}
292
293impl Display for MessageId {
294 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
295 match self {
296 MessageId::ArchiveAlreadyExists => write!(f, "Archive.AlreadyExists"),
297 MessageId::ArchiveDoesNotExist => write!(f, "Archive.DoesNotExist"),
298 MessageId::ArchiveIncompatibleFilesystemEncodingError => {
299 write!(f, "Archive.IncompatibleFilesystemEncodingError")
300 }
301 MessageId::BackupFileNotFoundError => write!(f, "BackupFileNotFoundError"),
302 MessageId::CacheCacheInitAbortedError => write!(f, "Cache.CacheInitAbortedError"),
303 MessageId::CacheEncryptionMethodMismatch => write!(f, "Cache.EncryptionMethodMismatch"),
304 MessageId::CacheRepositoryAccessAborted => write!(f, "Cache.RepositoryAccessAborted"),
305 MessageId::CacheRepositoryIDNotUnique => write!(f, "Cache.RepositoryIDNotUnique"),
306 MessageId::CacheRepositoryReplay => write!(f, "Cache.RepositoryReplay"),
307 MessageId::BufferMemoryLimitExceeded => write!(f, "Buffer.MemoryLimitExceeded"),
308 MessageId::ExtensionModuleError => write!(f, "ExtensionModuleError"),
309 MessageId::IntegrityError => write!(f, "IntegrityError"),
310 MessageId::NoManifestError => write!(f, "NoManifestError"),
311 MessageId::PlaceholderError => write!(f, "PlaceholderError"),
312 MessageId::KeyfileInvalidError => write!(f, "KeyfileInvalidError"),
313 MessageId::KeyfileMismatchError => write!(f, "KeyfileMismatchError"),
314 MessageId::KeyfileNotFoundError => write!(f, "KeyfileNotFoundError"),
315 MessageId::PassphraseWrong => write!(f, "PassphraseWrong"),
316 MessageId::PasswordRetriesExceeded => write!(f, "PasswordRetriesExceeded"),
317 MessageId::RepoKeyNotFoundError => write!(f, "RepoKeyNotFoundError"),
318 MessageId::UnsupportedManifestError => write!(f, "UnsupportedManifestError"),
319 MessageId::UnsupportedPayloadError => write!(f, "UnsupportedPayloadError"),
320 MessageId::NotABorgKeyFile => write!(f, "NotABorgKeyFile"),
321 MessageId::RepoIdMismatch => write!(f, "RepoIdMismatch"),
322 MessageId::UnencryptedRepo => write!(f, "UnencryptedRepo"),
323 MessageId::UnknownKeyType => write!(f, "UnknownKeyType"),
324 MessageId::LockError => write!(f, "LockError"),
325 MessageId::LockErrorT => write!(f, "LockErrorT"),
326 MessageId::ConnectionClosed => write!(f, "ConnectionClosed"),
327 MessageId::InvalidRPCMethod => write!(f, "InvalidRPCMethod"),
328 MessageId::PathNotAllowed => write!(f, "PathNotAllowed"),
329 MessageId::NoPassphraseFailure => write!(f, "NoPassphraseFailure"),
330 MessageId::RemoteRepositoryRPCServerOutdated => {
331 write!(f, "RemoteRepository.RPCServerOutdated")
332 }
333 MessageId::UnexpectedRPCDataFormatFromClient => {
334 write!(f, "UnexpectedRPCDataFormatFromClient")
335 }
336 MessageId::UnexpectedRPCDataFormatFromServer => {
337 write!(f, "UnexpectedRPCDataFormatFromServer")
338 }
339 MessageId::RepositoryAlreadyExists => write!(f, "Repository.AlreadyExists"),
340 MessageId::RepositoryCheckNeeded => write!(f, "Repository.CheckNeeded"),
341 MessageId::RepositoryDoesNotExist => write!(f, "Repository.DoesNotExist"),
342 MessageId::RepositoryInsufficientFreeSpaceError => {
343 write!(f, "Repository.InsufficientFreeSpaceError")
344 }
345 MessageId::RepositoryInvalidRepository => write!(f, "Repository.InvalidRepository"),
346 MessageId::RepositoryAtticRepository => write!(f, "Repository.AtticRepository"),
347 MessageId::RepositoryObjectNotFound => write!(f, "Repository.ObjectNotFound"),
348 MessageId::CacheBeginTransaction => write!(f, "cache.begin_transaction"),
349 MessageId::CacheDownloadChunks => write!(f, "cache.download_chunks"),
350 MessageId::CacheCommit => write!(f, "cache.commit"),
351 MessageId::CacheSync => write!(f, "cache.sync"),
352 MessageId::RepositoryCompactSegments => write!(f, "repository.compact_segments"),
353 MessageId::RepositoryReplaySegments => write!(f, "repository.replay_segments"),
354 MessageId::RepositoryCheck => write!(f, "repository.check"),
355 MessageId::CheckVerifyData => write!(f, "check.verify_data"),
356 MessageId::CheckRebuildManifest => write!(f, "check.rebuild_manifest"),
357 MessageId::Extract => write!(f, "extract"),
358 MessageId::ExtractPermissions => write!(f, "extract.permissions"),
359 MessageId::ArchiveDelete => write!(f, "archive.delete"),
360 MessageId::ArchiveCalcStats => write!(f, "archive.calc_stats"),
361 MessageId::Prune => write!(f, "prune"),
362 MessageId::UpgradeConvertSegments => write!(f, "upgrade.convert_segments"),
363 }
364 }
365}
366
367#[cfg(test)]
368mod tests {
369 use super::LoggingMessage;
370
371 #[test]
372 fn test_log_message_parse_mount() {
373 let message = "fusermount: entry for /home/david/fake-directory not found in /etc/mtab";
374 let log = LoggingMessage::from_str(message);
375 assert_eq!(
376 LoggingMessage::UMountError(message.to_string()),
377 log.expect("Expected LoggingMessage::UMountError to be parsed correctly")
378 )
379 }
380}