@@ -15,6 +15,9 @@ use log::Log;
1515
1616use crate :: { log_impl, Filter , FormatCallback , Formatter } ;
1717
18+ #[ cfg( feature = "colored" ) ]
19+ use crate :: colors:: ColoredLevelConfig ;
20+
1821#[ cfg( feature = "date-based" ) ]
1922use crate :: log_impl:: DateBasedState ;
2023
@@ -1230,3 +1233,141 @@ impl From<DateBased> for Output {
12301233 } ) ) )
12311234 }
12321235}
1236+
1237+ /// A generic formatter that easily provides good defaults while being configurable
1238+ pub struct FormatterBuilder {
1239+ #[ cfg( feature = "colored" ) ]
1240+ color_config : Option < ColoredLevelConfig > ,
1241+ #[ cfg( feature = "chrono" ) ]
1242+ chrono : bool ,
1243+ level : bool ,
1244+ target : bool ,
1245+ }
1246+
1247+ impl Default for FormatterBuilder {
1248+ fn default ( ) -> Self {
1249+ FormatterBuilder {
1250+ #[ cfg( feature = "colored" ) ]
1251+ color_config : Some ( Default :: default ( ) ) ,
1252+ #[ cfg( feature = "chrono" ) ]
1253+ chrono : true ,
1254+ level : true ,
1255+ target : true ,
1256+ }
1257+ }
1258+ }
1259+
1260+ impl FormatterBuilder {
1261+ pub fn new ( ) -> Self {
1262+ Self :: default ( )
1263+ }
1264+
1265+ pub fn level ( mut self , level : bool ) -> Self {
1266+ self . level = level;
1267+ self
1268+ }
1269+
1270+ pub fn target ( mut self , target : bool ) -> Self {
1271+ self . target = target;
1272+ self
1273+ }
1274+
1275+ #[ cfg( feature = "colored" ) ]
1276+ pub fn color ( mut self , color : bool ) -> Self {
1277+ self . color_config = if color {
1278+ self . color_config . or_else ( Default :: default)
1279+ } else {
1280+ None
1281+ } ;
1282+ self
1283+ }
1284+
1285+ #[ cfg( feature = "colored" ) ]
1286+ pub fn color_config (
1287+ mut self ,
1288+ modify_config : impl FnOnce ( ColoredLevelConfig ) -> ColoredLevelConfig ,
1289+ ) -> Self {
1290+ self . color_config = self . color_config . map ( modify_config) ;
1291+ self
1292+ }
1293+
1294+ #[ cfg( feature = "chrono" ) ]
1295+ pub fn chrono ( mut self , chrono : bool ) -> Self {
1296+ self . chrono = chrono;
1297+ self
1298+ }
1299+
1300+ #[ rustfmt:: skip]
1301+ pub fn build (
1302+ self ,
1303+ ) -> impl Fn ( FormatCallback < ' _ > , & std:: fmt:: Arguments < ' _ > , & log:: Record < ' _ > ) + Sync + Send + ' static
1304+ {
1305+ move |out, message, record| {
1306+ /* Type checking is hard */
1307+ #[ cfg( not( feature = "chrono" ) ) ]
1308+ type TimeType = String ;
1309+ #[ cfg( feature = "chrono" ) ]
1310+ type TimeType < ' a > = chrono:: format:: DelayedFormat < chrono:: format:: StrftimeItems < ' a > > ;
1311+
1312+ let time: Option < TimeType > = {
1313+ #[ cfg( feature = "chrono" ) ]
1314+ {
1315+ self . chrono
1316+ . then ( || chrono:: Local :: now ( ) . format ( "%Y-%m-%d %H:%M:%S,%3f" ) )
1317+ }
1318+ #[ cfg( not( feature = "chrono" ) ) ]
1319+ {
1320+ None
1321+ }
1322+ } ;
1323+
1324+ /* Type checking is hard */
1325+ #[ cfg( not( feature = "colored" ) ) ]
1326+ type LevelType = log:: Level ;
1327+ #[ cfg( feature = "colored" ) ]
1328+ type LevelType = crate :: colors:: WithFgColor < log:: Level > ;
1329+
1330+ let level: Option < LevelType > = if self . level {
1331+ #[ cfg( feature = "colored" ) ]
1332+ {
1333+ Some (
1334+ self . color_config
1335+ . map ( |config| config. color ( record. level ( ) ) )
1336+ . unwrap_or_else ( || crate :: colors:: WithFgColor {
1337+ text : record. level ( ) ,
1338+ color : None ,
1339+ } ) ,
1340+ )
1341+ }
1342+ #[ cfg( not( feature = "colored" ) ) ]
1343+ {
1344+ Some ( record. level ( ) )
1345+ }
1346+ } else {
1347+ None
1348+ } ;
1349+
1350+ let target = self . target . then ( || {
1351+ if !record. target ( ) . is_empty ( ) {
1352+ record. target ( )
1353+ } else {
1354+ record. module_path ( ) . unwrap_or_default ( )
1355+ }
1356+ } ) ;
1357+
1358+ /* Sadly we cannot store and compose std::fmt::Arguments due to lifetime issues.
1359+ * In order to avoid unnecessary write calls nevertheless, we must enumerate all options
1360+ */
1361+ match ( time, level, target) {
1362+ ( Some ( time) , Some ( level) , Some ( target) ) => out. finish ( format_args ! ( "{} {:<5} [{}] {}" , time, level, target, message) ) ,
1363+ ( Some ( time) , Some ( level) , None ) => out. finish ( format_args ! ( "{} {:<5} {}" , time, level, message) ) ,
1364+ ( Some ( time) , None , Some ( target) ) => out. finish ( format_args ! ( "{} [{}] {}" , time, target, message) ) ,
1365+ ( Some ( time) , None , None ) => out. finish ( format_args ! ( "{} {}" , time, message) ) ,
1366+ ( None , Some ( level) , Some ( target) ) => out. finish ( format_args ! ( "{:<5} [{}] {}" , level, target, message) ) ,
1367+ ( None , None , Some ( target) ) => out. finish ( format_args ! ( "[{}] {}" , target, message) ) ,
1368+ ( None , Some ( level) , None ) => out. finish ( format_args ! ( "{:<5} {}" , level, message) ) ,
1369+ ( None , None , None ) => out. finish ( format_args ! ( "{}" , message) ) ,
1370+ }
1371+ }
1372+ }
1373+ }
0 commit comments