From 9aced2c38f7819f09dbcd703b5b2ecd7caa9b4a0 Mon Sep 17 00:00:00 2001 From: Marco Gancitano Date: Mon, 31 Aug 2026 12:35:06 -0400 Subject: [PATCH 1/4] chore(aio): add Go OpenTelemetry setup to installation docs The posthog-go OTel bridge (PostHog/posthog-go#306) gives Go apps a supported path into AI observability. Add a Go tab to the OpenTelemetry installation steps (install, tracer setup, LLM call, session grouping), and point Go users on the provider wrapper pages at the OpenTelemetry integration, since no Go wrappers exist yet. Co-Authored-By: Claude Fable 5 --- .../_snippets/go-otel-tab.tsx | 7 ++ .../_snippets/openai-compatible.tsx | 2 + .../_snippets/otel-session-id.tsx | 37 +++++- .../onboarding/ai-observability/anthropic.tsx | 2 + .../ai-observability/aws-bedrock.tsx | 2 + .../ai-observability/azure-openai.tsx | 2 + docs/onboarding/ai-observability/google.tsx | 2 + docs/onboarding/ai-observability/openai.tsx | 2 + .../ai-observability/opentelemetry.tsx | 109 ++++++++++++++++-- .../shared/OnboardingDocsContentWrapper.tsx | 12 +- 10 files changed, 163 insertions(+), 14 deletions(-) create mode 100644 docs/onboarding/ai-observability/_snippets/go-otel-tab.tsx diff --git a/docs/onboarding/ai-observability/_snippets/go-otel-tab.tsx b/docs/onboarding/ai-observability/_snippets/go-otel-tab.tsx new file mode 100644 index 000000000000..6ec1db62b5e6 --- /dev/null +++ b/docs/onboarding/ai-observability/_snippets/go-otel-tab.tsx @@ -0,0 +1,7 @@ +/** A Go tab for provider code samples whose PostHog wrapper only exists for Python and Node. */ +export const GO_OTEL_TAB = { + // 'prose' renders as markdown text with a clickable link, not highlighted code + language: 'prose', + file: 'Go', + code: "PostHog doesn't have a Go wrapper for this SDK yet. Use the [OpenTelemetry integration](https://posthog.com/docs/ai-observability/installation/opentelemetry) instead.", +} diff --git a/docs/onboarding/ai-observability/_snippets/openai-compatible.tsx b/docs/onboarding/ai-observability/_snippets/openai-compatible.tsx index 3fbf5911c23b..b1a68db17078 100644 --- a/docs/onboarding/ai-observability/_snippets/openai-compatible.tsx +++ b/docs/onboarding/ai-observability/_snippets/openai-compatible.tsx @@ -1,6 +1,7 @@ import { OnboardingComponentsContext } from 'scenes/onboarding/shared/OnboardingDocsContentWrapper' import { StepDefinition } from '../../steps' +import { GO_OTEL_TAB } from './go-otel-tab' export interface OpenAICompatibleConfig { /** Display name, e.g. 'DeepSeek' */ @@ -58,6 +59,7 @@ export const getOpenAICompatibleSteps = ( npm install @posthog/ai posthog-node openai `, }, + GO_OTEL_TAB, ]} /> diff --git a/docs/onboarding/ai-observability/_snippets/otel-session-id.tsx b/docs/onboarding/ai-observability/_snippets/otel-session-id.tsx index 6f9e1c4091d8..7a29b4516c64 100644 --- a/docs/onboarding/ai-observability/_snippets/otel-session-id.tsx +++ b/docs/onboarding/ai-observability/_snippets/otel-session-id.tsx @@ -4,7 +4,7 @@ import { StepDefinition } from '../../steps' export interface OtelSessionIdConfig { /** Language tabs the surrounding page shows, in the order it shows them. */ - languages: ('Python' | 'Node')[] + languages: ('Python' | 'Node' | 'Go')[] } const PYTHON_CODE = ` @@ -67,9 +67,44 @@ class SessionIdSpanProcessor implements SpanProcessor { const reply = await sessionStore.run('conversation-abc', () => handleTurn(userMessage)) `.trim() +const GO_CODE = ` +import ( + "context" + + "go.opentelemetry.io/otel/attribute" + sdktrace "go.opentelemetry.io/otel/sdk/trace" +) + +type sessionKey struct{} + +// WithAISession returns a context whose spans carry this session ID. +func WithAISession(ctx context.Context, sessionID string) context.Context { + return context.WithValue(ctx, sessionKey{}, sessionID) +} + +type SessionIDSpanProcessor struct{} + +func (SessionIDSpanProcessor) OnStart(parent context.Context, span sdktrace.ReadWriteSpan) { + if sessionID, ok := parent.Value(sessionKey{}).(string); ok { + span.SetAttributes(attribute.String("$ai_session_id", sessionID)) + } +} +func (SessionIDSpanProcessor) OnEnd(sdktrace.ReadOnlySpan) {} +func (SessionIDSpanProcessor) Shutdown(context.Context) error { return nil } +func (SessionIDSpanProcessor) ForceFlush(context.Context) error { return nil } + +// Register it on the same provider as the PostHog processor: +// sdktrace.WithSpanProcessor(SessionIDSpanProcessor{}) + +// Every span started from this context carries the session ID +ctx = WithAISession(ctx, "conversation-abc") +reply := handleTurn(ctx, userMessage) +`.trim() + const CODE_BY_LANGUAGE = { Python: { language: 'python', file: 'Python', code: PYTHON_CODE }, Node: { language: 'typescript', file: 'Node', code: NODE_CODE }, + Go: { language: 'go', file: 'Go', code: GO_CODE }, } export const getOtelSessionIdStep = (ctx: OnboardingComponentsContext, config: OtelSessionIdConfig): StepDefinition => { diff --git a/docs/onboarding/ai-observability/anthropic.tsx b/docs/onboarding/ai-observability/anthropic.tsx index 835ecac799a7..f9ebb51b9377 100644 --- a/docs/onboarding/ai-observability/anthropic.tsx +++ b/docs/onboarding/ai-observability/anthropic.tsx @@ -1,6 +1,7 @@ import { OnboardingComponentsContext, createInstallation } from 'scenes/onboarding/shared/OnboardingDocsContentWrapper' import { StepDefinition } from '../steps' +import { GO_OTEL_TAB } from './_snippets/go-otel-tab' export const getAnthropicSteps = (ctx: OnboardingComponentsContext): StepDefinition[] => { const { CodeBlock, CalloutBox, Markdown, Blockquote, dedent, snippets } = ctx @@ -40,6 +41,7 @@ export const getAnthropicSteps = (ctx: OnboardingComponentsContext): StepDefinit npm install @posthog/ai posthog-node @anthropic-ai/sdk `, }, + GO_OTEL_TAB, ]} /> diff --git a/docs/onboarding/ai-observability/aws-bedrock.tsx b/docs/onboarding/ai-observability/aws-bedrock.tsx index cba3cee9a5ee..87a57bb90cce 100644 --- a/docs/onboarding/ai-observability/aws-bedrock.tsx +++ b/docs/onboarding/ai-observability/aws-bedrock.tsx @@ -1,6 +1,7 @@ import { OnboardingComponentsContext, createInstallation } from 'scenes/onboarding/shared/OnboardingDocsContentWrapper' import { StepDefinition } from '../steps' +import { GO_OTEL_TAB } from './_snippets/go-otel-tab' import { getOtelSessionIdStep } from './_snippets/otel-session-id' export const getAWSBedrockSteps = (ctx: OnboardingComponentsContext): StepDefinition[] => { @@ -34,6 +35,7 @@ export const getAWSBedrockSteps = (ctx: OnboardingComponentsContext): StepDefini npm install @aws-sdk/client-bedrock-runtime @opentelemetry/instrumentation-aws-sdk @opentelemetry/sdk-node @opentelemetry/resources @posthog/ai `, }, + GO_OTEL_TAB, ]} /> diff --git a/docs/onboarding/ai-observability/azure-openai.tsx b/docs/onboarding/ai-observability/azure-openai.tsx index 79a750bac02d..467846cc443e 100644 --- a/docs/onboarding/ai-observability/azure-openai.tsx +++ b/docs/onboarding/ai-observability/azure-openai.tsx @@ -1,6 +1,7 @@ import { OnboardingComponentsContext, createInstallation } from 'scenes/onboarding/shared/OnboardingDocsContentWrapper' import { StepDefinition } from '../steps' +import { GO_OTEL_TAB } from './_snippets/go-otel-tab' export const getAzureOpenAISteps = (ctx: OnboardingComponentsContext): StepDefinition[] => { const { CodeBlock, CalloutBox, Markdown, Blockquote, dedent, snippets } = ctx @@ -41,6 +42,7 @@ export const getAzureOpenAISteps = (ctx: OnboardingComponentsContext): StepDefin npm install @posthog/ai posthog-node openai `, }, + GO_OTEL_TAB, ]} /> diff --git a/docs/onboarding/ai-observability/google.tsx b/docs/onboarding/ai-observability/google.tsx index 1097af45947b..8894c87eb43e 100644 --- a/docs/onboarding/ai-observability/google.tsx +++ b/docs/onboarding/ai-observability/google.tsx @@ -1,6 +1,7 @@ import { OnboardingComponentsContext, createInstallation } from 'scenes/onboarding/shared/OnboardingDocsContentWrapper' import { StepDefinition } from '../steps' +import { GO_OTEL_TAB } from './_snippets/go-otel-tab' export const getGoogleSteps = (ctx: OnboardingComponentsContext): StepDefinition[] => { const { CodeBlock, CalloutBox, Markdown, Blockquote, dedent, snippets } = ctx @@ -39,6 +40,7 @@ export const getGoogleSteps = (ctx: OnboardingComponentsContext): StepDefinition npm install @posthog/ai posthog-node @google/genai `, }, + GO_OTEL_TAB, ]} /> diff --git a/docs/onboarding/ai-observability/openai.tsx b/docs/onboarding/ai-observability/openai.tsx index f1c95a21b67c..c055a2d13de8 100644 --- a/docs/onboarding/ai-observability/openai.tsx +++ b/docs/onboarding/ai-observability/openai.tsx @@ -1,6 +1,7 @@ import { OnboardingComponentsContext, createInstallation } from 'scenes/onboarding/shared/OnboardingDocsContentWrapper' import { StepDefinition } from '../steps' +import { GO_OTEL_TAB } from './_snippets/go-otel-tab' export const getOpenAISteps = (ctx: OnboardingComponentsContext): StepDefinition[] => { const { CodeBlock, CalloutBox, Markdown, Blockquote, dedent, snippets } = ctx @@ -40,6 +41,7 @@ export const getOpenAISteps = (ctx: OnboardingComponentsContext): StepDefinition npm install @posthog/ai posthog-node openai `, }, + GO_OTEL_TAB, ]} /> diff --git a/docs/onboarding/ai-observability/opentelemetry.tsx b/docs/onboarding/ai-observability/opentelemetry.tsx index 97f230d1fa84..0504cbf8227e 100644 --- a/docs/onboarding/ai-observability/opentelemetry.tsx +++ b/docs/onboarding/ai-observability/opentelemetry.tsx @@ -16,11 +16,11 @@ export const getOpenTelemetrySteps = (ctx: OnboardingComponentsContext): StepDef <> - The [Node.js](https://github.com/PostHog/posthog-js/tree/main/examples/example-ai-openai) - and - [Python](https://github.com/PostHog/posthog-python/tree/master/examples/example-ai-openai) - OpenAI examples show a complete end-to-end OpenTelemetry setup. Swap the instrumentation for - any other `gen_ai.*`-emitting library to trace a different provider or framework. + The [Node.js](https://github.com/PostHog/posthog-js/tree/main/examples/example-ai-openai), + [Python](https://github.com/PostHog/posthog-python/tree/master/examples/example-ai-openai), + and [Go](https://github.com/PostHog/posthog-go/tree/main/otel/example) examples show a + complete end-to-end OpenTelemetry setup. Swap the instrumentation for any other + `gen_ai.*`-emitting library to trace a different provider or framework. @@ -46,6 +46,13 @@ export const getOpenTelemetrySteps = (ctx: OnboardingComponentsContext): StepDef npm install openai @posthog/ai @opentelemetry/sdk-node @opentelemetry/resources @opentelemetry/instrumentation-openai `, }, + { + language: 'bash', + file: 'Go', + code: dedent` + go get github.com/posthog/posthog-go/otel go.opentelemetry.io/otel go.opentelemetry.io/otel/sdk + `, + }, ]} /> @@ -57,10 +64,10 @@ export const getOpenTelemetrySteps = (ctx: OnboardingComponentsContext): StepDef content: ( <> - Configure OpenTelemetry to export spans to PostHog via the `PostHogSpanProcessor`. The processor - only forwards AI-related spans — spans whose name or attribute keys start with `gen_ai.`, - `llm.`, `ai.`, or `traceloop.` — and drops everything else. PostHog converts `gen_ai.*` spans - into `$ai_generation` events automatically. + Configure OpenTelemetry to export spans to PostHog via the `PostHogSpanProcessor` + (`posthogotel.NewSpanProcessor` in Go). The processor only forwards AI-related spans — spans + whose name or attribute keys start with `gen_ai.`, `llm.`, `ai.`, or `traceloop.` — and drops + everything else. PostHog converts `gen_ai.*` spans into `$ai_generation` events automatically. ", + posthogotel.WithHost(""), + ) + if err != nil { + return nil, err + } + + resource := sdkresource.NewWithAttributes("", + attribute.String("service.name", "my-app"), + attribute.String("posthog.distinct_id", "user_123"), // optional: identifies the user in PostHog + attribute.String("foo", "bar"), // custom properties are passed through + ) + provider := sdktrace.NewTracerProvider( + sdktrace.WithResource(resource), + sdktrace.WithSpanProcessor(processor), + ) + otel.SetTracerProvider(provider) + return provider, nil + } + `, + }, ]} /> + + + {dedent` + In Go, if your app already has a \`TracerProvider\`, register the processor on it with + \`sdktrace.WithSpanProcessor\` instead of creating a new provider. Call + \`provider.Shutdown\` (or \`provider.ForceFlush\`) before exit so buffered spans are sent. + `} + ), }, @@ -135,6 +186,15 @@ export const getOpenTelemetrySteps = (ctx: OnboardingComponentsContext): StepDef `$ai_generation` event. + + {dedent` + Go has no instrumentation libraries for provider SDKs yet: start a span around each call + and set the \`gen_ai.*\` attributes yourself, as shown in the Go tab. Frameworks that + already emit \`gen_ai.*\` spans, like [ADK Go](https://google.golang.org/adk), are captured + automatically. + `} + + @@ -234,7 +321,7 @@ export const getOpenTelemetrySteps = (ctx: OnboardingComponentsContext): StepDef ), }, - getOtelSessionIdStep(ctx, { languages: ['Python', 'Node'] }), + getOtelSessionIdStep(ctx, { languages: ['Python', 'Node', 'Go'] }), { title: 'Other instrumentations, direct OTLP, and troubleshooting', badge: 'optional', @@ -253,7 +340,7 @@ export const getOpenTelemetrySteps = (ctx: OnboardingComponentsContext): StepDef {dedent` - **Direct OTLP export.** If you run an OpenTelemetry Collector, or want to export from a language that isn't Python or Node.js, point any OTLP/HTTP exporter directly at PostHog's AI ingestion endpoint. PostHog accepts OTLP over HTTP in both \`application/x-protobuf\` and \`application/json\`, authenticated with a \`Bearer\` token. The endpoint is signal-specific (traces only), so use the \`OTEL_EXPORTER_OTLP_TRACES_*\` variants rather than the general \`OTEL_EXPORTER_OTLP_*\` ones (the SDK appends \`/v1/traces\` to the latter and would 404). + **Direct OTLP export.** If you run an OpenTelemetry Collector, or want to export from a language PostHog has no OpenTelemetry helper for (Python, Node.js, and Go have one), point any OTLP/HTTP exporter directly at PostHog's AI ingestion endpoint. PostHog accepts OTLP over HTTP in both \`application/x-protobuf\` and \`application/json\`, authenticated with a \`Bearer\` token. The endpoint is signal-specific (traces only), so use the \`OTEL_EXPORTER_OTLP_TRACES_*\` variants rather than the general \`OTEL_EXPORTER_OTLP_*\` ones (the SDK appends \`/v1/traces\` to the latter and would 404). `} diff --git a/frontend/src/scenes/onboarding/shared/OnboardingDocsContentWrapper.tsx b/frontend/src/scenes/onboarding/shared/OnboardingDocsContentWrapper.tsx index 9fb0e383bf97..75ea1ea5e101 100644 --- a/frontend/src/scenes/onboarding/shared/OnboardingDocsContentWrapper.tsx +++ b/frontend/src/scenes/onboarding/shared/OnboardingDocsContentWrapper.tsx @@ -194,7 +194,11 @@ function CodeBlock({ const block = codeBlocks[0] return (
- {block.code} + {block.language === 'prose' ? ( + {block.code} + ) : ( + {block.code} + )} {hostHint}
) @@ -219,7 +223,11 @@ function CodeBlock({ }))} /> )} - {selectedBlock.code} + {selectedBlock.language === 'prose' ? ( + {selectedBlock.code} + ) : ( + {selectedBlock.code} + )} {hostHint} ) From a6202b67e1452ce791007e979aad85f270d51467 Mon Sep 17 00:00:00 2001 From: Marco Gancitano Date: Tue, 1 Sep 2026 10:03:16 -0400 Subject: [PATCH 2/4] chore(aio): fix go otel samples for existing providers and failed calls Co-Authored-By: Claude Fable 5 --- .../ai-observability/opentelemetry.tsx | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/docs/onboarding/ai-observability/opentelemetry.tsx b/docs/onboarding/ai-observability/opentelemetry.tsx index 0504cbf8227e..b6566145b235 100644 --- a/docs/onboarding/ai-observability/opentelemetry.tsx +++ b/docs/onboarding/ai-observability/opentelemetry.tsx @@ -167,8 +167,8 @@ export const getOpenTelemetrySteps = (ctx: OnboardingComponentsContext): StepDef {dedent` - In Go, if your app already has a \`TracerProvider\`, register the processor on it with - \`sdktrace.WithSpanProcessor\` instead of creating a new provider. Call + In Go, if your app already has a \`TracerProvider\`, attach the processor to it with + \`provider.RegisterSpanProcessor(processor)\` instead of creating a new provider. Call \`provider.Shutdown\` (or \`provider.ForceFlush\`) before exit so buffered spans are sent. `} @@ -237,23 +237,28 @@ export const getOpenTelemetrySteps = (ctx: OnboardingComponentsContext): StepDef code: dedent` tracer := otel.Tracer("my-app") _, span := tracer.Start(ctx, "chat gpt-5-mini") + // Set the request attributes before the call so a failed call still + // carries the gen_ai.* keys the PostHog span filter looks for + span.SetAttributes( + attribute.String("gen_ai.operation.name", "chat"), + attribute.String("gen_ai.provider.name", "openai"), + attribute.String("gen_ai.request.model", "gpt-5-mini"), + // JSON-serialized chat messages + attribute.String("gen_ai.input.messages", \`[{"role":"user","content":"Tell me a fun fact about hedgehogs"}]\`), + attribute.String("server.address", "api.openai.com"), + ) resp, err := client.Chat.Completions.New(ctx, params) // your existing LLM call if err != nil { + span.RecordError(err) span.End() return err } span.SetAttributes( - attribute.String("gen_ai.operation.name", "chat"), - attribute.String("gen_ai.provider.name", "openai"), - attribute.String("gen_ai.request.model", "gpt-5-mini"), - // JSON-serialized chat messages - attribute.String("gen_ai.input.messages", \`[{"role":"user","content":"Tell me a fun fact about hedgehogs"}]\`), attribute.String("gen_ai.output.messages", \`[{"role":"assistant","content":"Hedgehogs have around 5,000 spines."}]\`), attribute.Int("gen_ai.usage.input_tokens", int(resp.Usage.PromptTokens)), attribute.Int("gen_ai.usage.output_tokens", int(resp.Usage.CompletionTokens)), - attribute.String("server.address", "api.openai.com"), ) span.End() `, From 484baf420d96c1e5e3596591c06ad57cd4635a1d Mon Sep 17 00:00:00 2001 From: Marco Gancitano Date: Tue, 1 Sep 2026 12:05:19 -0400 Subject: [PATCH 3/4] chore(aio): address go otel docs review feedback Co-Authored-By: Claude Fable 5 --- .../onboarding/ai-observability/_snippets/go-otel-tab.tsx | 5 +++-- docs/onboarding/ai-observability/aws-bedrock.tsx | 8 ++++++-- docs/onboarding/ai-observability/opentelemetry.tsx | 7 +++++-- docs/onboarding/steps.ts | 3 +++ .../onboarding/shared/OnboardingDocsContentWrapper.tsx | 5 +++-- 5 files changed, 20 insertions(+), 8 deletions(-) diff --git a/docs/onboarding/ai-observability/_snippets/go-otel-tab.tsx b/docs/onboarding/ai-observability/_snippets/go-otel-tab.tsx index 6ec1db62b5e6..2dce199acf41 100644 --- a/docs/onboarding/ai-observability/_snippets/go-otel-tab.tsx +++ b/docs/onboarding/ai-observability/_snippets/go-otel-tab.tsx @@ -1,7 +1,8 @@ +import { PROSE_LANGUAGE } from '../../steps' + /** A Go tab for provider code samples whose PostHog wrapper only exists for Python and Node. */ export const GO_OTEL_TAB = { - // 'prose' renders as markdown text with a clickable link, not highlighted code - language: 'prose', + language: PROSE_LANGUAGE, file: 'Go', code: "PostHog doesn't have a Go wrapper for this SDK yet. Use the [OpenTelemetry integration](https://posthog.com/docs/ai-observability/installation/opentelemetry) instead.", } diff --git a/docs/onboarding/ai-observability/aws-bedrock.tsx b/docs/onboarding/ai-observability/aws-bedrock.tsx index 87a57bb90cce..08fcc10e858f 100644 --- a/docs/onboarding/ai-observability/aws-bedrock.tsx +++ b/docs/onboarding/ai-observability/aws-bedrock.tsx @@ -1,7 +1,7 @@ import { OnboardingComponentsContext, createInstallation } from 'scenes/onboarding/shared/OnboardingDocsContentWrapper' import { StepDefinition } from '../steps' -import { GO_OTEL_TAB } from './_snippets/go-otel-tab' +import { PROSE_LANGUAGE } from '../steps' import { getOtelSessionIdStep } from './_snippets/otel-session-id' export const getAWSBedrockSteps = (ctx: OnboardingComponentsContext): StepDefinition[] => { @@ -35,7 +35,11 @@ export const getAWSBedrockSteps = (ctx: OnboardingComponentsContext): StepDefini npm install @aws-sdk/client-bedrock-runtime @opentelemetry/instrumentation-aws-sdk @opentelemetry/sdk-node @opentelemetry/resources @posthog/ai `, }, - GO_OTEL_TAB, + { + language: PROSE_LANGUAGE, + file: 'Go', + code: "There are no Go instrumentation libraries for the AWS SDK yet. Register PostHog's span processor and set the `gen_ai.*` attributes on a span around each Bedrock call, as shown in the Go tab of the [OpenTelemetry integration](https://posthog.com/docs/ai-observability/installation/opentelemetry).", + }, ]} /> diff --git a/docs/onboarding/ai-observability/opentelemetry.tsx b/docs/onboarding/ai-observability/opentelemetry.tsx index b6566145b235..b7f0c29e9cbe 100644 --- a/docs/onboarding/ai-observability/opentelemetry.tsx +++ b/docs/onboarding/ai-observability/opentelemetry.tsx @@ -191,7 +191,8 @@ export const getOpenTelemetrySteps = (ctx: OnboardingComponentsContext): StepDef Go has no instrumentation libraries for provider SDKs yet: start a span around each call and set the \`gen_ai.*\` attributes yourself, as shown in the Go tab. Frameworks that already emit \`gen_ai.*\` spans, like [ADK Go](https://google.golang.org/adk), are captured - automatically. + automatically. ADK Go sends message content as log records rather than span attributes, + so its generations arrive without prompts and responses. `} @@ -251,6 +252,8 @@ export const getOpenTelemetrySteps = (ctx: OnboardingComponentsContext): StepDef resp, err := client.Chat.Completions.New(ctx, params) // your existing LLM call if err != nil { span.RecordError(err) + // Status Error is what marks the event as a failed generation in PostHog + span.SetStatus(codes.Error, err.Error()) span.End() return err } @@ -345,7 +348,7 @@ export const getOpenTelemetrySteps = (ctx: OnboardingComponentsContext): StepDef {dedent` - **Direct OTLP export.** If you run an OpenTelemetry Collector, or want to export from a language PostHog has no OpenTelemetry helper for (Python, Node.js, and Go have one), point any OTLP/HTTP exporter directly at PostHog's AI ingestion endpoint. PostHog accepts OTLP over HTTP in both \`application/x-protobuf\` and \`application/json\`, authenticated with a \`Bearer\` token. The endpoint is signal-specific (traces only), so use the \`OTEL_EXPORTER_OTLP_TRACES_*\` variants rather than the general \`OTEL_EXPORTER_OTLP_*\` ones (the SDK appends \`/v1/traces\` to the latter and would 404). + **Direct OTLP export.** If you run an OpenTelemetry Collector, or want to export from a language other than Python, Node.js, or Go, point any OTLP/HTTP exporter directly at PostHog's AI ingestion endpoint. PostHog accepts OTLP over HTTP in both \`application/x-protobuf\` and \`application/json\`, authenticated with a \`Bearer\` token. The endpoint is signal-specific (traces only), so use the \`OTEL_EXPORTER_OTLP_TRACES_*\` variants rather than the general \`OTEL_EXPORTER_OTLP_*\` ones (the SDK appends \`/v1/traces\` to the latter and would 404). `} diff --git a/docs/onboarding/steps.ts b/docs/onboarding/steps.ts index 465ad145ce81..3faa8395eaf2 100644 --- a/docs/onboarding/steps.ts +++ b/docs/onboarding/steps.ts @@ -24,3 +24,6 @@ export interface StepProps { export interface StepsProps { children: ReactNode } + +/** CodeBlock tab language that renders markdown prose with clickable links instead of highlighted code. */ +export const PROSE_LANGUAGE = 'prose' diff --git a/frontend/src/scenes/onboarding/shared/OnboardingDocsContentWrapper.tsx b/frontend/src/scenes/onboarding/shared/OnboardingDocsContentWrapper.tsx index 75ea1ea5e101..5fd6953d0bee 100644 --- a/frontend/src/scenes/onboarding/shared/OnboardingDocsContentWrapper.tsx +++ b/frontend/src/scenes/onboarding/shared/OnboardingDocsContentWrapper.tsx @@ -3,6 +3,7 @@ import React, { Children, ReactNode, createContext, isValidElement, useContext, import { StepProps, StepsProps } from '@posthog/shared-onboarding/steps' import { StepDefinition, StepModifier } from '@posthog/shared-onboarding/steps' +import { PROSE_LANGUAGE } from '@posthog/shared-onboarding/steps' import { CodeSnippet, getLanguage } from 'lib/components/CodeSnippet' import { CopyToClipboardInline } from 'lib/components/CopyToClipboard' @@ -194,7 +195,7 @@ function CodeBlock({ const block = codeBlocks[0] return (
- {block.language === 'prose' ? ( + {block.language === PROSE_LANGUAGE ? ( {block.code} ) : ( {block.code} @@ -223,7 +224,7 @@ function CodeBlock({ }))} /> )} - {selectedBlock.language === 'prose' ? ( + {selectedBlock.language === PROSE_LANGUAGE ? ( {selectedBlock.code} ) : ( {selectedBlock.code} From 7bc85e9a5b100677a5ffbae8b16812785dee0926 Mon Sep 17 00:00:00 2001 From: Carlos Marchal Date: Tue, 1 Sep 2026 18:12:44 +0200 Subject: [PATCH 4/4] chore(aio): add missing codes import to go otel snippet --- docs/onboarding/ai-observability/aws-bedrock.tsx | 3 +-- docs/onboarding/ai-observability/opentelemetry.tsx | 6 ++++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/docs/onboarding/ai-observability/aws-bedrock.tsx b/docs/onboarding/ai-observability/aws-bedrock.tsx index 08fcc10e858f..1d42198a39b1 100644 --- a/docs/onboarding/ai-observability/aws-bedrock.tsx +++ b/docs/onboarding/ai-observability/aws-bedrock.tsx @@ -1,7 +1,6 @@ import { OnboardingComponentsContext, createInstallation } from 'scenes/onboarding/shared/OnboardingDocsContentWrapper' -import { StepDefinition } from '../steps' -import { PROSE_LANGUAGE } from '../steps' +import { PROSE_LANGUAGE, StepDefinition } from '../steps' import { getOtelSessionIdStep } from './_snippets/otel-session-id' export const getAWSBedrockSteps = (ctx: OnboardingComponentsContext): StepDefinition[] => { diff --git a/docs/onboarding/ai-observability/opentelemetry.tsx b/docs/onboarding/ai-observability/opentelemetry.tsx index b7f0c29e9cbe..ae9da6ea77f8 100644 --- a/docs/onboarding/ai-observability/opentelemetry.tsx +++ b/docs/onboarding/ai-observability/opentelemetry.tsx @@ -236,6 +236,12 @@ export const getOpenTelemetrySteps = (ctx: OnboardingComponentsContext): StepDef language: 'go', file: 'Go', code: dedent` + import ( + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/codes" + ) + tracer := otel.Tracer("my-app") _, span := tracer.Start(ctx, "chat gpt-5-mini") // Set the request attributes before the call so a failed call still