Unverified Commit 86060dbc authored by Hong Minhee's avatar Hong Minhee
Browse files

Span for `handleWebFinger()`

parent 8cd887ee
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -57,7 +57,7 @@ To be released.
        null` (was `{ name: string; values: Record<string, string> } | null`).
     -  Added `RouterRouteResult` interface.

 -  Fedify now supports OpenTelemetry for tracing.
 -  Fedify now supports OpenTelemetry for tracing.  [[#170]]

     -  Added `CreateFederationOptions.tracerProvider` option.

@@ -75,6 +75,7 @@ To be released.

[SvelteKit]: https://kit.svelte.dev/
[#162]: https://github.com/dahlia/fedify/issues/162
[#170]: https://github.com/dahlia/fedify/issues/170
[#171]: https://github.com/dahlia/fedify/issues/171
[#173]: https://github.com/dahlia/fedify/issues/173
[#183]: https://github.com/dahlia/fedify/pull/183
+1 −0
Original line number Diff line number Diff line
@@ -118,6 +118,7 @@ spans:
| Operation            | Description                       |
|----------------------|-----------------------------------|
| `Federation.fetch()` | Serves the incoming HTTP request. |
| `handleWebFinger()`  | Handles the WebFinger request.    |

More operations will be instrumented in the future releases.

+5 −2
Original line number Diff line number Diff line
@@ -4,6 +4,7 @@ import {
  SpanKind,
  SpanStatusCode,
  trace,
  Tracer,
  type TracerProvider,
} from "@opentelemetry/api";
import {
@@ -1906,7 +1907,7 @@ export class FederationImpl<TContextData> implements Federation<TContextData> {
          }
          let response: Response;
          try {
            response = await this.#fetch(request, { ...options, span });
            response = await this.#fetch(request, { ...options, span, tracer });
          } catch (error) {
            span.setStatus({
              code: SpanStatusCode.ERROR,
@@ -1957,7 +1958,8 @@ export class FederationImpl<TContextData> implements Federation<TContextData> {
      onUnauthorized,
      contextData,
      span,
    }: FederationFetchOptions<TContextData> & { span: Span },
      tracer,
    }: FederationFetchOptions<TContextData> & { span: Span; tracer: Tracer },
  ): Promise<Response> {
    onNotFound ??= notFound;
    onNotAcceptable ??= notAcceptable;
@@ -1975,6 +1977,7 @@ export class FederationImpl<TContextData> implements Federation<TContextData> {
          actorDispatcher: this.actorCallbacks?.dispatcher,
          actorHandleMapper: this.actorCallbacks?.handleMapper,
          onNotFound,
          tracer,
        });
      case "nodeInfoJrd":
        return await handleNodeInfoJrd(request, context);
+44 −0
Original line number Diff line number Diff line
import { getLogger } from "@logtape/logtape";
import type { Span, Tracer } from "@opentelemetry/api";
import { SpanKind, SpanStatusCode } from "@opentelemetry/api";
import { toASCII } from "node:punycode";
import type {
  ActorDispatcher,
@@ -34,6 +36,16 @@ export interface WebFingerHandlerParameters<TContextData> {
   * The function to call when the actor is not found.
   */
  onNotFound(request: Request): Response | Promise<Response>;

  /**
   * The OpenTelemetry tracer.
   */
  tracer?: Tracer;

  /**
   * The span for the request.
   */
  span?: Span;
}

/**
@@ -44,12 +56,43 @@ export interface WebFingerHandlerParameters<TContextData> {
 * @returns The response to the request.
 */
export async function handleWebFinger<TContextData>(
  request: Request,
  options: WebFingerHandlerParameters<TContextData>,
): Promise<Response> {
  if (options.tracer == null) {
    return await handleWebFingerInternal(request, options);
  }
  return await options.tracer.startActiveSpan(
    "WebFinger",
    { kind: SpanKind.SERVER },
    async (span) => {
      try {
        const response = await handleWebFingerInternal(request, options);
        span.setStatus({
          code: response.ok ? SpanStatusCode.UNSET : SpanStatusCode.ERROR,
        });
        return response;
      } catch (error) {
        span.setStatus({
          code: SpanStatusCode.ERROR,
          message: String(error),
        });
        throw error;
      } finally {
        span.end();
      }
    },
  );
}

async function handleWebFingerInternal<TContextData>(
  request: Request,
  {
    context,
    actorDispatcher,
    actorHandleMapper,
    onNotFound,
    span,
  }: WebFingerHandlerParameters<TContextData>,
): Promise<Response> {
  if (actorDispatcher == null) return await onNotFound(request);
@@ -57,6 +100,7 @@ export async function handleWebFinger<TContextData>(
  if (resource == null) {
    return new Response("Missing resource parameter.", { status: 400 });
  }
  span?.setAttribute("webfinger.resource", resource);
  let resourceUrl: URL;
  try {
    resourceUrl = new URL(resource);