View Javadoc

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.IOException;
20  import java.io.OutputStream;
21  
22  /**
23   * Manage an OutputStream so that it can be shared by multiple Appenders and will
24   * allow appenders to reconfigure without requiring a new stream.
25   */
26  public class OutputStreamManager extends AbstractManager {
27  
28      private OutputStream os;
29  
30      private byte[] footer = null;
31  
32      protected OutputStreamManager(final OutputStream os, final String streamName) {
33          super(streamName);
34          this.os = os;
35      }
36  
37      /**
38       * Create a Manager.
39       *
40       * @param name The name of the stream to manage.
41       * @param data The data to pass to the Manager.
42       * @param factory The factory to use to create the Manager.
43       * @param <T> The type of the OutputStreamManager.
44       * @return An OutputStreamManager.
45       */
46      public static <T> OutputStreamManager getManager(final String name, final T data,
47                                                   final ManagerFactory<? extends OutputStreamManager, T> factory) {
48          return AbstractManager.getManager(name, factory, data);
49      }
50  
51      /**
52       * Set the header to write when the stream is opened.
53       * @param header The header.
54       */
55      public synchronized void setHeader(final byte[] header) {
56          if (header != null) {
57              try {
58                  this.os.write(header, 0, header.length);
59              } catch (final IOException ioe) {
60                  LOGGER.error("Unable to write header", ioe);
61              }
62          }
63      }
64  
65      /**
66       * Set the footer to write when the stream is closed.
67       * @param footer The footer.
68       */
69      public synchronized void setFooter(final byte[] footer) {
70          if (footer != null) {
71              this.footer = footer;
72          }
73      }
74  
75      /**
76       * Default hook to write footer during close.
77       */
78      @Override
79      public void releaseSub() {
80          if (footer != null) {
81              write(footer);
82          }
83          close();
84      }
85  
86      /**
87       * Returns the status of the stream.
88       * @return true if the stream is open, false if it is not.
89       */
90      public boolean isOpen() {
91          return getCount() > 0;
92      }
93  
94      protected OutputStream getOutputStream() {
95          return os;
96      }
97  
98      protected void setOutputStream(final OutputStream os) {
99          this.os = os;
100     }
101 
102     /**
103      * Some output streams synchronize writes while others do not. Synchronizing here insures that
104      * log events won't be intertwined.
105      * @param bytes The serialized Log event.
106      * @param offset The offset into the byte array.
107      * @param length The number of bytes to write.
108      * @throws AppenderRuntimeException if an error occurs.
109      */
110     protected synchronized void write(final byte[] bytes, final int offset, final int length)  {
111         //System.out.println("write " + count);
112         try {
113             os.write(bytes, offset, length);
114         } catch (final IOException ex) {
115             final String msg = "Error writing to stream " + getName();
116             throw new AppenderRuntimeException(msg, ex);
117         }
118     }
119 
120     /**
121      * Some output streams synchronize writes while others do not. Synchronizing here insures that
122      * log events won't be intertwined.
123      * @param bytes The serialized Log event.
124      * @throws AppenderRuntimeException if an error occurs.
125      */
126     protected void write(final byte[] bytes)  {
127         write(bytes, 0, bytes.length);
128     }
129 
130     protected void close() {
131         if (os == System.out || os == System.err) {
132             return;
133         }
134         try {
135             os.close();
136         } catch (final IOException ex) {
137             LOGGER.error("Unable to close stream " + getName() + ". " + ex);
138         }
139     }
140 
141     /**
142      * Flush any buffers.
143      */
144     public void flush() {
145         try {
146             os.flush();
147         } catch (final IOException ex) {
148             final String msg = "Error flushing stream " + getName();
149             throw new AppenderRuntimeException(msg, ex);
150         }
151     }
152 }