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

zipkin2.reporter.BaseHttpSender Maven / Gradle / Ivy

The newest version!
/*
 * Copyright The OpenZipkin Authors
 * SPDX-License-Identifier: Apache-2.0
 */
package zipkin2.reporter;

import java.io.IOException;
import java.net.URI;
import java.net.URL;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Logger;
import zipkin2.reporter.HttpEndpointSupplier.Factory;

import static zipkin2.reporter.Call.propagateIfFatal;

/**
 * Reports spans to Zipkin, using its POST endpoint.
 *
 * 

Calls to {@linkplain #postSpans(Object, Object)} happen on the same async reporting thread, * but {@linkplain #close()} might be called from any thread. * * @param The URL type for the HTTP client, such as {@linkplain URL} or {@linkplain URI}. * @param The POST body, such as {@code byte[]} or an HTTP client-specific body type. * @since 3.3 */ public abstract class BaseHttpSender extends BytesMessageSender.Base { final Logger logger; final HttpEndpointSupplier endpointSupplier; final U endpoint; /** close is typically called from a different thread */ final AtomicBoolean closeCalled = new AtomicBoolean(); /** * Called each invocation of {@linkplain #postSpans(Object, Object)}, unless the * {@linkplain HttpEndpointSupplier} is a {@linkplain HttpEndpointSupplier.Constant}, * Implementations should perform any validation needed here. * * @since 3.3 */ protected abstract U newEndpoint(String endpoint); /** * Creates a new POST body from the encoded spans. * *

Below is the simplest implementation, when {@linkplain BaseHttpSender#} is a byte array. *

{@code
   * @Override protected byte[] newBody(List encodedSpans) {
   *   return encoding.encode(encodedSpans);
   * }
   * }
* *

If you need the "Content-Type" value, you can access it via {@link Encoding#mediaType()}. * * @since 3.3 */ protected abstract B newBody(List encodedSpans) throws IOException; /** * Implement to POST spans to the given endpoint. * *

If you need the "Content-Type" value, you can access it via {@link Encoding#mediaType()}. * * @since 3.3 */ protected abstract void postSpans(U endpoint, B body) throws IOException; /** * Override to close any resources. * * @since 3.3 */ protected void doClose() { } protected BaseHttpSender(Encoding encoding, Factory endpointSupplierFactory, String endpoint) { this(Logger.getLogger(BaseHttpSender.class.getName()), encoding, endpointSupplierFactory, endpoint); } BaseHttpSender(Logger logger, Encoding encoding, Factory endpointSupplierFactory, String endpoint) { super(encoding); this.logger = logger; if (endpointSupplierFactory == null) { throw new NullPointerException("endpointSupplierFactory == null"); } if (endpoint == null) throw new NullPointerException("endpoint == null"); HttpEndpointSupplier endpointSupplier = endpointSupplierFactory.create(endpoint); if (endpointSupplier == null) { throw new NullPointerException("endpointSupplierFactory.create() returned null"); } if (endpointSupplier instanceof HttpEndpointSupplier.Constant) { this.endpoint = nextEndpoint(endpointSupplier); closeQuietly(endpointSupplier); this.endpointSupplier = null; } else { this.endpoint = null; this.endpointSupplier = endpointSupplier; } } final U nextEndpoint(HttpEndpointSupplier endpointSupplier) { String endpoint = endpointSupplier.get(); // eagerly resolve the endpoint if (endpoint == null) throw new NullPointerException("endpointSupplier.get() returned null"); return newEndpoint(endpoint); } /** Defaults to the most common max message size: 512KB. */ @Override public int messageMaxBytes() { return 512 * 1024; } /** Sends spans as an HTTP POST request. */ @Override public final void send(List encodedSpans) throws IOException { if (closeCalled.get()) throw new ClosedSenderException(); U endpoint = this.endpoint; if (endpoint == null) endpoint = nextEndpoint(endpointSupplier); B body = newBody(encodedSpans); if (body == null) throw new NullPointerException("newBody(encodedSpans) returned null"); postSpans(endpoint, body); } @Override public final void close() { if (!closeCalled.compareAndSet(false, true)) return; // already closed closeQuietly(endpointSupplier); doClose(); } final void closeQuietly(HttpEndpointSupplier endpointSupplier) { if (endpointSupplier == null) return; try { endpointSupplier.close(); } catch (Throwable t) { propagateIfFatal(t); logger.fine("ignoring error closing endpoint supplier: " + t.getMessage()); } } @Override public String toString() { String name = getClass().getSimpleName(); if (endpoint != null) { return name + "{" + endpoint + "}"; } return name + "{" + endpointSupplier + "}"; } }