    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    }