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