// ================================================================================================= // Copyright 2011 Twitter, Inc. // ------------------------------------------------------------------------------------------------- // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this work except in compliance with the License. // You may obtain a copy of the License in the LICENSE file, or 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 com.twitter.common.logging; import java.net.InetSocketAddress; import java.util.Arrays; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; import com.google.common.base.Preconditions; import com.google.common.base.Predicate; import com.google.common.collect.Sets; import org.apache.scribe.LogEntry; import org.apache.scribe.ResultCode; import org.apache.scribe.scribe; import org.apache.thrift.TException; import com.twitter.common.quantity.Amount; import com.twitter.common.quantity.Time; import com.twitter.common.thrift.Thrift; import com.twitter.common.thrift.ThriftFactory; /** * Implementation of the scribe client, logs message directly to scribe. * * @author William Farner */ public class ScribeLog implements Log<LogEntry, ResultCode> { private static final Logger LOG = Logger.getLogger(ScribeLog.class.getName()); // Connection pool options. private static final int MAX_CONNECTIONS_PER_HOST = 5; private static final Amount<Long, Time> REQUEST_TIMEOUT = Amount.of(4L, Time.SECONDS); // Max retries per request before giving up. private static final int MAX_RETRIES = 3; private final scribe.Iface client; /** * Creats a new scribe client, connecting to the given hosts on the given port. * * @param hosts Thrift servers to connect to. * @throws ThriftFactory.ThriftFactoryException If the client could not be created. */ public ScribeLog(List<InetSocketAddress> hosts) throws ThriftFactory.ThriftFactoryException { Preconditions.checkNotNull(hosts); Thrift<scribe.Iface> thrift = ThriftFactory.create(scribe.Iface.class) .withMaxConnectionsPerEndpoint(MAX_CONNECTIONS_PER_HOST) .useFramedTransport(true) .build(Sets.newHashSet(hosts)); client = thrift.builder() .withRetries(MAX_RETRIES) .withRequestTimeout(REQUEST_TIMEOUT) .create(); } @Override public ResultCode log(LogEntry entry) { return log(Arrays.asList(entry)); } @Override public ResultCode log(List<LogEntry> entries) { try { return client.Log(entries); } catch (TException e) { LOG.log(Level.WARNING, "Failed to submit log request!."); return ResultCode.TRY_LATER; } } @Override public void flush() { // No-op. } public static final Predicate<ResultCode> RETRY_FILTER = new Predicate<ResultCode>() { @Override public boolean apply(ResultCode result) { return result != ResultCode.OK; } }; }