001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.juneau.rest.server.tracing; 018 019import java.util.*; 020 021import org.apache.juneau.http.tracing.TraceContextCarrier; 022import org.apache.juneau.rest.server.*; 023 024/** 025 * SPI for recognizing a non-HTTP trace-context carrier inside a resolved {@code @RestOp} invocation. 026 * 027 * <p> 028 * {@code RestOpInvoker} resolves every operation argument (path/query/body parameters, parsed request 029 * beans, etc.) before it opens a {@code TracerHook} span. A registered {@code TraceContextExtractor} 030 * bean gets a look at those resolved arguments — not just the raw {@link RestRequest} — so 031 * it can recognize a domain-specific carrier (for example a parsed JSON-RPC/MCP request's nested 032 * {@code params._meta} object) and hand back a {@link TraceContextCarrier} plus a {@link TraceOperation} 033 * before the span is created. Neither this interface nor its default implementation depends on MCP, 034 * JSON-RPC, or OpenTelemetry. 035 * 036 * <p> 037 * Extraction only happens when a non-no-op {@code TracerHook} is active; a resource with no 038 * registered {@code TracerHook} bean never resolves a {@code TraceContextExtractor} either, preserving 039 * the existing zero-allocation no-op fast path. 040 * 041 * <h5 class='section'>See Also:</h5><ul> 042 * <li class='jc'>{@link TraceContextCarrier} 043 * <li class='jc'>{@link TraceOperation} 044 * <li class='jc'>{@link TracerHook} 045 * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/RestServerObservability">Observability — Micrometer + OpenTelemetry</a> 046 * </ul> 047 * 048 * @since 10.0.0 049 */ 050public interface TraceContextExtractor { 051 052 /** 053 * Attempts to recognize a non-HTTP trace-context carrier among the resolved operation arguments. 054 * 055 * @param request The in-flight {@link RestRequest}. Never <jk>null</jk>. 056 * @param resolvedArguments The fully-resolved {@code @RestOp} handler arguments, in declaration 057 * order. Never <jk>null</jk>; may be empty. 058 * @return The recognized {@link TraceContextCarrier}, or {@link Optional#empty()} if this 059 * extractor found nothing to extract from the resolved arguments (the bridge then falls back to 060 * HTTP headers only). Never <jk>null</jk>. 061 */ 062 Optional<TraceContextCarrier> extract(RestRequest request, Object[] resolvedArguments); 063 064 /** 065 * Derives the {@link TraceOperation} a bridge should name/attribute its span with. 066 * 067 * <p> 068 * The default implementation returns {@link TraceOperation#DEFAULT} — an extractor that 069 * overrides only {@link #extract} still satisfies {@code TracerHook.startSpan}'s three-argument 070 * overload, and the bridge keeps its own HTTP-derived span name/attributes. 071 * 072 * @param request The in-flight {@link RestRequest}. Never <jk>null</jk>. 073 * @param resolvedArguments The fully-resolved {@code @RestOp} handler arguments, in declaration 074 * order. Never <jk>null</jk>; may be empty. 075 * @return The derived {@link TraceOperation}. Never <jk>null</jk>. 076 */ 077 default TraceOperation operation(RestRequest request, Object[] resolvedArguments) { 078 return TraceOperation.DEFAULT; 079 } 080}