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