001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.apache.hadoop.hbase.server.trace;
019
020import static org.apache.hadoop.hbase.trace.HBaseSemanticAttributes.RPC_METHOD;
021import static org.apache.hadoop.hbase.trace.HBaseSemanticAttributes.RPC_SERVICE;
022import static org.apache.hadoop.hbase.trace.HBaseSemanticAttributes.RPC_SYSTEM;
023
024import io.opentelemetry.api.common.AttributeKey;
025import io.opentelemetry.api.trace.Span;
026import io.opentelemetry.api.trace.SpanBuilder;
027import io.opentelemetry.api.trace.SpanKind;
028import java.util.HashMap;
029import java.util.Map;
030import java.util.Optional;
031import java.util.function.Supplier;
032import org.apache.hadoop.hbase.client.trace.IpcClientSpanBuilder;
033import org.apache.hadoop.hbase.ipc.RpcCall;
034import org.apache.hadoop.hbase.trace.HBaseSemanticAttributes.RpcSystem;
035import org.apache.hadoop.hbase.trace.TraceUtil;
036import org.apache.yetus.audience.InterfaceAudience;
037
038import org.apache.hbase.thirdparty.com.google.protobuf.BlockingService;
039
040/**
041 * Construct {@link Span} instances originating from the server side of an IPC.
042 * @see <a href=
043 *      "https://github.com/open-telemetry/opentelemetry-specification/blob/3e380e249f60c3a5f68746f5e84d10195ba41a79/specification/trace/semantic_conventions/rpc.md">Semantic
044 *      conventions for RPC spans</a>
045 */
046@InterfaceAudience.Private
047public class IpcServerSpanBuilder implements Supplier<Span> {
048
049  private String name;
050  private final Map<AttributeKey<?>, Object> attributes = new HashMap<>();
051
052  public IpcServerSpanBuilder(final RpcCall rpcCall) {
053    final String packageAndService =
054      Optional.ofNullable(rpcCall.getService()).map(BlockingService::getDescriptorForType)
055        .map(IpcClientSpanBuilder::getRpcPackageAndService).orElse("");
056    final String method =
057      Optional.ofNullable(rpcCall.getMethod()).map(IpcClientSpanBuilder::getRpcName).orElse("");
058    setName(IpcClientSpanBuilder.buildSpanName(packageAndService, method));
059    addAttribute(RPC_SYSTEM, RpcSystem.HBASE_RPC.name());
060    addAttribute(RPC_SERVICE, packageAndService);
061    addAttribute(RPC_METHOD, method);
062  }
063
064  @Override
065  public Span get() {
066    return build();
067  }
068
069  public IpcServerSpanBuilder setName(final String name) {
070    this.name = name;
071    return this;
072  }
073
074  public <T> IpcServerSpanBuilder addAttribute(final AttributeKey<T> key, T value) {
075    attributes.put(key, value);
076    return this;
077  }
078
079  @SuppressWarnings("unchecked")
080  public Span build() {
081    final SpanBuilder builder =
082      TraceUtil.getGlobalTracer().spanBuilder(name).setSpanKind(SpanKind.SERVER);
083    attributes.forEach((k, v) -> builder.setAttribute((AttributeKey<? super Object>) k, v));
084    return builder.startSpan();
085  }
086}