1mod collector;
31mod filter;
32mod formatter;
33mod output;
34
35pub use collector::{LogCollector, LogEntry, LogSource, StopHandle};
36pub use filter::{LogFilter, LogLevel};
37pub use formatter::{LogFormatter, OutputFormat};
38pub use output::{FileRotation, LogOutput, OutputConfig};
39
40use serde::{Deserialize, Serialize};
41use std::path::PathBuf;
42
43#[derive(Debug, Clone, Serialize, Deserialize)]
45pub struct LogConfig {
46 pub format: OutputFormat,
48 pub output: OutputConfig,
50 pub filter: LogFilter,
52 pub domain_id: u32,
54 pub topic_pattern: String,
56}
57
58impl Default for LogConfig {
59 fn default() -> Self {
60 Self {
61 format: OutputFormat::Text,
62 output: OutputConfig::Stdout,
63 filter: LogFilter::default(),
64 domain_id: 0,
65 topic_pattern: "rt/rosout".to_string(),
66 }
67 }
68}
69
70impl LogConfig {
71 pub fn builder() -> LogConfigBuilder {
73 LogConfigBuilder::default()
74 }
75}
76
77#[derive(Debug, Default)]
79pub struct LogConfigBuilder {
80 format: Option<OutputFormat>,
81 output: Option<OutputConfig>,
82 filter: Option<LogFilter>,
83 domain_id: Option<u32>,
84 topic_pattern: Option<String>,
85}
86
87impl LogConfigBuilder {
88 pub fn format(mut self, format: OutputFormat) -> Self {
90 self.format = Some(format);
91 self
92 }
93
94 pub fn output_file(mut self, path: impl Into<PathBuf>) -> Self {
96 self.output = Some(OutputConfig::File {
97 path: path.into(),
98 rotation: None,
99 });
100 self
101 }
102
103 pub fn output_file_rotated(mut self, path: impl Into<PathBuf>, rotation: FileRotation) -> Self {
105 self.output = Some(OutputConfig::File {
106 path: path.into(),
107 rotation: Some(rotation),
108 });
109 self
110 }
111
112 pub fn output_stdout(mut self) -> Self {
114 self.output = Some(OutputConfig::Stdout);
115 self
116 }
117
118 pub fn output_syslog(mut self, facility: SyslogFacility) -> Self {
120 self.output = Some(OutputConfig::Syslog { facility });
121 self
122 }
123
124 pub fn level(mut self, level: LogLevel) -> Self {
126 let mut filter = self.filter.take().unwrap_or_default();
127 filter.min_level = level;
128 self.filter = Some(filter);
129 self
130 }
131
132 pub fn participant_filter(mut self, pattern: impl Into<String>) -> Self {
134 let mut filter = self.filter.take().unwrap_or_default();
135 filter.participant_pattern = Some(pattern.into());
136 self.filter = Some(filter);
137 self
138 }
139
140 pub fn topic_filter(mut self, pattern: impl Into<String>) -> Self {
142 let mut filter = self.filter.take().unwrap_or_default();
143 filter.topic_pattern = Some(pattern.into());
144 self.filter = Some(filter);
145 self
146 }
147
148 pub fn domain_id(mut self, id: u32) -> Self {
150 self.domain_id = Some(id);
151 self
152 }
153
154 pub fn topic_pattern(mut self, pattern: impl Into<String>) -> Self {
156 self.topic_pattern = Some(pattern.into());
157 self
158 }
159
160 pub fn build(self) -> LogConfig {
162 LogConfig {
163 format: self.format.unwrap_or(OutputFormat::Text),
164 output: self.output.unwrap_or(OutputConfig::Stdout),
165 filter: self.filter.unwrap_or_default(),
166 domain_id: self.domain_id.unwrap_or(0),
167 topic_pattern: self
168 .topic_pattern
169 .unwrap_or_else(|| "rt/rosout".to_string()),
170 }
171 }
172}
173
174#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
176pub enum SyslogFacility {
177 Kern,
178 User,
179 Mail,
180 Daemon,
181 Auth,
182 Syslog,
183 Lpr,
184 News,
185 Uucp,
186 Cron,
187 #[default]
188 Local0,
189 Local1,
190 Local2,
191 Local3,
192 Local4,
193 Local5,
194 Local6,
195 Local7,
196}
197
198impl SyslogFacility {
199 pub fn code(&self) -> u8 {
201 match self {
202 Self::Kern => 0,
203 Self::User => 1,
204 Self::Mail => 2,
205 Self::Daemon => 3,
206 Self::Auth => 4,
207 Self::Syslog => 5,
208 Self::Lpr => 6,
209 Self::News => 7,
210 Self::Uucp => 8,
211 Self::Cron => 9,
212 Self::Local0 => 16,
213 Self::Local1 => 17,
214 Self::Local2 => 18,
215 Self::Local3 => 19,
216 Self::Local4 => 20,
217 Self::Local5 => 21,
218 Self::Local6 => 22,
219 Self::Local7 => 23,
220 }
221 }
222}