Skip to content
Open
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
65 changes: 64 additions & 1 deletion sdk_v2/cpp/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,12 @@ endif()
if(NOT DEFINED FOUNDRY_LOCAL_BUILD_SERVICE OR FOUNDRY_LOCAL_BUILD_SERVICE)
list(APPEND VCPKG_MANIFEST_FEATURES "service")
endif()
# Telemetry must be selected before project() so vcpkg resolves the feature. Foundry Local Core always builds with
# telemetry; platforms that cannot link the 1DS transport are unsupported for this target.
if(CMAKE_SYSTEM_NAME STREQUAL "WindowsStore" OR VCPKG_TARGET_TRIPLET MATCHES "uwp")
message(FATAL_ERROR "Foundry Local Core always builds with telemetry; UWP/WindowsStore is not supported.")
endif()
list(APPEND VCPKG_MANIFEST_FEATURES "telemetry")

project(foundry_local VERSION 0.1.0 LANGUAGES CXX C)

Expand Down Expand Up @@ -45,6 +51,30 @@ option(FOUNDRY_LOCAL_BUILD_EXAMPLES "Build example programs" ON)
option(FOUNDRY_LOCAL_BUILD_SERVICE "Build web service support (requires oat++)" ON)
option(FOUNDRY_LOCAL_ENABLE_ASAN "Enable AddressSanitizer + UndefinedBehaviorSanitizer (Linux only)" OFF)

# Optional 1DS ingestion token override. Override only via environment so it does
# not appear in CMake cache files.
if(DEFINED CACHE{FOUNDRY_LOCAL_TELEMETRY_TOKEN}
AND NOT "$CACHE{FOUNDRY_LOCAL_TELEMETRY_TOKEN}" STREQUAL "")
message(FATAL_ERROR
"Do not pass FOUNDRY_LOCAL_TELEMETRY_TOKEN via -D or CMake cache. "
"Use the FOUNDRY_LOCAL_TELEMETRY_TOKEN environment variable for temporary test-tenant overrides.")
endif()
unset(FOUNDRY_LOCAL_TELEMETRY_TOKEN CACHE)

set(FOUNDRY_LOCAL_TELEMETRY_TOKEN "")
if(DEFINED ENV{FOUNDRY_LOCAL_TELEMETRY_TOKEN})
set(FOUNDRY_LOCAL_TELEMETRY_TOKEN "$ENV{FOUNDRY_LOCAL_TELEMETRY_TOKEN}")
endif()
if(FOUNDRY_LOCAL_TELEMETRY_TOKEN MATCHES "^\\$\\(")
set(FOUNDRY_LOCAL_TELEMETRY_TOKEN "")
endif()
if(FOUNDRY_LOCAL_TELEMETRY_TOKEN)
set(FOUNDRY_LOCAL_TELEMETRY_TOKEN_DEFINE
"#define FOUNDRY_LOCAL_TELEMETRY_TOKEN \"${FOUNDRY_LOCAL_TELEMETRY_TOKEN}\"")
else()
set(FOUNDRY_LOCAL_TELEMETRY_TOKEN_DEFINE "")
endif()

# Android: interactive examples and host tools don't run on device
if(ANDROID)
set(FOUNDRY_LOCAL_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE)
Expand Down Expand Up @@ -87,6 +117,13 @@ if(WIN32)
find_package(WinMLEpCatalog)
endif()

# 1DS C++ client telemetry — provided by the cpp-client-telemetry vcpkg port.
find_package(MSTelemetry CONFIG REQUIRED)
if(NOT WIN32)
find_package(OpenSSL REQUIRED)
endif()
message(STATUS "1DS telemetry: enabled (cpp-client-telemetry found)")

