All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.logstash.logback.layout.CompositeJsonLayout Maven / Gradle / Ivy

/*
 * Copyright 2013-2022 the original author or authors.
 *
 * 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 permissions and
 * limitations under the License.
 */
package net.logstash.logback.layout;

import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.Objects;

import net.logstash.logback.composite.AbstractCompositeJsonFormatter;
import net.logstash.logback.composite.JsonProviders;
import net.logstash.logback.decorate.JsonFactoryDecorator;
import net.logstash.logback.decorate.JsonGeneratorDecorator;
import net.logstash.logback.encoder.CompositeJsonEncoder;
import net.logstash.logback.encoder.SeparatorParser;
import net.logstash.logback.util.ReusableByteBuffer;
import net.logstash.logback.util.ThreadLocalReusableByteBuffer;

import ch.qos.logback.core.Layout;
import ch.qos.logback.core.LayoutBase;
import ch.qos.logback.core.pattern.PatternLayoutBase;
import ch.qos.logback.core.spi.DeferredProcessingAware;


public abstract class CompositeJsonLayout extends LayoutBase {

    private boolean immediateFlush = true;

    private Layout prefix;
    private Layout suffix;

    /**
     * Separator to use between events.
     *
     * 

By default, this is null (for backwards compatibility), indicating no separator. * Note that this default is different than the default of {@link CompositeJsonEncoder#lineSeparator}. * In a future major release, the default will likely change to be the same as {@link CompositeJsonEncoder#lineSeparator}.

*/ private String lineSeparator; /** * The minimum size of the byte buffer used when encoding events. * *

The buffer automatically grows above the {@code #minBufferSize} when needed to * accommodate with larger events. However, only the first {@code minBufferSize} bytes * will be reused by subsequent invocations. It is therefore strongly advised to set * the minimum size at least equal to the average size of the encoded events to reduce * unnecessary memory allocations and reduce pressure on the garbage collector. */ private int minBufferSize = 1024; /** * Per-thread {@link ReusableByteBuffer} */ private ThreadLocalReusableByteBuffer threadLocalBuffer; private final AbstractCompositeJsonFormatter formatter; public CompositeJsonLayout() { super(); this.formatter = Objects.requireNonNull(createFormatter()); } protected abstract AbstractCompositeJsonFormatter createFormatter(); @Override public String doLayout(Event event) { if (!isStarted()) { throw new IllegalStateException("Layout is not started"); } ReusableByteBuffer buffer = threadLocalBuffer.acquire(); try { writeEvent(buffer, event); return new String(buffer.toByteArray()); } catch (IOException e) { addWarn("Error formatting logging event", e); return null; } finally { threadLocalBuffer.release(); } } private void writeEvent(OutputStream outputStream, Event event) throws IOException { try (Writer writer = new OutputStreamWriter(outputStream)) { writeLayout(prefix, writer, event); formatter.writeEvent(event, outputStream); writeLayout(suffix, writer, event); if (lineSeparator != null) { writer.write(lineSeparator); } writer.flush(); } } private void writeLayout(Layout wrapped, Writer writer, Event event) throws IOException { if (wrapped == null) { return; } String str = wrapped.doLayout(event); if (str != null) { writer.write(str); writer.flush(); } } @Override public void start() { if (isStarted()) { return; } super.start(); formatter.setContext(getContext()); formatter.start(); startWrapped(prefix); startWrapped(suffix); this.threadLocalBuffer = new ThreadLocalReusableByteBuffer(minBufferSize); } private void startWrapped(Layout wrapped) { if (wrapped instanceof PatternLayoutBase) { /* * Don't ensure exception output (for ILoggingEvents) * or line separation (for IAccessEvents) */ PatternLayoutBase layout = (PatternLayoutBase) wrapped; layout.setPostCompileProcessor(null); /* * The pattern will be re-parsed during start. * Needed so that the pattern is re-parsed without * the postCompileProcessor. */ layout.start(); } if (wrapped != null && !wrapped.isStarted()) { wrapped.start(); } } @Override public void stop() { if (!isStarted()) { return; } super.stop(); formatter.stop(); stopWrapped(prefix); stopWrapped(suffix); this.threadLocalBuffer = null; } private void stopWrapped(Layout wrapped) { if (wrapped != null && !wrapped.isStarted()) { wrapped.stop(); } } public JsonProviders getProviders() { return formatter.getProviders(); } public void setProviders(JsonProviders jsonProviders) { formatter.setProviders(jsonProviders); } public boolean isImmediateFlush() { return immediateFlush; } public void setImmediateFlush(boolean immediateFlush) { this.immediateFlush = immediateFlush; } public JsonFactoryDecorator getJsonFactoryDecorator() { return formatter.getJsonFactoryDecorator(); } public void setJsonFactoryDecorator(JsonFactoryDecorator jsonFactoryDecorator) { formatter.setJsonFactoryDecorator(jsonFactoryDecorator); } public JsonGeneratorDecorator getJsonGeneratorDecorator() { return formatter.getJsonGeneratorDecorator(); } public void setJsonGeneratorDecorator(JsonGeneratorDecorator jsonGeneratorDecorator) { formatter.setJsonGeneratorDecorator(jsonGeneratorDecorator); } public void setFindAndRegisterJacksonModules(boolean findAndRegisterJacksonModules) { formatter.setFindAndRegisterJacksonModules(findAndRegisterJacksonModules); } protected AbstractCompositeJsonFormatter getFormatter() { return formatter; } public Layout getPrefix() { return prefix; } public void setPrefix(Layout prefix) { this.prefix = prefix; } public Layout getSuffix() { return suffix; } public void setSuffix(Layout suffix) { this.suffix = suffix; } public String getLineSeparator() { return lineSeparator; } /** * Sets which lineSeparator to use between events. * * The following values have special meaning: *

    *
  • {@code null} or empty string = no new line. (default)
  • *
  • "{@code SYSTEM}" = operating system new line.
  • *
  • "{@code UNIX}" = unix line ending ({@code \n}).
  • *
  • "{@code WINDOWS}" = windows line ending ({@code \r\n}).
  • *
* * Any other value will be used as given as the lineSeparator. * * @param lineSeparator the separator format */ public void setLineSeparator(String lineSeparator) { this.lineSeparator = SeparatorParser.parseSeparator(lineSeparator); } public int getMinBufferSize() { return minBufferSize; } /** * The minimum size of the byte buffer used when encoding events. * *

The buffer automatically grows above the {@code #minBufferSize} when needed to * accommodate with larger events. However, only the first {@code minBufferSize} bytes * will be reused by subsequent invocations. It is therefore strongly advised to set * the minimum size at least equal to the average size of the encoded events to reduce * unnecessary memory allocations and reduce pressure on the garbage collector. * *

Note: changes to the buffer size will not be taken into account after the encoder * is started. * * @param minBufferSize the minimum buffer size (in bytes) */ public void setMinBufferSize(int minBufferSize) { this.minBufferSize = minBufferSize; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy