/*- * ============LICENSE_START======================================================= * SDC * ================================================================================ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. * ================================================================================ * 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. * ============LICENSE_END========================================================= */ package org.openecomp.core.logging.logback; import ch.qos.logback.classic.Logger; import ch.qos.logback.classic.LoggerContext; import ch.qos.logback.classic.sift.MDCBasedDiscriminator; import ch.qos.logback.classic.spi.ILoggingEvent; import ch.qos.logback.core.Appender; import ch.qos.logback.core.AppenderBase; import ch.qos.logback.core.joran.spi.DefaultClass; import ch.qos.logback.core.sift.Discriminator; import org.slf4j.LoggerFactory; import java.util.Iterator; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; /** *

Allows to use EELF logging configuration almost as is, by using a custom routing function, but * pre-configured appenders attached to the standard EELF loggers.

Changes that must be made * in logback.xml supplied with EELF:

*
 *     <appender name="DISPATCHER" class="DispatchingAppender">
 *          <discriminator class="EventTypeDiscriminator"/>
 *          <appenderNamePattern>asyncEELF%s</appenderNamePattern>
 *     </appender>
 *     <root level="INFO" additivity="false">
 *          <appender-ref ref="DISPATCHER" />
 *      </root>
 * 
*/ public class DispatchingAppender extends AppenderBase { // "magic" appender to indicate a missing appender private static final Appender NO_APPENDER = new DispatchingAppender(); private Map> appenders = new ConcurrentHashMap<>(); private Discriminator discriminator; private String appenderNamePattern; public Discriminator getDiscriminator() { return this.discriminator; } @DefaultClass(MDCBasedDiscriminator.class) public void setDiscriminator(Discriminator discriminator) { this.discriminator = discriminator; } public String getAppenderNamePattern() { return this.appenderNamePattern; } public void setAppenderNamePattern(String pattern) { this.appenderNamePattern = pattern; } @Override protected void append(ILoggingEvent event) { if (this.isStarted()) { String discriminatingValue = this.discriminator.getDiscriminatingValue(event); String appenderName = String.format(this.appenderNamePattern, discriminatingValue); Appender appender = this.lookupAppender(appenderName); if (appender == NO_APPENDER) { this.addError(String.format("Appender %s does not exist", appenderName)); } else { appender.doAppend(event); } } } private Appender lookupAppender(String key) { Appender appender = appenders.get(key); if (appender != null) { return appender; } LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory(); for (Logger log : context.getLoggerList()) { Iterator> iterator = log.iteratorForAppenders(); while (iterator.hasNext()) { Appender element = iterator.next(); if (key.equals(element.getName())) { this.appenders.putIfAbsent(key, element); return element; } } } // to avoid consecutive lookups if the required appender does not exist this.appenders.putIfAbsent(key, NO_APPENDER); return NO_APPENDER; } @Override public void start() { int errors = 0; if (this.discriminator == null) { this.addError("Missing discriminator. Aborting"); } if (!this.discriminator.isStarted()) { this.addError("Discriminator has not started successfully. Aborting"); ++errors; } if (this.appenderNamePattern == null) { this.addError("Missing name pattern. Aborting"); ++errors; } if (errors == 0) { super.start(); } } }