2273e1c7efe8d6882ac4f135df83252a1c6ab033
[sdc.git] /
1 /*-
2  * ============LICENSE_START=======================================================
3  * SDC
4  * ================================================================================
5  * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6  * ================================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  * 
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  * 
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  * ============LICENSE_END=========================================================
19  */
20
21 package org.openecomp.sdc.logging.logback;
22
23 import ch.qos.logback.classic.Logger;
24 import ch.qos.logback.classic.LoggerContext;
25 import ch.qos.logback.classic.sift.MDCBasedDiscriminator;
26 import ch.qos.logback.classic.spi.ILoggingEvent;
27 import ch.qos.logback.core.Appender;
28 import ch.qos.logback.core.AppenderBase;
29 import ch.qos.logback.core.joran.spi.DefaultClass;
30 import ch.qos.logback.core.sift.Discriminator;
31 import org.slf4j.LoggerFactory;
32
33 import java.util.Iterator;
34 import java.util.Map;
35 import java.util.concurrent.ConcurrentHashMap;
36
37 /**
38  * <p>Allows to use EELF logging configuration almost as is, by using a custom routing function, but pre-configured
39  * appenders attached to the standard EELF loggers.</p>
40  *
41  * <p>Changes that must be made in <i>logback.xml</i> supplied with EELF:</p>
42  *
43  * <pre>
44  *     &lt;appender name="DISPATCHER" class="org.openecomp.sdc.logging.logback.DispatchingAppender"&gt;
45  *          &lt;discriminator class="org.openecomp.sdc.logging.logback.EventTypeDiscriminator"/&gt;
46  *          &lt;appenderNamePattern&gt;asyncEELF%s&lt;/appenderNamePattern&gt;
47  *     &lt;/appender&gt;
48  *
49  *     &lt;root level="INFO" additivity="false"&gt;
50  *          &lt;appender-ref ref="DISPATCHER" /&gt;
51  *      &lt;/root&gt;
52  * </pre>
53  *
54  * @author EVITALIY
55  * @since 17/08/2016.
56  */
57 public class DispatchingAppender extends AppenderBase<ILoggingEvent> {
58
59     // "magic" appender to indicate a missing appender
60     private static final Appender<ILoggingEvent> NO_APPENDER = new DispatchingAppender();
61
62     private Map<String, Appender<ILoggingEvent>> appenders = new ConcurrentHashMap<>();
63
64     private Discriminator<ILoggingEvent> discriminator;
65     private String appenderNamePattern;
66
67     @DefaultClass(MDCBasedDiscriminator.class)
68     public void setDiscriminator(Discriminator<ILoggingEvent> discriminator) {
69         this.discriminator = discriminator;
70     }
71
72     public Discriminator<ILoggingEvent> getDiscriminator() {
73         return this.discriminator;
74     }
75
76     public void setAppenderNamePattern(String pattern) {
77         this.appenderNamePattern = pattern;
78     }
79
80     public String getAppenderNamePattern() {
81         return this.appenderNamePattern;
82     }
83
84     @Override
85     protected void append(ILoggingEvent event) {
86
87         if (this.isStarted()) {
88
89             String discriminatingValue = this.discriminator.getDiscriminatingValue(event);
90             String appenderName = String.format(this.appenderNamePattern, discriminatingValue);
91             Appender<ILoggingEvent> appender = this.lookupAppender(appenderName);
92             if (appender == NO_APPENDER) {
93                 this.addError(String.format("Appender %s does not exist", appenderName));
94             } else {
95                 appender.doAppend(event);
96             }
97         }
98     }
99
100     private Appender<ILoggingEvent> lookupAppender(String key) {
101
102         Appender<ILoggingEvent> appender = appenders.get(key);
103         if (appender != null) {
104             return appender;
105         }
106
107         LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();
108         for (Logger log : context.getLoggerList()) {
109
110             Iterator<Appender<ILoggingEvent>> iterator = log.iteratorForAppenders();
111             while (iterator.hasNext()) {
112
113                 Appender<ILoggingEvent> element = iterator.next();
114                 if (key.equals(element.getName())) {
115                     this.appenders.putIfAbsent(key, element);
116                     return element;
117                 }
118             }
119         }
120
121         // to avoid consecutive lookups if the required appender does not exist
122         this.appenders.putIfAbsent(key, NO_APPENDER);
123         return NO_APPENDER;
124     }
125
126     @Override
127     public void start() {
128
129         int errors = 0;
130         if (this.discriminator == null) {
131             this.addError("Missing discriminator. Aborting");
132         }
133
134         if (!this.discriminator.isStarted()) {
135             this.addError("Discriminator has not started successfully. Aborting");
136             ++errors;
137         }
138
139         if (this.appenderNamePattern == null) {
140             this.addError("Missing name pattern. Aborting");
141             ++errors;
142         }
143
144         if (errors == 0) {
145             super.start();
146         }
147     }
148 }