/*
* Copyright (c) 2009-present the original author or authors.
*
* 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 com.planet57.gshell.logging.logback;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.stream.Collectors;
import javax.inject.Named;
import javax.inject.Singleton;
import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.LoggerContext;
import com.google.common.collect.ImmutableList;
import com.planet57.gshell.logging.LevelComponent;
import com.planet57.gshell.logging.LoggerComponent;
import com.planet57.gshell.logging.LoggingComponent;
import com.planet57.gshell.logging.LoggingComponentSupport;
import com.planet57.gshell.logging.LoggingSystem;
import org.slf4j.LoggerFactory;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static org.slf4j.Logger.ROOT_LOGGER_NAME;
/**
* <a href="http://logback.qos.ch/">LOGBack</a> {@link LoggingSystem} component.
*
* @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
* @since 2.6.4
*/
@Named
@Singleton
public class LogbackLoggingSystem
implements LoggingSystem
{
private static final List<Level> ALL_LEVELS = ImmutableList.of(
Level.ALL,
Level.TRACE,
Level.DEBUG,
Level.INFO,
Level.WARN,
Level.ERROR,
Level.OFF
);
private final LoggerContext loggerContext;
private final Map<String, LevelComponentImpl> levels;
public LogbackLoggingSystem() {
// Make sure Logback is actually configured, attach to the context
Object tmp = LoggerFactory.getILoggerFactory();
checkState(tmp instanceof LoggerContext, "SLF4J logger factory does not appear to be LOGBack; found: %s", tmp.getClass().getName());
this.loggerContext = (LoggerContext) tmp;
// generate logger level mapping
this.levels = ALL_LEVELS.stream().collect(Collectors.toMap(level -> level.toString().toUpperCase(Locale.US), LevelComponentImpl::new));
}
//
// LevelComponentImpl
//
private class LevelComponentImpl
implements LevelComponent
{
private final Level target;
private LevelComponentImpl(final Level level) {
this.target = checkNotNull(level);
}
@Override
public String getName() {
return target.toString();
}
public Level getTarget() {
return target;
}
@Override
public int hashCode() {
return getName().hashCode();
}
@Override
public String toString() {
return getName();
}
}
@Override
public LevelComponent getLevel(final String name) {
checkNotNull(name);
LevelComponent level = levels.get(name.toUpperCase(Locale.US));
checkArgument(level != null, "Invalid level name: %s", name);
return level;
}
private LevelComponentImpl levelFor(final String name) {
return (LevelComponentImpl) getLevel(name);
}
@Override
public Collection<? extends LevelComponent> getLevels() {
return levels.values();
}
//
// LoggerComponentImpl
//
private class LoggerComponentImpl
implements LoggerComponent
{
private final Logger target;
public LoggerComponentImpl(final Logger logger) {
this.target = checkNotNull(logger);
}
@Override
public String getName() {
return target.getName();
}
@Override
public LevelComponent getLevel() {
Level tmp = target.getLevel();
if (tmp != null) {
return levelFor(tmp.toString());
}
return null;
}
@Override
public void setLevel(final LevelComponent level) {
target.setLevel(levelFor(level.getName()).getTarget());
}
@Override
public void setLevel(final String level) {
setLevel(levelFor(level));
}
@Override
public boolean isRoot() {
return getName().equals(ROOT_LOGGER_NAME);
}
@Override
public int hashCode() {
return getName().hashCode();
}
@Override
public String toString() {
return getName();
}
}
@Override
public Collection<String> getLoggerNames() {
return loggerContext.getLoggerList().stream().map(Logger::getName).collect(Collectors.toList());
}
@Override
public LoggerComponent getLogger(final String name) {
checkNotNull(name);
return new LoggerComponentImpl(loggerContext.getLogger(name));
}
@Override
public Collection<? extends LoggingComponent> getComponents() {
List<LoggingComponent> components = new ArrayList<>();
LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();
components.add(new LoggingComponentSupport(context));
// add all context-listeners
context.getCopyOfListenerList().forEach(listener -> components.add(new LoggingComponentSupport(listener)));
// add all turbo-filters
context.getTurboFilterList().forEach(filter -> components.add(new LoggingComponentSupport(filter)));
// add all root appenders
Logger root = context.getLogger(ROOT_LOGGER_NAME);
root.iteratorForAppenders().forEachRemaining(appender -> components.add(new LoggingComponentSupport(appender)));
return components;
}
}