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

org.appenders.log4j2.elasticsearch.ahc.AHCHttp 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

The newest version!
package org.appenders.log4j2.elasticsearch.ahc;

/*-
 * #%L
 * log4j2-elasticsearch
 * %%
 * Copyright (C) 2022 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 org.appenders.log4j2.elasticsearch.BatchOperations;
import org.appenders.log4j2.elasticsearch.LifeCycle;
import org.appenders.log4j2.elasticsearch.OperationFactory;
import org.appenders.log4j2.elasticsearch.ahc.failover.HCFailedItemOps;
import org.appenders.log4j2.elasticsearch.backoff.BackoffPolicy;
import org.appenders.log4j2.elasticsearch.failover.FailedItemOps;
import org.appenders.log4j2.elasticsearch.metrics.Measured;
import org.appenders.log4j2.elasticsearch.metrics.MetricConfig;
import org.appenders.log4j2.elasticsearch.metrics.MetricsRegistry;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;

import static org.appenders.core.logging.InternalLogging.getLogger;

/**
 * Creates {@link HttpClient} and batch handlers.
 */
public class AHCHttp extends BatchingClientObjectFactory {

    protected final BatchOperations batchOperations;
    protected final OperationFactory operationFactory;

    public AHCHttp(final Builder builder) {
        super(builder);
        this.batchOperations = builder.batchOperations;
        this.operationFactory = builder.operationFactory;
    }

    public static List metricConfigs(final boolean enabled) {
        return new ArrayList<>(BatchingClientMetrics.metricConfigs(enabled));
    }

    @Override
    public BatchOperations createBatchOperations() {
        return batchOperations;
    }

    @Override
    public OperationFactory setupOperationFactory() {
        return operationFactory;
    }

    protected ResponseHandler createResultHandler(final BatchRequest request, final Function failureHandler) {
        return new AHCResponseHandler(request, failureHandler);
    }

    public static class Builder extends BatchingClientObjectFactory.Builder {

        protected BatchOperations batchOperations;
        protected OperationFactory operationFactory;

        @Override
        public AHCHttp build() {
            return new AHCHttp(validate());
        }

        protected Builder validate() {
            super.validate();

            if (operationFactory == null) {
                throw new IllegalArgumentException(nullValidationExceptionMessage(OperationFactory.class.getSimpleName()));
            }

            if (batchOperations == null) {
                throw new IllegalArgumentException(nullValidationExceptionMessage(BatchOperations.class.getSimpleName()));
            }

            return this;

        }

        private String nullValidationExceptionMessage(final String className) {
            return String.format("No %s provided for %s", className, AHCHttp.class.getSimpleName());
        }

        protected FailedItemOps createFailedItemOps() {
            return new HCFailedItemOps();
        }

        @Override
        public final Builder withClientProvider(final HttpClientProvider clientProvider) {
            return (Builder) super.withClientProvider(clientProvider);
        }

        @Override
        public final Builder withBackoffPolicy(final BackoffPolicy backoffPolicy) {
            return (Builder) super.withBackoffPolicy(backoffPolicy);
        }

        @Override
        public final Builder withFailedItemOps(final FailedItemOps failedItemOps) {
            return (Builder) super.withFailedItemOps(failedItemOps);
        }

        public Builder withBatchOperations(final BatchOperations batchOperations) {
            this.batchOperations = batchOperations;
            return this;
        }

        public Builder withOperationFactory(final OperationFactory operationFactory) {
            this.operationFactory = operationFactory;
            return this;
        }

    }

    @Override
    public void startExtensions() {
        LifeCycle.of(batchOperations).start();
        LifeCycle.of(operationFactory).start();
    }

    @Override
    public void stopExtensions() {
        LifeCycle.of(batchOperations).stop();
        LifeCycle.of(operationFactory).stop();
    }

    @Override
    public void register(final MetricsRegistry registry) {
        super.register(registry);
        Measured.of(batchOperations).register(registry);
    }

    @Override
    public void deregister() {
        super.deregister();
        Measured.of(batchOperations).deregister();
    }

    private class AHCResponseHandler implements ResponseHandler {

        private final BatchRequest request;
        private final Function failureHandler;

        public AHCResponseHandler(final BatchRequest request, final Function failureHandler) {
            this.request = request;
            this.failureHandler = failureHandler;
        }

        @Override
        public void completed(final BatchResult result) {

            metrics.serverTookMs(result.getTook());

            backoffPolicy.deregister(request);

            if (!result.isSucceeded()) {
                // TODO: filter only failed indexRequests when retry is ready.
                // failing whole request for now
                failureHandler.apply(request);
            } else {
                metrics.itemsDelivered(request.size());
            }
            request.completed();

        }

        @Override
        public void failed(final Exception ex) {

            getLogger().warn(ex.getMessage(), ex);

            backoffPolicy.deregister(request);

            failureHandler.apply(request);
            request.completed();

        }

        @Override
        public BatchResult deserializeResponse(final InputStream responseBody) throws IOException {
            return request.deserialize(responseBody);
        }

    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy