Skip to content
Draft
Show file tree
Hide file tree
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
15 changes: 15 additions & 0 deletions .github/workflows/pr-validation.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,21 @@ jobs:
- name: Build
run: npm run build

- name: Install Agent365 S2S sample dependencies
run: npm ci --prefix samples/agent365-s2s

- name: Format Agent365 S2S sample
run: npm run --prefix samples/agent365-s2s format

- name: Lint Agent365 S2S sample
run: npm run --prefix samples/agent365-s2s lint

- name: Build Agent365 S2S sample
run: npm run --prefix samples/agent365-s2s build

- name: Test Agent365 S2S sample
run: npm test --prefix samples/agent365-s2s

- name: Format check
run: npm run format

Expand Down
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@

## [Unreleased]

### Features Added
- Add a self-contained Agent365 S2S sample with two-stage MSAL app-only authentication and expiry-aware token caching. [#244](https://github.com/microsoft/opentelemetry-distro-javascript/pull/244)

### Other Changes
- Include successful Agent365 exporter HTTP status and correlation ID in safe diagnostics. [#244](https://github.com/microsoft/opentelemetry-distro-javascript/pull/244)
- Consolidate Dependabot updates for Vitest 4.1.11, Hono 4.13.7, qs 6.16.0, fast-uri 3.1.7, actions/deploy-pages 5.0.1, and actions/checkout 7.0.1.

## [1.4.0] - 2026-09-08
Expand Down
2 changes: 2 additions & 0 deletions samples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ These sample programs show how to use the `@microsoft/opentelemetry` distributio
| [a365Export.ts][a365export] | Demonstrates A365 observability export: token resolver setup, dual export with Azure Monitor, and span routing by tenant/agent. |
| [a365ManualScopes.ts][a365manualscopes] | Traces a full agent turn with manual scopes (InvokeAgent → Inference → ExecuteTool → Inference → Output) and cross-service context propagation. |
| [a365HostingMiddleware.ts][a365hostingmiddleware] | Demonstrates A365 hosting middleware (BaggageMiddleware, OutputLoggingMiddleware, ObservabilityHostingManager, ScopeUtils). |
| [agent365-s2s][agent365s2s] | Standalone Agent365 S2S sample with two-stage MSAL app-only authentication, expiry-aware token caching, and four deterministic manual spans. |

## Prerequisites

Expand Down Expand Up @@ -116,3 +117,4 @@ useMicrosoftOpenTelemetry({
[a365export]: https://github.com/microsoft/opentelemetry-distro-javascript/blob/main/samples/src/a365Export.ts
[a365manualscopes]: https://github.com/microsoft/opentelemetry-distro-javascript/blob/main/samples/src/a365ManualScopes.ts
[a365hostingmiddleware]: https://github.com/microsoft/opentelemetry-distro-javascript/blob/main/samples/src/a365HostingMiddleware.ts
[agent365s2s]: https://github.com/microsoft/opentelemetry-distro-javascript/tree/main/samples/agent365-s2s
4 changes: 4 additions & 0 deletions samples/agent365-s2s/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
appsettings.json
dist/
node_modules/
.test-tmp/
112 changes: 112 additions & 0 deletions samples/agent365-s2s/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
# Agent365 service-to-service observability sample

This standalone Node.js 22 sample publishes a deterministic agent trace to the
Agent365 service-to-service observability endpoint. It uses app-only
authentication; no interactive user sign-in or pre-generated bearer token is
required.

## Prerequisites

- Node.js 22 or later.
- An Agent365 blueprint application with a client secret.
- An Agent365 agent application in the same Microsoft Entra tenant.
- The Agent365 agent application must have the
`Agent365.Observability.OtelWrite` application permission with tenant admin
consent.
- The blueprint and agent application must be configured for the Agent365
federated managed identity (FMI) token-exchange flow.

Never commit `appsettings.json`. The included `.gitignore` excludes it.

## Configure and run

Build the root distro first so the sample's local `file:../..` dependency can
resolve its generated package exports:

```powershell
Set-Location ..\..
npm ci
npm run build
Set-Location samples\agent365-s2s
```

Then configure and run the sample:

```powershell
Copy-Item appsettings.example.json appsettings.json
npm ci
npm run build
npm start
```

Replace every placeholder in `appsettings.json`:

| Setting | Description |
| ----------------------- | ------------------------------------------------------------------------------------- |
| `authority` | HTTPS Microsoft Entra authority root, for example `https://login.microsoftonline.com` |
| `blueprintClientId` | Blueprint application client ID |
| `blueprintClientSecret` | Blueprint application client secret |
| `tenantId` | Microsoft Entra tenant ID |
| `agentId` | Agent365 agent application client ID and FMI path |
| `clusterCategory` | Must be `prod` |

The sample rejects missing placeholders, malformed GUIDs, non-HTTPS
authorities, and authorities containing tenant paths, queries, or fragments.
Configuration errors name only the invalid setting and never echo its value.

## Authentication flow

The sample performs exactly two confidential-client requests:

1. The blueprint application requests
`api://AzureADTokenExchange/.default`, using the configured `agentId` as
`fmiPath`.
2. The returned blueprint token becomes the `clientAssertion` for the agent
application, which requests
`api://9b975845-388f-4429-889e-eab1ef63949c/.default`.

The final observability token is cached per normalized tenant/agent identity
and reused only while it expires more than 60 seconds in the future.
Concurrent refreshes share one request, and failed refreshes can be retried.

## Expected telemetry

Each run creates exactly four spans in one trace:

1. `invoke_agent` for the complete synthetic request.
2. `Chat` inference selecting `lookup_weather`.
3. `execute_tool` with deterministic synthetic arguments and result.
4. `Chat` inference producing the final answer.

All three operation spans are direct children of `invoke_agent`. The run starts
at the current time and uses fixed relative offsets and durations; tests inject
a fixed start time for repeatability. Published agent, caller, user,
conversation, message, and tool values are explicitly synthetic; only the
configured tenant and agent IDs identify the destination.

The distro is configured with `enableObservabilityExporter: true`,
`useS2SEndpoint: true`, the exact observability scope, and `prod` routing. The
sample shuts down the SDK after the scenario so queued telemetry is flushed
without a fixed sleep.

## Safe diagnostics

The logger prints only preformatted messages and discards additional error
arguments. Tokens, client secrets, raw MSAL responses, exception messages,
nested errors, and stacks are never rendered. Authentication failures contain
only the failed stage and a sanitized MSAL error code. Successful exporter
diagnostics contain only the HTTP status and correlation ID (`N/A` when the
header is absent).

Run the focused tests with:

```powershell
npm test
```

The sample also reuses the repository's root Prettier and ESLint configuration:

```powershell
npm run format
npm run lint
```
8 changes: 8 additions & 0 deletions samples/agent365-s2s/appsettings.example.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"authority": "https://login.microsoftonline.com",
"blueprintClientId": "<blueprint-application-client-id>",
"blueprintClientSecret": "<blueprint-application-client-secret>",
"tenantId": "<microsoft-entra-tenant-id>",
"agentId": "<agent365-agent-application-client-id>",
"clusterCategory": "prod"
}
Loading
Loading