blob: bf76e47b25a3d714245fb5b8f6d1849b07e68c43 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache license, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the license for the specific language governing permissions and
* limitations under the license.
*/
package org.apache.logging.log4j.core.appender;
import java.io.IOException;
import java.io.Writer;
import java.util.concurrent.TimeUnit;
import org.apache.logging.log4j.core.StringLayout;
/**
* Manages a Writer so that it can be shared by multiple Appenders and will
* allow appenders to reconfigure without requiring a new writer.
*/
public class WriterManager extends AbstractManager {
/**
* Creates a Manager.
*
* @param name The name of the stream to manage.
* @param data The data to pass to the Manager.
* @param factory The factory to use to create the Manager.
* @param <T> The type of the WriterManager.
* @return A WriterManager.
*/
public static <T> WriterManager getManager(final String name, final T data,
final ManagerFactory<? extends WriterManager, T> factory) {
return AbstractManager.getManager(name, factory, data);
}
protected final StringLayout layout;
private volatile Writer writer;
public WriterManager(final Writer writer, final String streamName, final StringLayout layout,
final boolean writeHeader) {
super(null, streamName);
this.writer = writer;
this.layout = layout;
if (writeHeader && layout != null) {
final byte[] header = layout.getHeader();
if (header != null) {
try {
this.writer.write(new String(header, layout.getCharset()));
} catch (final IOException e) {
logError("Unable to write header", e);
}
}
}
}
protected synchronized void closeWriter() {
final Writer w = writer; // access volatile field only once per method
try {
w.close();
} catch (final IOException ex) {
logError("Unable to close stream", ex);
}
}
/**
* Flushes any buffers.
*/
public synchronized void flush() {
try {
writer.flush();
} catch (final IOException ex) {
final String msg = "Error flushing stream " + getName();
throw new AppenderLoggingException(msg, ex);
}
}
protected Writer getWriter() {
return writer;
}
/**
* Returns the status of the stream.
* @return true if the stream is open, false if it is not.
*/
public boolean isOpen() {
return getCount() > 0;
}
/**
* Default hook to write footer during close.
*/
@Override
public boolean releaseSub(final long timeout, final TimeUnit timeUnit) {
writeFooter();
closeWriter();
return true;
}
protected void setWriter(final Writer writer) {
final byte[] header = layout.getHeader();
if (header != null) {
try {
writer.write(new String(header, layout.getCharset()));
this.writer = writer; // only update field if writer.write() succeeded
} catch (final IOException ioe) {
logError("Unable to write header", ioe);
}
} else {
this.writer = writer;
}
}
/**
* Some output streams synchronize writes while others do not. Synchronizing here insures that
* log events won't be intertwined.
* @param str the string to write
* @throws AppenderLoggingException if an error occurs.
*/
protected synchronized void write(final String str) {
try {
writer.write(str);
} catch (final IOException ex) {
final String msg = "Error writing to stream " + getName();
throw new AppenderLoggingException(msg, ex);
}
}
/**
* Writes the footer.
*/
protected void writeFooter() {
if (layout == null) {
return;
}
final byte[] footer = layout.getFooter();
if (footer != null && footer.length > 0) {
write(new String(footer, layout.getCharset()));
}
}
}