[DRAFT] Add SDK v2 telemetry core#879
Draft
bmehta001 wants to merge 32 commits into
Draft
Conversation
Port the C# Foundry Core telemetry event taxonomy to C++ in advance of the
1DS bridge. The interface refactor is the source of truth — all backend
implementations and call sites are wired against it.
ITelemetry additions:
- 4 new `Action` values (EpDownloadAttempt, EpDownloadAndRegister,
ModelFileDownload, ModelInference).
- 4 new payload structs (`EpDownloadAttemptInfo`,
`EpDownloadAndRegisterInfo`, `ModelUsageInfo`, `DownloadInfo`).
- 3 new virtual methods (`RecordEpDownloadAttempt`,
`RecordEpDownloadAndRegister`, `RecordDownload`).
- Replaced `RecordModelUsage(model_id, prompt_tokens, completion_tokens,
duration_ms)` with `RecordModelUsage(const ModelUsageInfo&)` so callers
can populate richer fields (TimeToFirstToken, EP, memory).
- Extended `RecordModelId(action, model_id)` to take `status` and
`user_agent`; added `RecordException(action, ex, user_agent)` overload.
New supporting code (all in `sdk_v2/cpp/src/telemetry/`):
- `telemetry_environment.{h,cc}` — `IsCiEnvironment` /
`IsTestingMode` / `IsTruthyValue` / `GetEnv`. 13 CI env-var
names ported verbatim from neutron-server's `TelemetryEnvironment.cs`.
- `telemetry_metadata.{h,cc}` — captures per-process metadata
(`app_session_guid`, version, os_name / os_version / cpu_arch,
test_mode flag) for stamping on every event.
- `ep_download_tracker.{h,cc}` — RAII tracker that emits one
`EPDownloadAndRegister` event per bootstrapper, recording stage
transitions (initial -> download -> register). Default failure
semantics: dtor records remaining stages as `kFailure`; `Done()`
records them as `kSkipped` for happy-path early exit.
- `download_tracker.{h,cc}` — RAII tracker that emits one `Download`
event per `DownloadManager::DownloadModel` call.
`TelemetryLogger` (the fallback / mirror) implements every new method,
formatting events as `[Telemetry] EventName Field=value ...` at Debug.
Test stubs (`NullTelemetry` and the `RecordingTelemetry` used by
`telemetry_test.cc`) were updated for the new interface.
Build verified RelWithDebInfo --no_telemetry.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
OneDsTelemetry is the production ITelemetry implementation. It embeds a
TelemetryLogger mirror so every event is also logged locally to ILogger for
diagnostics, then conditionally uploads to 1DS through the Microsoft
cpp-client-telemetry SDK.
Suppression model (three-state):
- CI environment detected -> skip `LogManager::Initialize`; local logging
still happens, but no upload occurs.
- Tenant token empty (build did not pass `-DFOUNDRY_LOCAL_TELEMETRY_TOKEN`)
-> same as CI: no upload, only local logging.
- Otherwise -> upload. Every event is stamped with `test=true` when
`FOUNDRY_TESTING_MODE` is truthy, `test=false` otherwise.
Common context, propagated to every event via `ILogger::SetContext`:
- `app_name` (from `Configuration::app_name`).
- `app_session_guid` (random v4 UUID; on Windows the special
`UTCReplace_AppSessionGuid` field also gets the OS app session GUID).
- `version` (from the generated `version.h`).
- `os_name` / `os_version` / `cpu_arch` (Win: `GetVersionExA` +
`GetNativeSystemInfo`; POSIX: `uname`).
The `MICROSOFT_KEYWORD_CRITICAL_DATA` (bit 47) policy flag is set on
every event via `SetPolicyBitFlags` so the data passes 1DS classifier.
Build / packaging:
- `vcpkg.json`: `telemetry` feature pulls `cpp-client-telemetry`.
The port is pending in microsoft/vcpkg#52316; until that merges,
builds must pass `--no_telemetry`.
- `CMakeLists.txt`: new `FOUNDRY_LOCAL_USE_TELEMETRY` option
(default ON) and `FOUNDRY_LOCAL_TELEMETRY_TOKEN` advanced cache
variable. Calls `find_package(MSTelemetry CONFIG REQUIRED)`, includes
`one_ds_telemetry.cc` and `configure_file`-generates
`one_ds_tenant_token.h` containing the build-time token, then links
`MSTelemetry::mat` and defines `FOUNDRY_LOCAL_HAS_1DS=1`.
- `build.py`: new `--no_telemetry` and `--telemetry_token` flags;
forwards through to CMake / VCPKG_MANIFEST_FEATURES.
Build verified RelWithDebInfo --no_telemetry; --use_telemetry will be
validated once the vcpkg port lands.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Plumb the typed telemetry interface through the orchestration layer so
that real workloads produce the new EPDownloadAttempt, EPDownloadAndRegister
and Download events.
Manager:
- Construct `telemetry_` before `ep_detector_` so the detector can be
handed a non-null sink at ctor time. When `FOUNDRY_LOCAL_HAS_1DS` is
defined, the implementation is `OneDsTelemetry` and reads the
build-time token from the generated `one_ds_tenant_token.h`; otherwise
it falls back to `TelemetryLogger`.
- Member-declaration order in `manager.h` reorganised so consumers
(`ep_detector_`, `download_manager_`) appear after the providers
(`telemetry_`). C++ destroys in reverse declaration order, so this
keeps the raw `ITelemetry*` held by `EpDetector` and
`DownloadManager` valid for their entire lifetime.
- Explicit `~Manager()` Shutdown reset order updated to match: the
telemetry sink is reset last (after ep_detector and download_manager).
EpDetector:
- New optional `ITelemetry* telemetry` ctor arg (default nullptr) so
unit tests that instantiate EpDetector directly continue to compile.
- `DownloadAndRegisterEps` emits one `EPDownloadAndRegister` event
per bootstrapper via `EpDownloadTracker` and a single aggregate
`EPDownloadAttempt` event at the end with attempt / success / fail
counts and an overall status.
- Exceptions thrown from a bootstrapper invoke
`EpDownloadTracker::RecordException` before re-throwing so the failure
is recorded regardless of how it propagates.
DownloadManager:
- New optional `ITelemetry* telemetry` ctor arg. When non-null,
`DownloadModel` wraps the call with a `DownloadTracker` that
captures lock-wait, enumeration and download timings, total bytes,
file count, max concurrency and final status (Success / Skipped /
Failure). `RecordException` is invoked on the exception path before
re-throwing.
- `DownloadModel` now takes an optional `user_agent` parameter so
HTTP-driven downloads can attribute the event to the calling client.
DownloadBlobsToDirectory:
- New optional `BlobDownloadStats*` out parameter populated with
`total_size_bytes`, `file_count`, `enumeration_ms`,
`download_ms`. All existing 4-argument callers (including unit
tests) keep working because the parameter defaults to nullptr.
Verified RelWithDebInfo --no_telemetry: 756 tests pass; 54 skipped
(environmental, missing local test data); 0 functional failures.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Now that microsoft/vcpkg#52316 has merged, bump the manifest baseline from 256acc64 to 44819aa2 (current master) so the cpp-client-telemetry 3.10.161.1 port resolves. Also rename the using-declaration in one_ds_telemetry.cc's anonymous namespace from `using ::Microsoft::Applications::Events::ILogger;` to `using MatILogger = ::Microsoft::Applications::Events::ILogger;` so it no longer collides with the local `fl::ILogger` interface from src/logger.h. Three callsites (SetCommonContext, SafeLog, GetMatLogger) updated; the OneDsTelemetry ctor's `ILogger& logger` parameter correctly resolves to fl::ILogger after the rename. Verified with: python sdk_v2/cpp/build.py --use_telemetry --config RelWithDebInfo --skip_examples foundry_local.dll = 12.19 MB (telemetry on, empty token). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add /OPT:REF, /OPT:ICF, and /INCREMENTAL:NO to the foundry_local shared library target for Release and RelWithDebInfo configs. MSVC's /DEBUG flag (needed for PDB generation) silently disables these optimizations unless they are explicitly re-enabled, leaving all unreferenced symbols from statically-linked dependencies (notably cpp-client-telemetry/mat.lib) in the final binary. Also add -Wl,--gc-sections (Linux) and -Wl,-dead_strip (macOS) equivalents for non-Windows builds. Additionally, declare sqlite3 with default-features:false in vcpkg.json to drop the unused json1 extension from the SQLite transitive dependency. Measured impact (RelWithDebInfo, x64-windows, telemetry ON): foundry_local.dll: 12.19 MB -> 4.51 MB (-7.68 MB, -63%) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…t) foundation
Reworks the telemetry core ahead of broadening route/inference coverage:
- New InvocationContext {user_agent, correlation_id, indirect} threaded through
the ITelemetry interface in place of the loose user_agent/indirect params.
Direct() mints a fresh correlation id; AsIndirect() derives a caused-by child
that reuses it. ActionTracker now carries the context and guarantees an id.
- Every event (Action/Error/Model/ModelId/Download/EP*) now carries a
CorrelationId so all events from one operation can be grouped. The Model event
also gains Stream and Direct.
- indirect now means "happened as a consequence of another action": the
per-provider EPDownloadAndRegister is marked indirect and shares the overall
EPDownloadAttempt's correlation id.
- Add ActionStatus::kClientError to separate 4xx client rejects from 5xx/internal
failures (wired into handlers in a follow-up).
- Prune dead Action enum entries (kModelDownload/kModelDelete/kCoreAudioTranscribe)
and add kServiceRequestUnmatched for the upcoming router catch-all.
- Share the v4 UUID generator (MakeGuidV4Hex) between metadata and correlation.
Builds clean (/W4 /WX); telemetry + ActionTracker unit tests pass.
…to-end - Session::ProcessRequest now emits the previously-dead Model (kModelInference) event once per inference with model id, tokens, duration, stream flag and the caller's correlation id / indirect flag. Adds Session::SetRequestContext so an HTTP route can stage an indirect child context (shared correlation id), and a virtual ExecutionProvider() hook for the EP field. - Chat completions handler: derive a Direct route context from the User-Agent header; map 4xx early-returns (empty body, invalid JSON, model not found/loaded) to kClientError instead of the default kFailure; emit kSessionCreate (indirect) on the HTTP path; stage the indirect session context. - Streaming fix: the route action is no longer recorded (as a premature success with ~0ms) when the handler returns. The route ActionTracker is moved into the streaming thread and records on completion with the real duration and terminal status, so mid-stream failures surface as failures instead of vanishing. Builds clean (/W4 /WX); telemetry/webservice/sse tests pass.
…, sampling) Extends the chat-route pattern to every handler: - Streaming completion fix also applied to the audio transcriptions route (its ActionTracker moved into the streaming thread). - Embeddings, audio, responses (create + get/list/delete/input_items), and the model load/unload/list/retrieve routes now derive a Direct context from the User-Agent header, map 4xx early-returns to kClientError, and (for the inference routes) emit kSessionCreate and stage an indirect session context. - Instrument GET /models/loaded (kModelList), previously untracked. - Sample GET /status: emit a kServiceStatus action at most once per hour per process so the orchestrator heartbeat doesn't dominate volume. Builds clean (/W4 /WX); telemetry/webservice/sse tests pass.
…ests
- UnmatchedRouteInterceptor: a request interceptor that, before routing, checks
the router for a matching route. When none matches (unknown path or wrong
method) it records a kServiceRequestUnmatched action (kClientError) and replies
404, so requests that reach the service but no handler are no longer invisible.
- Tests (WebServiceTelemetryTest, using a capturing ITelemetry + empty catalog,
no real model required):
* unmatched route records kServiceRequestUnmatched with the right status,
user agent, Direct flag and a correlation id;
* an empty chat-completions body records kClientError (not kFailure) and
emits no Model event;
* three rapid GET /status calls record kServiceStatus exactly once (hourly
sampling).
Builds clean (/W4 /WX); 72 telemetry/webservice/sse tests pass.
Every access to a model catalog source is now recorded, with success/failure:
- New CatalogFetch typed event carrying operation ("FetchAll" or the cached-id
"FetchByIds" lookup), endpoint/region/format parsed from the catalog URL,
status, duration, model count, error message, and a correlation id shared
across the accesses of one refresh.
- FetchAllModelInfosWithCachedModels gains optional telemetry params (defaulted,
so the snapshot tool and existing tests are unchanged) and emits an event for
the primary fetch and, when it runs, the secondary cached-id lookup.
- AzureModelCatalog parses the catalog URL into endpoint/region/format
(https://ai.azure.com/api/eastus/ux/v1.0 -> {ai.azure.com, eastus, ux/v1.0};
"static" for the embedded snapshot) and threads an ITelemetry from Manager.
- Tests assert the primary and secondary accesses are each tracked with the
right operation, status, endpoint, correlation id and model count.
Builds clean (/W4 /WX); catalog + telemetry + webservice tests pass.
…ions - Drop the UTCReplace_ magic from the per-process correlation GUID: it only fires on the Windows UTC transmission path (not our direct upload, and never off-Windows), so it was dead weight. The field is now plainly "AppSessionGuid" — a stable per-process correlation id on every platform. - Add ITelemetry::StartSession()/EndSession() (default no-op; OneDsTelemetry maps them to 1DS LogSession(Started/Ended), TelemetryLogger logs them). Manager opens a session when the web service starts and closes it on stop, so events carry the standard, cross-platform usage-session id (ext.app.sesId) and the backend gets session duration. This is additive — it complements the per-run AppSessionGuid and the per-operation CorrelationId. Builds clean (/W4 /WX); telemetry/webservice/catalog tests pass.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Contributor
There was a problem hiding this comment.
Pull request overview
Adds SDK v2 telemetry infrastructure, 1DS transport, correlation contexts, and instrumentation across inference, downloads, catalogs, EP registration, and HTTP services.
Changes:
- Introduces typed telemetry payloads, trackers, metadata, and optional 1DS upload support.
- Instruments SDK operations and streaming HTTP routes with correlated telemetry.
- Adds telemetry dependencies, build options, tests, and linker-size optimizations.
Reviewed changes
Copilot reviewed 49 out of 49 changed files in this pull request and generated 20 comments.
Show a summary per file
| File | Description |
|---|---|
sdk_v2/cpp/vcpkg.json |
Adds telemetry dependencies and feature. |
sdk_v2/cpp/test/internal_api/web_service_test.cc |
Tests HTTP telemetry behavior. |
sdk_v2/cpp/test/internal_api/telemetry_test.cc |
Updates telemetry unit tests. |
sdk_v2/cpp/test/internal_api/null_telemetry.h |
Updates no-op test sink. |
sdk_v2/cpp/src/telemetry/telemetry.h |
Defines telemetry API and payloads. |
sdk_v2/cpp/src/telemetry/telemetry.cc |
Maps actions and statuses. |
sdk_v2/cpp/src/telemetry/telemetry_metadata.h |
Declares process metadata. |
sdk_v2/cpp/src/telemetry/telemetry_metadata.cc |
Collects platform metadata. |
sdk_v2/cpp/src/telemetry/telemetry_logger.h |
Expands local telemetry logger. |
sdk_v2/cpp/src/telemetry/telemetry_logger.cc |
Formats typed telemetry events. |
sdk_v2/cpp/src/telemetry/telemetry_environment.h |
Declares runtime telemetry gating. |
sdk_v2/cpp/src/telemetry/telemetry_environment.cc |
Implements CI/test detection. |
sdk_v2/cpp/src/telemetry/telemetry_action_tracker.h |
Adds invocation-context tracking. |
sdk_v2/cpp/src/telemetry/telemetry_action_tracker.cc |
Emits correlated action events. |
sdk_v2/cpp/src/telemetry/one_ds_tenant_token.h.in |
Generates the tenant-token header. |
sdk_v2/cpp/src/telemetry/one_ds_telemetry.h |
Declares the 1DS sink. |
sdk_v2/cpp/src/telemetry/one_ds_telemetry.cc |
Implements 1DS event uploads. |
sdk_v2/cpp/src/telemetry/invocation_context.h |
Defines correlation context. |
sdk_v2/cpp/src/telemetry/invocation_context.cc |
Generates correlation UUIDs. |
sdk_v2/cpp/src/telemetry/ep_download_tracker.h |
Declares EP telemetry tracker. |
sdk_v2/cpp/src/telemetry/ep_download_tracker.cc |
Emits EP attempt details. |
sdk_v2/cpp/src/telemetry/download_tracker.h |
Declares model-download tracker. |
sdk_v2/cpp/src/telemetry/download_tracker.cc |
Emits model-download telemetry. |
sdk_v2/cpp/src/service/web_service.cc |
Instruments status and unmatched routes. |
sdk_v2/cpp/src/service/responses_handler.h |
Passes streaming route trackers. |
sdk_v2/cpp/src/service/responses_handler.cc |
Instruments Responses API operations. |
sdk_v2/cpp/src/service/models_handlers.cc |
Instruments model endpoints. |
sdk_v2/cpp/src/service/handler_utils.h |
Extracts request user agents. |
sdk_v2/cpp/src/service/embeddings_handler.cc |
Instruments embedding inference. |
sdk_v2/cpp/src/service/chat_completions_handler.h |
Extends streaming tracker ownership. |
sdk_v2/cpp/src/service/chat_completions_handler.cc |
Instruments chat streaming. |
sdk_v2/cpp/src/service/audio_transcriptions_handler.h |
Extends audio tracker ownership. |
sdk_v2/cpp/src/service/audio_transcriptions_handler.cc |
Instruments audio streaming. |
sdk_v2/cpp/src/manager.h |
Adjusts telemetry lifetime ordering. |
sdk_v2/cpp/src/manager.cc |
Constructs sinks and manages sessions. |
sdk_v2/cpp/src/inferencing/session/session.h |
Adds per-request telemetry context. |
sdk_v2/cpp/src/inferencing/session/session.cc |
Emits inference usage metrics. |
sdk_v2/cpp/src/ep_detection/ep_detector.h |
Accepts an optional telemetry sink. |
sdk_v2/cpp/src/ep_detection/ep_detector.cc |
Instruments EP registration. |
sdk_v2/cpp/src/download/download_manager.h |
Extends download telemetry API. |
sdk_v2/cpp/src/download/download_manager.cc |
Instruments model downloads. |
sdk_v2/cpp/src/download/blob_downloader.h |
Defines download statistics. |
sdk_v2/cpp/src/download/blob_downloader.cc |
Collects transfer statistics. |
sdk_v2/cpp/src/catalog/catalog_client.h |
Extends catalog telemetry API. |
sdk_v2/cpp/src/catalog/catalog_client.cc |
Emits catalog-fetch events. |
sdk_v2/cpp/src/catalog/azure_model_catalog.h |
Stores the telemetry sink. |
sdk_v2/cpp/src/catalog/azure_model_catalog.cc |
Adds catalog URL dimensions. |
sdk_v2/cpp/CMakeLists.txt |
Configures 1DS and linker stripping. |
sdk_v2/cpp/build.py |
Adds telemetry build options. |
Comments suppressed due to low confidence (1)
sdk_v2/cpp/src/service/responses_handler.cc:605
- Calling
Remove()makes shutdown stop waiting for this worker, but the capturedroute_trackeris destroyed only after the lambda returns. Manager teardown can consequently destroy telemetry in that gap and the tracker destructor will dereference freed telemetry. Emit/destroy the tracker before untracking the thread.
// Terminal event per spec
body_ptr->Push("data: [DONE]\n\n");
body_ptr->Finish();
tracker.Remove(std::this_thread::get_id());
Comment on lines
+481
to
+482
| if args.telemetry_token is not None: | ||
| command += [f"-DFOUNDRY_LOCAL_TELEMETRY_TOKEN={args.telemetry_token}"] |
Comment on lines
+26
to
+30
| // GetVersionExA is deprecated and lies for unmanifested apps. The reliable | ||
| // approach is to read the build number directly from kernel32 via | ||
| // RtlGetVersion, or fall back to the OS version registry. For now, use | ||
| // GetVersionEx — the deprecation only affects apps without a manifest, and | ||
| // Foundry Local has a manifest declaring Win10 / Win11 compat. |
Comment on lines
+215
to
+217
| // Re-throw to preserve existing semantics — the wrapper RAII guard above | ||
| // resets download_in_progress_; the tracker dtor records the EP event. | ||
| throw; |
Comment on lines
+231
to
+233
| if (tracker) { | ||
| tracker->RecordDownloadComplete(ActionStatus::kSuccess, "Installed"); | ||
| tracker->RecordRegisterComplete(ActionStatus::kSuccess, "Registered"); |
Comment on lines
+263
to
+268
| std::unique_ptr<DownloadTracker> tracker; | ||
| if (telemetry_ != nullptr) { | ||
| tracker = std::make_unique<DownloadTracker>(info.model_id, user_agent, *telemetry_); | ||
| tracker->SetLockWaitMs(lock_wait_ms); | ||
| tracker->SetMaxConcurrency(static_cast<int32_t>(max_concurrency_)); | ||
| } |
Comment on lines
251
to
+252
| body_ptr->Finish(); | ||
| tracker.Remove(std::this_thread::get_id()); | ||
| thread_tracker.Remove(std::this_thread::get_id()); |
Comment on lines
+23
to
+26
| telemetry_.RecordAction(action_, status_, context_, duration_ms); | ||
|
|
||
| if (!model_id_.empty()) { | ||
| telemetry_.RecordModelId(action_, model_id_); | ||
| telemetry_.RecordModelId(action_, model_id_, status_, context_); |
Comment on lines
+20
to
+24
| DownloadTracker::~DownloadTracker() { | ||
| // Emit the Download event regardless of outcome. The default status is | ||
| // kFailure so abrupt exits (exceptions) are recorded as failures. | ||
| telemetry_.RecordDownload(info_); | ||
| } |
Comment on lines
+30
to
+35
| EpDownloadTracker::~EpDownloadTracker() { | ||
| // Mirror neutron-server: if the caller didn't reach Done() or | ||
| // RecordRegisterComplete, assume the abrupt exit was an exception path and | ||
| // record any unfinished stage as kFailure. | ||
| RecordEvent(ActionStatus::kFailure); | ||
| } |
Comment on lines
+168
to
+174
| parser.add_argument( | ||
| "--no_telemetry", action="store_true", | ||
| help="Skip building the 1DS (cpp-client-telemetry) bridge. Useful while the vcpkg " | ||
| "port (microsoft/vcpkg#52316) is unmerged or when building forks that should " | ||
| "not link any telemetry transport. Local diagnostic logging via TelemetryLogger " | ||
| "still works.", | ||
| ) |
Remove CLI tenant-token plumbing, use manifest-independent Windows OS metadata, make telemetry trackers best-effort, improve EP/download/session telemetry accuracy, and guard moved stream route trackers. Files changed: - sdk_v2/cpp/build.py - sdk_v2/cpp/CMakeLists.txt - sdk_v2/cpp/src/telemetry/* - sdk_v2/cpp/src/ep_detection/ep_detector.cc - sdk_v2/cpp/src/download/* - sdk_v2/cpp/src/inferencing/session/session.cc - sdk_v2/cpp/src/service/*handler.cc Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 297bc539-5f7f-4a70-9411-48e91a5bf532
bmehta001
added a commit
that referenced
this pull request
Jul 13, 2026
Bring PR #879's Copilot round-1 telemetry fixes into the stacked hardening PR while preserving the hardening branch's broader implementations for conflicting files. Files changed: - sdk_v2/cpp/src/download/download_manager.cc - sdk_v2/cpp/src/ep_detection/ep_detector.cc - sdk_v2/cpp/src/inferencing/session/session.cc - sdk_v2/cpp/src/telemetry/download_tracker.h - sdk_v2/cpp/src/telemetry/telemetry_metadata.cc Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 297bc539-5f7f-4a70-9411-48e91a5bf532
| .count(); | ||
| usage.total_tokens = static_cast<int32_t>(response.usage.total_tokens); | ||
| usage.input_token_count = static_cast<int32_t>(response.usage.prompt_tokens); | ||
| telemetry_.RecordModelUsage(usage); |
| info.duration_ms = duration_ms; | ||
| info.model_count = model_count; | ||
| info.error_message = error; | ||
| telemetry->RecordCatalogFetch(info); |
| attempt_info.duration_ms = std::chrono::duration_cast<std::chrono::milliseconds>( | ||
| std::chrono::steady_clock::now() - attempt_start) | ||
| .count(); | ||
| telemetry_->RecordEpDownloadAttempt(attempt_info); |
| web_service_running_ = true; | ||
| // Open an app-usage session for the lifetime of the running service so events | ||
| // carry ext.app.sesId and the backend gets session duration. | ||
| telemetry_->StartSession(); |
| web_service_.reset(); | ||
| web_service_running_ = false; | ||
| bound_urls_.clear(); | ||
| telemetry_->EndSession(); |
| std::string correlation_id; | ||
| bool stream = false; // True if the inference was streamed (SSE) vs a single response | ||
| bool indirect = false; // True if the inference was driven by another action (e.g. an HTTP route) | ||
| int64_t time_to_first_token_ms = 0; |
Comment on lines
+256
to
+258
| int64_t lock_wait_ms = std::chrono::duration_cast<std::chrono::milliseconds>( | ||
| clock::now() - lock_wait_start) | ||
| .count(); |
Comment on lines
+46
to
+50
| if (auto slash = rest.find('/'); slash == std::string::npos) { | ||
| out.endpoint = rest; | ||
| } else { | ||
| out.endpoint = rest.substr(0, slash); | ||
| path = rest.substr(slash + 1); |
Make telemetry sink calls best-effort across model/catalog/session paths, sanitize 1DS error text, mirror session events locally, use an unknown TTFT sentinel, improve catalog URL dimensions and status sampling, and measure download lock waits accurately. Files changed: - sdk_v2/cpp/src/catalog/* - sdk_v2/cpp/src/download/download_manager.cc - sdk_v2/cpp/src/ep_detection/ep_detector.cc - sdk_v2/cpp/src/inferencing/session/session.cc - sdk_v2/cpp/src/manager.cc - sdk_v2/cpp/src/service/web_service.cc - sdk_v2/cpp/src/telemetry/* Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 297bc539-5f7f-4a70-9411-48e91a5bf532
Comment on lines
+158
to
+161
| ActionTracker create_tracker(Action::kSessionCreate, ctx_.telemetry, session_ctx); | ||
| create_tracker.SetModelId(model_name); | ||
| ChatSession session(*model, *loaded, ctx_.logger, ctx_.telemetry); | ||
| create_tracker.SetStatus(ActionStatus::kSuccess); |
Comment on lines
+206
to
+209
| ActionTracker create_tracker(Action::kSessionCreate, ctx_.telemetry, session_ctx); | ||
| create_tracker.SetModelId(model_name); | ||
| session = std::make_unique<ChatSession>(*model, *loaded, ctx_.logger, ctx_.telemetry); | ||
| create_tracker.SetStatus(ActionStatus::kSuccess); |
Comment on lines
+84
to
+87
| ActionTracker create_tracker(Action::kSessionCreate, ctx_.telemetry, session_ctx); | ||
| create_tracker.SetModelId(model_name); | ||
| EmbeddingsSession session(*model, *loaded, ctx_.logger, ctx_.telemetry); | ||
| create_tracker.SetStatus(ActionStatus::kSuccess); |
Comment on lines
+142
to
+145
| ActionTracker create_tracker(Action::kSessionCreate, ctx_.telemetry, session_ctx); | ||
| create_tracker.SetModelId(model_name); | ||
| AudioSession session(*model, *loaded, ctx_.logger, ctx_.telemetry); | ||
| create_tracker.SetStatus(ActionStatus::kSuccess); |
Comment on lines
+105
to
+109
| // Use the context the caller staged (an HTTP route stages an indirect child | ||
| // with the route's correlation id); otherwise mint a direct context per call | ||
| // for direct SDK use. | ||
| InvocationContext context = request_context_ ? *request_context_ : InvocationContext::Direct(); | ||
| context.EnsureCorrelationId(); |
Comment on lines
+140
to
+142
| /// Payload for the CatalogFetch event — emitted once per access to a model | ||
| /// catalog source (the live Azure catalog or the embedded static snapshot). | ||
| struct CatalogFetchInfo { |
Comment on lines
+256
to
+260
| // RAII telemetry tracker — emits a "Download" event on destruction with whatever | ||
| // fields have been populated. Default status is kFailure so abrupt exits (exceptions) | ||
| // are recorded as failures; the happy path explicitly sets kSuccess / kSkipped. | ||
| std::unique_ptr<DownloadTracker> tracker; | ||
| if (telemetry_ != nullptr) { |
Comment on lines
+84
to
+88
| bool TelemetryEnvironment::IsTruthyValue(std::string_view value) { | ||
| auto trimmed = Trim(value); | ||
| if (trimmed.empty()) { | ||
| return false; | ||
| } |
Comment on lines
+65
to
+67
| // Use the W variant so we don't depend on the legacy CRT _CRT_SECURE_NO_WARNINGS. | ||
| // Env-var values are ASCII for the CI flags we care about; if a value is unicode | ||
| // we still get the bytes round-tripped correctly because we only do truthiness checks. |
bmehta001
added a commit
that referenced
this pull request
Jul 13, 2026
Bring PR #879's second Copilot telemetry fixes into the hardening stack while retaining stronger redaction and lifecycle behavior already present here. Files changed: - sdk_v2/cpp/src/catalog/* - sdk_v2/cpp/src/download/download_manager.cc - sdk_v2/cpp/src/ep_detection/ep_detector.cc - sdk_v2/cpp/src/inferencing/session/session.cc - sdk_v2/cpp/src/service/web_service.cc - sdk_v2/cpp/src/telemetry/one_ds_telemetry.cc Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 297bc539-5f7f-4a70-9411-48e91a5bf532
Scope session-create timing to construction, consume staged request telemetry context once, and clean up remaining telemetry contract/duplicate-download-wait details. Files changed: - sdk_v2/cpp/src/inferencing/session/* - sdk_v2/cpp/src/service/*handler.cc - sdk_v2/cpp/src/download/download_manager.cc - sdk_v2/cpp/src/telemetry/telemetry.h Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 297bc539-5f7f-4a70-9411-48e91a5bf532
Copy ORT's 1DS offline-cache and teardown pattern: keep non-blocking teardown timeout, set an explicit cache DB path under the device-id cache directory, and call Flush before FlushAndTeardown.
Capture inference end time before telemetry-only message counting so Model TotalTimeMs excludes telemetry JSON parsing overhead.
Files changed:
- sdk_v2/cpp/src/telemetry/one_ds_telemetry.cc
- sdk_v2/cpp/src/telemetry/device_id.{h,cc}
- sdk_v2/cpp/src/inferencing/session/session.cc
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 297bc539-5f7f-4a70-9411-48e91a5bf532
| auto& config = LogManager::GetLogConfiguration(); | ||
| config[CFG_BOOL_SESSION_RESET_ENABLED] = true; | ||
| config[CFG_INT_TRACE_LEVEL_MASK] = 0; | ||
| config[CFG_INT_MAX_TEARDOWN_TIME] = 0; |
| "telemetry": { | ||
| "description": "Build with 1DS (cpp-client-telemetry) telemetry uploads", | ||
| "dependencies": [ | ||
| "cpp-client-telemetry", |
Comment on lines
+232
to
+233
| device_id_ = MakeGuidV4Hex(); | ||
| if (WriteDeviceIdFile(file_path, device_id_)) { |
Comment on lines
+192
to
+195
| const bool regenerated_from_corruption = status_ == TelemetryDeviceIdStatus::kCorrupted; | ||
| device_id_ = MakeGuidV4Hex(); | ||
| if (WriteWindowsRegistryDeviceId(device_id_)) { | ||
| status_ = regenerated_from_corruption ? TelemetryDeviceIdStatus::kCorrupted : TelemetryDeviceIdStatus::kNew; |
Add Privacy.md covering CI suppression, device identity storage, redaction, ProcessInfo, and 1DS cache behavior. Guard the telemetry vcpkg feature and CMake option for UWP, and publish OneDsTelemetry initialized_ only after startup logging completes. Files changed: - sdk_v2/cpp/docs/Privacy.md - sdk_v2/cpp/CMakeLists.txt - sdk_v2/cpp/vcpkg.json - sdk_v2/cpp/src/telemetry/one_ds_telemetry.cc Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 297bc539-5f7f-4a70-9411-48e91a5bf532
| auto& config = LogManager::GetLogConfiguration(); | ||
| config[CFG_BOOL_SESSION_RESET_ENABLED] = true; | ||
| config[CFG_INT_TRACE_LEVEL_MASK] = 0; | ||
| config[CFG_INT_MAX_TEARDOWN_TIME] = 0; |
| # 1DS ingestion token. Treat as a secret: CI supplies it via the protected | ||
| # FOUNDRY_LOCAL_TELEMETRY_TOKEN environment variable so it is not exposed in the | ||
| # CMake command line or build.py logs. Empty dev/fork builds don't transmit. | ||
| set(FOUNDRY_LOCAL_TELEMETRY_TOKEN "$ENV{FOUNDRY_LOCAL_TELEMETRY_TOKEN}") |
Comment on lines
+168
to
+172
| void TelemetryDeviceId::InitializeLocked() { | ||
| if (initialized_) { | ||
| return; | ||
| } | ||
| initialized_ = true; |
Comment on lines
+418
to
+421
| } catch (const std::exception& e) { | ||
| if (tracker != nullptr) { | ||
| tracker->SetDownloadWaitResult("Failed"); | ||
| tracker->RecordException(e); |
Comment on lines
+267
to
+269
| tracker->RecordDownloadComplete(ActionStatus::kSkipped, | ||
| was_registered_before ? "Registered" : "Unknown"); | ||
| tracker->RecordRegisterComplete(ActionStatus::kSuccess, "Registered"); |
Add an ORT-style privacy notice near the top-level Foundry Local description and link to the SDK v2 C++ Privacy.md telemetry details. Files changed: - README.md Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 297bc539-5f7f-4a70-9411-48e91a5bf532
| auto& config = LogManager::GetLogConfiguration(); | ||
| config[CFG_BOOL_SESSION_RESET_ENABLED] = true; | ||
| config[CFG_INT_TRACE_LEVEL_MASK] = 0; | ||
| config[CFG_INT_MAX_TEARDOWN_TIME] = 0; |
Comment on lines
+54
to
+57
| # 1DS ingestion token. Treat as a secret: CI supplies it via the protected | ||
| # FOUNDRY_LOCAL_TELEMETRY_TOKEN environment variable so it is not exposed in the | ||
| # CMake command line or build.py logs. Empty dev/fork builds don't transmit. | ||
| set(FOUNDRY_LOCAL_TELEMETRY_TOKEN "$ENV{FOUNDRY_LOCAL_TELEMETRY_TOKEN}") |
Comment on lines
+123
to
+128
| if (auto* semantic_context = LogManager::GetSemanticContext(); semantic_context != nullptr) { | ||
| const auto hashed_device_id = TelemetryDeviceId::HashForTelemetry(TelemetryDeviceId::Instance().GetValue()); | ||
| if (!hashed_device_id.empty()) { | ||
| semantic_context->SetDeviceId(hashed_device_id); | ||
| } | ||
| } |
Comment on lines
+192
to
+195
| const bool regenerated_from_corruption = status_ == TelemetryDeviceIdStatus::kCorrupted; | ||
| device_id_ = MakeGuidV4Hex(); | ||
| if (WriteWindowsRegistryDeviceId(device_id_)) { | ||
| status_ = regenerated_from_corruption ? TelemetryDeviceIdStatus::kCorrupted : TelemetryDeviceIdStatus::kNew; |
Comment on lines
+232
to
+234
| device_id_ = MakeGuidV4Hex(); | ||
| if (WriteDeviceIdFile(file_path, device_id_)) { | ||
| status_ = regenerated_from_corruption ? TelemetryDeviceIdStatus::kCorrupted : TelemetryDeviceIdStatus::kNew; |
FOUNDRY_TESTING_MODE stamped a `test` property on every event via an env var that no longer serves a purpose. Remove it end to end -- IsTestingMode(), the test_mode metadata field, the MakeEvent test_mode parameter and per-event `test` property, the init log field, and the unit-test assertion -- so events carry no test flag. Privacy.md now presents the build-time FOUNDRY_LOCAL_USE_TELEMETRY / --no_telemetry option as the way to disable telemetry and drops the FOUNDRY_TESTING_MODE note. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
bmehta001
added a commit
that referenced
this pull request
Jul 14, 2026
Bring all remaining #879 telemetry updates into #880, including FOUNDRY_TESTING_MODE removal, privacy-doc updates, and the OneDsTelemetry merge resolution. Files changed: - sdk_v2/cpp/docs/Privacy.md - sdk_v2/cpp/src/telemetry/one_ds_telemetry.cc - sdk_v2/cpp/src/telemetry/telemetry_environment.{h,cc} - sdk_v2/cpp/src/telemetry/telemetry_logger.h - sdk_v2/cpp/src/telemetry/telemetry_metadata.{h,cc} - sdk_v2/cpp/test/internal_api/telemetry_test.cc Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 297bc539-5f7f-4a70-9411-48e91a5bf532
Rewrite the SDK privacy doc as a high-level, user-facing statement matching ONNX Runtime and ONNX Runtime GenAI: standard Data Collection notice, an overview, what is collected, and how to disable. Drops implementation details (CI-upload suppression, exact device-id storage paths, offline-cache and inference-timing internals, tenant-token plumbing, UWP specifics). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add an opt-out telemetry control to the SDK configuration: set disable_telemetry to true (default false) and the Manager keeps only local diagnostic logging -- no 1DS uploader is created, no device identifier is written, and no ProcessInfo is emitted. Wired through the core fl::Configuration struct, the C API (flConfigurationApi::SetDisableTelemetry), and the header-only C++ wrapper (Configuration::SetDisableTelemetry). Privacy.md documents this as the way to disable telemetry; a config test covers the default and the field. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Mirror the C++ SDK's disable_telemetry option in the three language bindings so their users can opt out without rebuilding: C# Configuration.DisableTelemetry, Python Configuration(disable_telemetry=...), and JS/TS FoundryLocalConfig.disableTelemetry. Each mirrors the existing setter pattern; the C# delegate table and the CFFI cdef append SetDisableTelemetry last, matching the C flConfigurationApi order. Validated: JS TypeScript typechecks and the native addon compiles; Python files syntax-check; the C++ core builds and its config tests pass. The C# build and Python editable install were blocked by this environment's restricted NuGet/pip feeds, not by the changes. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Exercises the disable_telemetry option end to end through the CFFI cdef and the C API SetDisableTelemetry setter (Configuration._build_native applies it), mirroring the existing additional_settings/catalog_urls native-build cases. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
DisableTelemetryDefaultsFalseAndIsSettable only asserted that a bool field stores a bool, and its default check duplicates the one now in DefaultValues. Keep the consolidated DefaultValues check, matching how every other config field's default is tested. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Move the disable_telemetry gating out of the Manager (which swapped TelemetryLogger vs OneDsTelemetry and was not unit-testable) into OneDsTelemetry itself, alongside its existing CI and empty-token suppression: when disabled the constructor skips 1DS Initialize, so IsUploadEnabled() is false and only the local diagnostic mirror runs. The Manager now always constructs OneDsTelemetry (when 1DS is built), passing config_.disable_telemetry. This makes the behavior testable: OneDsTelemetryTest.DisableTelemetrySuppressesUpload constructs OneDsTelemetry with a non-empty token but disable_telemetry=true and asserts IsUploadEnabled() is false -- a real behavior check. Verified: objects + tests build and the test passes. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Notes