![]() |
VOOZH | about |
dotnet add package PostHog.AI --version 0.1.2
NuGet\Install-Package PostHog.AI -Version 0.1.2
<PackageReference Include="PostHog.AI" Version="0.1.2" />
<PackageVersion Include="PostHog.AI" Version="0.1.2" />Directory.Packages.props
<PackageReference Include="PostHog.AI" />Project file
paket add PostHog.AI --version 0.1.2
#r "nuget: PostHog.AI, 0.1.2"
#:package PostHog.AI@0.1.2
#addin nuget:?package=PostHog.AI&version=0.1.2Install as a Cake Addin
#tool nuget:?package=PostHog.AI&version=0.1.2Install as a Cake Tool
This package provides AI Observability for .NET applications using PostHog. It currently supports intercepting and tracing requests to OpenAI and Azure OpenAI.
This package is currently in a pre-release stage. We're making it available publicly to solicit feedback. While we always strive to maintain a high level of quality, use this package at your own risk. There will be many breaking changes until we reach a stable release.
Install the PostHog.AI package via NuGet:
dotnet add package PostHog.AI
The easiest way to use PostHog.AI is via the AddPostHogOpenAIClient extension method. This registers an OpenAIClient that is automatically configured to use PostHog for observability.
using PostHog;
using PostHog.AI;
using OpenAI;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
var builder = Host.CreateApplicationBuilder(args);
// 1. Configure PostHog
builder.Services.AddPostHog(options =>
{
options.ProjectToken = "YOUR_PROJECT_TOKEN";
options.HostUrl = new Uri("https://us.i.posthog.com"); // or eu.i.posthog.com
});
// 2. Register OpenAI Client with PostHog integration
// This registers OpenAIClient as a Singleton and configures it to use the PostHog interceptor.
// You can also chain additional HTTP handlers here (e.g., for resilience).
builder.Services.AddPostHogOpenAIClient("YOUR_OPENAI_API_KEY", options =>
{
// Optional: Configure OpenAIClientOptions here
});
var host = builder.Build();
// 3. Inject and use OpenAIClient
var openAIClient = host.Services.GetRequiredService<OpenAIClient>();
// ... use client
Note:
AddPostHogOpenAIClientoverrides theTransportproperty ofOpenAIClientOptionsto inject the PostHog handler. If you need a custom Transport implementation (rare), you should manually configure the client as shown below.
If you need more control or are not using the helper method:
using PostHog.AI;
using OpenAI;
using System.ClientModel;
using System.ClientModel.Primitives;
// 1. Register PostHog AI services
builder.Services.AddPostHogAI();
// 2. Configure OpenAI Client with the intercepting handler manually
builder.Services.AddHttpClient("PostHogOpenAI") // Named client
.AddPostHogOpenAIHandler();
builder.Services.AddSingleton<OpenAIClient>(sp =>
{
var httpClientFactory = sp.GetRequiredService<IHttpClientFactory>();
var httpClient = httpClientFactory.CreateClient("PostHogOpenAI");
// Explicitly set the transport
var options = new OpenAIClientOptions
{
Transport = new HttpClientPipelineTransport(httpClient)
};
return new OpenAIClient(new ApiKeyCredential("YOUR_OPENAI_API_KEY"), options);
});
$ai_generation and $ai_embedding events.$ai_embedding events for embedding requests.PostHogAIContext.The handler automatically extracts and captures the following properties from OpenAI API requests and responses:
$ai_trace_id - Unique identifier (UUID) for grouping AI events$ai_provider - AI service provider (e.g., "openai")$ai_lib - Library identifier ("posthog-dotnet")$ai_model - Model name used for the generation$ai_latency - Request latency in seconds$ai_base_url - Base URL of the API endpoint$ai_request_url - Full URL of the API request$ai_http_status - HTTP status code of the response$ai_temperature - Temperature parameter used in the request$ai_max_tokens - Maximum tokens setting$ai_stream - Whether the response was streamed$ai_tools - Tools/functions available to the model$ai_model_parameters - Dictionary of other model parameters (top_p, frequency_penalty, presence_penalty, stop, etc.)$ai_input - Input messages, prompt, or input data$ai_output_choices - Response choices from the LLM (for generation events)$ai_input_tokens - Number of tokens in the input$ai_output_tokens - Number of tokens in the output$ai_total_tokens - Total number of tokens usedThese properties can be set via PostHogAIContext (see below):
$ai_session_id - Groups related traces together$ai_span_id - Unique identifier for this generation$ai_span_name - Name given to this generation$ai_parent_id - Parent span ID for tree view grouping$ai_cache_read_input_tokens - Number of tokens read from cache (when available)$ai_cache_creation_input_tokens - Number of tokens written to cache (when available)$ai_is_error - Boolean indicating if the request was an error$ai_error - Error message or objectPostHogAIContext allows you to set additional context for AI events within a scope, including session tracking, span tracking, and custom properties.
using PostHog.AI;
// Begin a scope with context
using (PostHogAIContext.BeginScope(
distinctId: "user-123",
traceId: "trace-abc",
sessionId: "session-xyz",
spanId: "span-1",
spanName: "summarize_text",
parentId: null))
{
// All OpenAI API calls within this scope will include the context
var chatClient = openAIClient.GetChatClient("gpt-4");
var response = await chatClient.CompleteChatAsync("Summarize this text");
}
// Context is automatically restored when the scope ends
using PostHog.AI;
// Parent span
using (PostHogAIContext.BeginScope(
traceId: "trace-123",
spanId: "span-parent",
spanName: "process_document"))
{
// Child span 1
using (PostHogAIContext.BeginScope(
traceId: "trace-123", // Same trace
spanId: "span-child-1",
spanName: "extract_summary",
parentId: "span-parent")) // Link to parent
{
// First AI call
var chatClient = openAIClient.GetChatClient("gpt-4");
await chatClient.CompleteChatAsync("Summarize the document");
}
// Child span 2
using (PostHogAIContext.BeginScope(
traceId: "trace-123",
spanId: "span-child-2",
spanName: "extract_keywords",
parentId: "span-parent"))
{
// Second AI call
var chatClient = openAIClient.GetChatClient("gpt-4");
await chatClient.CompleteChatAsync("Extract keywords from the document");
}
}
You can add custom properties that will be merged into the event properties:
using PostHog.AI;
var customProperties = new Dictionary<string, object>
{
{ "workflow_id", "workflow-123" },
{ "feature_flag", "new-model-v2" },
{ "$ai_session_id", "override-session" } // Can override context properties
};
using (PostHogAIContext.BeginScope(
sessionId: "default-session",
properties: customProperties))
{
// Properties dictionary takes precedence over context properties
// In this case, $ai_session_id will be "override-session"
var chatClient = openAIClient.GetChatClient("gpt-4");
await chatClient.CompleteChatAsync("Hello");
}
Properties are applied in the following order (later values override earlier ones):
SessionId, SpanId, etc.)This allows you to set default context properties via BeginScope and override them for specific events via the Properties dictionary.
The handler uses the configured IPostHogClient to send events. Ensure your PostHog client is correctly configured with your API key and host URL.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 net5.0 was computed. net5.0-windows net5.0-windows was computed. net6.0 net6.0 was computed. net6.0-android net6.0-android was computed. net6.0-ios net6.0-ios was computed. net6.0-maccatalyst net6.0-maccatalyst was computed. net6.0-macos net6.0-macos was computed. net6.0-tvos net6.0-tvos was computed. net6.0-windows net6.0-windows was computed. net7.0 net7.0 was computed. net7.0-android net7.0-android was computed. net7.0-ios net7.0-ios was computed. net7.0-maccatalyst net7.0-maccatalyst was computed. net7.0-macos net7.0-macos was computed. net7.0-tvos net7.0-tvos was computed. net7.0-windows net7.0-windows was computed. net8.0 net8.0 is compatible. net8.0-android net8.0-android was computed. net8.0-browser net8.0-browser was computed. net8.0-ios net8.0-ios was computed. net8.0-maccatalyst net8.0-maccatalyst was computed. net8.0-macos net8.0-macos was computed. net8.0-tvos net8.0-tvos was computed. net8.0-windows net8.0-windows was computed. net9.0 net9.0 was computed. net9.0-android net9.0-android was computed. net9.0-browser net9.0-browser was computed. net9.0-ios net9.0-ios was computed. net9.0-maccatalyst net9.0-maccatalyst was computed. net9.0-macos net9.0-macos was computed. net9.0-tvos net9.0-tvos was computed. net9.0-windows net9.0-windows was computed. net10.0 net10.0 was computed. net10.0-android net10.0-android was computed. net10.0-browser net10.0-browser was computed. net10.0-ios net10.0-ios was computed. net10.0-maccatalyst net10.0-maccatalyst was computed. net10.0-macos net10.0-macos was computed. net10.0-tvos net10.0-tvos was computed. net10.0-windows net10.0-windows was computed. |
| .NET Core | netcoreapp3.0 netcoreapp3.0 was computed. netcoreapp3.1 netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.1 netstandard2.1 is compatible. |
| MonoAndroid | monoandroid monoandroid was computed. |
| MonoMac | monomac monomac was computed. |
| MonoTouch | monotouch monotouch was computed. |
| Tizen | tizen60 tizen60 was computed. |
| Xamarin.iOS | xamarinios xamarinios was computed. |
| Xamarin.Mac | xamarinmac xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos xamarinwatchos was computed. |
This package is not used by any NuGet packages.
This package is not used by any popular GitHub repositories.