@Override public CheckResult check() { return sender.check(); }
Builder(Sender sender) { if (sender == null) throw new NullPointerException("sender == null"); this.sender = sender; this.messageMaxBytes = sender.messageMaxBytes(); }
@Override public boolean accept(byte[] next) { buffer.add(next); // speculatively add to the buffer so we can size it int x = sender.messageSizeInBytes(buffer); int y = maxBytes; int includingNextVsMaxBytes = (x < y) ? -1 : ((x == y) ? 0 : 1); // If we can fit queued spans and the next into one message... if (includingNextVsMaxBytes <= 0) { sizeInBytes = x; if (includingNextVsMaxBytes == 0) { bufferFull = true; } return true; } else { buffer.remove(buffer.size() - 1); return false; // we couldn't fit the next message into this buffer } }
void flush(BufferNextMessage bundler) { if (closed.get()) throw new IllegalStateException("closed"); pending.drainTo(bundler, bundler.remainingNanos()); // record after flushing reduces the amount of gauge events vs on doing this on report metrics.updateQueuedSpans(pending.count); metrics.updateQueuedBytes(pending.sizeInBytes); // loop around if we are running, and the bundle isn't full // if we are closed, try to send what's pending if (!bundler.isReady() && !closed.get()) return; // Signal that we are about to send a message of a known size in bytes metrics.incrementMessages(); metrics.incrementMessageBytes(bundler.sizeInBytes()); List<byte[]> nextMessage = bundler.drain(); // In failure case, we increment messages and spans dropped. Callback failureCallback = sendSpansCallback(nextMessage.size()); try { sender.sendSpans(nextMessage, failureCallback); } catch (RuntimeException e) { failureCallback.onError(e); // Raise in case the sender was closed out-of-band. if (e instanceof IllegalStateException) throw e; } }
/** Returns true if the was encoded and accepted onto the queue. */ @Override public void report(S span) { if (span == null) throw new NullPointerException("span == null"); metrics.incrementSpans(1); byte[] next = encoder.encode(span); int messageSizeOfNextSpan = sender.messageSizeInBytes(Collections.singletonList(next)); metrics.incrementSpanBytes(next.length); if (closed.get() || // don't enqueue something larger than we can drain messageSizeOfNextSpan > messageMaxBytes || !pending.offer(next)) { metrics.incrementSpansDropped(1); } }
/** Builds an async reporter that encodes zipkin spans as they are reported. */ public AsyncReporter<Span> build() { switch (sender.encoding()) { case JSON: return build(Encoder.JSON); case THRIFT: return build(Encoder.THRIFT); default: throw new UnsupportedOperationException(sender.encoding().name()); } }
/** * Maximum bytes sendable per message including overhead. Defaults to, and is limited by {@link * Sender#messageMaxBytes()}. */ public Builder messageMaxBytes(int messageMaxBytes) { if (messageMaxBytes < 0) { throw new IllegalArgumentException("messageMaxBytes < 0: " + messageMaxBytes); } this.messageMaxBytes = Math.min(messageMaxBytes, sender.messageMaxBytes()); return this; }
/** Builds an async reporter that encodes arbitrary spans as they are reported. */ public <S> AsyncReporter<S> build(Encoder<S> encoder) { if (encoder == null) throw new NullPointerException("encoder == null"); if (encoder.encoding() != sender.encoding()) { throw new IllegalArgumentException(String.format( "Encoder doesn't match Sender: %s %s", encoder.encoding(), sender.encoding())); } final BoundedAsyncReporter<S> result = new BoundedAsyncReporter<>(this, encoder); if (messageTimeoutNanos > 0) { // Start a thread that flushes the queue in a loop. final BufferNextMessage consumer = new BufferNextMessage(sender, messageMaxBytes, messageTimeoutNanos); final Thread flushThread = new Thread(() -> { try { while (!result.closed.get()) { result.flush(consumer); } } finally { for (byte[] next : consumer.drain()) result.pending.offer(next); result.close.countDown(); } }, "AsyncReporter(" + sender + ")"); flushThread.setDaemon(true); flushThread.start(); } return result; } }