# --------------------------------------------------------------------------
# Library target
# --------------------------------------------------------------------------
Expand Down Expand Up @@ -197,7 +234,11 @@ set(FOUNDRY_LOCAL_SOURCES
src/service/web_service.cc
src/telemetry/telemetry.cc
src/telemetry/telemetry_action_tracker.cc
src/telemetry/device_id.cc
src/telemetry/invocation_context.cc
src/telemetry/telemetry_environment.cc
src/telemetry/telemetry_logger.cc
src/telemetry/telemetry_metadata.cc
src/utils.cc
src/util/file_lock.cc
src/http/http_download.cc
Expand All @@ -209,6 +250,12 @@ set(FOUNDRY_LOCAL_SOURCES
${FOUNDRY_LOCAL_INTERNAL_HEADERS}
)

# 1DS bridge — always compiled for Foundry Local Core.
list(APPEND FOUNDRY_LOCAL_SOURCES src/telemetry/one_ds_telemetry.cc)
if(ANDROID)
list(APPEND FOUNDRY_LOCAL_SOURCES src/telemetry/android_telemetry_bridge.cc)
endif()

# Organize headers into filters matching the directory structure in Visual Studio
source_group(TREE "${CMAKE_CURRENT_SOURCE_DIR}" PREFIX "Source" FILES ${FOUNDRY_LOCAL_SOURCES})
source_group(TREE "${CMAKE_CURRENT_SOURCE_DIR}/include" PREFIX "Public Headers" FILES ${FOUNDRY_LOCAL_PUBLIC_HEADERS})
Expand Down Expand Up @@ -251,12 +298,18 @@ function(foundry_local_configure_target TARGET LINK_SCOPE)
endif()

if(WIN32)
target_link_libraries(${TARGET} ${LINK_SCOPE} dbghelp bcrypt)
target_link_libraries(${TARGET} ${LINK_SCOPE} dbghelp bcrypt version)
# UWP builds have CMAKE_SYSTEM_NAME = "WindowsStore"; desktop = "Windows".
# WinHTTP is not available in UWP, so only define this on desktop Windows.
if(NOT CMAKE_SYSTEM_NAME STREQUAL "WindowsStore")
target_compile_definitions(${TARGET} PRIVATE FOUNDRY_LOCAL_USE_WINHTTP_TRANSPORT=1)
endif()
else()
target_link_libraries(${TARGET} ${LINK_SCOPE} OpenSSL::Crypto)
endif()

if(APPLE)
target_link_libraries(${TARGET} ${LINK_SCOPE} "-framework CoreFoundation")
endif()

if(ANDROID)
Expand All @@ -274,6 +327,9 @@ function(foundry_local_configure_target TARGET LINK_SCOPE)
else()
target_compile_definitions(${TARGET} ${LINK_SCOPE} FOUNDRY_LOCAL_HAS_EP_CATALOG=0)
endif()

target_link_libraries(${TARGET} ${LINK_SCOPE} MSTelemetry::mat)

endfunction()

# --------------------------------------------------------------------------
Expand All @@ -297,6 +353,13 @@ configure_file(
@ONLY
)

# Generate the 1DS tenant-token header.
configure_file(
"${CMAKE_CURRENT_SOURCE_DIR}/src/telemetry/one_ds_tenant_token.h.in"
"${CMAKE_CURRENT_BINARY_DIR}/generated/one_ds_tenant_token.h"
@ONLY
)

# --------------------------------------------------------------------------
# Object library — compiles all sources once. Both the shared (DLL) and
# static library targets re-use these object files, avoiding a double build.
Expand Down
13 changes: 10 additions & 3 deletions sdk_v2/cpp/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,6 @@ class HelpFormatter(argparse.ArgumentDefaultsHelpFormatter, argparse.RawDescript
help="Override the Microsoft.Windows.AI.MachineLearning NuGet version for the WinML EP "
"catalog (Windows only). Defaults to the version pinned in deps_versions.json.",
)

# Cross-compilation (mutually exclusive targets)
cross_group = parser.add_mutually_exclusive_group()
cross_group.add_argument(
Expand Down Expand Up @@ -439,6 +438,10 @@ def configure(args: argparse.Namespace) -> None:
if triplets_dir.is_dir():
command += [f"-DVCPKG_OVERLAY_TRIPLETS={triplets_dir}"]

ports_dir = SCRIPT_DIR / "ports"
if ports_dir.is_dir():
command += [f"-DVCPKG_OVERLAY_PORTS={ports_dir}"]

# Project options
build_tests = "ON"

Expand All @@ -451,9 +454,13 @@ def configure(args: argparse.Namespace) -> None:
f"-DFOUNDRY_LOCAL_BUILD_SERVICE={build_service}",
]

# Enable vcpkg manifest features for tests
# Enable vcpkg manifest features as needed. Multiple features are passed as a
# semicolon-separated list in a single -D flag.
manifest_features = []
if build_tests == "ON":
command += ["-DVCPKG_MANIFEST_FEATURES=tests"]
manifest_features.append("tests")
if manifest_features:
command += [f"-DVCPKG_MANIFEST_FEATURES={';'.join(manifest_features)}"]

# WinML EP catalog is enabled automatically on Windows by CMake. Allow an
# optional version override for the Microsoft.Windows.AI.MachineLearning NuGet.
Expand Down
4 changes: 4 additions & 0 deletions sdk_v2/cpp/include/foundry_local/foundry_local_cpp.h
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,10 @@ class Configuration {
/// Defaults to "centralus" when not set.
Configuration& SetCatalogRegion(const std::string& region);

/// Optional. Disable non-essential telemetry. Foundry Local may still send a minimal ProcessInfo event.
/// Defaults to false (telemetry enabled).
Configuration& SetDisableNonessentialTelemetry(bool disable);

const flConfiguration* native_handle() const noexcept { return handle_.get(); }

private:
Expand Down
6 changes: 6 additions & 0 deletions sdk_v2/cpp/include/foundry_local/foundry_local_cpp.inline.h
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,12 @@ inline Configuration& Configuration::SetCatalogRegion(const std::string& region)
return *this;
}

inline Configuration& Configuration::SetDisableNonessentialTelemetry(bool disable) {
KeyValuePairs options;
options.Set("DisableNonessentialTelemetry", disable ? "true" : "false");
return SetAdditionalOptions(options);
}

inline flConfiguration* detail::CreateConfiguration(const std::string& app_name) {
flConfiguration* config = nullptr;
Check(detail::config_api()->Create(app_name.c_str(), &config));
Expand Down
50 changes: 50 additions & 0 deletions sdk_v2/cpp/ports/cpp-client-telemetry/portfile.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
vcpkg_from_github(
OUT_SOURCE_PATH SOURCE_PATH
REPO microsoft/cpp_client_telemetry
REF 5152cb4067c3c0f46ffd79672702ffcffcade9c8
SHA512 d46e929f1724333f41574829da2521d0c76cb07273b00baf978f459b38416a8cb7eeba9b0898364540b9a6ad1f2319f70c5e89f92e15c6f80ef59921e7ee0325
HEAD_REF main
)

set(MATSDK_BUILD_APPLE_HTTP OFF)
if(VCPKG_TARGET_IS_OSX OR VCPKG_TARGET_IS_IOS)
set(MATSDK_BUILD_APPLE_HTTP ON)
endif()

set(MATSDK_BUILD_IOS OFF)
if(VCPKG_TARGET_IS_IOS)
set(MATSDK_BUILD_IOS ON)
endif()

vcpkg_check_features(
OUT_FEATURE_OPTIONS FEATURE_OPTIONS
FEATURES
minimal-sqlite MATSDK_MINIMAL_SQLITE
)

vcpkg_cmake_configure(
SOURCE_PATH "${SOURCE_PATH}"
OPTIONS
${FEATURE_OPTIONS}
-DMATSDK_USE_VCPKG_DEPS=ON
-DBUILD_HEADERS=ON
-DBUILD_LIBRARY=ON
-DBUILD_TEST_TOOL=OFF
-DBUILD_UNIT_TESTS=OFF
-DBUILD_FUNC_TESTS=OFF
-DBUILD_JNI_WRAPPER=OFF
-DBUILD_OBJC_WRAPPER=OFF
-DBUILD_SWIFT_WRAPPER=OFF
-DBUILD_PACKAGE=OFF
-DBUILD_VERSION=${VERSION}
-DBUILD_APPLE_HTTP=${MATSDK_BUILD_APPLE_HTTP}
-DBUILD_IOS=${MATSDK_BUILD_IOS}
)

vcpkg_cmake_install()
vcpkg_cmake_config_fixup(PACKAGE_NAME MSTelemetry CONFIG_PATH lib/cmake/MSTelemetry)

file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/debug/include")
file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/debug/share")

vcpkg_install_copyright(FILE_LIST "${SOURCE_PATH}/LICENSE")
54 changes: 54 additions & 0 deletions sdk_v2/cpp/ports/cpp-client-telemetry/vcpkg.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
{
"name": "cpp-client-telemetry",
"version": "3.10.173.1",
"port-version": 1,
"description": "Microsoft 1DS C/C++ Client Telemetry Library",
"homepage": "https://github.com/microsoft/cpp_client_telemetry",
"license": "Apache-2.0",
"supports": "((windows & !mingw) | linux | osx | ios | android) & !uwp",
"dependencies": [
"nlohmann-json",
{
"name": "vcpkg-cmake",
"host": true
},
{
"name": "vcpkg-cmake-config",
"host": true
},
{
"name": "zlib",
"platform": "!osx & !ios"
}
],
"default-features": [
"system-sqlite",
"curl-openssl"
],
"features": {
"system-sqlite": {
"description": "Use the external vcpkg sqlite3 package for offline storage.",
"dependencies": [
{
"name": "sqlite3",
"default-features": false,
"platform": "!osx & !ios"
}
]
},
"minimal-sqlite": {
"description": "Build the SDK's private feature-stripped SQLite."
},
"curl-openssl": {
"description": "Use the built-in libcurl client with OpenSSL on Linux and Android.",
"dependencies": [
{
"name": "curl",
"default-features": false,
"features": ["openssl"],
"platform": "linux | android"
}
]
}
}
}
4 changes: 4 additions & 0 deletions sdk_v2/cpp/src/configuration.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ struct Configuration {
/// inference) via the external service's HTTP endpoints.
std::optional<std::string> external_service_url;

/// Disable non-essential telemetry. Foundry Local may still send a minimal ProcessInfo event.
/// Defaults to false.
bool disable_nonessential_telemetry = false;

/// Additional/undocumented options passed through to the core.
std::map<std::string, std::string> additional_options;

Expand Down
22 changes: 20 additions & 2 deletions sdk_v2/cpp/src/manager.cc
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@
#include "inferencing/session/session_manager.h"
#include "spdlog_logger.h"
#include "telemetry/telemetry_action_tracker.h"
#include "telemetry/telemetry_logger.h"
#include "telemetry/one_ds_telemetry.h"
#include "telemetry/telemetry_environment.h"
#include "telemetry/telemetry_metadata.h"
#include "util/string_utils.h"
#include "utils.h"

Expand Down Expand Up @@ -302,7 +304,23 @@ Manager::Manager(const Configuration& config)
disable_region_fallback);
model_load_manager_ = std::make_unique<ModelLoadManager>(*ep_detector_, *logger_);
session_manager_ = std::make_unique<SessionManager>(*logger_);
telemetry_ = std::make_unique<TelemetryLogger>(config_.app_name, *logger_);
const bool disable_nonessential_telemetry =
config_.disable_nonessential_telemetry ||
IsAdditionalOptionEnabled(config_, "DisableNonessentialTelemetry");
const bool telemetry_hard_disabled =
TelemetryEnvironment::IsCiEnvironment() || TelemetryEnvironment::IsTelemetryDisabledByEnvVar();
telemetry_ = std::make_unique<OneDsTelemetry>(config_.app_name, *logger_, disable_nonessential_telemetry);
try {
telemetry_->RecordProcessInfo(
BuildProcessInfo(BuildTelemetryMetadata(config_.app_name),
!disable_nonessential_telemetry && !telemetry_hard_disabled));
} catch (const std::exception& ex) {
logger_->Log(
LogLevel::Warning,
fmt::format("telemetry ProcessInfo failed during Manager initialization: {}", ex.what()));
} catch (...) {
logger_->Log(LogLevel::Warning, "telemetry ProcessInfo failed during Manager initialization.");
}
catalog_ = std::make_unique<AzureModelCatalog>(
config_.catalog_urls,
download_manager_->GetCacheDirectory(),
Expand Down
12 changes: 12 additions & 0 deletions sdk_v2/cpp/src/telemetry/android_telemetry_bridge.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

#include "http/HttpClient_Android.hpp"

extern "C" __attribute__((visibility("default"))) bool FoundryLocalIsAndroidTelemetryReady() noexcept {
try {
return Microsoft::Applications::Events::HttpClient_Android::GetClientInstance() != nullptr;
} catch (...) {
return false;
}
}
Loading
Loading