001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache license, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the license for the specific language governing permissions and 015 * limitations under the license. 016 */ 017package org.apache.log4j.builders.appender; 018 019import static org.apache.log4j.builders.BuilderManager.CATEGORY; 020import static org.apache.log4j.config.Log4j1Configuration.THRESHOLD_PARAM; 021import static org.apache.log4j.xml.XmlConfiguration.FILTER_TAG; 022import static org.apache.log4j.xml.XmlConfiguration.LAYOUT_TAG; 023import static org.apache.log4j.xml.XmlConfiguration.NAME_ATTR; 024import static org.apache.log4j.xml.XmlConfiguration.PARAM_TAG; 025import static org.apache.log4j.xml.XmlConfiguration.VALUE_ATTR; 026import static org.apache.log4j.xml.XmlConfiguration.forEachElement; 027 028import java.util.Properties; 029import java.util.concurrent.atomic.AtomicBoolean; 030import java.util.concurrent.atomic.AtomicInteger; 031import java.util.concurrent.atomic.AtomicReference; 032 033import org.apache.log4j.Appender; 034import org.apache.log4j.Layout; 035import org.apache.log4j.bridge.AppenderWrapper; 036import org.apache.log4j.bridge.LayoutAdapter; 037import org.apache.log4j.bridge.LayoutWrapper; 038import org.apache.log4j.builders.AbstractBuilder; 039import org.apache.log4j.config.Log4j1Configuration; 040import org.apache.log4j.config.PropertiesConfiguration; 041import org.apache.log4j.spi.Filter; 042import org.apache.log4j.xml.XmlConfiguration; 043import org.apache.logging.log4j.Logger; 044import org.apache.logging.log4j.core.appender.FileAppender; 045import org.apache.logging.log4j.core.config.plugins.Plugin; 046import org.apache.logging.log4j.status.StatusLogger; 047import org.w3c.dom.Element; 048 049/** 050 * Build a File Appender 051 */ 052@Plugin(name = "org.apache.log4j.FileAppender", category = CATEGORY) 053public class FileAppenderBuilder extends AbstractBuilder implements AppenderBuilder { 054 055 private static final Logger LOGGER = StatusLogger.getLogger(); 056 057 public FileAppenderBuilder() { 058 } 059 060 public FileAppenderBuilder(String prefix, Properties props) { 061 super(prefix, props); 062 } 063 064 @Override 065 public Appender parseAppender(Element appenderElement, XmlConfiguration config) { 066 String name = appenderElement.getAttribute(NAME_ATTR); 067 AtomicReference<Layout> layout = new AtomicReference<>(); 068 AtomicReference<Filter> filter = new AtomicReference<>(); 069 AtomicReference<String> fileName = new AtomicReference<>(); 070 AtomicReference<String> level = new AtomicReference<>(); 071 AtomicBoolean immediateFlush = new AtomicBoolean(); 072 AtomicBoolean append = new AtomicBoolean(); 073 AtomicBoolean bufferedIo = new AtomicBoolean(); 074 AtomicInteger bufferSize = new AtomicInteger(8192); 075 forEachElement(appenderElement.getChildNodes(), currentElement -> { 076 switch (currentElement.getTagName()) { 077 case LAYOUT_TAG: 078 layout.set(config.parseLayout(currentElement)); 079 break; 080 case FILTER_TAG: 081 filter.set(config.parseFilters(currentElement)); 082 break; 083 case PARAM_TAG: { 084 switch (currentElement.getAttribute(NAME_ATTR)) { 085 case FILE_PARAM: 086 fileName.set(currentElement.getAttribute(VALUE_ATTR)); 087 break; 088 case APPEND_PARAM: { 089 String bool = currentElement.getAttribute(VALUE_ATTR); 090 if (bool != null) { 091 append.set(Boolean.parseBoolean(bool)); 092 } else { 093 LOGGER.warn("No value provided for append parameter"); 094 } 095 break; 096 } 097 case BUFFERED_IO_PARAM: { 098 String bool = currentElement.getAttribute(VALUE_ATTR); 099 if (bool != null) { 100 bufferedIo.set(Boolean.parseBoolean(bool)); 101 } else { 102 LOGGER.warn("No value provided for bufferedIo parameter"); 103 } 104 break; 105 } 106 case BUFFER_SIZE_PARAM: { 107 String size = currentElement.getAttribute(VALUE_ATTR); 108 if (size != null) { 109 bufferSize.set(Integer.parseInt(size)); 110 } else { 111 LOGGER.warn("No value provide for bufferSize parameter"); 112 } 113 break; 114 } 115 case THRESHOLD_PARAM: { 116 String value = currentElement.getAttribute(VALUE_ATTR); 117 if (value == null) { 118 LOGGER.warn("No value supplied for Threshold parameter, ignoring."); 119 } else { 120 level.set(value); 121 } 122 break; 123 } 124 } 125 break; 126 } 127 } 128 }); 129 130 return createAppender(name, config, layout.get(), filter.get(), fileName.get(), level.get(), 131 immediateFlush.get(), append.get(), bufferedIo.get(), bufferSize.get()); 132 } 133 134 135 @Override 136 public Appender parseAppender(final String name, final String appenderPrefix, final String layoutPrefix, 137 final String filterPrefix, final Properties props, final PropertiesConfiguration configuration) { 138 Layout layout = configuration.parseLayout(layoutPrefix, name, props); 139 Filter filter = configuration.parseAppenderFilters(props, filterPrefix, name); 140 String level = getProperty(THRESHOLD_PARAM); 141 String fileName = getProperty(FILE_PARAM); 142 boolean append = getBooleanProperty(APPEND_PARAM); 143 boolean immediateFlush = false; 144 boolean bufferedIo = getBooleanProperty(BUFFERED_IO_PARAM); 145 int bufferSize = Integer.parseInt(getProperty(BUFFER_SIZE_PARAM, "8192")); 146 return createAppender(name, configuration, layout, filter, fileName, level, immediateFlush, 147 append, bufferedIo, bufferSize); 148 } 149 150 private Appender createAppender(final String name, final Log4j1Configuration configuration, final Layout layout, 151 final Filter filter, final String fileName, String level, boolean immediateFlush, final boolean append, 152 final boolean bufferedIo, final int bufferSize) { 153 org.apache.logging.log4j.core.Layout<?> fileLayout = null; 154 if (bufferedIo) { 155 immediateFlush = true; 156 } 157 if (layout instanceof LayoutWrapper) { 158 fileLayout = ((LayoutWrapper) layout).getLayout(); 159 } else if (layout != null) { 160 fileLayout = new LayoutAdapter(layout); 161 } 162 org.apache.logging.log4j.core.Filter fileFilter = buildFilters(level, filter); 163 if (fileName == null) { 164 LOGGER.warn("Unable to create File Appender, no file name provided"); 165 return null; 166 } 167 return new AppenderWrapper(FileAppender.newBuilder() 168 .setName(name) 169 .setConfiguration(configuration) 170 .setLayout(fileLayout) 171 .setFilter(fileFilter) 172 .withFileName(fileName) 173 .withImmediateFlush(immediateFlush) 174 .withAppend(append) 175 .withBufferedIo(bufferedIo) 176 .withBufferSize(bufferSize) 177 .build()); 178 } 179}