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