Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 82 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,88 @@ When `nubx` is available, OASmith runs its pinned Oxfmt version through
`nubx`'s local discovery and registry fallback. No Node project or installed
Oxfmt dependency is required. Generation still works without `nubx`.

## OpenTelemetry trace propagation

Generated clients leave OpenTelemetry dependencies and SDK setup to the
application. Pass an instrumented transport to a Go client or an instrumented
`fetch` implementation to a TypeScript client. These examples assume the
application has initialized an OpenTelemetry SDK; `@opentelemetry/api` alone
uses no-op tracing and propagation implementations.

### Go

Install `go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp`, wrap an
explicit HTTP transport, and pass the active `context.Context` to every
generated operation:

```go
transport := otelhttp.NewTransport(http.DefaultTransport)
httpClient := &http.Client{Transport: transport}

client, err := apiclient.NewClient(
apiclient.ClientOptions{BaseURL: "https://api.example.com"},
apiclient.WithHTTPClient(httpClient),
)
if err != nil {
return err
}

ctx, span := otel.Tracer("example-app").Start(ctx, "create thing")
defer span.End()

_, err = client.CreateThing(ctx, params)
return err
```

The generated request keeps the operation context. `otelhttp.Transport` reads
its span context and injects the configured propagation headers, such as
`traceparent`, before sending the request. Pass the derived `ctx`; replacing it
with `context.Background()` breaks the parent trace.

### TypeScript

The generated `ClientOptions.fetch` hook can ask the registered global
propagator to inject the active OpenTelemetry context immediately before
transport execution:

```typescript
import { context, propagation, trace } from '@opentelemetry/api';
import { DefaultApi } from './gen/api.ts';

const baseFetch = globalThis.fetch;
const otelFetch: typeof globalThis.fetch = async (input, init) => {
const request = new Request(input, init);
const headers = new Headers(request.headers);
propagation.inject(context.active(), headers, {
set(carrier, key, value): void {
carrier.set(key, value);
},
});
return await baseFetch(new Request(request, { headers }));
};

const api = new DefaultApi({
baseURL: 'https://api.example.com',
fetch: otelFetch,
});

const tracer = trace.getTracer('example-app');
await tracer.startActiveSpan('create thing', async span => {
try {
await api.createThing(params);
} finally {
span.end();
}
});
```

The application SDK must register both a context manager and a text-map
propagator. `context.active()` must contain a valid span context, and a W3C Trace
Context propagator must be registered for `propagation.inject` to add
`traceparent`; otherwise it adds no trace header. For browser calls across
origins, the API's CORS policy must also allow the propagation headers configured
by the application, commonly `traceparent`, `tracestate`, and `baggage`.

## Develop

[Nub](https://nubjs.com) resolves pinned Oxfmt and Vitest versions on demand.
Expand Down
Loading