Skip to content

Commit 42ce584

Browse files
authored
refactor!: NonBlocking becomes an internal concept (#123)
Signed-off-by: tison <[email protected]>
1 parent c21adb2 commit 42ce584

File tree

13 files changed

+405
-231
lines changed

13 files changed

+405
-231
lines changed

CHANGELOG.md

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,72 @@ All notable changes to this project will be documented in this file.
99
* `Diagnostic` is now a trait. `Visitor`'s method signature is simplified.
1010
* `Append::flush` is now fallible.
1111
* `Diagnostic`'s and `Visitor`'s `visit` methods are fallible.
12+
* `NonBlocking` related types and the feature flag are now private.
13+
* Constructing `RollingFile` and `Syslog` appender is heavily simplified.
14+
15+
Before:
16+
17+
```rust
18+
fn construct_rolling_file() {
19+
let rolling_writer = RollingFileWriter::builder()
20+
.rotation(Rotation::Daily)
21+
.filename_prefix("app_log")
22+
.build("logs")
23+
.unwrap();
24+
25+
let (non_blocking, _guard) = rolling_file::non_blocking(rolling_writer).finish();
26+
27+
logforth::builder()
28+
.dispatch(|d| {
29+
d.filter(log::LevelFilter::Trace)
30+
.append(RollingFile::new(non_blocking).with_layout(JsonLayout::default()))
31+
})
32+
.apply();
33+
}
34+
35+
fn construct_syslog() {
36+
let syslog_writer = SyslogWriter::tcp_well_known().unwrap();
37+
let (non_blocking, _guard) = syslog::non_blocking(syslog_writer).finish();
38+
39+
logforth::builder()
40+
.dispatch(|d| {
41+
d.filter(log::LevelFilter::Trace)
42+
.append(Syslog::new(non_blocking))
43+
})
44+
.apply();
45+
}
46+
```
47+
48+
After:
49+
50+
```rust
51+
fn construct_rolling_file() {
52+
let (rolling_writer, _guard) = RollingFileBuilder::new("logs")
53+
.layout(JsonLayout::default())
54+
.rotation(Rotation::Daily)
55+
.filename_prefix("app_log")
56+
.build()
57+
.unwrap();
58+
59+
logforth::builder()
60+
.dispatch(|d| d.filter(log::LevelFilter::Trace).append(rolling_writer))
61+
.apply();
62+
}
63+
64+
fn construct_syslog() {
65+
let (append, _guard) = SyslogBuilder::tcp_well_known().unwrap().build();
66+
67+
logforth::builder()
68+
.dispatch(|d| d.filter(log::LevelFilter::Trace).append(append))
69+
.apply();
70+
}
71+
```
72+
73+
74+
### New features
75+
76+
* Add `LogfmtLayout` to support logfmt format.
77+
* Add `GoogleStructuredLogLayout` to support Google structured log format.
1278

1379
## [0.23.1] 2025-03-23
1480

Cargo.toml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,16 +40,16 @@ google_structured_log = ["internal-serde", "dep:serde_json"]
4040
journald = ["dep:libc"]
4141
json = ["internal-serde", "dep:serde_json"]
4242
native-tls = ["dep:native-tls", "fasyslog?/native-tls"]
43-
non-blocking = ["dep:crossbeam-channel"]
4443
opentelemetry = [
4544
"dep:opentelemetry",
4645
"dep:opentelemetry-otlp",
4746
"dep:opentelemetry_sdk",
4847
]
49-
rolling-file = ["non-blocking"]
50-
syslog = ["non-blocking", "dep:fasyslog"]
48+
rolling-file = ["internal-non-blocking"]
49+
syslog = ["internal-non-blocking", "dep:fasyslog"]
5150

5251
# Internal features - not intended for directly public use
52+
internal-non-blocking = ["dep:crossbeam-channel"]
5353
internal-serde = ["dep:serde", "log/kv_serde", "jiff/serde"]
5454

5555
[dependencies]

examples/rolling_file.rs

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,26 +12,20 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15-
use logforth::append::rolling_file;
16-
use logforth::append::rolling_file::RollingFile;
17-
use logforth::append::rolling_file::RollingFileWriter;
15+
use logforth::append::rolling_file::RollingFileBuilder;
1816
use logforth::append::rolling_file::Rotation;
1917
use logforth::layout::JsonLayout;
2018

2119
fn main() {
22-
let rolling_writer = RollingFileWriter::builder()
20+
let (rolling_writer, _guard) = RollingFileBuilder::new("logs")
21+
.layout(JsonLayout::default())
2322
.rotation(Rotation::Daily)
2423
.filename_prefix("app_log")
25-
.build("logs")
24+
.build()
2625
.unwrap();
2726

28-
let (non_blocking, _guard) = rolling_file::non_blocking(rolling_writer).finish();
29-
3027
logforth::builder()
31-
.dispatch(|d| {
32-
d.filter(log::LevelFilter::Trace)
33-
.append(RollingFile::new(non_blocking).with_layout(JsonLayout::default()))
34-
})
28+
.dispatch(|d| d.filter(log::LevelFilter::Trace).append(rolling_writer))
3529
.apply();
3630

3731
let repeat = 1;

examples/syslog.rs

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,19 +12,13 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15-
use logforth::append::syslog;
16-
use logforth::append::syslog::Syslog;
17-
use logforth::append::syslog::SyslogWriter;
15+
use logforth::append::syslog::SyslogBuilder;
1816

1917
fn main() {
20-
let syslog_writer = SyslogWriter::tcp_well_known().unwrap();
21-
let (non_blocking, _guard) = syslog::non_blocking(syslog_writer).finish();
18+
let (append, _guard) = SyslogBuilder::tcp_well_known().unwrap().build();
2219

2320
logforth::builder()
24-
.dispatch(|d| {
25-
d.filter(log::LevelFilter::Trace)
26-
.append(Syslog::new(non_blocking))
27-
})
21+
.dispatch(|d| d.filter(log::LevelFilter::Trace).append(append))
2822
.apply();
2923

3024
let repeat = 1;

src/append/opentelemetry.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ pub enum OpentelemetryWireProtocol {
5050
}
5151

5252
/// A builder to configure and create an [`OpentelemetryLog`] appender.
53+
#[derive(Debug)]
5354
pub struct OpentelemetryLogBuilder {
5455
name: String,
5556
endpoint: String,

src/append/rolling_file/append.rs

Lines changed: 120 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,38 +12,146 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15+
use std::path::PathBuf;
16+
use std::time::Duration;
17+
1518
use log::Record;
1619

17-
use crate::append::rolling_file::RollingFileWriter;
20+
use crate::append::rolling_file::rolling::RollingFileWriter;
21+
use crate::append::rolling_file::rolling::RollingFileWriterBuilder;
22+
use crate::append::rolling_file::Rotation;
1823
use crate::append::Append;
1924
use crate::layout::TextLayout;
2025
use crate::non_blocking::NonBlocking;
26+
use crate::non_blocking::NonBlockingBuilder;
2127
use crate::Diagnostic;
28+
use crate::DropGuard;
2229
use crate::Layout;
2330

24-
/// An appender that writes log records to rolling files.
31+
/// A builder to configure and create an [`RollingFile`] appender.
2532
#[derive(Debug)]
26-
pub struct RollingFile {
33+
pub struct RollingFileBuilder {
34+
builder: RollingFileWriterBuilder,
2735
layout: Box<dyn Layout>,
28-
writer: NonBlocking<RollingFileWriter>,
36+
37+
// non-blocking options
38+
thread_name: String,
39+
buffered_lines_limit: Option<usize>,
40+
shutdown_timeout: Option<Duration>,
2941
}
3042

31-
impl RollingFile {
32-
/// Creates a new [`RollingFile`] appender.
33-
///
34-
/// This appender by default uses [`TextLayout`] to format log records.
35-
pub fn new(writer: NonBlocking<RollingFileWriter>) -> Self {
43+
impl RollingFileBuilder {
44+
/// Create a new builder.
45+
pub fn new(basedir: impl Into<PathBuf>) -> Self {
3646
Self {
47+
builder: RollingFileWriterBuilder::new(basedir),
3748
layout: Box::new(TextLayout::default().no_color()),
38-
writer,
49+
50+
thread_name: "logforth-rolling-file".to_string(),
51+
buffered_lines_limit: None,
52+
shutdown_timeout: None,
3953
}
4054
}
4155

42-
/// Sets the layout used to format log records.
43-
pub fn with_layout(mut self, layout: impl Into<Box<dyn Layout>>) -> Self {
56+
/// Build the [`RollingFile`] appender.
57+
///
58+
/// # Errors
59+
///
60+
/// Returns an error if the log directory cannot be created.
61+
pub fn build(self) -> anyhow::Result<(RollingFile, DropGuard)> {
62+
let RollingFileBuilder {
63+
builder,
64+
layout,
65+
thread_name,
66+
buffered_lines_limit,
67+
shutdown_timeout,
68+
} = self;
69+
let writer = builder.build()?;
70+
let (non_blocking, guard) = NonBlockingBuilder::new(thread_name, writer)
71+
.buffered_lines_limit(buffered_lines_limit)
72+
.shutdown_timeout(shutdown_timeout)
73+
.build();
74+
Ok((RollingFile::new(non_blocking, layout), Box::new(guard)))
75+
}
76+
77+
/// Sets the layout for the logs.
78+
///
79+
/// Default to [`TextLayout`].
80+
///
81+
/// # Examples
82+
///
83+
/// ```
84+
/// use logforth::append::rolling_file::RollingFileBuilder;
85+
/// use logforth::layout::JsonLayout;
86+
///
87+
/// let builder = RollingFileBuilder::new("my_service");
88+
/// builder.layout(JsonLayout::default());
89+
/// ```
90+
pub fn layout(mut self, layout: impl Into<Box<dyn Layout>>) -> Self {
4491
self.layout = layout.into();
4592
self
4693
}
94+
95+
/// Sets the buffer size of pending messages.
96+
pub fn buffered_lines_limit(mut self, buffered_lines_limit: Option<usize>) -> Self {
97+
self.buffered_lines_limit = buffered_lines_limit;
98+
self
99+
}
100+
101+
/// Sets the shutdown timeout before the worker guard dropped.
102+
pub fn shutdown_timeout(mut self, shutdown_timeout: Option<Duration>) -> Self {
103+
self.shutdown_timeout = shutdown_timeout;
104+
self
105+
}
106+
107+
/// Sets the thread name for the background sender thread.
108+
pub fn thread_name(mut self, thread_name: impl Into<String>) -> Self {
109+
self.thread_name = thread_name.into();
110+
self
111+
}
112+
113+
/// Sets the rotation policy.
114+
pub fn rotation(mut self, rotation: Rotation) -> Self {
115+
self.builder = self.builder.rotation(rotation);
116+
self
117+
}
118+
119+
/// Sets the filename prefix.
120+
pub fn filename_prefix(mut self, prefix: impl Into<String>) -> Self {
121+
self.builder = self.builder.filename_prefix(prefix);
122+
self
123+
}
124+
125+
/// Sets the filename suffix.
126+
pub fn filename_suffix(mut self, suffix: impl Into<String>) -> Self {
127+
self.builder = self.builder.filename_suffix(suffix);
128+
self
129+
}
130+
131+
/// Sets the maximum number of log files to keep.
132+
pub fn max_log_files(mut self, n: usize) -> Self {
133+
self.builder = self.builder.max_log_files(n);
134+
self
135+
}
136+
137+
/// Sets the maximum size of a log file in bytes.
138+
pub fn max_file_size(mut self, n: usize) -> Self {
139+
self.builder = self.builder.max_file_size(n);
140+
self
141+
}
142+
}
143+
144+
/// An appender that writes log records to rolling files.
145+
#[derive(Debug)]
146+
pub struct RollingFile {
147+
layout: Box<dyn Layout>,
148+
writer: NonBlocking<RollingFileWriter>,
149+
}
150+
151+
impl RollingFile {
152+
fn new(writer: NonBlocking<RollingFileWriter>, layout: Box<dyn Layout>) -> Self {
153+
Self { layout, writer }
154+
}
47155
}
48156

49157
impl Append for RollingFile {

src/append/rolling_file/mod.rs

Lines changed: 6 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -19,41 +19,29 @@
1919
//!```
2020
//! use logforth::append::rolling_file;
2121
//! use logforth::append::rolling_file::RollingFile;
22-
//! use logforth::append::rolling_file::RollingFileWriter;
22+
//! use logforth::append::rolling_file::RollingFileBuilder;
2323
//! use logforth::append::rolling_file::Rotation;
2424
//! use logforth::layout::JsonLayout;
2525
//!
26-
//! let rolling_writer = RollingFileWriter::builder()
26+
//! let (rolling_writer, _guard) = RollingFileBuilder::new("logs")
27+
//! .layout(JsonLayout::default())
2728
//! .rotation(Rotation::Daily)
2829
//! .filename_prefix("app_log")
29-
//! .build("logs")
30+
//! .build()
3031
//! .unwrap();
3132
//!
32-
//! let (non_blocking, _guard) = rolling_file::non_blocking(rolling_writer).finish();
33-
//!
3433
//! logforth::builder()
35-
//! .dispatch(|d| {
36-
//! d.filter(log::LevelFilter::Trace)
37-
//! .append(RollingFile::new(non_blocking).with_layout(JsonLayout::default()))
38-
//! })
34+
//! .dispatch(|d| d.filter(log::LevelFilter::Trace).append(rolling_writer))
3935
//! .apply();
4036
//!
4137
//! log::info!("This log will be written to a rolling file.");
4238
//! ```
4339
4440
pub use append::RollingFile;
45-
pub use rolling::RollingFileWriter;
46-
pub use rolling::RollingFileWriterBuilder;
41+
pub use append::RollingFileBuilder;
4742
pub use rotation::Rotation;
4843

49-
use crate::non_blocking::NonBlockingBuilder;
50-
5144
mod append;
5245
mod clock;
5346
mod rolling;
5447
mod rotation;
55-
56-
/// Create a non-blocking builder for rolling file writers.
57-
pub fn non_blocking(writer: RollingFileWriter) -> NonBlockingBuilder<RollingFileWriter> {
58-
NonBlockingBuilder::new("logforth-rolling-file", writer)
59-
}

0 commit comments

Comments
 (0)