
org.ogema.impl.logging.DefaultLoggerFactory Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of ogema-logger Show documentation
Show all versions of ogema-logger Show documentation
Reference implementation of the OGEMA 2.0 logger by Fraunhofer Society.
The newest version!
/**
* Copyright 2011-2018 Fraunhofer-Gesellschaft zur Förderung der angewandten Wissenschaften e.V.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.ogema.impl.logging;
import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.PatternLayout;
import ch.qos.logback.classic.joran.JoranConfigurator;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.Appender;
import ch.qos.logback.core.ConsoleAppender;
import ch.qos.logback.core.helpers.NOPAppender;
import ch.qos.logback.core.joran.spi.JoranException;
import ch.qos.logback.core.rolling.RollingFileAppender;
import ch.qos.logback.core.rolling.RollingPolicy;
import ch.qos.logback.core.util.FileSize;
import ch.qos.logback.core.util.StatusPrinter;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.security.AccessController;
import java.security.Permission;
import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.LoggingPermission;
import org.ogema.core.administration.AdminLogger;
import org.ogema.core.logging.LoggerFactory;
import org.ogema.core.logging.OgemaLogger;
/**
* Logger factory of the OGEMA reference implementation. Creates {@link OgemaLogger}s.
*
* @author jlapp
*/
// TODO SocketAppender should be closed explicitly (maybe also others?) - https://logback.qos.ch/manual/appenders.html
public enum DefaultLoggerFactory implements LoggerFactory {
// this singleton class is implemented as an enum.
INSTANCE;
public static final String DEFAULTLOGGERNAME = "StdLog";
static final long CACHE_SIZE_LIMIT = FileSize.valueOf("100MB").getSize();
static final long TOTAL_FILESIZE_LIMIT = FileSize.valueOf("2GB").getSize();
static final long TOTAL_FILESIZE_MINIMUM = 0;
// cache settings
protected String dumpfile = "temp/cache_%d.log"; // default: use with
// String.format(dumpfile,System.currentTimeMillis())
final protected Map loggersByName = new HashMap<>();
final protected Appender fileOutput;
final protected Appender cacheOutput;
final protected Appender consoleOutput;
final protected List> addOnAppenders;
final protected LoggerContext context;
public static DefaultLoggerFactory getLoggerFactory() {
return INSTANCE;
}
@SuppressWarnings({ "unchecked", "rawtypes", "UseOfSystemOutOrSystemErr" })
private DefaultLoggerFactory() {
final StringBuilder configMessage = new StringBuilder();
configMessage.append("logging configured with logback defaults");
context = new LoggerContext();
AccessController.doPrivileged(new PrivilegedAction() {
@Override
public Void run() {
final URL defaultConfig = getClass().getResource("/logback.xml");
final String userConfig = System.getProperty("logback.configurationFile", "config/logback.xml");
final boolean configFileExists = new File(userConfig).exists();
// read configuration from file or, if file doesn't exist, from bundle default configuration.
try {
if (configFileExists) {
JoranConfigurator configurator = new JoranConfigurator();
configurator.setContext(context);
context.reset();
configurator.doConfigure(userConfig);
configMessage.append("logging configured from file ").append(userConfig);
}
else {
if (defaultConfig != null) {
JoranConfigurator configurator = new JoranConfigurator();
configurator.setContext(context);
context.reset();
configurator.doConfigure(defaultConfig);
configMessage.append("logging configured from OGEMA reference implementation bundle");
}
else {
// work on logback default config, setup fallback appenders below
}
}
} catch (JoranException je) {
// StatusPrinter will handle this
} finally {
StatusPrinter.printInCaseOfErrorsOrWarnings(context);
}
return null;
}
});
final Logger root = context.getLogger("ROOT");
final StringBuilder error = new StringBuilder();
String additionalAppenders = AccessController.doPrivileged(new PrivilegedAction() {
@Override
public String run() {
return System.getProperty("org.ogema.logging.appenders");
}
});
final List> addOnAppenders =new ArrayList<>();
if (additionalAppenders != null) {
for (String appender: additionalAppenders.split(",")) {
appender = appender.trim().toUpperCase();
if (appender.isEmpty()) {
System.err.println("Invalid appender: empty");
continue;
}
Appender appenderObj = root.getAppender(appender);
if (appenderObj == null) {
System.err.println("Specified logger appender " + appender +" does not exist -> this will likely lead to wrong configurations");
continue;
}
root.detachAppender(appenderObj);
addOnAppenders.add(appenderObj);
}
}
this.addOnAppenders = (!addOnAppenders.isEmpty() ? Collections.unmodifiableList(addOnAppenders) : null);
consoleOutput = AccessController.doPrivileged(new PrivilegedAction>() {
@Override
public Appender run() {
final Appender consoleOutput;
if (root.getAppender("CONSOLE") != null) {
consoleOutput = root.getAppender("CONSOLE");
root.detachAppender(consoleOutput);
}
else {
ConsoleAppender app = new ConsoleAppender<>();
PatternLayout pl = new PatternLayout();
pl.setPattern("%d{HH:mm:ss.SSS} %logger{36} [%thread] %-5level - %msg%n");
pl.setContext(context);
pl.start();
app.setName("CONSOLE");
app.setLayout(pl);
app.setContext(context);
app.start();
root.addAppender(app);
consoleOutput = app;
error.append("ERROR: broken logging configuration: CONSOLE appender not found\n");
}
return consoleOutput;
}
});
fileOutput = AccessController.doPrivileged(new PrivilegedAction>() {
@Override
public Appender run() {
final Appender fileOutput;
if (root.getAppender("FILE") != null) {
fileOutput = root.getAppender("FILE");
root.detachAppender(fileOutput);
}
else {
fileOutput = new NOPAppender<>();
fileOutput.setName("FILE");
fileOutput.setContext(context);
fileOutput.start();
root.addAppender(fileOutput);
error.append("ERROR: broken logging configuration: FILE appender not found\n");
}
return fileOutput;
}
});
cacheOutput = AccessController.doPrivileged(new PrivilegedAction>() {
@Override
public Appender run() {
final Appender cacheOutput;
if (root.getAppender("CACHE") != null) {
cacheOutput = root.getAppender("CACHE");
root.detachAppender(cacheOutput);
}
else {
cacheOutput = new NOPAppender<>();
cacheOutput.setName("CACHE");
cacheOutput.setContext(context);
cacheOutput.start();
root.addAppender(cacheOutput);
error.append("ERROR: broken logging configuration: CACHE appender not found\n");
}
return cacheOutput;
}
});
final String errorStr = error.toString();
if (!errorStr.isEmpty()) {
context.getLogger(DEFAULTLOGGERNAME).error(errorStr);
System.err.println(error);
}
context.getLogger(DEFAULTLOGGERNAME).info(configMessage.toString());
}
public List getAdminLoggers() {
checkLoggingControlPermission();
synchronized (loggersByName) {
List rval = new ArrayList<>(loggersByName.size());
for (DefaultLogger l : loggersByName.values()) {
rval.add(new DefaultAdminLogger(l));
}
return rval;
}
}
static void checkLoggingControlPermission(){
if (System.getSecurityManager() != null){
Permission loggingControlPermission = new LoggingPermission("control", null);
System.getSecurityManager().checkPermission(loggingControlPermission);
}
}
/**
* Directory containing log files, or null if file output does not work because of misconfiguration.
* @return the log file directory
*/
public File getFilePath() {
if (fileOutput instanceof RollingFileAppender) {
RollingFileAppender> rfa = (RollingFileAppender) fileOutput;
String activeFileName = rfa.getRollingPolicy().getActiveFileName();
File activeFile = new File(activeFileName);
return activeFile.getParentFile();
}
else {
return null;
}
}
/**
* Dump cache to file.
*/
synchronized void saveCache() throws IOException {
if (cacheOutput instanceof CacheAppender) {
((CacheAppender) cacheOutput).saveCache();
}
else {
// running with a broken config - do nothing
}
}
/**
* Dump cache to file.
*/
@SuppressWarnings("unchecked")
synchronized List getCache(){
if (cacheOutput instanceof CacheAppender) {
return CacheAppender.class.cast(cacheOutput).getCache();
}
else {
return Collections.emptyList();
}
}
protected void setCacheSize(long size) {
checkLoggingControlPermission();
if (size < 0 || size > CACHE_SIZE_LIMIT){
return;
}
if (cacheOutput instanceof CacheAppender) {
CacheAppender.class.cast(cacheOutput).setSize(Long.toString(size));
}
else {
// running with a broken config - do nothing
}
}
/**
* Maximum size of the log message cache, may be {@code -1} if the cache if unavailable due to misconfiguration.
* @return cache size in bytes
*/
public long getCacheSize() {
if (cacheOutput instanceof CacheAppender) {
return ((CacheAppender) cacheOutput).getSizeLong();
}
else {
return -1;
}
}
protected void setLogfileSize(long size) {
checkLoggingControlPermission();
if (size <= TOTAL_FILESIZE_MINIMUM || size > TOTAL_FILESIZE_LIMIT) {
return;
}
if (fileOutput instanceof RollingFileAppender) {
RollingFileAppender> rfa = (RollingFileAppender) fileOutput;
RollingPolicy rp = rfa.getRollingPolicy();
if (rp instanceof HousekeepingPolicy) {
((HousekeepingPolicy) rp).setMaxTotalSizeLong(size);
}
}
else {
// running with a broken config - do nothing
}
}
/**
* Maximum size of all log files, may be {@code -1} if file output if unavailable due to misconfiguration.
* @return maximum total log file size
*/
public long getLogfileSize() {
if (fileOutput instanceof RollingFileAppender) {
RollingFileAppender> rfa = (RollingFileAppender) fileOutput;
RollingPolicy rp = rfa.getRollingPolicy();
if (rp instanceof HousekeepingPolicy) {
return ((HousekeepingPolicy) rp).getMaxTotalSizeLong();
}
}
return -1;
}
@Override
public OgemaLogger getLogger(Class> clazz) {
if (clazz == null) {
return getLogger(DEFAULTLOGGERNAME);
}
else {
return getLogger(clazz.getName());
}
}
@Override
@SuppressWarnings("UseOfSystemOutOrSystemErr")
public OgemaLogger getLogger(String name) {
if (name == null || name.isEmpty()) {
name = DEFAULTLOGGERNAME;
}
if (name.equalsIgnoreCase("ROOT")) {
/*
* ensures that we only return the logback root logger once. strange logback behaviour: logger names are
* usually case sensitive, except "root"
*/
name = "ROOT";
}
DefaultLogger logger = loggersByName.get(name);
if (logger == null) {
Logger logbackLogger = context.getLogger(name);
logger = new DefaultLogger(INSTANCE, logbackLogger);
synchronized (loggersByName) {
loggersByName.put(name, logger);
if (!name.equals(logger.getName())) {
System.err.printf("warning: logback logger name (%s) does not match requested name (%s)%n",
logger.getName(), name);
}
}
}
return logger;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy