33import io .avaje .simplelogger .LoggerContext ;
44import org .slf4j .helpers .Reporter ;
55
6- import java .io .IOException ;
7- import java .io .InputStream ;
8- import java .io .PrintStream ;
6+ import java .io .*;
97import java .time .format .DateTimeFormatter ;
108import java .util .*;
119
1412 */
1513public final class Bootstrap {
1614
15+ private static final int LOG_LEVEL_PREFIX_LENGTH = "log.level." .length ();
16+
1717 public static LoggerContext init () {
1818 Properties properties = loadProperties ();
1919 LogWriter logWriter = createWriter (properties , logFormat (properties ));
2020
21- String info = properties .getProperty ("logger.defaultLogLevel" , "info" );
22- int defaultLevel = SimpleLoggerFactory .stringToLevel (info );
21+ String defaultLogLevel = properties .getProperty ("logger.defaultLogLevel" , "info" );
22+ int defaultLevel = SimpleLoggerFactory .stringToLevel (defaultLogLevel );
2323
2424 String nameLength = properties .getProperty ("logger.nameTargetLength" , "full" );
2525 Abbreviator abbreviator = Abbreviator .create (nameLength );
@@ -38,7 +38,7 @@ private static Map<String, String> initialNameLevels(Properties properties) {
3838 if (key .startsWith ("log.level." )) {
3939 String val = properties .getProperty (key );
4040 if (val != null ) {
41- nameLevels .put (key .substring (10 ), val );
41+ nameLevels .put (key .substring (LOG_LEVEL_PREFIX_LENGTH ), val );
4242 }
4343 }
4444 }
@@ -73,17 +73,77 @@ private static boolean propertyShowThreadName(Properties properties) {
7373 return Boolean .parseBoolean (Eval .eval (properties .getProperty ("logger.showThreadName" , "true" )));
7474 }
7575
76- private static Properties loadProperties () {
76+ static Properties loadProperties () {
77+ String config = System .getProperty ("logger.config" , System .getenv ("LOGGER_CONFIG" ));
78+ if (config != null && !config .isEmpty ()) {
79+ final var properties = loadExternal (config );
80+ if (isMergeDefaultProperties (properties )) {
81+ // merge with default properties from avaje-logger.properties
82+ for (Map .Entry <Object , Object > entry : defaultProperties ().entrySet ()) {
83+ properties .putIfAbsent (entry .getKey (), entry .getValue ());
84+ }
85+ }
86+ return properties ;
87+ }
88+ return loadTestProperties (defaultProperties ());
89+ }
90+
91+ private static boolean isMergeDefaultProperties (Properties properties ) {
92+ return Optional .ofNullable (System .getProperty ("logger.config.merge" ))
93+ .or (() -> Optional .ofNullable (System .getenv ("LOGGER_CONFIG_MERGE" )))
94+ .or (() -> Optional .ofNullable (properties .getProperty ("logger.config.merge" )))
95+ .orElse ("true" )
96+ .equalsIgnoreCase ("true" );
97+ }
98+
99+ static Properties defaultProperties () {
77100 final var properties = new Properties ();
78- load (properties , "avaje-logger.properties" );
79- load (properties , "avaje-logger-test.properties" );
101+ loadResource (properties , "avaje-logger.properties" );
102+ return properties ;
103+ }
104+
105+ static Properties loadTestProperties (Properties properties ) {
106+ loadResource (properties , "avaje-logger-test.properties" );
80107 return properties ;
81108 }
82109
83- private static void load (Properties properties , String resourceName ) {
110+ static Properties loadExternal (String fileName ) {
111+ final var properties = new Properties ();
112+ if (fileName .startsWith ("~/" )) {
113+ fileName = System .getProperty ("user.home" ) + fileName .substring (1 );
114+ }
115+ if (loadFile (fileName , properties )) {
116+ return properties ;
117+ }
118+ if (!fileName .endsWith (".properties" ) && loadFile (fileName + ".properties" , properties )) {
119+ return properties ;
120+ }
121+ Reporter .error ("External logger config file not found: " + fileName );
122+ return properties ;
123+ }
124+
125+ private static boolean loadFile (String fileName , Properties properties ) {
126+ var file = new File (fileName );
127+ if (!file .exists ()) {
128+ return false ;
129+ } else {
130+ loadFileIntoProperties (file , properties );
131+ return true ;
132+ }
133+ }
134+
135+ private static void loadFileIntoProperties (File file , Properties properties ) {
136+ try (var is = new FileInputStream (file )) {
137+ properties .load (is );
138+ } catch (IOException e ) {
139+ Reporter .error ("Error loading external logger config file: " + file , e );
140+ }
141+ }
142+
143+ private static void loadResource (Properties properties , String resourceName ) {
84144 InputStream is = resource (resourceName );
85145 if (is != null ) {
86- try {
146+ try ( is ) {
87147 properties .load (is );
88148 } catch (IOException e ) {
89149 Reporter .error ("Error loading " + resourceName , e );
0 commit comments