/**
* Copyright 2013 Cloudera Inc.
*
* 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.
*/
package org.kitesdk.data.flume;
import java.net.URI;
import org.kitesdk.data.Dataset;
import org.kitesdk.data.URIBuilder;
import org.kitesdk.data.impl.Accessor;
import org.kitesdk.data.spi.DataModelUtil;
import org.kitesdk.data.spi.EntityAccessor;
import org.kitesdk.data.spi.FieldPartitioner;
import org.kitesdk.data.PartitionStrategy;
import java.net.URL;
import java.util.Map;
import org.apache.avro.Schema;
import org.apache.flume.FlumeException;
import org.kitesdk.data.Datasets;
import org.kitesdk.data.spi.StorageKey;
import org.kitesdk.data.spi.filesystem.PathConversion;
public class Log4jAppender extends org.apache.flume.clients.log4jappender.Log4jAppender {
private static final String PARTITION_PREFIX = "kite.partition.";
private String datasetRepositoryUri;
private String datasetNamespace;
private String datasetName;
private boolean initialized;
private PartitionStrategy partitionStrategy;
private EntityAccessor<Object> accessor;
private StorageKey key;
public Log4jAppender() {
super();
setAvroReflectionEnabled(true);
}
/**
* Sets the hostname and port. Even if these are passed the
* <tt>activateOptions()</tt> function must be called before calling
* <tt>append()</tt>, else <tt>append()</tt> will throw an Exception.
* @param hostname The first hop where the client should connect to.
* @param port The port to connect on the host.
*
*/
public Log4jAppender(String hostname, int port) {
super(hostname, port);
setAvroReflectionEnabled(true);
}
@Override
public boolean requiresLayout() {
// We don't support use of a layout
return false;
}
/**
* @deprecated Use datasetRepositoryUri with a 'repo:' URI.
*/
@Deprecated
public void setDatasetRepositoryClass(String datasetRepositoryClass) {
throw new UnsupportedOperationException("datasetRepositoryClass is no longer " +
"supported. Use datasetRepositoryUri with a 'repo:' URI.");
}
public void setDatasetRepositoryUri(String datasetRepositoryUri) {
this.datasetRepositoryUri = datasetRepositoryUri;
}
public void setDatasetNamespace(String datasetNamespace) {
this.datasetNamespace = datasetNamespace;
}
public void setDatasetName(String datasetName) {
this.datasetName = datasetName;
}
@Override
@SuppressWarnings({"unchecked", "deprecation"})
protected void populateAvroHeaders(Map<String, String> hdrs, Schema schema,
Object message) {
if (!initialized) {
// initialize here rather than in activateOptions to avoid initialization
// cycle in Configuration and log4j
try {
URI datasetUri;
if (datasetNamespace == null) {
datasetUri = new URIBuilder(datasetRepositoryUri, URIBuilder.NAMESPACE_DEFAULT, datasetName).build();
} else {
datasetUri = new URIBuilder(datasetRepositoryUri, datasetNamespace, datasetName).build();
}
Dataset<Object> dataset = Datasets.load(datasetUri, Object.class);
if (dataset.getDescriptor().isPartitioned()) {
partitionStrategy = dataset.getDescriptor().getPartitionStrategy();
accessor = DataModelUtil.accessor(
dataset.getType(), dataset.getDescriptor().getSchema());
key = new StorageKey(partitionStrategy);
}
URL schemaUrl = dataset.getDescriptor().getSchemaUrl();
if (schemaUrl != null) {
setAvroSchemaUrl(schemaUrl.toExternalForm());
}
} catch (Exception e) {
throw new FlumeException(e);
} finally {
initialized = true;
}
}
super.populateAvroHeaders(hdrs, schema, message);
if (partitionStrategy != null) {
key.reuseFor(message, accessor);
int i = 0;
for (FieldPartitioner fp :
Accessor.getDefault().getFieldPartitioners(partitionStrategy)) {
hdrs.put(PARTITION_PREFIX + fp.getName(),
PathConversion.valueToString(fp, key.get(i++)));
}
}
}
}