{"slug": "set-up-a-net-application-w-th-opentelemetry-and-trace-evaluate-in-langfuse", "title": "Set up a .NET application w/th OpenTelemetry, and trace/evaluate in Langfuse", "summary": "A developer at Tiger Tribe Heineken detailed a method for instrumenting .NET AI applications with OpenTelemetry and exporting traces to Langfuse, which currently lacks an official SDK for ingesting OpenTelemetry data. The approach uses the official OpenTelemetry SDKs and the emerging Generative AI semantic conventions to send telemetry from a Weather Station Agent and Weather MCP Server to both an Aspire dashboard and Langfuse via OTLP. The team shortlisted Langfuse and Microsoft Foundry as evaluation platforms after testing Arize Phoenix and others.", "body_md": "Currently, we are working on many products infused with AI across [the company](https://www.linkedin.com/company/tiger-tribe-heineken). Instead of relying solely on a [harness](https://dev.to/thangchung/my-claw-on-microsoft-foundry-hosted-agents-3b9) to provide AI agents with tools, context, memory, and other capabilities to make them smarter and more aware of the environments in which they operate, we also need the ability to evaluate these agents and provide feedback so they can continuously improve.\n\nWe have researched and experimented with several AI evaluation platforms, including [Arize Phoenix](https://github.com/arize-ai/phoenix), [Microsoft Foundry](https://learn.microsoft.com/en-us/azure/foundry/how-to/evaluate-generative-ai-app), and [Langfuse](https://langfuse.com/). After evaluating them against our requirements and roadmap, we shortlisted Microsoft Foundry and Langfuse because they fit well with our company's direction.\n\nLet's start with Langfuse in this post, and we will cover Microsoft Foundry in a future post.\n\nWith Langfuse, there is currently [no official SDK](https://github.com/orgs/langfuse/discussions/9281) specifically designed to instrument OpenTelemetry data and ingest it into Langfuse. Fortunately, the OpenTelemetry community is working actively to extend the existing specification with [Generative AI semantic conventions](https://github.com/open-telemetry/semantic-conventions-genai).\n\nThis is significant for us because it means we can use the [official OpenTelemetry SDKs](https://github.com/open-telemetry) for different languages — such as Node.js, .NET, Java, Rust, and Go — to instrument our applications and send telemetry data to our chosen destination, in this case, Langfuse.\n\nHowever, we still need a few tips and tricks to make the integration work properly. These are the details we will cover in this post.\n\nLook at the Dashboard ([Aspire](https://aspire.dev/)) and Langfuse components at the bottom of the above picture; we notice that the code in `Weather Station Agent` and `Weather MCP Server` needs to push telemetry info to both Dashboard and Langfuse. And to make it work, we need to modify the ingest code:\n\n``` js\nvar langfuseOtlpEndpoint = Environment.GetEnvironmentVariable(\"LANGFUSE_OTLP_ENDPOINT\");\nvar langfuseOtlpHeaders  = Environment.GetEnvironmentVariable(\"LANGFUSE_OTLP_HEADERS\") ?? \"\";\n\nbuilder.Services.AddOpenTelemetry()\n    .ConfigureResource(r => r.AddService(\"weather-station-agent\"))\n    .WithTracing(t =>\n    {\n        t.AddSource(\"WeatherStationAgent\")\n         .AddSource(\"Experimental.ModelContextProtocol\")\n         .AddSource(\"Experimental.Microsoft.Extensions.AI\")\n         .AddHttpClientInstrumentation()   // ← keep outgoing HTTP spans\n         .AddOtlpExporter();  // → Aspire dashboard (OTEL_EXPORTER_OTLP_* env vars)\n        if (!string.IsNullOrEmpty(langfuseOtlpEndpoint))\n            t.AddOtlpExporter(o =>\n            {\n                o.Endpoint = new Uri(langfuseOtlpEndpoint.TrimEnd('/') + \"/v1/traces\");\n                o.Headers  = langfuseOtlpHeaders;\n                o.Protocol = OtlpExportProtocol.HttpProtobuf;\n            });\n    });\n```\n\nThen, in the `apphost.cs`, we need to set up some environment variables:\n\n``` js\nvar weatherStationAgent = builder.AddProject(\"weather-station-agent\", \"MafLangfuseClient/MafLangfuseClient.csproj\")\n    .WithHttpEndpoint(port: 5002)\n    .WithEnvironment(\"ASPNETCORE_ENVIRONMENT\", \"Development\");\n\nvar langfuseHost = GetEnv(dotEnv, \"LANGFUSE_HOST\", \"http://localhost:3000\");\nvar otlpEndpoint = $\"{langfuseHost.TrimEnd('/')}/api/public/otel\";\nvar langfuseAuth = Convert.ToBase64String(\n    System.Text.Encoding.UTF8.GetBytes(\n        $\"{GetEnv(dotEnv, \"LANGFUSE_PUBLIC_KEY\", \"\")}:{GetEnv(dotEnv, \"LANGFUSE_SECRET_KEY\", \"\")}\"));\nvar otlpHeaders = $\"Authorization=Basic {langfuseAuth},x-langfuse-ingestion-version=4\";\n\n// ...\n\nweatherStationAgent\n    .WithReference(weatherMcp)\n    .WithEnvironment(\"MCP_ENDPOINT\", weatherMcp.GetEndpoint(\"http\"))\n    .WithEnvironment(\"LANGFUSE_OTLP_ENDPOINT\", otlpEndpoint)\n    .WithEnvironment(\"LANGFUSE_OTLP_HEADERS\", otlpHeaders)\n    .WithEnvironment(\"OTEL_SERVICE_NAME\", \"weather-station-agent\")\n    .WithEnvironment(\"OTEL_RESOURCE_ATTRIBUTES\", \"service.name=weather-station-agent\")\n    .WithEnvironment(\"OPENAI_BASE_URL\", GetEnv(dotEnv, \"OPENAI_BASE_URL\", \"http://localhost:4000/v1\"))\n    .WithEnvironment(\"OPENAI_API_KEY\", GetEnv(dotEnv, \"OPENAI_API_KEY\", \"placeholder-key\"))\n    .WithEnvironment(\"OPENAI_MODEL\", GetEnv(dotEnv, \"OPENAI_MODEL\", \"gpt-4o-mini\"));\n\nbuilder.Build().Run();\n```\n\nWith some of the official OpenTelemetry NuGet packages:\n\n```\n<Project Sdk=\"Microsoft.NET.Sdk.Web\">\n\n  <PropertyGroup>\n    <TargetFramework>net10.0</TargetFramework>\n    <Nullable>enable</Nullable>\n    <ImplicitUsings>enable</ImplicitUsings>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.Agents.AI\" />\n    <PackageReference Include=\"Microsoft.Agents.AI.OpenAI\" />\n    <PackageReference Include=\"Microsoft.Extensions.AI.OpenAI\" />\n    <PackageReference Include=\"ModelContextProtocol\" />\n    <PackageReference Include=\"OpenTelemetry\" />\n    <PackageReference Include=\"OpenTelemetry.Exporter.OpenTelemetryProtocol\" />\n    <PackageReference Include=\"OpenTelemetry.Instrumentation.AspNetCore\" />\n    <PackageReference Include=\"OpenTelemetry.Instrumentation.Http\" />\n    <PackageReference Include=\"OpenTelemetry.Extensions.Hosting\" />\n  </ItemGroup>\n\n</Project>\n```\n\nNothing is really special or customised here; we just use very basic and [standard OpenTelemetry NuGet packages](https://www.nuget.org/packages?q=OpenTelemetry&includeComputedFrameworks=true&prerel=true).\n\n```\n> git clone git@github.com:langfuse/langfuse.git\n> cd langfuse\n# Make sure you have Docker Desktop or OrbStack running on your box\n> docker compose up -d\n```\n\nOpen the browser, make sure that you can access [`http://localhost:3000`](http://localhost:3000), create a test project and test user, and then you are all set.\n\nNow, open another terminal, go to the root of the .NET app, then type:\n\n```\n> aspire run\n# Wait for the app to start\n```\n\nGo to [`http://localhost:5002`](http://localhost:5002), you should see:\n\nClick the `Run Text Scenario` button and wait a bit:\n\nLook at the link in the red box above: [http://localhost:3000/trace/385617c79a20fc8b6355321a738c0ce3](http://localhost:3000/trace/385617c79a20fc8b6355321a738c0ce3). Click this link; it will bring you to the `langfuse` dashboard:\n\nClick the `385617c79a20fc8b6355321a738c0ce3` trace; you will be taken to:\n\nCheck the screen; you can see that the agent prompt, cost, number of tokens used, LLM model, and all traces are there. Now you are ready to do the work on Langfuse. Happy coding.", "url": "https://wpnews.pro/news/set-up-a-net-application-w-th-opentelemetry-and-trace-evaluate-in-langfuse", "canonical_source": "https://dev.to/thangchung/set-up-a-net-application-wth-opentelemetry-and-traceevaluate-in-langfuse-249f", "published_at": "2026-09-21 10:06:38+00:00", "updated_at": "2026-09-21 10:31:26.583162+00:00", "lang": "en", "topics": ["ai-agents", "mlops", "ai-tools", "developer-tools", "ai-infrastructure"], "entities": ["Langfuse", "OpenTelemetry", "Microsoft Foundry", "Arize Phoenix", "Tiger Tribe Heineken", ".NET", "Aspire", "Model Context Protocol"], "alternates": {"html": "https://wpnews.pro/news/set-up-a-net-application-w-th-opentelemetry-and-trace-evaluate-in-langfuse", "markdown": "https://wpnews.pro/news/set-up-a-net-application-w-th-opentelemetry-and-trace-evaluate-in-langfuse.md", "text": "https://wpnews.pro/news/set-up-a-net-application-w-th-opentelemetry-and-trace-evaluate-in-langfuse.txt", "jsonld": "https://wpnews.pro/news/set-up-a-net-application-w-th-opentelemetry-and-trace-evaluate-in-langfuse.jsonld"}}