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.Serializable; 020 021import org.apache.logging.log4j.core.Filter; 022import org.apache.logging.log4j.core.Layout; 023import org.apache.logging.log4j.core.LogEvent; 024import org.apache.logging.log4j.core.util.Constants; 025 026/** 027 * Appends log events as bytes to a byte output stream. The stream encoding is defined in the layout. 028 * 029 * @param <M> The kind of {@link OutputStreamManager} under management 030 */ 031public abstract class AbstractOutputStreamAppender<M extends OutputStreamManager> extends AbstractAppender { 032 033 /** 034 * Immediate flush means that the underlying writer or output stream will be flushed at the end of each append 035 * operation. Immediate flush is slower but ensures that each append request is actually written. If 036 * <code>immediateFlush</code> is set to {@code false}, then there is a good chance that the last few logs events 037 * are not actually written to persistent media if and when the application crashes. 038 */ 039 private final boolean immediateFlush; 040 041 private final M manager; 042 043 /** 044 * Instantiates a WriterAppender and set the output destination to a new {@link java.io.OutputStreamWriter} 045 * initialized with <code>os</code> as its {@link java.io.OutputStream}. 046 * 047 * @param name The name of the Appender. 048 * @param layout The layout to format the message. 049 * @param manager The OutputStreamManager. 050 */ 051 protected AbstractOutputStreamAppender(final String name, final Layout<? extends Serializable> layout, 052 final Filter filter, final boolean ignoreExceptions, final boolean immediateFlush, final M manager) { 053 super(name, filter, layout, ignoreExceptions); 054 this.manager = manager; 055 this.immediateFlush = immediateFlush; 056 } 057 058 /** 059 * Gets the immediate flush setting. 060 * 061 * @return immediate flush. 062 */ 063 public boolean getImmediateFlush() { 064 return immediateFlush; 065 } 066 067 /** 068 * Gets the manager. 069 * 070 * @return the manager. 071 */ 072 public M getManager() { 073 return manager; 074 } 075 076 @Override 077 public void start() { 078 if (getLayout() == null) { 079 LOGGER.error("No layout set for the appender named [" + getName() + "]."); 080 } 081 if (manager == null) { 082 LOGGER.error("No OutputStreamManager set for the appender named [" + getName() + "]."); 083 } 084 super.start(); 085 } 086 087 @Override 088 public void stop() { 089 super.stop(); 090 manager.release(); 091 } 092 093 /** 094 * Actual writing occurs here. 095 * <p> 096 * Most subclasses of <code>AbstractOutputStreamAppender</code> will need to override this method. 097 * </p> 098 * 099 * @param event The LogEvent. 100 */ 101 @Override 102 public void append(final LogEvent event) { 103 try { 104 tryAppend(event); 105 } catch (final AppenderLoggingException ex) { 106 error("Unable to write to stream " + manager.getName() + " for appender " + getName() + ": " + ex); 107 throw ex; 108 } 109 } 110 111 private void tryAppend(final LogEvent event) { 112 if (Constants.ENABLE_DIRECT_ENCODERS) { 113 directEncodeEvent(event); 114 } else { 115 writeByteArrayToManager(event); 116 } 117 } 118 119 protected void directEncodeEvent(final LogEvent event) { 120 getLayout().encode(event, manager); 121 if (this.immediateFlush || event.isEndOfBatch()) { 122 manager.flush(); 123 } 124 } 125 126 protected void writeByteArrayToManager(final LogEvent event) { 127 final byte[] bytes = getLayout().toByteArray(event); 128 if (bytes != null && bytes.length > 0) { 129 manager.write(bytes, this.immediateFlush || event.isEndOfBatch()); 130 } 131 } 132}