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