Closed norrs closed 2 years ago
It's difficult to give a general answer since there are several possible scenarios with combination of configuration from different sources.
org.logevents.config.DefaultLogEventConfigurator
has several methods that are suitable for overriding. Perhaps the best one is loadPropertiesFromFile():
@Override
protected Map<String, String> loadPropertiesFromFiles(List<String> configurationFileNames) {
Map<String, String> properties = super.loadPropertiesFromFiles(configurationFileNames);
properties.putIfAbsent("observer.file.filename", "logs/%application.log");
properties.putIfAbsent("observer.file.archivedFilename", "logs/%date{yyyy-MM}/%application-%date.log");
properties.putIfAbsent("logevents.jmx", "true");
properties.putIfAbsent("logevents.installExceptionHandler", "true");
properties.putIfAbsent("observer.*.packageFilter", getPackageFilter());
return properties;
}
This is pretty similar to what you're doing. But you seem to have some other configuration system that you get properties from as well, so it will depend a lot on what you want to do with this.
There's also a method org.logevents.config.DefaultLogEventConfigurator#installDefaultObservers which can be useful. With this, you can install things like the WebLogEventObserver and then use more flexible configuration to decide whether it should be used.
I've also added support for specifying root.observer.servlet=DEBUG
(for example) instead of joining together as you do with logConfig.put("root", "INFO ${observers.joinToString()}")
Thinking a bit more, I think I would recommend:
observer.humio.cooldown
and observer.slack.marker.WORKER.throttle
in a logevents.properties
file in your classpathlogevents.properties
file in your working directory or in environment variables. This is things like root.observer.slack=WARN
(LOGEVENTS_ROOT_OBSERVER_SLACK=WARN
)installDefaultObservers
to get the rest.Alternatively, you can just access LogEventFactory.getInstance()
in your main method (or wherever) and do LogEventFactory.getInstance().addRootObserver(new LevelThresholdObserver(WARN, new SlackLogEventObserver(config.slackUrl)))
. (Please not that the logging threshold on a specific logger will override the threshold of an observer, so you may want to do LogEventFactory.getInstance().setRootLevel(Level.DEBUG)
, for example)
Next answer....
public class CustomConfigurator extends DefaultLogEventConfigurator {
private Config config = Config.getInstance();
@Override
protected void configureRootLogger(LogEventFactory factory, Map<String, String> properties, Map<String, String> environment) {
super.configureRootLogger(factory, properties, environment);
getSlackObserver(properties).ifPresent(factory::addRootObserver);
}
private Optional<LogEventObserver> getSlackObserver(Map<String, String> configuration) {
if (config.isSlackDisabled()) {
return Optional.empty();
}
configuration.put("observer.slack.slackUrl", config.getSlackUrl());
SlackLogEventObserver observer = new SlackLogEventObserver(configuration, "observer.slack");
observer.setThreshold(Level.WARN);
return Optional.of(observer);
}
}
configureGlobalObserversFromProperties
instead of configure
(you could also override installDefaultObservers
if you want logevents.properties to add them to specific categories or applyConfigurationProperties
if you want to do other things with the LogEventFactory, or even configureGlobalObserversFromProperties
)As mentioned before, you can also get the LogEventFactory.getInstance directly if you don't want to use Config as a singleton.
I've adjusted the implementation of DefaultLogEventConfigurator and added some more documentation in the JavaDoc of LogEventConfigurator: https://jhannes.github.io/logevents/apidocs/org/logevents/LogEventConfigurator.html
I wonder what is the best way to combine configuration from both properties files and code. Currently we configure standard stuff by
logevents.properties
andlogevents-<profile>.properties
which is bundled with the application. However, fetching of secrets is done via another system, soSlackObserver
etc needs to be added by code.I didn't find the "right way" to ensure both sources of configuration was loaded before any logging were done.
This is my current approach which I'm not very proud of (in Kotlin):
Register my own class which subclasses the
DefaultLogEventConfigurator
as suggested by the documentation and loaded viaService Loader
(META-INF/services/org.logevents.LogEventConfigurator
file containingfullyqualified.ApplicationLogEventsConfigurator
):Something tells me there is a nicer way to do this?