// Path: layout/src/main/java/com/vlkan/log4j2/logstash/layout/util/BufferedPrintWriter.java
// public final class BufferedPrintWriter extends PrintWriter {
// 
//     private final BufferedWriter bufferedWriter;
// 
//     private BufferedPrintWriter(BufferedWriter bufferedWriter) {
//         super(bufferedWriter, false);
//         this.bufferedWriter = bufferedWriter;
//     }
// 
//     public static BufferedPrintWriter ofCapacity(int capacity) {
//         BufferedWriter bufferedWriter = new BufferedWriter(capacity);
//         return new BufferedPrintWriter(bufferedWriter);
//     }
// 
//     public char[] getBuffer() {
//         return bufferedWriter.getBuffer();
//     }
// 
//     public int getPosition() {
//         return bufferedWriter.getPosition();
//     }
// 
//     public int getCapacity() {
//         return bufferedWriter.getCapacity();
//     }
// 
//     public boolean isOverflow() {
//         return bufferedWriter.isOverflow();
//     }
// 
//     @Override
//     public void close() {
//         bufferedWriter.close();
//     }
// 
// }


import com.fasterxml.jackson.core.JsonGenerator;
import com.vlkan.log4j2.logstash.layout.util.BufferedPrintWriter;
import org.apache.logging.log4j.util.Constants;
import java.io.IOException;
import java.util.function.Supplier;
/*
 * Copyright 2017-2020 Volkan Yazıcı
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permits and
 * limitations under the License.
 */

package com.vlkan.log4j2.logstash.layout.resolver;



class StackTraceTextResolver implements StackTraceResolver {

    private final Supplier<BufferedPrintWriter> writerSupplier;

    private final ThreadLocal<BufferedPrintWriter> writerRef;

    StackTraceTextResolver(int writerCapacity) {
        this.writerSupplier = () -> BufferedPrintWriter.ofCapacity(writerCapacity);
        this.writerRef = Constants.ENABLE_THREADLOCALS
                ? ThreadLocal.withInitial(writerSupplier)
                : null;
    }

    @Override
    public void resolve(Throwable throwable, JsonGenerator jsonGenerator) throws IOException {
        BufferedPrintWriter writer = getResetWriter();
        Throwable lastThrowable = throwable;
        while (true) {
            try {
                lastThrowable.printStackTrace(writer);
                break;
            }
            // It is indeed not a good practice to catch `Throwable`s, but what
            // one should do while trying to dump the stack trace of a failure?
            // Hence, if `Throwable#printStackTrace(PrintWriter)` fails for some
            // reason, at least try to dump the reason of the failure.
            catch (Throwable newThrowable) {
                writer.close();
                lastThrowable = newThrowable;
            }
        }
        jsonGenerator.writeString(writer.getBuffer(), 0, writer.getPosition());
    }

    private BufferedPrintWriter getResetWriter() {
        BufferedPrintWriter writer;
        if (Constants.ENABLE_THREADLOCALS) {
// Path: layout/src/main/java/com/vlkan/log4j2/logstash/layout/util/BufferedPrintWriter.java
// public final class BufferedPrintWriter extends PrintWriter {
// 
//     private final BufferedWriter bufferedWriter;
// 
//     private BufferedPrintWriter(BufferedWriter bufferedWriter) {
//         super(bufferedWriter, false);
//         this.bufferedWriter = bufferedWriter;
//     }
// 
//     public static BufferedPrintWriter ofCapacity(int capacity) {
//         BufferedWriter bufferedWriter = new BufferedWriter(capacity);
//         return new BufferedPrintWriter(bufferedWriter);
//     }
// 
//     public char[] getBuffer() {
//         return bufferedWriter.getBuffer();
//     }
// 
//     public int getPosition() {
//         return bufferedWriter.getPosition();
//     }
// 
//     public int getCapacity() {
//         return bufferedWriter.getCapacity();
//     }
// 
//     public boolean isOverflow() {
//         return bufferedWriter.isOverflow();
//     }
// 
//     @Override
//     public void close() {
//         bufferedWriter.close();
//     }
// 
// }


// Path: layout/src/main/java/com/vlkan/log4j2/logstash/layout/resolver/StackTraceTextResolver.java
import com.fasterxml.jackson.core.JsonGenerator;
import com.vlkan.log4j2.logstash.layout.util.BufferedPrintWriter;
import org.apache.logging.log4j.util.Constants;
import java.io.IOException;
import java.util.function.Supplier;

/*
 * Copyright 2017-2020 Volkan Yazıcı
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permits and
 * limitations under the License.
 */

package com.vlkan.log4j2.logstash.layout.resolver;



class StackTraceTextResolver implements StackTraceResolver {

    private final Supplier<BufferedPrintWriter> writerSupplier;

    private final ThreadLocal<BufferedPrintWriter> writerRef;

    StackTraceTextResolver(int writerCapacity) {
        this.writerSupplier = () -> BufferedPrintWriter.ofCapacity(writerCapacity);
        this.writerRef = Constants.ENABLE_THREADLOCALS
                ? ThreadLocal.withInitial(writerSupplier)
                : null;
    }

    @Override
    public void resolve(Throwable throwable, JsonGenerator jsonGenerator) throws IOException {
        BufferedPrintWriter writer = getResetWriter();
        Throwable lastThrowable = throwable;
        while (true) {
            try {
                lastThrowable.printStackTrace(writer);
                break;
            }
            // It is indeed not a good practice to catch `Throwable`s, but what
            // one should do while trying to dump the stack trace of a failure?
            // Hence, if `Throwable#printStackTrace(PrintWriter)` fails for some
            // reason, at least try to dump the reason of the failure.
            catch (Throwable newThrowable) {
                writer.close();
                lastThrowable = newThrowable;
            }
        }
        jsonGenerator.writeString(writer.getBuffer(), 0, writer.getPosition());
    }

    private BufferedPrintWriter getResetWriter() {
        BufferedPrintWriter writer;
        if (Constants.ENABLE_THREADLOCALS) {
            writer = writerRef.get();