fiberplane / fpx

Supercharge your local development
https://fiberplane.dev
MIT License
43 stars 1 forks source link

Client-library-otel #83

Closed flenter closed 1 month ago

flenter commented 1 month ago

This is the initial implementation of the open telemetry compliant version of the fpx client library.

The api is slightly different. First the current library:

import { createHonoMiddleware } from "@fiberplane/hono";

const app = new Hono()
app.use(createHonoMiddleware(app))

app.get("/", (c) => {
  return c.text("Hello Hono!");
});

export default app;

New:

import { instrument } from "@fiberplane/hono-otel"

const app = new Hono()

app.get("/", (c) => {
  return c.text("Hello Hono!");
});

export default instrument(app);

There's also a measure function which you can use to wrap functions you want to measure.

So:

// Simple for testing synchronous javascript execution
const loop = measure("loop", (n: number) => {
  for (let i = 0; i < n; i++) {
    console.log(`Loop iteration: ${i}`);
  }
});

Or a function that returns a promise:

// Simple function that sleeps for a bit, logs the duration and returns it
const sleep = measure("sleep", (ms: number) => {
  return new Promise<number>((resolve) =>
    setTimeout(() => {
      console.log(`Slept for ${ms}ms`);
      resolve();
    }, ms),
  );
});

Instead of passing in a string, you can also pass in an options object, which you can use to do things like setting attributes on the active span and change the spanKind:

type MeasureOptions<
  /**
   * Arguments for the function being measured
   */
  ARGS,
  /**
   * The return type of the function being measured
   * (awaited result if the return value is a promise)
   */
  RESULT,
  /**
   * The raw return type of the function being measured
   * (it is used to determine if the onEnd function can be async)
   */
  RAW_RESULT,
> = {
  name: string;
  /**
   * The kind of the span
   */
  spanKind?: SpanKind;
  /**
   * Attributes to be added to the span
   */
  attributes?: Attributes;

  onStart?: (span: Span, args: ARGS) => void;
  /**
   * Allows you to specify a function that will be called when the span ends
   * and will be passed the span & result of the function being measured.
   *
   * This way you can do things like add additional attributes to the span
   */
  onEnd?: (
    span: Span,
    result: RESULT,
  ) => RAW_RESULT extends Promise<unknown> ? Promise<void> | void : void;

  /**
   * Allows you to specify a function that will be called when the span ends
   * with an error and will be passed the (current) span & error that occurred.
   *
   * This way you can do things like add additional attributes to the span
   */
  onError?: (span: Span, error: unknown) => void;
};