org.appenders.log4j2.elasticsearch.ahc.AHCHttp Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of log4j2-elasticsearch-ahc Show documentation
Show all versions of log4j2-elasticsearch-ahc Show documentation
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);
}
}
}