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