b4abb8b368ed58d4eb078274d879061d7f001878
[sdc.git] /
1 /*
2  * Copyright © 2016-2017 European Support Limited
3  *
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
7  * 
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  * 
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.
15  */
16
17 package org.openecomp.sdc.logging.logback;
18
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 org.slf4j.LoggerFactory;
28
29 import java.util.Iterator;
30 import java.util.Map;
31 import java.util.concurrent.ConcurrentHashMap;
32
33 /**
34  * <p>Allows to use EELF logging configuration almost as is, by using a custom routing function, but pre-configured
35  * appenders attached to the standard EELF loggers.</p>
36  *
37  * <p>Changes that must be made in <i>logback.xml</i> supplied with EELF:</p>
38  *
39  * <pre>
40  *     &lt;appender name="DISPATCHER" class="org.openecomp.sdc.logging.logback.DispatchingAppender"&gt;
41  *          &lt;discriminator class="org.openecomp.sdc.logging.logback.EventTypeDiscriminator"/&gt;
42  *          &lt;appenderNamePattern&gt;asyncEELF%s&lt;/appenderNamePattern&gt;
43  *     &lt;/appender&gt;
44  *
45  *     &lt;root level="INFO" additivity="false"&gt;
46  *          &lt;appender-ref ref="DISPATCHER" /&gt;
47  *      &lt;/root&gt;
48  * </pre>
49  *
50  * @author EVITALIY
51  * @since 17/08/2016.
52  */
53 public class DispatchingAppender extends AppenderBase<ILoggingEvent> {
54
55     // "magic" appender to indicate a missing appender
56     private static final Appender<ILoggingEvent> NO_APPENDER = new DispatchingAppender();
57
58     private Map<String, Appender<ILoggingEvent>> appenders = new ConcurrentHashMap<>();
59
60     private Discriminator<ILoggingEvent> discriminator;
61     private String appenderNamePattern;
62
63     @DefaultClass(MDCBasedDiscriminator.class)
64     public void setDiscriminator(Discriminator<ILoggingEvent> discriminator) {
65         this.discriminator = discriminator;
66     }
67
68     public Discriminator<ILoggingEvent> getDiscriminator() {
69         return this.discriminator;
70     }
71
72     public void setAppenderNamePattern(String pattern) {
73         this.appenderNamePattern = pattern;
74     }
75
76     public String getAppenderNamePattern() {
77         return this.appenderNamePattern;
78     }
79
80     @Override
81     protected void append(ILoggingEvent event) {
82
83         if (this.isStarted()) {
84
85             String discriminatingValue = this.discriminator.getDiscriminatingValue(event);
86             String appenderName = String.format(this.appenderNamePattern, discriminatingValue);
87             Appender<ILoggingEvent> appender = this.lookupAppender(appenderName);
88             if (appender == NO_APPENDER) {
89                 this.addError(String.format("Appender %s does not exist", appenderName));
90             } else {
91                 appender.doAppend(event);
92             }
93         }
94     }
95
96     private Appender<ILoggingEvent> lookupAppender(String key) {
97
98         Appender<ILoggingEvent> appender = appenders.get(key);
99         if (appender != null) {
100             return appender;
101         }
102
103         LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();
104         for (Logger log : context.getLoggerList()) {
105
106             Iterator<Appender<ILoggingEvent>> iterator = log.iteratorForAppenders();
107             while (iterator.hasNext()) {
108
109                 Appender<ILoggingEvent> element = iterator.next();
110                 if (key.equals(element.getName())) {
111                     this.appenders.putIfAbsent(key, element);
112                     return element;
113                 }
114             }
115         }
116
117         // to avoid consecutive lookups if the required appender does not exist
118         this.appenders.putIfAbsent(key, NO_APPENDER);
119         return NO_APPENDER;
120     }
121
122     @Override
123     public void start() {
124
125         int errors = 0;
126         if (this.discriminator == null) {
127             this.addError("Missing discriminator. Aborting");
128         }
129
130         if (!this.discriminator.isStarted()) {
131             this.addError("Discriminator has not started successfully. Aborting");
132             ++errors;
133         }
134
135         if (this.appenderNamePattern == null) {
136             this.addError("Missing name pattern. Aborting");
137             ++errors;
138         }
139
140         if (errors == 0) {
141             super.start();
142         }
143     }
144 }