/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
package gobblin.metrics.reporter;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.io.UnsupportedEncodingException;
import java.text.DateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.Queue;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.base.Charsets;
import gobblin.metrics.GobblinTrackingEvent;
import gobblin.metrics.MetricContext;
import gobblin.metrics.reporter.util.AvroJsonSerializer;
import gobblin.metrics.reporter.util.AvroSerializer;
import gobblin.metrics.reporter.util.NoopSchemaVersionWriter;
/**
* {@link gobblin.metrics.reporter.EventReporter} that writes {@link gobblin.metrics.GobblinTrackingEvent}s to an
* {@link java.io.OutputStream}.
*/
public class OutputStreamEventReporter extends EventReporter {
private static final Logger LOGGER = LoggerFactory.getLogger(OutputStreamEventReporter.class);
private static final int CONSOLE_WIDTH = 80;
private final PrintStream output;
protected final AvroSerializer<GobblinTrackingEvent> serializer;
private final ByteArrayOutputStream outputBuffer;
private final PrintStream outputBufferPrintStream;
private final DateFormat dateFormat;
public OutputStreamEventReporter(Builder builder) throws IOException {
super(builder);
this.serializer = this.closer.register(
new AvroJsonSerializer<GobblinTrackingEvent>(GobblinTrackingEvent.SCHEMA$, new NoopSchemaVersionWriter()));
this.output = builder.output;
this.outputBuffer = new ByteArrayOutputStream();
this.outputBufferPrintStream = this.closer.register(new PrintStream(this.outputBuffer, false, Charsets.UTF_8.toString()));
this.dateFormat = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.MEDIUM, Locale.getDefault());
}
@Override
public void reportEventQueue(Queue<GobblinTrackingEvent> queue) {
if(queue.size() <= 0) {
return;
}
this.outputBuffer.reset();
GobblinTrackingEvent nextEvent;
final String dateTime = dateFormat.format(new Date());
printWithBanner(dateTime, '=');
this.outputBufferPrintStream.println();
printWithBanner("-- Events", '-');
while(null != (nextEvent = queue.poll())) {
this.outputBufferPrintStream.println(new String(this.serializer.serializeRecord(nextEvent), Charsets.UTF_8));
}
this.outputBufferPrintStream.println();
try {
this.outputBuffer.writeTo(this.output);
} catch(IOException exception) {
LOGGER.warn("Failed to write events to output stream.");
}
}
private void printWithBanner(String s, char c) {
this.outputBufferPrintStream.print(s);
this.outputBufferPrintStream.print(' ');
for (int i = 0; i < (CONSOLE_WIDTH - s.length() - 1); i++) {
this.outputBufferPrintStream.print(c);
}
this.outputBufferPrintStream.println();
}
/**
* Returns a new {@link gobblin.metrics.kafka.KafkaEventReporter.Builder} for {@link gobblin.metrics.kafka.KafkaEventReporter}.
* Will automatically add all Context tags to the reporter.
*
* @param context the {@link gobblin.metrics.MetricContext} to report
* @return KafkaReporter builder
*/
public static Builder<? extends Builder> forContext(MetricContext context) {
return new BuilderImpl(context);
}
private static class BuilderImpl extends Builder<BuilderImpl> {
public BuilderImpl(MetricContext context) {
super(context);
}
@Override
protected BuilderImpl self() {
return this;
}
}
public static abstract class Builder<T extends Builder<T>> extends EventReporter.Builder<T> {
protected PrintStream output;
public Builder(MetricContext context) {
super(context);
this.output = System.out;
}
/**
* Write to the given {@link java.io.PrintStream}.
*
* @param output a {@link java.io.PrintStream} instance.
* @return {@code this}
*/
public T outputTo(PrintStream output) {
this.output = output;
return self();
}
/**
* Write to the given {@link java.io.OutputStream}.
* @param stream a {@link java.io.OutputStream} instance
* @return {@code this}
*/
public T outputTo(OutputStream stream) {
try {
this.output = new PrintStream(stream, false, Charsets.UTF_8.toString());
} catch(UnsupportedEncodingException exception) {
LOGGER.error("Unsupported encoding in OutputStreamReporter. This is an error with the code itself.", exception);
throw new RuntimeException(exception);
}
return self();
}
public OutputStreamEventReporter build() throws IOException {
return new OutputStreamEventReporter(this);
}
}
}