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