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.net.server;
18  
19  import java.io.IOException;
20  import java.io.InputStream;
21  import java.nio.charset.Charset;
22  
23  import org.apache.logging.log4j.core.LogEvent;
24  import org.apache.logging.log4j.core.LogEventListener;
25  import org.apache.logging.log4j.core.impl.Log4jLogEvent;
26  import org.apache.logging.log4j.util.Strings;
27  
28  import com.fasterxml.jackson.databind.ObjectMapper;
29  import com.fasterxml.jackson.databind.ObjectReader;
30  
31  /**
32   * Reads and logs {@link LogEvent}s from an {@link InputStream}.
33   */
34  public abstract class InputStreamLogEventBridge extends AbstractLogEventBridge<InputStream> {
35  
36      private final int bufferSize;
37  
38      private final Charset charset;
39  
40      private final String eventEndMarker;
41      
42      private final ObjectReader objectReader;
43      
44      public InputStreamLogEventBridge(final ObjectMapper mapper, final int bufferSize, final Charset charset, final String eventEndMarker) {
45          this.bufferSize = bufferSize;
46          this.charset = charset;
47          this.eventEndMarker = eventEndMarker;
48          this.objectReader = mapper.reader(Log4jLogEvent.class);
49      }
50  
51      abstract protected int[] getEventIndices(final String text, int beginIndex);
52  
53      @Override
54      public void logEvents(final InputStream inputStream, final LogEventListener logEventListener) throws IOException {
55          String workingText = Strings.EMPTY;
56          try {
57              // Allocate buffer once
58              final byte[] buffer = new byte[bufferSize];
59              String textRemains = workingText = Strings.EMPTY;
60              while (true) {
61                  // Process until the stream is EOF.
62                  final int streamReadLength = inputStream.read(buffer);
63                  if (streamReadLength == END) {
64                      // The input stream is EOF
65                      break;
66                  }
67                  final String text = workingText = textRemains + new String(buffer, 0, streamReadLength, charset);
68                  int beginIndex = 0;
69                  while (true) {
70                      // Extract and log all XML events in the buffer
71                      final int[] pair = getEventIndices(text, beginIndex);
72                      final int eventStartMarkerIndex = pair[0];
73                      if (eventStartMarkerIndex < 0) {
74                          // No more events or partial XML only in the buffer.
75                          // Save the unprocessed string part
76                          textRemains = text.substring(beginIndex);
77                          break;
78                      }
79                      final int eventEndMarkerIndex = pair[1];
80                      if (eventEndMarkerIndex > 0) {
81                          final int eventEndXmlIndex = eventEndMarkerIndex + eventEndMarker.length();
82                          final String textEvent = workingText = text.substring(eventStartMarkerIndex, eventEndXmlIndex);
83                          final LogEvent logEvent = unmarshal(textEvent);
84                          logEventListener.log(logEvent);
85                          beginIndex = eventEndXmlIndex;
86                      } else {
87                          // No more events or partial XML only in the buffer.
88                          // Save the unprocessed string part
89                          textRemains = text.substring(beginIndex);
90                          break;
91                      }
92                  }
93              }
94          } catch (final IOException ex) {
95              logger.error(workingText, ex);
96          }
97      }
98  
99      protected Log4jLogEvent unmarshal(final String jsonEvent) throws IOException {
100         return this.objectReader.readValue(jsonEvent);
101     }
102 
103 }