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

org.appenders.log4j2.elasticsearch.hc.BatchRequest Maven / Gradle / Ivy

Go to download

Log4j2 Appender plugin pushing logs in batches to Elasticsearch (2.x/5.x/6.x/7.x/8.x) clusters

There is a newer version: 1.6.1
Show newest version
package org.appenders.log4j2.elasticsearch.hc;

/*-
 * #%L
 * log4j2-elasticsearch
 * %%
 * Copyright (C) 2019 Rafal Foltynski
 * %%
 * 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.
 * #L%
 */

import com.fasterxml.jackson.databind.ObjectWriter;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufOutputStream;
import org.appenders.log4j2.elasticsearch.ItemSource;

import java.io.IOException;
import java.io.OutputStream;
import java.util.Collection;
import java.util.concurrent.ConcurrentLinkedQueue;

/**
 * {@link org.appenders.log4j2.elasticsearch.ByteBufItemSource}-backed /_bulk request.
 * Allows to index multiple {@link org.appenders.log4j2.elasticsearch.hc.IndexRequest} documents
 * in a single request.
 */
public class BatchRequest implements Request {

    public static final String HTTP_METHOD_NAME = "POST";
    public static final char LINE_SEPARATOR = '\n';

    private final ObjectWriter objectWriter;
    private ItemSource buffer;

    protected final Collection indexRequests;

    protected BatchRequest(Builder builder) {
        this.indexRequests = builder.items;
        this.objectWriter = builder.objectWriter;
        this.buffer = builder.buffer;
    }

    /**
     * Serializes and writes {@link #indexRequests} into {@link #buffer}
     *
     * @return underlying buffer filled with serialized indexRequests
     * @throws IOException if serialization failed
     */
    public ItemSource serialize() throws IOException {

        ByteBufOutputStream byteBufOutputStream = new ByteBufOutputStream(buffer.getSource());

        // in current impl with no IDs, it's possible to reduce serialization by reusing first action
        IndexRequest identicalAction = uniformAction(indexRequests);
        byte[] actionTemplate = identicalAction != null ? objectWriter.writeValueAsBytes(identicalAction) : null;

        for (IndexRequest action : indexRequests) {

            if (actionTemplate == null) {
                objectWriter.writeValue((OutputStream) byteBufOutputStream, action);
            } else {
                byteBufOutputStream.write(actionTemplate);
            }
            byteBufOutputStream.writeByte(LINE_SEPARATOR);

            ByteBuf source = action.getSource().getSource();
            buffer.getSource().writeBytes(source);
            byteBufOutputStream.writeByte(LINE_SEPARATOR);

        }
        return buffer;
    }

    /**
     * Checks if all items in given collection are equal
     * ({@link IndexRequest#index} and {@link IndexRequest#type} are the same for all elements)
     *
     * @param indexRequests collection of items to be checked
     * @return {@link IndexRequest} first action in given collection if all items are equal, null otherwise
     */
    IndexRequest uniformAction(Collection indexRequests) {

        IndexRequest current = null;
        for (IndexRequest indexRequest : indexRequests) {
            if (current == null) {
                current = indexRequest;
                continue;
            }
            if (!current.index.equals(indexRequest.index) || !current.type.equals(indexRequest.type)) {
                // fail fast and serialize each item
                return null;
            }
        }
        return current;
    }

    /**
     * Clears underlying collection of indexRequests and releases all {@link ItemSource} instances.
     * 

MUST be called when request is completed. Otherwise it may lead to excessive resource usage and memory leaks */ public void completed() { for (IndexRequest indexRequest : indexRequests) { indexRequest.release(); } indexRequests.clear(); buffer.release(); buffer = null; } public Collection getIndexRequests() { return indexRequests; } @Override public String getURI() { return "/_bulk"; } @Override public String getHttpMethodName() { return HTTP_METHOD_NAME; } public static class Builder { protected final Collection items = new ConcurrentLinkedQueue<>(); private ItemSource buffer; private ObjectWriter objectWriter; public Builder add(IndexRequest item) { this.items.add(item); return this; } public Builder add(Collection items) { this.items.addAll(items); return this; } public BatchRequest build() { if (buffer == null) { throw new IllegalArgumentException("buffer cannot be null"); } if (objectWriter == null) { throw new IllegalArgumentException("objectWriter cannot be null"); } return new BatchRequest(this); } public Builder withBuffer(ItemSource buffer) { this.buffer = buffer; return this; } public Builder withObjectWriter(ObjectWriter objectWriter) { this.objectWriter = objectWriter; return this; } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy