This is an automated email from the ASF dual-hosted git repository.

richardstartin pushed a commit to branch tracing-spi
in repository https://gitbox.apache.org/repos/asf/pinot.git

commit 4aaa19eef2a7016e4e2b725a7aa357fc51f491d5
Author: richardstartin <rich...@startree.ai>
AuthorDate: Fri Apr 1 16:21:43 2022 +0100

    add tracing SPI
---
 .../apache/pinot/core/operator/BaseOperator.java   |  23 ++---
 .../query/executor/ServerQueryExecutorV1Impl.java  |   3 +-
 .../pinot/core/util/trace/DefaultTracer.java       | 100 +++++++++++++++++++++
 .../pinot/core/util/trace/TraceContextTest.java    |   3 +-
 .../apache/pinot/spi/trace/ExecutionRecording.java |  71 +++++++++++++++
 .../org/apache/pinot/spi/trace/FilterType.java     |  24 +++++
 .../apache/pinot/spi/trace/OperatorExecution.java  |  22 +++++
 .../java/org/apache/pinot/spi/trace/Phase.java     |  27 ++++++
 .../java/org/apache/pinot/spi/trace/Scope.java     |  25 ++++++
 .../java/org/apache/pinot/spi/trace/Tracer.java    |  30 +++++++
 .../java/org/apache/pinot/spi/trace/Tracing.java   |  70 +++++++++++++++
 11 files changed, 382 insertions(+), 16 deletions(-)

diff --git 
a/pinot-core/src/main/java/org/apache/pinot/core/operator/BaseOperator.java 
b/pinot-core/src/main/java/org/apache/pinot/core/operator/BaseOperator.java
index e99d5c59a1..369f936e95 100644
--- a/pinot-core/src/main/java/org/apache/pinot/core/operator/BaseOperator.java
+++ b/pinot-core/src/main/java/org/apache/pinot/core/operator/BaseOperator.java
@@ -20,36 +20,31 @@ package org.apache.pinot.core.operator;
 
 import org.apache.pinot.core.common.Block;
 import org.apache.pinot.core.common.Operator;
-import org.apache.pinot.core.util.trace.TraceContext;
 import org.apache.pinot.spi.exception.EarlyTerminationException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import org.apache.pinot.spi.trace.ExecutionRecording;
+import org.apache.pinot.spi.trace.OperatorExecution;
+import org.apache.pinot.spi.trace.Tracing;
 
 
 /**
  * Any other Pinot Operators should extend BaseOperator
  */
 public abstract class BaseOperator<T extends Block> implements Operator<T> {
-  private static final Logger LOGGER = 
LoggerFactory.getLogger(BaseOperator.class);
 
   @Override
   public final T nextBlock() {
     if (Thread.interrupted()) {
       throw new EarlyTerminationException();
     }
-    if (TraceContext.traceEnabled()) {
-      long start = System.currentTimeMillis();
-      T nextBlock = getNextBlock();
-      long end = System.currentTimeMillis();
-      String operatorName = getOperatorName();
-      LOGGER.trace("Time spent in {}: {}", operatorName, (end - start));
-      TraceContext.logTime(operatorName, (end - start));
-      return nextBlock;
-    } else {
-      return getNextBlock();
+    try (OperatorExecution execution = 
Tracing.getTracer().startOperatorExecution(getClass())) {
+      return getNextBlock(execution);
     }
   }
 
   // Make it protected because we should always call nextBlock()
   protected abstract T getNextBlock();
+
+  protected T getNextBlock(ExecutionRecording recording) {
+    return getNextBlock();
+  }
 }
diff --git 
a/pinot-core/src/main/java/org/apache/pinot/core/query/executor/ServerQueryExecutorV1Impl.java
 
b/pinot-core/src/main/java/org/apache/pinot/core/query/executor/ServerQueryExecutorV1Impl.java
index 6dcf6a9d95..af5465d199 100644
--- 
a/pinot-core/src/main/java/org/apache/pinot/core/query/executor/ServerQueryExecutorV1Impl.java
+++ 
b/pinot-core/src/main/java/org/apache/pinot/core/query/executor/ServerQueryExecutorV1Impl.java
@@ -66,6 +66,7 @@ import org.apache.pinot.segment.spi.MutableSegment;
 import org.apache.pinot.segment.spi.SegmentMetadata;
 import org.apache.pinot.spi.env.PinotConfiguration;
 import org.apache.pinot.spi.exception.BadQueryRequestException;
+import org.apache.pinot.spi.trace.Tracing;
 import org.apache.pinot.spi.utils.CommonConstants;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -195,7 +196,7 @@ public class ServerQueryExecutorV1Impl implements 
QueryExecutor {
 
     boolean enableTrace = queryRequest.isEnableTrace();
     if (enableTrace) {
-      TraceContext.register(requestId);
+      Tracing.getTracer().register(requestId);
     }
 
     DataTable dataTable = null;
diff --git 
a/pinot-core/src/main/java/org/apache/pinot/core/util/trace/DefaultTracer.java 
b/pinot-core/src/main/java/org/apache/pinot/core/util/trace/DefaultTracer.java
new file mode 100644
index 0000000000..91522f2591
--- /dev/null
+++ 
b/pinot-core/src/main/java/org/apache/pinot/core/util/trace/DefaultTracer.java
@@ -0,0 +1,100 @@
+/**
+ * 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.pinot.core.util.trace;
+
+import org.apache.pinot.spi.data.FieldSpec;
+import org.apache.pinot.spi.trace.FilterType;
+import org.apache.pinot.spi.trace.OperatorExecution;
+import org.apache.pinot.spi.trace.Phase;
+import org.apache.pinot.spi.trace.Tracer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+public class DefaultTracer implements Tracer {
+
+  private static final Logger LOGGER = 
LoggerFactory.getLogger(DefaultTracer.class);
+
+  private static class NoOpExecution implements OperatorExecution {
+
+    @Override
+    public void setDocsScanned(long docsScanned) {
+    }
+
+    @Override
+    public void setBytesProcessed(long bytesScanned) {
+    }
+
+    @Override
+    public void setFilterType(FilterType filterType, String predicateType) {
+    }
+
+    @Override
+    public void setPhase(Phase phase) {
+    }
+
+    @Override
+    public void setDataTypes(FieldSpec.DataType inputDataType, 
FieldSpec.DataType outputDataType) {
+    }
+
+    @Override
+    public void setDocIdRange(int firstDocId, int lastDocId) {
+    }
+
+    @Override
+    public void setColumnCardinality(int cardinality) {
+    }
+
+    @Override
+    public void close() {
+    }
+  }
+
+  private static final NoOpExecution NO_OP_SPAN = new NoOpExecution();
+
+  private static final class MillisExecution extends NoOpExecution {
+
+    private final long _startTimeMillis = System.currentTimeMillis();
+    private final Class<?> _operator;
+
+    public MillisExecution(Class<?> operator) {
+      _operator = operator;
+    }
+
+    @Override
+    public void close() {
+      String operatorName = _operator.getSimpleName();
+      long duration = System.currentTimeMillis() - _startTimeMillis;
+      if (LOGGER.isTraceEnabled()) {
+        LOGGER.trace("Time spent in {}: {}", operatorName, duration);
+      }
+      TraceContext.logTime(operatorName, duration);
+    }
+  }
+
+  @Override
+  public void register(long requestId) {
+    TraceContext.register(requestId);
+  }
+
+  @Override
+  public OperatorExecution startOperatorExecution(Class<?> operatorClass) {
+    return TraceContext.traceEnabled() ? new MillisExecution(operatorClass) : 
NO_OP_SPAN;
+  }
+}
diff --git 
a/pinot-core/src/test/java/org/apache/pinot/core/util/trace/TraceContextTest.java
 
b/pinot-core/src/test/java/org/apache/pinot/core/util/trace/TraceContextTest.java
index 5ebdf7c7de..ba4a4acb0c 100644
--- 
a/pinot-core/src/test/java/org/apache/pinot/core/util/trace/TraceContextTest.java
+++ 
b/pinot-core/src/test/java/org/apache/pinot/core/util/trace/TraceContextTest.java
@@ -26,6 +26,7 @@ import java.util.Set;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 import java.util.concurrent.Future;
+import org.apache.pinot.spi.trace.Tracing;
 import org.apache.pinot.spi.utils.JsonUtils;
 import org.testng.Assert;
 import org.testng.annotations.Test;
@@ -73,7 +74,7 @@ public class TraceContextTest {
   private void testSingleRequest(ExecutorService executorService, final long 
requestId)
       throws Exception {
     Set<String> expectedTraces = new HashSet<>(NUM_CHILDREN_PER_REQUEST + 1);
-    TraceContext.register(requestId);
+    Tracing.getTracer().register(requestId);
     String key = Integer.toString(RANDOM.nextInt());
     int value = RANDOM.nextInt();
     expectedTraces.add(getTraceString(key, value));
diff --git 
a/pinot-spi/src/main/java/org/apache/pinot/spi/trace/ExecutionRecording.java 
b/pinot-spi/src/main/java/org/apache/pinot/spi/trace/ExecutionRecording.java
new file mode 100644
index 0000000000..dd08aaa1ed
--- /dev/null
+++ b/pinot-spi/src/main/java/org/apache/pinot/spi/trace/ExecutionRecording.java
@@ -0,0 +1,71 @@
+/**
+ * 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.pinot.spi.trace;
+
+import org.apache.pinot.spi.data.FieldSpec;
+
+
+public interface ExecutionRecording {
+
+  /**
+   * Sets the number of docs scanned by the operator.
+   * @param docsScanned how many docs were scanned.
+   */
+  void setDocsScanned(long docsScanned);
+
+  /**
+   * Sets the number of bytes scanned by the operator if this is possible to 
compute.
+   * @param bytesScanned the number of bytes scanned
+   */
+  void setBytesProcessed(long bytesScanned);
+
+  /**
+   * If the operator is a filter, determines the filter type (scan or index) 
and the predicate type
+   * @param filterType SCAN or INDEX
+   * @param predicateType e.g. BETWEEN, REGEXP_LIKE
+   */
+  void setFilterType(FilterType filterType, String predicateType);
+
+  /**
+   * The phase of the query
+   * @param phase the phase
+   */
+  void setPhase(Phase phase);
+
+  /**
+   * Records whether type transformation took place during the operator's 
invocation and what the types were
+   * @param inputDataType the input data type
+   * @param outputDataType the output data type
+   */
+  void setDataTypes(FieldSpec.DataType inputDataType, FieldSpec.DataType 
outputDataType);
+
+  /**
+   * Records the range of docIds during the operator invocation. This is 
useful for implicating a range of records
+   * in a slow operator invocation.
+   * @param firstDocId the first docId in the block
+   * @param lastDocId the last docId in the block
+   */
+  void setDocIdRange(int firstDocId, int lastDocId);
+
+  /**
+   * If known, record the cardinality of the column within the segment this 
operator invoked on
+   * @param cardinality the number of distinct values
+   */
+  void setColumnCardinality(int cardinality);
+}
diff --git a/pinot-spi/src/main/java/org/apache/pinot/spi/trace/FilterType.java 
b/pinot-spi/src/main/java/org/apache/pinot/spi/trace/FilterType.java
new file mode 100644
index 0000000000..89eaee8611
--- /dev/null
+++ b/pinot-spi/src/main/java/org/apache/pinot/spi/trace/FilterType.java
@@ -0,0 +1,24 @@
+/**
+ * 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.pinot.spi.trace;
+
+public enum FilterType {
+  INDEX,
+  SCAN
+}
diff --git 
a/pinot-spi/src/main/java/org/apache/pinot/spi/trace/OperatorExecution.java 
b/pinot-spi/src/main/java/org/apache/pinot/spi/trace/OperatorExecution.java
new file mode 100644
index 0000000000..ec2eafd135
--- /dev/null
+++ b/pinot-spi/src/main/java/org/apache/pinot/spi/trace/OperatorExecution.java
@@ -0,0 +1,22 @@
+/**
+ * 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.pinot.spi.trace;
+
+public interface OperatorExecution extends Scope, ExecutionRecording {
+}
diff --git a/pinot-spi/src/main/java/org/apache/pinot/spi/trace/Phase.java 
b/pinot-spi/src/main/java/org/apache/pinot/spi/trace/Phase.java
new file mode 100644
index 0000000000..c7f3d6808c
--- /dev/null
+++ b/pinot-spi/src/main/java/org/apache/pinot/spi/trace/Phase.java
@@ -0,0 +1,27 @@
+/**
+ * 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.pinot.spi.trace;
+
+public enum Phase {
+  EXTRACT,
+  FILTER,
+  TRANSFORM,
+  PROJECT,
+  AGGREGATE
+}
diff --git a/pinot-spi/src/main/java/org/apache/pinot/spi/trace/Scope.java 
b/pinot-spi/src/main/java/org/apache/pinot/spi/trace/Scope.java
new file mode 100644
index 0000000000..4ff56d0b6c
--- /dev/null
+++ b/pinot-spi/src/main/java/org/apache/pinot/spi/trace/Scope.java
@@ -0,0 +1,25 @@
+/**
+ * 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.pinot.spi.trace;
+
+public interface Scope extends AutoCloseable {
+
+  @Override
+  void close();
+}
diff --git a/pinot-spi/src/main/java/org/apache/pinot/spi/trace/Tracer.java 
b/pinot-spi/src/main/java/org/apache/pinot/spi/trace/Tracer.java
new file mode 100644
index 0000000000..92a77b4985
--- /dev/null
+++ b/pinot-spi/src/main/java/org/apache/pinot/spi/trace/Tracer.java
@@ -0,0 +1,30 @@
+/**
+ * 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.pinot.spi.trace;
+
+public interface Tracer {
+
+    /**
+     * Registers the requestId on the current thread. This means the request 
will be traced.
+     * @param requestId the requestId
+     */
+    void register(long requestId);
+
+    OperatorExecution startOperatorExecution(Class<?> clazz);
+}
diff --git a/pinot-spi/src/main/java/org/apache/pinot/spi/trace/Tracing.java 
b/pinot-spi/src/main/java/org/apache/pinot/spi/trace/Tracing.java
new file mode 100644
index 0000000000..9ae8b30708
--- /dev/null
+++ b/pinot-spi/src/main/java/org/apache/pinot/spi/trace/Tracing.java
@@ -0,0 +1,70 @@
+/**
+ * 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.pinot.spi.trace;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
+import java.util.concurrent.atomic.AtomicReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+public class Tracing {
+
+  private Tracing() {
+  }
+
+  private static final Logger LOGGER = LoggerFactory.getLogger(Tracing.class);
+
+  private static final AtomicReference<Tracer> REGISTRATION = new 
AtomicReference<>();
+
+  /**
+   * User once registration point to allow customization of tracing behaviour. 
Registration will be successful
+   * if this was the first attempt to register and registration happened 
before first use of the tracer.
+   * @param tracer the tracer implementation
+   * @return true if the registration was successful.
+   */
+  public static boolean register(Tracer tracer) {
+    return REGISTRATION.compareAndSet(null, tracer);
+  }
+
+  private static final class Holder {
+    static final Tracer TRACER = REGISTRATION.get() == null ? 
createDefaultTracer() : REGISTRATION.get();
+  }
+
+  /**
+   * @return the registered tracer.
+   */
+  public static Tracer getTracer() {
+    return Holder.TRACER;
+  }
+
+  private static Tracer createDefaultTracer() {
+    // create the default tracer via method handles if no override is 
registered
+    String defaultImplementationClassName = 
"org.apache.pinot.core.util.trace.DefaultTracer";
+    try {
+      Class<?> clazz = Class.forName(defaultImplementationClassName, false, 
Tracing.class.getClassLoader());
+      return (Tracer) MethodHandles.publicLookup()
+          .findConstructor(clazz, MethodType.methodType(void.class)).invoke();
+    } catch (Throwable missing) {
+      LOGGER.error("could not construct MethodHandle for {}", 
defaultImplementationClassName, missing);
+      return null;
+    }
+  }
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscr...@pinot.apache.org
For additional commands, e-mail: commits-h...@pinot.apache.org

Reply via email to