001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache license, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the license for the specific language governing permissions and 015 * limitations under the license. 016 */ 017 package org.apache.logging.log4j.core.net.server; 018 019 import java.io.IOException; 020 import java.io.InputStream; 021 import java.nio.charset.Charset; 022 023 import org.apache.logging.log4j.core.LogEvent; 024 import org.apache.logging.log4j.core.LogEventListener; 025 import org.apache.logging.log4j.core.impl.Log4jLogEvent; 026 import org.apache.logging.log4j.util.Strings; 027 028 import com.fasterxml.jackson.databind.ObjectMapper; 029 import com.fasterxml.jackson.databind.ObjectReader; 030 031 /** 032 * Reads and logs {@link LogEvent}s from an {@link InputStream}. 033 */ 034 public abstract class InputStreamLogEventBridge extends AbstractLogEventBridge<InputStream> { 035 036 private final int bufferSize; 037 038 private final Charset charset; 039 040 private final String eventEndMarker; 041 042 private final ObjectReader objectReader; 043 044 public InputStreamLogEventBridge(final ObjectMapper mapper, final int bufferSize, final Charset charset, final String eventEndMarker) { 045 this.bufferSize = bufferSize; 046 this.charset = charset; 047 this.eventEndMarker = eventEndMarker; 048 this.objectReader = mapper.reader(Log4jLogEvent.class); 049 } 050 051 abstract protected int[] getEventIndices(final String text, int beginIndex); 052 053 @Override 054 public void logEvents(final InputStream inputStream, final LogEventListener logEventListener) throws IOException { 055 String workingText = Strings.EMPTY; 056 try { 057 // Allocate buffer once 058 final byte[] buffer = new byte[bufferSize]; 059 String textRemains = workingText = Strings.EMPTY; 060 while (true) { 061 // Process until the stream is EOF. 062 final int streamReadLength = inputStream.read(buffer); 063 if (streamReadLength == END) { 064 // The input stream is EOF 065 break; 066 } 067 final String text = workingText = textRemains + new String(buffer, 0, streamReadLength, charset); 068 int beginIndex = 0; 069 while (true) { 070 // Extract and log all XML events in the buffer 071 final int[] pair = getEventIndices(text, beginIndex); 072 final int eventStartMarkerIndex = pair[0]; 073 if (eventStartMarkerIndex < 0) { 074 // No more events or partial XML only in the buffer. 075 // Save the unprocessed string part 076 textRemains = text.substring(beginIndex); 077 break; 078 } 079 final int eventEndMarkerIndex = pair[1]; 080 if (eventEndMarkerIndex > 0) { 081 final int eventEndXmlIndex = eventEndMarkerIndex + eventEndMarker.length(); 082 final String textEvent = workingText = text.substring(eventStartMarkerIndex, eventEndXmlIndex); 083 final LogEvent logEvent = unmarshal(textEvent); 084 logEventListener.log(logEvent); 085 beginIndex = eventEndXmlIndex; 086 } else { 087 // No more events or partial XML only in the buffer. 088 // Save the unprocessed string part 089 textRemains = text.substring(beginIndex); 090 break; 091 } 092 } 093 } 094 } catch (final IOException ex) { 095 logger.error(workingText, ex); 096 } 097 } 098 099 protected Log4jLogEvent unmarshal(final String jsonEvent) throws IOException { 100 return this.objectReader.readValue(jsonEvent); 101 } 102 103 }