blob: 2ab960bcbd693bbcc8c4718b5676063cd83b2259 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.apache.sling.commons.log.logback.internal;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.Appender;
import ch.qos.logback.core.filter.Filter;
import ch.qos.logback.core.util.ContextUtil;
import org.apache.sling.commons.log.logback.internal.util.Util;
import org.osgi.framework.BundleContext;
import org.osgi.framework.FrameworkUtil;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.ServiceReference;
import org.osgi.util.tracker.ServiceTracker;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
public class FilterTracker extends ServiceTracker implements LogbackResetListener{
private static final String ALL_APPENDERS = "*";
private static final String PROP_APPENDER = "appenders";
private final LoggerContext loggerContext;
private final ContextUtil contextUtil;
private final LogbackManager logbackManager;
private Map<ServiceReference, FilterInfo> filters = new ConcurrentHashMap<ServiceReference, FilterInfo>();
public FilterTracker(BundleContext context, LogbackManager logbackManager) throws InvalidSyntaxException {
super(context, createFilter(), null);
this.logbackManager = logbackManager;
this.loggerContext = logbackManager.getLoggerContext();
this.contextUtil = new ContextUtil(loggerContext);
super.open();
}
@SuppressWarnings("unchecked")
@Override
public Object addingService(ServiceReference reference) {
Filter<ILoggingEvent> f = (Filter<ILoggingEvent>) super.addingService(reference);
f.setContext(loggerContext);
f.start();
FilterInfo fi = new FilterInfo(reference, f);
filters.put(reference, fi);
attachFilter(fi, getAppenderMap());
return f;
}
@SuppressWarnings("unchecked")
@Override
public void modifiedService(ServiceReference reference, Object service) {
FilterInfo fi = filters.remove(reference);
detachFilter(fi, getAppenderMap());
filters.put(reference, new FilterInfo(reference, (Filter<ILoggingEvent>) service));
attachFilter(fi, getAppenderMap());
}
@Override
public void removedService(ServiceReference reference, Object service) {
FilterInfo fi = filters.remove(reference);
fi.stop();
detachFilter(fi, getAppenderMap());
super.removedService(reference, service);
}
@Override
public synchronized void close() {
super.close();
filters.clear();
}
//~-----------------------------------LogbackResetListener
@Override
public void onResetStart(LoggerContext context) {
}
@Override
public void onResetComplete(LoggerContext context) {
//The filters are attached at end when all appenders have been instantiated
Map<String,Appender<ILoggingEvent>> appenderMap = getAppenderMap();
for(FilterInfo fi : filters.values()){
attachFilter(fi,appenderMap);
}
}
//~-----------------------------------Internal Methods
private void attachFilter(FilterInfo fi, Map<String, Appender<ILoggingEvent>> appenderMap) {
if (fi.registerAgainstAllAppenders){
for (Appender<ILoggingEvent> appender : appenderMap.values()){
attachFilter(appender, fi);
}
return;
}
for (String appenderName : fi.appenderNames) {
Appender<ILoggingEvent> appender = appenderMap.get(appenderName);
if (appender != null) {
attachFilter(appender, fi);
} else {
contextUtil.addWarn("No appender with name [" + appenderName + "] found " +
"to which " + fi.filter + " can be attached");
}
}
}
private void detachFilter(FilterInfo fi, Map<String, Appender<ILoggingEvent>> appenderMap) {
if (fi.registerAgainstAllAppenders){
for (Appender<ILoggingEvent> appender : appenderMap.values()){
detachFilter(appender, fi);
}
return;
}
for (String appenderName : fi.appenderNames) {
Appender<ILoggingEvent> appender = appenderMap.get(appenderName);
if (appender != null) {
detachFilter(appender, fi);
}
}
}
private void attachFilter(Appender<ILoggingEvent> appender, FilterInfo fi){
//TOCHECK Should we add based on some ranking
if(!appender.getCopyOfAttachedFiltersList().contains(fi.filter)){
appender.addFilter(fi.filter);
}
}
private void detachFilter(Appender<ILoggingEvent> appender, FilterInfo fi){
//No method to directly remove filter. So clone -> remove -> add
if(appender.getCopyOfAttachedFiltersList().contains(fi.filter)){
//Clone
List<Filter<ILoggingEvent>> filters = appender.getCopyOfAttachedFiltersList();
//Clear
appender.clearAllFilters();
//Add
for(Filter<ILoggingEvent> filter : filters){
if(!fi.filter.equals(filter)){
appender.addFilter(filter);
}
}
}
}
private Map<String,Appender<ILoggingEvent>> getAppenderMap() {
return logbackManager.determineLoggerState().getAppenderMap();
}
private static org.osgi.framework.Filter createFilter() throws InvalidSyntaxException {
String filter = String.format("(&(objectClass=%s)(%s=*))", Filter.class.getName(), PROP_APPENDER);
return FrameworkUtil.createFilter(filter);
}
public static class FilterInfo {
final ServiceReference reference;
final Filter<ILoggingEvent> filter;
final Set<String> appenderNames;
final boolean registerAgainstAllAppenders;
FilterInfo(ServiceReference reference, Filter<ILoggingEvent> filter) {
this.reference = reference;
this.filter = filter;
this.appenderNames = Collections.unmodifiableSet(
new HashSet<String>(Util.toList(reference.getProperty(PROP_APPENDER))));
this.registerAgainstAllAppenders = appenderNames.contains(ALL_APPENDERS);
}
public void stop(){
if(filter.isStarted()){
filter.stop();
}
}
}
}