| /* |
| * 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(); |
| } |
| } |
| } |
| } |