blob: cae666ebb5dc6774529b37fc5b69e45bfeb1b86b [file] [log] [blame]
/*
* Copyright (c) 2009, 2021 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0,
* or the Eclipse Distribution License v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
// Contributors:
// Jaro Kuruc - Initial API and implementation.
// Tomas Kraus - EclipseLink 2.7 integration.
package org.eclipse.persistence.logging.slf4j;
import java.security.AccessController;
import org.eclipse.persistence.config.PersistenceUnitProperties;
import org.eclipse.persistence.internal.security.PrivilegedAccessHelper;
import org.eclipse.persistence.internal.security.PrivilegedGetSystemProperty;
import org.eclipse.persistence.logging.AbstractSessionLog;
import org.eclipse.persistence.logging.LogCategory;
import org.eclipse.persistence.logging.LogLevel;
import org.eclipse.persistence.logging.SessionLogEntry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* EclipseLink logger bridge over SLF4J.
*/
public class SLF4JLogger extends AbstractSessionLog {
/** Logger callback interface. */
private interface LoggerCall {
void log(final Logger logger, final String msg, final Throwable t);
void log(final Logger logger, final String message);
}
/** {@code TRACE} level log. */
private static final class LogTrace implements LoggerCall {
@Override
public void log(final Logger logger, final String msg, final Throwable t) {
logger.trace(msg, t);
}
@Override
public void log(final Logger logger, final String message) {
logger.trace(message);
}
}
/** {@code DEBUG} level log. */
private static final class LogDebug implements LoggerCall {
@Override
public void log(final Logger logger, final String msg, final Throwable t) {
logger.debug(msg, t);
}
@Override
public void log(final Logger logger, final String message) {
logger.debug(message);
}
}
/** {@code INFO} level log. */
private static final class LogInfo implements LoggerCall {
@Override
public void log(final Logger logger, final String msg, final Throwable t) {
logger.info(msg, t);
}
@Override
public void log(final Logger logger, final String message) {
logger.info(message);
}
}
/** {@code WARN} level log. */
private static final class LogWarn implements LoggerCall {
@Override
public void log(final Logger logger, final String msg, final Throwable t) {
logger.warn(msg, t);
}
@Override
public void log(final Logger logger, final String message) {
logger.warn(message);
}
}
/** {@code ERROR} level log. */
private static final class LogError implements LoggerCall {
@Override
public void log(final Logger logger, final String msg, final Throwable t) {
logger.error(msg, t);
}
@Override
public void log(final Logger logger, final String message) {
logger.error(message);
}
}
/** Do not log anything. */
private static final class LogNop implements LoggerCall {
@Override
public void log(final Logger logger, final String msg, final Throwable t) {
}
@Override
public void log(final Logger logger, final String message) {
}
}
/** The default session name in case there is session name is missing. */
public static final String ECLIPSELINK_NAMESPACE = "org.eclipse.persistence";
/** SLF4J logger calls mapping for EclipseLink logging levels. */
private static final LoggerCall[] loggerCall = new LoggerCall[LogLevel.length];
/** Loggers lookup array. */
private static final Logger[] categoryLoggers = new Logger[LogCategory.length];
static {
// Initialize loggers lookup array.
for (int i = 0; i < LogCategory.length; i++) {
categoryLoggers[i] = null;
}
// Initialize SLF4J logger calls mapping for EclipseLink logging levels.
loggerCall[LogLevel.ALL.getId()] = loggerCall[LogLevel.FINEST.getId()] = new LogTrace();
loggerCall[LogLevel.FINER.getId()] = loggerCall[LogLevel.FINE.getId()] = new LogDebug();
loggerCall[LogLevel.CONFIG.getId()] = loggerCall[LogLevel.INFO.getId()] = new LogInfo();
loggerCall[LogLevel.WARNING.getId()] = new LogWarn();
loggerCall[LogLevel.SEVERE.getId()] = new LogError();
loggerCall[LogLevel.OFF.getId()] = new LogNop();
}
/**
* Retrieve Logger for the given category.
* @param category EclipseLink logging category
* @return Logger for the given logging category.
*/
private static Logger getLogger(final LogCategory category) {
final Logger logger = categoryLoggers[category.getId()];
if (logger != null) {
return logger;
}
return categoryLoggers[category.getId()] = LoggerFactory.getLogger(category.getNameSpace());
}
/** Logging levels for individual logging categories. */
private final LogLevel[] logLevels;
/**
* Creates an instance of EclipseLink logger bridge over SLF4J
*/
public SLF4JLogger() {
super();
// Set default logging levels for all logging categories.
final byte defaultLevel = LogLevel.toValue(level).getId();
logLevels = new LogLevel[LogCategory.length];
for (LogCategory category : LogCategory.values()) {
final int i = category.getId();
switch(category) {
case ALL:
logLevels[i] = LogLevel.toValue(defaultLevel);
break;
default:
final String property = PersistenceUnitProperties.CATEGORY_LOGGING_LEVEL_ + category.getName();
final String logLevelStr = PrivilegedAccessHelper.shouldUsePrivilegedAccess()
? AccessController.doPrivileged(new PrivilegedGetSystemProperty(property))
: System.getProperty(property);
logLevels[i] = LogLevel.toValue(
logLevelStr != null ? translateStringToLoggingLevel(logLevelStr) : defaultLevel);
}
}
}
/**
* Get the logging level for the default logging category.
* @return level Current logging level for default the default logging category.
*/
@Override
public int getLevel() {
return logLevels[LogCategory.ALL.getId()].getId();
}
/**
* Get the logging level for the specified logging category.
* @param categoryName The {@link String} representation of an EclipseLink logging category.
* @return level Current logging level for default the default logging category.
*/
@Override
public int getLevel(final String categoryName) {
final LogCategory category = LogCategory.toValue(categoryName);
if (category == null) {
throw new IllegalArgumentException("Unknown logging category name.");
}
return logLevels[category.getId()].getId();
}
/**
* Set the logging level for the default logging category.
* @param level The logging level to be set.
*/
@Override
public void setLevel(final int level) {
super.setLevel(level);
logLevels[LogCategory.ALL.getId()] = LogLevel.toValue(level);
// TODO: Handle logging levels on SLF4J side too.
}
/**
* Set the logging level for the specified logging category.
* @param level The logging level to be set.
* @param categoryName The {@link String} representation of an EclipseLink logging category.
*/
@Override
public void setLevel(final int level, final String categoryName) {
final LogCategory category = LogCategory.toValue(categoryName);
if (category == null) {
throw new IllegalArgumentException("Unknown logging category name.");
}
logLevels[category.getId()] = LogLevel.toValue(level);
// TODO: Handle logging levels on SLF4J side too.
}
/**
* Check if a message of the given level would actually be logged under logging level for the default logging
* category.
* @param level Message logging level.
* @return Value of {@code true} if the given message logging level will be logged or {@code false} otherwise.
*/
@Override
public boolean shouldLog(final int level) {
return logLevels[LogCategory.ALL.getId()].shouldLog((byte)level);
}
/**
* Check if a message of the given level would actually be logged under logging level for the specified logging
* category.
* @param level Message logging level.
* @param categoryName The {@link String} representation of an EclipseLink logging category.
* @return Value of {@code true} if the given message logging level will be logged or {@code false} otherwise.
*/
@Override
public boolean shouldLog(final int level, final String categoryName) {
final LogCategory category = LogCategory.toValue(categoryName);
if (category == null) {
throw new IllegalArgumentException("Unknown logging category name.");
}
return logLevels[category.getId()].shouldLog((byte)level);
}
@Override
public void log(final SessionLogEntry logEntry) {
if (logEntry == null) {
return;
}
final LogCategory category = LogCategory.toValue(logEntry.getNameSpace());
if (category == null) {
throw new IllegalArgumentException("Unknown logging category name.");
}
final byte levelId = (byte)logEntry.getLevel();
if (logLevels[category.getId()].shouldLog(levelId)) {
final LogLevel level = LogLevel.toValue(levelId);
final Logger logger = getLogger(category);
if (logEntry.hasException()) {
if (shouldLogExceptionStackTrace()) {
// Message is rendered on EclipseLink side. SLF4J gets final String. Exception is passed too.
loggerCall[level.getId()].log(logger, formatMessage(logEntry), logEntry.getException());
} else {
// Exception message is rendered on EclipseLink side. SLF4J gets final String.
loggerCall[level.getId()].log(logger, logEntry.getException().toString());
}
} else {
// Message is rendered on EclipseLink side. SLF4J gets final String.
loggerCall[level.getId()].log(logger, formatMessage(logEntry));
}
}
}
}