2 * Copyright © 2016-2017 European Support Limited
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package org.openecomp.sdc.logging.logback;
19 import ch.qos.logback.classic.Logger;
20 import ch.qos.logback.classic.LoggerContext;
21 import ch.qos.logback.classic.sift.MDCBasedDiscriminator;
22 import ch.qos.logback.classic.spi.ILoggingEvent;
23 import ch.qos.logback.core.Appender;
24 import ch.qos.logback.core.AppenderBase;
25 import ch.qos.logback.core.joran.spi.DefaultClass;
26 import ch.qos.logback.core.sift.Discriminator;
27 import java.util.Iterator;
29 import java.util.concurrent.ConcurrentHashMap;
30 import org.slf4j.LoggerFactory;
33 * <p>Allows to use EELF logging configuration almost as is, by using a custom routing function, but pre-configured
34 * appenders attached to the standard EELF loggers.</p>
36 * <p>Changes that must be made in <i>logback.xml</i> supplied with EELF:</p>
39 * <appender name="DISPATCHER" class="org.openecomp.sdc.logging.logback.DispatchingAppender">
40 * <discriminator class="org.openecomp.sdc.logging.logback.EventTypeDiscriminator"/>
41 * <appenderNamePattern>asyncEELF%s</appenderNamePattern>
44 * <root level="INFO" additivity="false">
45 * <appender-ref ref="DISPATCHER" />
52 public class DispatchingAppender extends AppenderBase<ILoggingEvent> {
54 // "magic" appender to indicate a missing appender
55 private static final Appender<ILoggingEvent> NO_APPENDER = new DispatchingAppender();
57 private final Map<String, Appender<ILoggingEvent>> appenders = new ConcurrentHashMap<>();
59 private Discriminator<ILoggingEvent> discriminator;
60 private String appenderNamePattern;
62 @DefaultClass(MDCBasedDiscriminator.class)
63 public void setDiscriminator(Discriminator<ILoggingEvent> discriminator) {
64 this.discriminator = discriminator;
67 public Discriminator<ILoggingEvent> getDiscriminator() {
68 return this.discriminator;
71 public void setAppenderNamePattern(String pattern) {
72 this.appenderNamePattern = pattern;
75 public String getAppenderNamePattern() {
76 return this.appenderNamePattern;
80 protected void append(ILoggingEvent event) {
82 if (this.isStarted()) {
84 String discriminatingValue = this.discriminator.getDiscriminatingValue(event);
85 String appenderName = String.format(this.appenderNamePattern, discriminatingValue);
86 Appender<ILoggingEvent> appender = this.lookupAppender(appenderName);
87 if (appender == NO_APPENDER) {
88 this.addError(String.format("Appender %s does not exist", appenderName));
90 appender.doAppend(event);
95 private Appender<ILoggingEvent> lookupAppender(String key) {
97 Appender<ILoggingEvent> appender = appenders.get(key);
98 if (appender != null) {
102 LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();
103 for (Logger log : context.getLoggerList()) {
105 Iterator<Appender<ILoggingEvent>> iterator = log.iteratorForAppenders();
106 while (iterator.hasNext()) {
108 Appender<ILoggingEvent> element = iterator.next();
109 if (key.equals(element.getName())) {
110 this.appenders.putIfAbsent(key, element);
116 // to avoid consecutive lookups if the required appender does not exist
117 this.appenders.putIfAbsent(key, NO_APPENDER);
122 public void start() {
125 if (this.discriminator == null) {
126 this.addError("Missing discriminator. Aborting");
129 if (!this.discriminator.isStarted()) {
130 this.addError("Discriminator has not started successfully. Aborting");
134 if (this.appenderNamePattern == null) {
135 this.addError("Missing name pattern. Aborting");