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 /** 132 * Creates a WriterAppender. 133 * 134 * @param layout 135 * The layout to use or null to get the default layout. 136 * @param filter 137 * The Filter or null. 138 * @param target 139 * The target Writer 140 * @param follow 141 * If true will follow changes to the underlying output stream. 142 * Use false as the default. 143 * @param name 144 * The name of the Appender (required). 145 * @param ignore 146 * If {@code "true"} (default) exceptions encountered when 147 * appending events are logged; otherwise they are propagated to 148 * the caller. Use true as the default. 149 * @return The ConsoleAppender. 150 */ 151 @PluginFactory 152 public static WriterAppender createAppender(StringLayout layout, final Filter filter, final Writer target, 153 final String name, final boolean follow, final boolean ignore) { 154 if (name == null) { 155 LOGGER.error("No name provided for WriterAppender"); 156 return null; 157 } 158 if (layout == null) { 159 layout = PatternLayout.createDefaultLayout(); 160 } 161 return new WriterAppender(name, layout, filter, getManager(target, follow, layout), ignore); 162 } 163 164 private static WriterManager getManager(final Writer target, final boolean follow, final StringLayout layout) { 165 final Writer writer = new CloseShieldWriter(target); 166 final String managerName = target.getClass().getName() + "@" + Integer.toHexString(target.hashCode()) + '.' 167 + follow; 168 return WriterManager.getManager(managerName, new FactoryData(writer, managerName, layout), factory); 169 } 170 171 @PluginBuilderFactory 172 public static Builder newBuilder() { 173 return new Builder(); 174 } 175 176 private WriterAppender(final String name, final StringLayout layout, final Filter filter, 177 final WriterManager manager, final boolean ignoreExceptions) { 178 super(name, layout, filter, ignoreExceptions, true, manager); 179 } 180 181}