View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements. See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache license, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License. You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the license for the specific language governing permissions and
15   * limitations under the license.
16   */
17  package org.apache.log4j.builders.appender;
18  
19  import static org.apache.log4j.builders.BuilderManager.CATEGORY;
20  import static org.apache.log4j.config.Log4j1Configuration.THRESHOLD_PARAM;
21  import static org.apache.log4j.xml.XmlConfiguration.FILTER_TAG;
22  import static org.apache.log4j.xml.XmlConfiguration.LAYOUT_TAG;
23  import static org.apache.log4j.xml.XmlConfiguration.NAME_ATTR;
24  import static org.apache.log4j.xml.XmlConfiguration.PARAM_TAG;
25  import static org.apache.log4j.xml.XmlConfiguration.VALUE_ATTR;
26  import static org.apache.log4j.xml.XmlConfiguration.forEachElement;
27  
28  import java.util.ArrayList;
29  import java.util.List;
30  import java.util.Properties;
31  import java.util.concurrent.atomic.AtomicReference;
32  
33  import org.apache.log4j.Appender;
34  import org.apache.log4j.Layout;
35  import org.apache.log4j.bridge.AppenderWrapper;
36  import org.apache.log4j.bridge.LayoutAdapter;
37  import org.apache.log4j.bridge.LayoutWrapper;
38  import org.apache.log4j.builders.AbstractBuilder;
39  import org.apache.log4j.config.Log4j1Configuration;
40  import org.apache.log4j.config.PropertiesConfiguration;
41  import org.apache.log4j.spi.Filter;
42  import org.apache.log4j.xml.XmlConfiguration;
43  import org.apache.logging.log4j.Logger;
44  import org.apache.logging.log4j.core.appender.ConsoleAppender;
45  import org.apache.logging.log4j.core.config.plugins.Plugin;
46  import org.apache.logging.log4j.status.StatusLogger;
47  import org.w3c.dom.Element;
48  
49  /**
50   * Build a Console Appender
51   */
52  @Plugin(name = "org.apache.log4j.ConsoleAppender", category = CATEGORY)
53  public class ConsoleAppenderBuilder extends AbstractBuilder implements AppenderBuilder {
54      private static final String SYSTEM_OUT = "System.out";
55      private static final String SYSTEM_ERR = "System.err";
56      private static final String TARGET = "target";
57  
58      private static final Logger LOGGER = StatusLogger.getLogger();
59  
60      public ConsoleAppenderBuilder() {
61      }
62  
63      public ConsoleAppenderBuilder(String prefix, Properties props) {
64          super(prefix, props);
65      }
66  
67      @Override
68      public Appender parseAppender(final Element appenderElement, final XmlConfiguration config) {
69          String name = appenderElement.getAttribute(NAME_ATTR);
70          AtomicReference<String> target = new AtomicReference<>(SYSTEM_OUT);
71          AtomicReference<Layout> layout = new AtomicReference<>();
72          AtomicReference<List<Filter>> filters = new AtomicReference<>(new ArrayList<>());
73          AtomicReference<String> level = new AtomicReference<>();
74          forEachElement(appenderElement.getChildNodes(), currentElement -> {
75              switch (currentElement.getTagName()) {
76                  case LAYOUT_TAG:
77                      layout.set(config.parseLayout(currentElement));
78                      break;
79                  case FILTER_TAG:
80                      filters.get().add(config.parseFilters(currentElement));
81                      break;
82                  case PARAM_TAG: {
83                      switch (currentElement.getAttribute(NAME_ATTR)) {
84                          case TARGET: {
85                              String value = currentElement.getAttribute(VALUE_ATTR);
86                              if (value == null) {
87                                  LOGGER.warn("No value supplied for target parameter. Defaulting to System.out.");
88                              } else {
89                                  switch (value) {
90                                      case SYSTEM_OUT:
91                                          target.set(SYSTEM_OUT);
92                                          break;
93                                      case SYSTEM_ERR:
94                                          target.set(SYSTEM_ERR);
95                                          break;
96                                      default:
97                                          LOGGER.warn("Invalid value \"{}\" for target parameter. Using default of System.out",
98                                                  value);
99                                  }
100                             }
101                             break;
102                         }
103                         case THRESHOLD_PARAM: {
104                             String value = currentElement.getAttribute(VALUE_ATTR);
105                             if (value == null) {
106                                 LOGGER.warn("No value supplied for Threshold parameter, ignoring.");
107                             } else {
108                                 level.set(value);
109                             }
110                             break;
111                         }
112                     }
113                     break;
114                 }
115             }
116         });
117         Filter head = null;
118         Filter current = null;
119         for (Filter f : filters.get()) {
120             if (head == null) {
121                 head = f;
122             } else {
123                 current.next = f;
124             }
125             current = f;
126         }
127         return createAppender(name, layout.get(), head, level.get(), target.get(), config);
128     }
129 
130     @Override
131     public Appender parseAppender(final String name, final String appenderPrefix, final String layoutPrefix,
132             final String filterPrefix, final Properties props, final PropertiesConfiguration configuration) {
133         Layout layout = configuration.parseLayout(layoutPrefix, name, props);
134         Filter filter = configuration.parseAppenderFilters(props, filterPrefix, name);
135         String level = getProperty(THRESHOLD_PARAM);
136         String target = getProperty(TARGET);
137         return createAppender(name, layout, filter, level, target, configuration);
138     }
139 
140     private <T extends Log4j1Configuration> Appender createAppender(String name, Layout layout, Filter filter,
141             String level, String target, T configuration) {
142         org.apache.logging.log4j.core.Layout<?> consoleLayout = null;
143 
144         if (layout instanceof LayoutWrapper) {
145             consoleLayout = ((LayoutWrapper) layout).getLayout();
146         } else if (layout != null) {
147             consoleLayout = new LayoutAdapter(layout);
148         }
149         org.apache.logging.log4j.core.Filter consoleFilter = buildFilters(level, filter);
150         ConsoleAppender.Target consoleTarget = SYSTEM_ERR.equals(target)
151                 ? ConsoleAppender.Target.SYSTEM_ERR : ConsoleAppender.Target.SYSTEM_OUT;
152         return new AppenderWrapper(ConsoleAppender.newBuilder()
153                 .setName(name)
154                 .setTarget(consoleTarget)
155                 .setLayout(consoleLayout)
156                 .setFilter(consoleFilter)
157                 .setConfiguration(configuration)
158                 .build());
159     }
160 }