use std::{
convert::Infallible,
fs::File,
io::{BufWriter, Write},
path::{Path, PathBuf},
};
use crate::{
sink::{helper, Sink},
sync::*,
utils, Error, Record, Result, StringBuf,
};
pub struct FileSink {
common_impl: helper::CommonImpl,
file: SpinMutex<BufWriter<File>>,
}
impl FileSink {
#[must_use]
pub fn builder() -> FileSinkBuilder<()> {
FileSinkBuilder {
path: (),
truncate: false,
common_builder_impl: helper::CommonBuilderImpl::new(),
}
}
#[deprecated(
since = "0.3.0",
note = "it may be removed in the future, use `FileSink::builder()` instead"
)]
pub fn new<P>(path: P, truncate: bool) -> Result<FileSink>
where
P: AsRef<Path>,
{
Self::builder()
.path(path.as_ref())
.truncate(truncate)
.build()
}
}
impl Sink for FileSink {
fn log(&self, record: &Record) -> Result<()> {
if !self.should_log(record.level()) {
return Ok(());
}
let mut string_buf = StringBuf::new();
self.common_impl
.formatter
.read()
.format(record, &mut string_buf)?;
self.file
.lock()
.write_all(string_buf.as_bytes())
.map_err(Error::WriteRecord)?;
Ok(())
}
fn flush(&self) -> Result<()> {
self.file.lock().flush().map_err(Error::FlushBuffer)
}
helper::common_impl!(@Sink: common_impl);
}
impl Drop for FileSink {
fn drop(&mut self) {
if let Err(err) = self.file.lock().flush() {
self.common_impl
.non_returnable_error("FileSink", Error::FlushBuffer(err))
}
}
}
#[doc = include_str!("../include/doc/generic-builder-note.md")]
pub struct FileSinkBuilder<ArgPath> {
common_builder_impl: helper::CommonBuilderImpl,
path: ArgPath,
truncate: bool,
}
impl<ArgPath> FileSinkBuilder<ArgPath> {
#[must_use]
pub fn path<P>(self, path: P) -> FileSinkBuilder<PathBuf>
where
P: Into<PathBuf>,
{
FileSinkBuilder {
common_builder_impl: self.common_builder_impl,
path: path.into(),
truncate: self.truncate,
}
}
#[must_use]
pub fn truncate(mut self, truncate: bool) -> Self {
self.truncate = truncate;
self
}
helper::common_impl!(@SinkBuilder: common_builder_impl);
}
impl FileSinkBuilder<()> {
#[doc(hidden)]
#[deprecated(note = "\n\n\
builder compile-time error:\n\
- missing required field `path`\n\n\
")]
pub fn build(self, _: Infallible) {}
}
impl FileSinkBuilder<PathBuf> {
pub fn build(self) -> Result<FileSink> {
let file = utils::open_file(self.path, self.truncate)?;
let sink = FileSink {
common_impl: helper::CommonImpl::from_builder(self.common_builder_impl),
file: SpinMutex::new(BufWriter::new(file)),
};
Ok(sink)
}
}