org.apache.phoenix.trace.TraceWriter Maven / Gradle / Ivy
/**
* 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 org.apache.phoenix.trace;
import static org.apache.phoenix.metrics.MetricInfo.ANNOTATION;
import static org.apache.phoenix.metrics.MetricInfo.DESCRIPTION;
import static org.apache.phoenix.metrics.MetricInfo.END;
import static org.apache.phoenix.metrics.MetricInfo.HOSTNAME;
import static org.apache.phoenix.metrics.MetricInfo.PARENT;
import static org.apache.phoenix.metrics.MetricInfo.SPAN;
import static org.apache.phoenix.metrics.MetricInfo.START;
import static org.apache.phoenix.metrics.MetricInfo.TAG;
import static org.apache.phoenix.metrics.MetricInfo.TRACE;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.util.Pair;
import org.apache.htrace.Span;
import org.apache.htrace.TimelineAnnotation;
import org.apache.phoenix.compile.MutationPlan;
import org.apache.phoenix.execute.MutationState;
import org.apache.phoenix.jdbc.PhoenixConnection;
import org.apache.phoenix.jdbc.PhoenixDatabaseMetaData;
import org.apache.phoenix.jdbc.PhoenixPreparedStatement;
import org.apache.phoenix.metrics.MetricInfo;
import org.apache.phoenix.query.QueryServices;
import org.apache.phoenix.schema.TableNotFoundException;
import org.apache.phoenix.trace.util.Tracing;
import org.apache.phoenix.util.PhoenixRuntime;
import org.apache.phoenix.util.QueryUtil;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Joiner;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
/**
* Sink for the trace spans pushed into the queue by {@link TraceSpanReceiver}. The class
* instantiates a thread pool of configurable size, which will pull the data from queue and write to
* the Phoenix Trace Table in batches. Various configuration options include thread pool size and
* batch commit size.
*/
public class TraceWriter {
private static final Log LOG = LogFactory.getLog(TraceWriter.class);
private static final String VARIABLE_VALUE = "?";
private static final Joiner COLUMN_JOIN = Joiner.on(".");
static final String TAG_FAMILY = "tags";
/**
* Count of the number of tags we are storing for this row
*/
static final String TAG_COUNT = COLUMN_JOIN.join(TAG_FAMILY, "count");
static final String ANNOTATION_FAMILY = "annotations";
static final String ANNOTATION_COUNT = COLUMN_JOIN.join(ANNOTATION_FAMILY, "count");
/**
* Join strings on a comma
*/
private static final Joiner COMMAS = Joiner.on(',');
private String tableName;
private int batchSize;
private int numThreads;
private TraceSpanReceiver traceSpanReceiver;
protected ScheduledExecutorService executor;
public TraceWriter(String tableName, int numThreads, int batchSize) {
this.batchSize = batchSize;
this.numThreads = numThreads;
this.tableName = tableName;
}
public void start() {
traceSpanReceiver = getTraceSpanReceiver();
if (traceSpanReceiver == null) {
LOG.warn(
"No receiver has been initialized for TraceWriter. Traces will not be written.");
LOG.warn("Restart Phoenix to try again.");
return;
}
ThreadFactoryBuilder builder = new ThreadFactoryBuilder();
builder.setDaemon(true).setNameFormat("PHOENIX-METRICS-WRITER");
executor = Executors.newScheduledThreadPool(this.numThreads, builder.build());
for (int i = 0; i < this.numThreads; i++) {
executor.scheduleAtFixedRate(new FlushMetrics(), 0, 10, TimeUnit.SECONDS);
}
LOG.info("Writing tracing metrics to phoenix table");
}
@VisibleForTesting
protected TraceSpanReceiver getTraceSpanReceiver() {
return Tracing.getTraceSpanReceiver();
}
public class FlushMetrics implements Runnable {
private Connection conn;
private int counter = 0;
public FlushMetrics() {
conn = getConnection(tableName);
}
@Override
public void run() {
if (conn == null) return;
while (!traceSpanReceiver.isSpanAvailable()) {
Span span = traceSpanReceiver.getSpan();
if (null == span) break;
if (LOG.isTraceEnabled()) {
LOG.trace("Span received: " + span.toJson());
}
addToBatch(span);
counter++;
if (counter >= batchSize) {
commitBatch(conn);
counter = 0;
}
}
}
private void addToBatch(Span span) {
String stmt = "UPSERT INTO " + tableName + " (";
// drop it into the queue of things that should be written
List keys = new ArrayList();
List
© 2015 - 2024 Weber Informatics LLC | Privacy Policy