Merge "Add get-config commit edit-config to testtool"
[controller.git] / opendaylight / config / logback-config / src / main / java / org / opendaylight / controller / config / yang / logback / config / ContextSetterImpl.java
1 /*
2  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.controller.config.yang.logback.config;
9
10 import java.io.Closeable;
11 import java.io.IOException;
12 import java.util.HashMap;
13 import java.util.Iterator;
14 import java.util.List;
15 import java.util.Map;
16 import java.util.Set;
17
18 import org.slf4j.LoggerFactory;
19
20 import ch.qos.logback.classic.Level;
21 import ch.qos.logback.classic.LoggerContext;
22 import ch.qos.logback.classic.encoder.PatternLayoutEncoder;
23 import ch.qos.logback.classic.filter.ThresholdFilter;
24 import ch.qos.logback.classic.spi.ILoggingEvent;
25 import ch.qos.logback.core.Appender;
26 import ch.qos.logback.core.rolling.FixedWindowRollingPolicy;
27 import ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy;
28 import ch.qos.logback.core.rolling.TimeBasedRollingPolicy;
29
30 import com.google.common.base.Optional;
31 import com.google.common.base.Preconditions;
32 import com.google.common.collect.Sets;
33
34 /**
35  * Implementation of {@link ContextSetter}. Resets running logback
36  * configuration.
37  */
38 public class ContextSetterImpl implements ContextSetter, Closeable {
39
40     private final LogbackStatusListener statusListener;
41     private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger(ContextSetterImpl.class);
42
43     public ContextSetterImpl(LogbackRuntimeRegistrator rootRuntimeBeanRegistratorWrapper) {
44         statusListener = new LogbackStatusListener(rootRuntimeBeanRegistratorWrapper);
45         statusListener.register();
46     }
47
48     public void updateContext(LogbackModule module) {
49         LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();
50
51         List<ch.qos.logback.classic.Logger> loggersBefore = context.getLoggerList();
52
53         createLoggers(context, module, Sets.newHashSet(loggersBefore));
54     }
55
56     private Map<String, Appender<ILoggingEvent>> createConsoleAppenders(LoggerContext context, LogbackModule module) {
57         Map<String, Appender<ILoggingEvent>> appendersMap = new HashMap<>();
58         for (ConsoleAppenderTO appender : module.getConsoleAppenderTO()) {
59             Preconditions.checkState(appendersMap.containsKey(appender.getName()) == false,
60                     "Duplicate appender name %s", appender.getName());
61             ch.qos.logback.core.ConsoleAppender app = new ch.qos.logback.core.ConsoleAppender();
62             app.setContext(context);
63             PatternLayoutEncoder encoder = new PatternLayoutEncoder();
64             encoder.setContext(context);
65             encoder.setPattern(appender.getEncoderPattern());
66             encoder.start();
67             app.setEncoder(encoder);
68             ThresholdFilter filter = new ThresholdFilter();
69             filter.setContext(context);
70             filter.setLevel(appender.getThresholdFilter());
71             filter.start();
72             app.getCopyOfAttachedFiltersList().add(filter);
73             app.setName(appender.getName());
74             app.start();
75             appendersMap.put(app.getName(), app);
76         }
77         return appendersMap;
78     }
79
80     private void createLoggers(LoggerContext context, LogbackModule module,
81             Set<ch.qos.logback.classic.Logger> loggersBefore) {
82
83         Map<String, Appender<ILoggingEvent>> appendersMap = getAppenders(module, context);
84
85         for (LoggerTO logger : module.getLoggerTO()) {
86             LOGGER.trace("Setting configuration for logger {}", logger.getLoggerName());
87             final ch.qos.logback.classic.Logger logbackLogger = context.getLogger(logger.getLoggerName());
88
89             Optional<Set<Appender<ILoggingEvent>>> appendersBefore = getAppendersBefore(loggersBefore, logbackLogger);
90             LOGGER.trace("Logger {}: Appenders registered before: {}", logger.getLoggerName(),
91                     appendersBefore.isPresent() ? appendersBefore.get() : "NO APPENDERS BEFORE");
92
93             logbackLogger.setLevel(Level.toLevel(logger.getLevel()));
94
95             addNewAppenders(appendersMap, logger, logbackLogger, appendersBefore);
96             removeBeforeAppenders(loggersBefore, logger, logbackLogger, appendersBefore);
97         }
98     }
99
100     private void addNewAppenders(Map<String, Appender<ILoggingEvent>> appendersMap, LoggerTO logger,
101             ch.qos.logback.classic.Logger logbackLogger, Optional<Set<Appender<ILoggingEvent>>> appendersBefore) {
102         if (logger.getAppenders() != null) {
103             for (String appenderName : logger.getAppenders()) {
104                 if (appendersMap.containsKey(appenderName)) {
105                     logbackLogger.addAppender(appendersMap.get(appenderName));
106                     LOGGER.trace("Logger {}: Adding new appender: {}", logger.getLoggerName(), appenderName);
107                 } else {
108                     throw new IllegalStateException("No appender " + appenderName
109                             + " found. This error should have been discovered by validation");
110                 }
111             }
112         }
113     }
114
115     private void removeBeforeAppenders(Set<ch.qos.logback.classic.Logger> loggersBefore, LoggerTO logger,
116             ch.qos.logback.classic.Logger logbackLogger, Optional<Set<Appender<ILoggingEvent>>> appendersBefore) {
117         if (appendersBefore.isPresent()) {
118             for (Appender<ILoggingEvent> appenderBefore : appendersBefore.get()) {
119                 logbackLogger.detachAppender(appenderBefore);
120                 appenderBefore.stop();
121                 LOGGER.trace("Logger {}: Removing old appender: {}", logger.getLoggerName(),
122                         appenderBefore.getName());
123             }
124             loggersBefore.remove(logbackLogger);
125         }
126     }
127
128     private Optional<Set<Appender<ILoggingEvent>>> getAppendersBefore(Set<ch.qos.logback.classic.Logger> loggersBefore,
129             ch.qos.logback.classic.Logger logbackLogger) {
130         if (loggersBefore.contains(logbackLogger)) {
131             Iterator<Appender<ILoggingEvent>> appenderIt = logbackLogger.iteratorForAppenders();
132             Set<Appender<ILoggingEvent>> appendersBefore = Sets.newHashSet();
133             while (appenderIt.hasNext()) {
134                 appendersBefore.add(appenderIt.next());
135             }
136             return Optional.of(appendersBefore);
137         } else {
138             return Optional.absent();
139         }
140
141     }
142
143     private Map<String, Appender<ILoggingEvent>> getAppenders(LogbackModule module, LoggerContext context) {
144         Map<String, Appender<ILoggingEvent>> appendersMap = new HashMap<>();
145         addAllAppenders(appendersMap, createRollingAppenders(context, module));
146         addAllAppenders(appendersMap, createFileAppenders(context, module));
147         addAllAppenders(appendersMap, createConsoleAppenders(context, module));
148
149         return appendersMap;
150     }
151
152     private void addAllAppenders(Map<String, Appender<ILoggingEvent>> allAppenders,
153             Map<String, Appender<ILoggingEvent>> appendersToAdd) {
154         for (String appenderName : appendersToAdd.keySet()) {
155             Preconditions.checkState(allAppenders.containsKey(appenderName) == false, "Duplicate appender name %s",
156                     appenderName);
157             allAppenders.put(appenderName, appendersToAdd.get(appenderName));
158         }
159     }
160
161     private Map<String, Appender<ILoggingEvent>> createFileAppenders(LoggerContext context, LogbackModule module) {
162         Map<String, Appender<ILoggingEvent>> appendersMap = new HashMap<>();
163         for (FileAppenderTO appender : module.getFileAppenderTO()) {
164             Preconditions.checkState(appendersMap.containsKey(appender.getName()) == false,
165                     "Duplicate appender name %s", appender.getName());
166             ch.qos.logback.core.FileAppender app = new ch.qos.logback.core.FileAppender<>();
167             app.setAppend(appender.getAppend());
168             app.setContext(context);
169             PatternLayoutEncoder encoder = new PatternLayoutEncoder();
170             encoder.setContext(context);
171             encoder.setPattern(appender.getEncoderPattern());
172             encoder.start();
173             app.setEncoder(encoder);
174             app.setFile(appender.getFileName());
175             app.setName(appender.getName());
176             app.start();
177             appendersMap.put(app.getName(), app);
178         }
179
180         return appendersMap;
181     }
182
183     private Map<String, Appender<ILoggingEvent>> createRollingAppenders(LoggerContext context, LogbackModule module) {
184         Map<String, Appender<ILoggingEvent>> appendersMap = new HashMap<>();
185         for (RollingFileAppenderTO appender : module.getRollingFileAppenderTO()) {
186             Preconditions.checkState(appendersMap.containsKey(appender.getName()) == false,
187                     "Duplicate appender name %s", appender.getName());
188             ch.qos.logback.core.rolling.RollingFileAppender app = new ch.qos.logback.core.rolling.RollingFileAppender<>();
189             app.setAppend(appender.getAppend());
190             app.setContext(context);
191             PatternLayoutEncoder encoder = new PatternLayoutEncoder();
192             encoder.setContext(context);
193             encoder.setPattern(appender.getEncoderPattern());
194             encoder.start();
195             app.setEncoder(encoder);
196             app.setFile(appender.getFileName());
197             if (appender.getRollingPolicyType().equals("FixedWindowRollingPolicy")) {
198                 FixedWindowRollingPolicy policy = new FixedWindowRollingPolicy();
199                 policy.setContext(context);
200                 policy.setMaxIndex(appender.getMaxIndex());
201                 policy.setMinIndex(appender.getMinIndex());
202                 policy.setFileNamePattern(appender.getFileNamePattern());
203                 policy.setParent(app);
204                 policy.start();
205                 app.setRollingPolicy(policy);
206             } else if (appender.getRollingPolicyType().equals("TimeBasedRollingPolicy")) {
207                 TimeBasedRollingPolicy policy = new TimeBasedRollingPolicy();
208                 policy.setContext(context);
209                 policy.setMaxHistory(appender.getMaxHistory());
210                 if (appender.getCleanHistoryOnStart() != null) {
211                     policy.setCleanHistoryOnStart(appender.getCleanHistoryOnStart());
212                 }
213                 policy.setFileNamePattern(appender.getFileNamePattern());
214                 policy.setParent(app);
215                 policy.start();
216                 app.setRollingPolicy(policy);
217             }
218             SizeBasedTriggeringPolicy triggeringPolicy = new SizeBasedTriggeringPolicy();
219             triggeringPolicy.setContext(context);
220             triggeringPolicy.setMaxFileSize(appender.getMaxFileSize());
221             triggeringPolicy.start();
222             app.setTriggeringPolicy(triggeringPolicy);
223             app.setName(appender.getName());
224             app.start();
225             appendersMap.put(app.getName(), app);
226         }
227         return appendersMap;
228     }
229
230     @Override
231     public void close() throws IOException {
232         statusListener.close();
233     }
234 }