1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache license, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the license for the specific language governing permissions and
15 * limitations under the license.
16 */
17 package org.apache.logging.log4j.core.appender;
18
19 import java.io.Serializable;
20 import java.util.concurrent.locks.Lock;
21 import java.util.concurrent.locks.ReadWriteLock;
22 import java.util.concurrent.locks.ReentrantReadWriteLock;
23
24 import org.apache.logging.log4j.core.Filter;
25 import org.apache.logging.log4j.core.Layout;
26 import org.apache.logging.log4j.core.LogEvent;
27
28 /**
29 * Appends log events as bytes to a byte output stream. The stream encoding is defined in the layout.
30 *
31 * @param <M> The kind of {@link OutputStreamManager} under management
32 */
33 public abstract class AbstractOutputStreamAppender<M extends OutputStreamManager> extends AbstractAppender {
34
35 private static final long serialVersionUID = 1L;
36
37 /**
38 * Immediate flush means that the underlying writer or output stream
39 * will be flushed at the end of each append operation. Immediate
40 * flush is slower but ensures that each append request is actually
41 * written. If <code>immediateFlush</code> is set to
42 * {@code false}, then there is a good chance that the last few
43 * logs events are not actually written to persistent media if and
44 * when the application crashes.
45 */
46 protected final boolean immediateFlush;
47
48 private final M manager;
49
50 private final ReadWriteLock rwLock = new ReentrantReadWriteLock();
51 private final Lock readLock = rwLock.readLock();
52
53 /**
54 * Instantiate a WriterAppender and set the output destination to a
55 * new {@link java.io.OutputStreamWriter} initialized with <code>os</code>
56 * as its {@link java.io.OutputStream}.
57 * @param name The name of the Appender.
58 * @param layout The layout to format the message.
59 * @param manager The OutputStreamManager.
60 */
61 protected AbstractOutputStreamAppender(final String name, final Layout<? extends Serializable> layout, final Filter filter,
62 final boolean ignoreExceptions, final boolean immediateFlush,
63 final M manager) {
64 super(name, filter, layout, ignoreExceptions);
65 this.manager = manager;
66 this.immediateFlush = immediateFlush;
67 }
68
69 /**
70 * Gets the manager.
71 *
72 * @return the manager.
73 */
74 public M getManager() {
75 return manager;
76 }
77
78 @Override
79 public void start() {
80 if (getLayout() == null) {
81 LOGGER.error("No layout set for the appender named [" + getName() + "].");
82 }
83 if (manager == null) {
84 LOGGER.error("No OutputStreamManager set for the appender named [" + getName() + "].");
85 }
86 super.start();
87 }
88
89 @Override
90 public void stop() {
91 super.stop();
92 manager.release();
93 }
94
95 /**
96 * Actual writing occurs here.
97 * <p>
98 * Most subclasses of <code>AbstractOutputStreamAppender</code> will need to override this method.
99 * </p>
100 *
101 * @param event
102 * The LogEvent.
103 */
104 @Override
105 public void append(final LogEvent event) {
106 readLock.lock();
107 try {
108 final byte[] bytes = getLayout().toByteArray(event);
109 if (bytes.length > 0) {
110 manager.write(bytes);
111 if (this.immediateFlush || event.isEndOfBatch()) {
112 manager.flush();
113 }
114 }
115 } catch (final AppenderLoggingException ex) {
116 error("Unable to write to stream " + manager.getName() + " for appender " + getName());
117 throw ex;
118 } finally {
119 readLock.unlock();
120 }
121 }
122 }