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.logging.log4j.core.appender; 018 019import java.io.Writer; 020 021import org.apache.logging.log4j.core.Filter; 022import org.apache.logging.log4j.core.StringLayout; 023import org.apache.logging.log4j.core.config.plugins.Plugin; 024import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory; 025import org.apache.logging.log4j.core.config.plugins.PluginFactory; 026import org.apache.logging.log4j.core.layout.PatternLayout; 027import org.apache.logging.log4j.core.util.CloseShieldWriter; 028 029/** 030 * Appends log events to a {@link Writer}. 031 */ 032@Plugin(name = "Writer", category = "Core", elementType = "appender", printObject = true) 033public final class WriterAppender extends AbstractWriterAppender<WriterManager> { 034 035 /** 036 * Builds WriterAppender instances. 037 */ 038 public static class Builder implements org.apache.logging.log4j.core.util.Builder<WriterAppender> { 039 040 private Filter filter; 041 042 private boolean follow = false; 043 044 private boolean ignoreExceptions = true; 045 046 private StringLayout layout = PatternLayout.createDefaultLayout(); 047 048 private String name; 049 050 private Writer target; 051 052 @Override 053 public WriterAppender build() { 054 return new WriterAppender(name, layout, filter, getManager(target, follow, layout), ignoreExceptions); 055 } 056 057 public Builder setFilter(final Filter aFilter) { 058 this.filter = aFilter; 059 return this; 060 } 061 062 public Builder setFollow(final boolean shouldFollow) { 063 this.follow = shouldFollow; 064 return this; 065 } 066 067 public Builder setIgnoreExceptions(final boolean shouldIgnoreExceptions) { 068 this.ignoreExceptions = shouldIgnoreExceptions; 069 return this; 070 } 071 072 public Builder setLayout(final StringLayout aLayout) { 073 this.layout = aLayout; 074 return this; 075 } 076 077 public Builder setName(final String aName) { 078 this.name = aName; 079 return this; 080 } 081 082 public Builder setTarget(final Writer aTarget) { 083 this.target = aTarget; 084 return this; 085 } 086 } 087 /** 088 * Holds data to pass to factory method. 089 */ 090 private static class FactoryData { 091 private final StringLayout layout; 092 private final String name; 093 private final Writer writer; 094 095 /** 096 * Builds instances. 097 * 098 * @param writer 099 * The OutputStream. 100 * @param type 101 * The name of the target. 102 * @param layout 103 * A String layout 104 */ 105 public FactoryData(final Writer writer, final String type, final StringLayout layout) { 106 this.writer = writer; 107 this.name = type; 108 this.layout = layout; 109 } 110 } 111 112 private static class WriterManagerFactory implements ManagerFactory<WriterManager, FactoryData> { 113 114 /** 115 * Creates a WriterManager. 116 * 117 * @param name 118 * The name of the entity to manage. 119 * @param data 120 * The data required to create the entity. 121 * @return The WriterManager 122 */ 123 @Override 124 public WriterManager createManager(final String name, final FactoryData data) { 125 return new WriterManager(data.writer, data.name, data.layout, true); 126 } 127 } 128 129 private static WriterManagerFactory factory = new WriterManagerFactory(); 130 131 private static final long serialVersionUID = 1L; 132 133 /** 134 * Creates a WriterAppender. 135 * 136 * @param layout 137 * The layout to use or null to get the default layout. 138 * @param filter 139 * The Filter or null. 140 * @param target 141 * The target Writer 142 * @param follow 143 * If true will follow changes to the underlying output stream. 144 * Use false as the default. 145 * @param name 146 * The name of the Appender (required). 147 * @param ignore 148 * If {@code "true"} (default) exceptions encountered when 149 * appending events are logged; otherwise they are propagated to 150 * the caller. Use true as the default. 151 * @return The ConsoleAppender. 152 */ 153 @PluginFactory 154 public static WriterAppender createAppender(StringLayout layout, final Filter filter, final Writer target, 155 final String name, final boolean follow, final boolean ignore) { 156 if (name == null) { 157 LOGGER.error("No name provided for WriterAppender"); 158 return null; 159 } 160 if (layout == null) { 161 layout = PatternLayout.createDefaultLayout(); 162 } 163 return new WriterAppender(name, layout, filter, getManager(target, follow, layout), ignore); 164 } 165 166 private static WriterManager getManager(final Writer target, final boolean follow, final StringLayout layout) { 167 final Writer writer = new CloseShieldWriter(target); 168 final String managerName = target.getClass().getName() + "@" + Integer.toHexString(target.hashCode()) + '.' 169 + follow; 170 return WriterManager.getManager(managerName, new FactoryData(writer, managerName, layout), factory); 171 } 172 173 @PluginBuilderFactory 174 public static Builder newBuilder() { 175 return new Builder(); 176 } 177 178 private WriterAppender(final String name, final StringLayout layout, final Filter filter, 179 final WriterManager manager, final boolean ignoreExceptions) { 180 super(name, layout, filter, ignoreExceptions, true, manager); 181 } 182 183}