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    
018    package org.apache.logging.log4j.io;
019    
020    import java.nio.CharBuffer;
021    
022    import org.apache.logging.log4j.Level;
023    import org.apache.logging.log4j.Marker;
024    import org.apache.logging.log4j.spi.ExtendedLogger;
025    
026    /**
027     * 
028     * @since 2.1
029     */
030    public class CharStreamLogger {
031        private final ExtendedLogger logger;
032        private final Level level;
033        private final Marker marker;
034        private final StringBuilder msg = new StringBuilder();
035        private boolean closed = false;
036    
037        public CharStreamLogger(final ExtendedLogger logger, final Level level, final Marker marker) {
038            this.logger = logger;
039            this.level = level == null ? logger.getLevel() : level;
040            this.marker = marker;
041        }
042    
043        public void close(final String fqcn) {
044            synchronized (this.msg) {
045                this.closed = true;
046                logEnd(fqcn);
047            }
048        }
049    
050        private void log(final String fqcn) {
051            // convert to string now so async loggers work
052            this.logger.logIfEnabled(fqcn, this.level, this.marker, this.msg.toString());
053            this.msg.setLength(0);
054        }
055    
056        private void logEnd(final String fqcn) {
057            if (this.msg.length() > 0) {
058                log(fqcn);
059            }
060        }
061    
062        public void put(final String fqcn, final char[] cbuf, final int off, final int len) {
063            put(fqcn, CharBuffer.wrap(cbuf), off, len);
064        }
065    
066        public void put(final String fqcn, final CharSequence str, final int off, final int len) {
067            if (len >= 0) {
068                synchronized (this.msg) {
069                    if (this.closed) {
070                        return;
071                    }
072                    int start = off;
073                    final int end = off + len;
074                    for (int pos = off; pos < end; pos++) {
075                        final char c = str.charAt(pos);
076                        switch (c) {
077                        case '\r':
078                        case '\n':
079                            this.msg.append(str, start, pos);
080                            start = pos + 1;
081                            if (c == '\n') {
082                                log(fqcn);
083                            }
084                            break;
085                        }
086                    }
087                    this.msg.append(str, start, end);
088                }
089            } else {
090                logEnd(fqcn);
091            }
092        }
093    
094        public void put(final String fqcn, final int c) {
095            if (c >= 0) {
096                synchronized (this.msg) {
097                    if (this.closed) {
098                        return;
099                    }
100                    switch (c) {
101                    case '\n':
102                        log(fqcn);
103                        break;
104                    case '\r':
105                        break;
106                    default:
107                        this.msg.append((char) c);
108                    }
109                }
110            } else {
111                logEnd(fqcn);
112            }
113        }
114    }