/* * 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.extensions.logback.internal; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import ch.qos.logback.classic.Level; import ch.qos.logback.classic.Logger; import ch.qos.logback.classic.LoggerContext; import ch.qos.logback.classic.spi.ILoggingEvent; import ch.qos.logback.core.Appender; import org.apache.sling.extensions.logback.internal.util.Util; import org.osgi.framework.BundleContext; import org.osgi.framework.Filter; import org.osgi.framework.FrameworkUtil; import org.osgi.framework.InvalidSyntaxException; import org.osgi.framework.ServiceReference; import org.osgi.util.tracker.ServiceTracker; public class AppenderTracker extends ServiceTracker implements LogbackResetListener{ private static final String PROP_LOGGER = "loggers"; private final LoggerContext loggerContext; private final Map<ServiceReference,AppenderInfo> appenders = new ConcurrentHashMap<ServiceReference, AppenderInfo>(); public AppenderTracker(BundleContext context, LoggerContext loggerContext) throws InvalidSyntaxException { super(context, createFilter(), null); this.loggerContext = loggerContext; super.open(); } @SuppressWarnings("unchecked") @Override public Object addingService(ServiceReference reference) { Appender<ILoggingEvent> a = (Appender<ILoggingEvent>) super.addingService(reference); a.setContext(loggerContext); a.start(); AppenderInfo ai = new AppenderInfo(reference,a); appenders.put(reference,ai); attachAppender(ai); return ai; } @SuppressWarnings("unchecked") @Override public void modifiedService(ServiceReference reference, Object service) { AppenderInfo ai = appenders.remove(reference); detachAppender(ai); appenders.put(reference, new AppenderInfo(reference, (Appender<ILoggingEvent>) service)); } @Override public void removedService(ServiceReference reference, Object service) { detachAppender(appenders.remove(reference)); //Probably we should remove the context from appender super.removedService(reference, service); } public Collection<AppenderInfo> getAppenderInfos(){ return appenders.values(); } private void detachAppender(AppenderInfo ai) { if(ai != null){ for(LoggerInfo li : ai.loggers){ Logger logger = loggerContext.getLogger(li.name); //Reset values back to old ones if they match the //ones we modified to if(li.level.equals(logger.getLevel())){ logger.setLevel(li.oldLevel); } if(logger.isAdditive() == li.additive){ logger.setAdditive(li.oldAdditive); } logger.detachAppender(ai.appender); } } } private void attachAppender(AppenderInfo ai) { if (ai == null) { return; } for (LoggerInfo li : ai.loggers) { Logger logger = loggerContext.getLogger(li.name); li.oldLevel = logger.getLevel(); li.oldAdditive = logger.isAdditive(); logger.setLevel(li.level); logger.setAdditive(li.additive); logger.addAppender(ai.appender); } } public void onReset(LoggerContext context) { for(AppenderInfo ai : appenders.values()){ attachAppender(ai); } } @Override public synchronized void close() { appenders.clear(); super.close(); } private static Filter createFilter() throws InvalidSyntaxException { String filter = String.format("(&(objectClass=%s)(%s=*))",Appender.class.getName(),PROP_LOGGER); return FrameworkUtil.createFilter(filter); } static class AppenderInfo { final List<LoggerInfo> loggers; final Appender<ILoggingEvent> appender; final ServiceReference serviceReference; public AppenderInfo(ServiceReference ref,Appender<ILoggingEvent> appender){ this.appender = appender; this.serviceReference = ref; List<LoggerInfo> loggers = new ArrayList<LoggerInfo>(); for(String logger : Util.toList(ref.getProperty(PROP_LOGGER))){ loggers.add(new LoggerInfo(logger)); } this.loggers = loggers; } } private static class LoggerInfo { final Level level; final String name; final boolean additive; Level oldLevel; boolean oldAdditive; public LoggerInfo(String loggerSpec) { String[] parts = loggerSpec.split(":"); Level level = Level.INFO; if(parts.length >= 2){ level = Level.valueOf(safeTrim(parts[1])); } boolean additive = false; if(parts.length >= 3){ additive = Boolean.valueOf(parts[2]); } this.level = level; this.name = safeTrim(parts[0]); this.additive = additive; } } private static String safeTrim(String s){ if(s != null){ return s.trim(); } return null; } }