mirror of
https://github.com/NLnetLabs/dnst.git
synced 2026-10-01 14:15:07 +02:00
add log module and warning/error printing macros
This commit is contained in:
+5
-10
@@ -13,6 +13,7 @@ use lexopt::Arg;
|
||||
|
||||
use crate::env::Env;
|
||||
use crate::error::Error;
|
||||
use crate::log::warning;
|
||||
use crate::parse::TSigInfo;
|
||||
use crate::Args;
|
||||
|
||||
@@ -223,24 +224,18 @@ impl Notify {
|
||||
}
|
||||
|
||||
let Ok(name) = Name::<Vec<u8>>::from_str(server) else {
|
||||
writeln!(
|
||||
env.stderr(),
|
||||
"warning: invalid domain name \"{server}\", skipping."
|
||||
);
|
||||
warning!(env, "invalid domain name \"{server}\", skipping.");
|
||||
continue;
|
||||
};
|
||||
|
||||
let Ok(hosts) = resolver.lookup_host(&name).await else {
|
||||
writeln!(
|
||||
env.stderr(),
|
||||
"warning: could not resolve host \"{name}\", skipping."
|
||||
);
|
||||
warning!(env, "could not resolve host \"{name}\", skipping.");
|
||||
continue;
|
||||
};
|
||||
|
||||
if hosts.is_empty() {
|
||||
writeln!(
|
||||
env.stderr(),
|
||||
warning!(
|
||||
env,
|
||||
"skipping bad address: {name}: Name or service not known"
|
||||
);
|
||||
continue;
|
||||
|
||||
Vendored
+8
-2
@@ -61,11 +61,17 @@ impl Env for FakeEnv {
|
||||
}
|
||||
|
||||
fn stdout(&self) -> Stream<impl fmt::Write> {
|
||||
Stream(self.stdout.clone())
|
||||
Stream {
|
||||
writer: self.stdout.clone(),
|
||||
is_terminal: false,
|
||||
}
|
||||
}
|
||||
|
||||
fn stderr(&self) -> Stream<impl fmt::Write> {
|
||||
Stream(self.stderr.clone())
|
||||
Stream {
|
||||
writer: self.stderr.clone(),
|
||||
is_terminal: false,
|
||||
}
|
||||
}
|
||||
|
||||
fn in_cwd<'a>(&self, path: &'a impl AsRef<Path>) -> Cow<'a, Path> {
|
||||
|
||||
Vendored
+9
-2
@@ -59,7 +59,10 @@ pub trait Env {
|
||||
/// [`std::io::Write`]. Additionally, this `write_fmt` does not return a
|
||||
/// result. This means that we can use the [`write!`] and [`writeln`] macros
|
||||
/// without handling errors.
|
||||
pub struct Stream<T: fmt::Write>(T);
|
||||
pub struct Stream<T: fmt::Write> {
|
||||
writer: T,
|
||||
is_terminal: bool,
|
||||
}
|
||||
|
||||
impl<T: fmt::Write> Stream<T> {
|
||||
pub fn write_fmt(&mut self, args: fmt::Arguments<'_>) {
|
||||
@@ -68,7 +71,11 @@ impl<T: fmt::Write> Stream<T> {
|
||||
// fake stream also does not return an error. If this fails, it means
|
||||
// we can't write to stdout anymore so a graceful exit will be very
|
||||
// hard anyway.
|
||||
self.0.write_fmt(args).unwrap();
|
||||
self.writer.write_fmt(args).unwrap();
|
||||
}
|
||||
|
||||
pub fn is_terminal(&self) -> bool {
|
||||
self.is_terminal
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Vendored
+11
-3
@@ -1,6 +1,6 @@
|
||||
use std::ffi::OsString;
|
||||
use std::fmt;
|
||||
use std::io;
|
||||
use std::io::{self, IsTerminal};
|
||||
use std::path::Path;
|
||||
|
||||
use domain::net::client::protocol::{AsyncConnect, AsyncDgramRecv, AsyncDgramSend, UdpConnect};
|
||||
@@ -19,11 +19,19 @@ impl Env for RealEnv {
|
||||
}
|
||||
|
||||
fn stdout(&self) -> Stream<impl fmt::Write> {
|
||||
Stream(FmtWriter(io::stdout()))
|
||||
let stdout = io::stdout();
|
||||
Stream {
|
||||
is_terminal: stdout.is_terminal(),
|
||||
writer: FmtWriter(io::stdout()),
|
||||
}
|
||||
}
|
||||
|
||||
fn stderr(&self) -> Stream<impl fmt::Write> {
|
||||
Stream(FmtWriter(io::stderr()))
|
||||
let stderr = io::stderr();
|
||||
Stream {
|
||||
is_terminal: stderr.is_terminal(),
|
||||
writer: FmtWriter(io::stdout()),
|
||||
}
|
||||
}
|
||||
|
||||
fn in_cwd<'a>(&self, path: &'a impl AsRef<Path>) -> std::borrow::Cow<'a, std::path::Path> {
|
||||
|
||||
+4
-14
@@ -4,6 +4,7 @@ use std::{error, io};
|
||||
use domain::base::wire::ParseError;
|
||||
|
||||
use crate::env::Env;
|
||||
use crate::log::error;
|
||||
|
||||
//------------ Error ---------------------------------------------------------
|
||||
|
||||
@@ -57,33 +58,22 @@ impl Error {
|
||||
|
||||
/// Pretty-print this error.
|
||||
pub fn pretty_print(&self, env: impl Env) {
|
||||
use std::io::IsTerminal;
|
||||
let mut err = env.stderr();
|
||||
|
||||
let error = match &self.0.primary {
|
||||
let msg = match &self.0.primary {
|
||||
// Clap errors are already styled. We don't want our own pretty
|
||||
// styling around that and context does not make sense for command
|
||||
// line arguments either. So we just print the styled string that
|
||||
// clap produces and return.
|
||||
PrimaryError::Clap(e) => {
|
||||
let mut err = env.stderr();
|
||||
writeln!(err, "{}", e.render().ansi());
|
||||
return;
|
||||
}
|
||||
PrimaryError::Other(error) => error,
|
||||
};
|
||||
|
||||
// NOTE: This is a multicall binary, so argv[0] is necessary for
|
||||
// program operation. We would fail very early if it didn't exist.
|
||||
let prog = std::env::args().next().unwrap();
|
||||
let term = std::io::stderr().is_terminal();
|
||||
|
||||
let error_marker = if term {
|
||||
"\x1B[31mERROR:\x1B[0m"
|
||||
} else {
|
||||
"ERROR:"
|
||||
};
|
||||
|
||||
writeln!(err, "[{prog}] {error_marker} {error}");
|
||||
error!(env, "{msg}");
|
||||
for context in &self.0.context {
|
||||
writeln!(err, "... while {context}");
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ pub mod args;
|
||||
pub mod commands;
|
||||
pub mod env;
|
||||
pub mod error;
|
||||
pub mod log;
|
||||
pub mod parse;
|
||||
pub mod util;
|
||||
|
||||
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
use std::fmt::Display;
|
||||
|
||||
use crate::env::Env;
|
||||
|
||||
mod color {
|
||||
pub const BLUE: u8 = 34;
|
||||
pub const YELLOW: u8 = 33;
|
||||
pub const RED: u8 = 31;
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub enum LogLevel {
|
||||
Info,
|
||||
Warning,
|
||||
Error,
|
||||
}
|
||||
|
||||
impl LogLevel {
|
||||
fn color(self) -> u8 {
|
||||
match self {
|
||||
Self::Info => color::BLUE,
|
||||
Self::Warning => color::YELLOW,
|
||||
Self::Error => color::RED,
|
||||
}
|
||||
}
|
||||
|
||||
fn text(self) -> &'static str {
|
||||
match self {
|
||||
LogLevel::Info => "INFO",
|
||||
LogLevel::Warning => "WARNING",
|
||||
LogLevel::Error => "ERROR",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for LogLevel {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_str(self.text())
|
||||
}
|
||||
}
|
||||
|
||||
struct Logger(&'static Env);
|
||||
|
||||
pub fn log(env: impl Env, level: LogLevel, text: impl Display) {
|
||||
let mut err = env.stderr();
|
||||
let prog = std::env::args().next().unwrap();
|
||||
|
||||
if err.is_terminal() {
|
||||
let color = level.color();
|
||||
writeln!(err, "[{prog}] \x1B[{color}m{level}\x1B[0m: {text}");
|
||||
} else {
|
||||
writeln!(err, "[{prog}] {level}: {text}");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user