Conversation
Co-authored-by: nikhilNava <211831449+nikhilNava@users.noreply.github.com>
…ndling in test Co-authored-by: nikhilNava <211831449+nikhilNava@users.noreply.github.com>
| mockActivity.Setup(a => a.ChannelId).Returns(new ChannelId("test-channel")); | ||
|
|
||
| mockTurnContext.Setup(tc => tc.Activity).Returns(mockActivity.Object); | ||
| mockTurnContext.Setup(tc => tc.StackState).Returns(new TurnContextStateCollection()); |
|
|
||
| // Read parent span lazily so the agent handler can set it during logic() | ||
| string? parentId = null; | ||
| if (turnContext.StackState.ContainsKey(A365ParentSpanKey)) |
| foreach (var pair in pairs) | ||
| { | ||
| if (pair.Key == OpenTelemetryConstants.GenAiExecutionTypeKey) | ||
| { | ||
| return pair.Value?.ToString(); | ||
| } | ||
| } |
| foreach (var a in activities) | ||
| { | ||
| if (string.Equals(a.Type, ActivityTypes.Message, StringComparison.OrdinalIgnoreCase) | ||
| && !string.IsNullOrEmpty(a.Text)) | ||
| { | ||
| messages.Add(a.Text); | ||
| } | ||
| } |
| parentId = turnContext.StackState[A365ParentSpanKey]?.ToString(); | ||
| } | ||
|
|
||
| var outputScope = OutputScope.Start( |
Dependency ReviewThe following issues were found:
License Issuessrc/Tests/Microsoft.Agents.A365.Observability.Hosting.Tests/Microsoft.Agents.A365.Observability.Hosting.Tests.csproj
OpenSSF Scorecard
Scanned Files
|
…ts and docs Co-authored-by: nikhilNava <211831449+nikhilNava@users.noreply.github.com>
…d restore design.md Co-authored-by: nikhilNava <211831449+nikhilNava@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR appears to adjust the Observability Hosting surface area by adding Bot Framework middleware for OpenTelemetry baggage propagation and output span creation, along with corresponding unit tests and test dependencies.
Changes:
- Added
BaggageTurnMiddlewareto establish/dispose OpenTelemetry baggage per turn (skipping ContinueConversation events). - Added
OutputLoggingMiddlewareto createOutputScopespans for outgoing message activities and optionally link to a parent span. - Added/updated Hosting test project assets: new middleware unit tests and a
Moqpackage reference.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| src/Observability/Hosting/Middleware/BaggageTurnMiddleware.cs | Adds Bot Framework middleware to set OpenTelemetry baggage derived from ITurnContext. |
| src/Observability/Hosting/Middleware/OutputLoggingMiddleware.cs | Adds Bot Framework middleware to create output tracing spans for sent message activities. |
| src/Tests/Microsoft.Agents.A365.Observability.Hosting.Tests/Middleware/BaggageTurnMiddlewareTests.cs | Adds unit tests covering baggage behavior and ContinueConversation skip behavior. |
| src/Tests/Microsoft.Agents.A365.Observability.Hosting.Tests/Middleware/OutputLoggingMiddlewareTests.cs | Adds unit tests verifying handler registration and pass-through behavior for missing context. |
| src/Tests/Microsoft.Agents.A365.Observability.Hosting.Tests/Microsoft.Agents.A365.Observability.Hosting.Tests.csproj | Adds Moq dependency needed by the new tests. |
| <ItemGroup> | ||
| <PackageReference Include="FluentAssertions" /> | ||
| <PackageReference Include="Moq" /> | ||
| <PackageReference Include="coverlet.collector" /> |
There was a problem hiding this comment.
PR metadata says this change only reverts the UseObservabilityMiddleware extension and restores docs, but this PR also introduces new middleware (BaggageTurnMiddleware, OutputLoggingMiddleware) plus new tests and a new Moq dependency. Please update the PR title/description to reflect these additional additions, or split them into a separate PR so the revert can be reviewed/merged independently.
| parentId: parentId); | ||
|
|
||
| try | ||
| { | ||
| outputScope.SetTagMaybe(OpenTelemetryConstants.GenAiConversationIdKey, conversationId); | ||
| outputScope.SetTagMaybe(OpenTelemetryConstants.GenAiExecutionTypeKey, executionType); | ||
|
|
||
| if (sourceMetadata != null) | ||
| { | ||
| outputScope.SetTagMaybe(OpenTelemetryConstants.GenAiChannelNameKey, sourceMetadata.Name); | ||
| outputScope.SetTagMaybe(OpenTelemetryConstants.GenAiChannelLinkKey, sourceMetadata.Description); | ||
| } | ||
|
|
||
| if (callerDetails != null) | ||
| { | ||
| outputScope.SetTagMaybe(OpenTelemetryConstants.GenAiCallerIdKey, callerDetails.CallerId); | ||
| outputScope.SetTagMaybe(OpenTelemetryConstants.GenAiCallerUpnKey, callerDetails.CallerUpn); | ||
| outputScope.SetTagMaybe(OpenTelemetryConstants.GenAiCallerNameKey, callerDetails.CallerName); | ||
| outputScope.SetTagMaybe(OpenTelemetryConstants.GenAiCallerTenantIdKey, callerDetails.TenantId); | ||
| } | ||
|
|
There was a problem hiding this comment.
OutputScope.Start(...) (via OpenTelemetryScope) already accepts conversationId, sourceMetadata, and callerDetails and will apply the corresponding tags in one place. The current implementation passes those as null and then manually sets the same tags, which duplicates logic and risks drifting if tag behavior changes. Consider passing these values into OutputScope.Start and only setting tags here for values that aren’t covered by the scope constructor (e.g., execution type).
| parentId: parentId); | |
| try | |
| { | |
| outputScope.SetTagMaybe(OpenTelemetryConstants.GenAiConversationIdKey, conversationId); | |
| outputScope.SetTagMaybe(OpenTelemetryConstants.GenAiExecutionTypeKey, executionType); | |
| if (sourceMetadata != null) | |
| { | |
| outputScope.SetTagMaybe(OpenTelemetryConstants.GenAiChannelNameKey, sourceMetadata.Name); | |
| outputScope.SetTagMaybe(OpenTelemetryConstants.GenAiChannelLinkKey, sourceMetadata.Description); | |
| } | |
| if (callerDetails != null) | |
| { | |
| outputScope.SetTagMaybe(OpenTelemetryConstants.GenAiCallerIdKey, callerDetails.CallerId); | |
| outputScope.SetTagMaybe(OpenTelemetryConstants.GenAiCallerUpnKey, callerDetails.CallerUpn); | |
| outputScope.SetTagMaybe(OpenTelemetryConstants.GenAiCallerNameKey, callerDetails.CallerName); | |
| outputScope.SetTagMaybe(OpenTelemetryConstants.GenAiCallerTenantIdKey, callerDetails.TenantId); | |
| } | |
| conversationId: conversationId, | |
| sourceMetadata: sourceMetadata, | |
| callerDetails: callerDetails, | |
| parentId: parentId); | |
| try | |
| { | |
| outputScope.SetTagMaybe(OpenTelemetryConstants.GenAiExecutionTypeKey, executionType); |
| if (turnContext.StackState.ContainsKey(A365ParentSpanKey)) | ||
| { | ||
| parentId = turnContext.StackState[A365ParentSpanKey]?.ToString(); |
There was a problem hiding this comment.
Reading A365ParentSpanKey via ContainsKey(...) followed by the indexer performs two dictionary lookups and can race if the key is removed between calls. Prefer a single read (e.g., TryGetValue) and then ToString() on the retrieved value.
| if (turnContext.StackState.ContainsKey(A365ParentSpanKey)) | |
| { | |
| parentId = turnContext.StackState[A365ParentSpanKey]?.ToString(); | |
| if (turnContext.StackState.TryGetValue(A365ParentSpanKey, out var parentSpanValue) && parentSpanValue is not null) | |
| { | |
| parentId = parentSpanValue.ToString(); |
Reverts the
UseObservabilityMiddlewareIChannelAdapter extension added in the previous commit, per author request.ObservabilityMiddlewareExtensions.csand its test filedesign.mdto its prior stateWarning
Firewall rules blocked me from connecting to one or more addresses (expand for details)
I tried to connect to the following addresses, but was blocked by firewall rules:
agent365.svc.cloud.microsoft/usr/share/dotnet/dotnet /usr/share/dotnet/dotnet exec --runtimeconfig /home/REDACTED/work/Agent365-dotnet/Agent365-dotnet/src/Tests/Microsoft.Agents.A365.Observability.Runtime.Tests/bin/Debug/net8.0/Microsoft.Agents.A365.Observability.Runtime.Tests.runtimeconfig.json --depsfile /home/REDACTED/work/Agent365-dotnet/Agent365-dotnet/src/Tests/Microsoft.Agents.A365.Observability.Runtime.Tests/bin/Debug/net8.0/Microsoft.Agents.A365.Observability.Runtime.Tests.deps.json /home/REDACTED/work/Agent365-dotnet/Agent365-dotnet/src/Tests/Microsoft.Agents.A365.Observability.Runtime.Tests/bin/Debug/net8.0/testhost.dll --port 46691 --endpoint 127.0.0.1:046691 --role client --parentprocessid 4310 --telemetryoptedin false(dns block)/usr/share/dotnet/dotnet /usr/share/dotnet/dotnet exec --runtimeconfig /home/REDACTED/work/Agent365-dotnet/Agent365-dotnet/src/Tests/Microsoft.Agents.A365.Observability.Runtime.Tests/bin/Debug/net8.0/Microsoft.Agents.A365.Observability.Runtime.Tests.runtimeconfig.json --depsfile /home/REDACTED/work/Agent365-dotnet/Agent365-dotnet/src/Tests/Microsoft.Agents.A365.Observability.Runtime.Tests/bin/Debug/net8.0/Microsoft.Agents.A365.Observability.Runtime.Tests.deps.json /home/REDACTED/work/Agent365-dotnet/Agent365-dotnet/src/Tests/Microsoft.Agents.A365.Observability.Runtime.Tests/bin/Debug/net8.0/testhost.dll --port 44183 --endpoint 127.0.0.1:044183 --role client --parentprocessid 4967 --telemetryoptedin false(dns block)override.example.com/usr/share/dotnet/dotnet /usr/share/dotnet/dotnet exec --runtimeconfig /home/REDACTED/work/Agent365-dotnet/Agent365-dotnet/src/Tests/Microsoft.Agents.A365.Observability.Runtime.Tests/bin/Debug/net8.0/Microsoft.Agents.A365.Observability.Runtime.Tests.runtimeconfig.json --depsfile /home/REDACTED/work/Agent365-dotnet/Agent365-dotnet/src/Tests/Microsoft.Agents.A365.Observability.Runtime.Tests/bin/Debug/net8.0/Microsoft.Agents.A365.Observability.Runtime.Tests.deps.json /home/REDACTED/work/Agent365-dotnet/Agent365-dotnet/src/Tests/Microsoft.Agents.A365.Observability.Runtime.Tests/bin/Debug/net8.0/testhost.dll --port 46691 --endpoint 127.0.0.1:046691 --role client --parentprocessid 4310 --telemetryoptedin false(dns block)/usr/share/dotnet/dotnet /usr/share/dotnet/dotnet exec --runtimeconfig /home/REDACTED/work/Agent365-dotnet/Agent365-dotnet/src/Tests/Microsoft.Agents.A365.Observability.Runtime.Tests/bin/Debug/net8.0/Microsoft.Agents.A365.Observability.Runtime.Tests.runtimeconfig.json --depsfile /home/REDACTED/work/Agent365-dotnet/Agent365-dotnet/src/Tests/Microsoft.Agents.A365.Observability.Runtime.Tests/bin/Debug/net8.0/Microsoft.Agents.A365.Observability.Runtime.Tests.deps.json /home/REDACTED/work/Agent365-dotnet/Agent365-dotnet/src/Tests/Microsoft.Agents.A365.Observability.Runtime.Tests/bin/Debug/net8.0/testhost.dll --port 44183 --endpoint 127.0.0.1:044183 --role client --parentprocessid 4967 --telemetryoptedin false(dns block)If you need me to access, download, or install something from one of these locations, you can either:
💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.