Telemetry.h#

Fully qualified name: omni/structuredlog/Telemetry.h

File members: omni/structuredlog/Telemetry.h

// Copyright (c) 2021-2024, NVIDIA CORPORATION. All rights reserved.
//
// NVIDIA CORPORATION and its licensors retain all intellectual property
// and proprietary rights in and to this software, related documentation
// and any modifications thereto. Any use, reproduction, disclosure or
// distribution of this software and related documentation without an express
// license agreement from NVIDIA CORPORATION is strictly prohibited.
//
#pragma once

#include "IStructuredLogSettings.h"
#include "../extras/UniqueApp.h"
#include "../../carb/launcher/ILauncher.h"
#include "../../carb/launcher/LauncherUtils.h"
#include "../../carb/settings/ISettings.h"

namespace omni
{
namespace telemetry
{

constexpr const char* const kStayAliveSetting = "/telemetry/stayAlive";

constexpr const char* kUploadAllAndExitSetting = "/telemetry/uploadAllAndExit";

constexpr const char* const kPollTimeSetting = "/telemetry/pollTime";

constexpr const char* const kTelemetryModeSetting = "/telemetry/mode";

constexpr const char* const kTelemetryTagSetting = "/telemetry/modeTag";

constexpr const char* const kTelemetryEnableAnonymousDataSetting = "/telemetry/enableAnonymousData";

constexpr const char* const kTelemetryDisableAnonymousDataEnvvar = "OMNI_TELEMETRY_DISABLE_ANONYMOUS_DATA";

constexpr const char* const kTelemetryRunEnvironmentSetting = "/telemetry/runEnvironment";

constexpr const char* const kAllowRootSetting = "/telemetry/allowRoot";

constexpr const char* const kRestrictedRegionsSetting = "/telemetry/restrictedRegions";

constexpr const char* const kRestrictedRegionAssumptionSetting = "/telemetry/restrictedRegionAssumption";

constexpr const char* const kLogFileSetting = "/telemetry/log/file";

constexpr const char* const kLogLevelSetting = "/telemetry/log/level";

constexpr const char* const kUseOpenEndpointSetting = "/telemetry/useOpenEndpoint";

constexpr const char* const kExtraFieldsToAddSetting = "/telemetry/extraFieldsToAdd";

constexpr const char* const kReplaceExtraFieldsSetting = "/telemetry/replaceExtraFields";

constexpr const char* const kLaunchGuardNameSetting = "/telemetry/launchGuardName";

constexpr const char* const kTransmitterSetting = "/telemetry/transmitter";

constexpr const char* const kResendEventsSettingLeaf = "resendEvents";

constexpr const char* const kTransmissionLimitSettingLeaf = "transmissionLimit";

constexpr const char* const kQueueLimitSettingLeaf = "queueLimit";

constexpr const char* const kTelemetryEndpointSettingLeaf = "endpoint";

constexpr const char* const kTelemetrySchemasUrlSettingLeaf = "schemasUrl";

constexpr const char* const kTelemetryAuthenticateSettingLeaf = "authenticate";

constexpr const char* const kTelemetryAuthTokenUrlSettingLeaf = "authTokenUrl";

constexpr const char* const kTelemetryAuthTokenKeyNameSettingLeaf = "authTokenKeyName";

constexpr const char* const kTelemetryAuthTokenExpiryNameSettingLeaf = "authTokenExpiryName";

constexpr const char* const kEventProtocolLeaf = "eventProtocol";

constexpr const char* const kSeekTagNameLeaf = "seekTagName";

constexpr const char* const kTelemetryAuthTokenTypeLeaf = "authTokenType";

constexpr const char* const kOldEventThresholdSettingLeaf = "oldEventThreshold";

constexpr const char* const kIgnoreOldEventsSettingLeaf = "ignoreOldEvents";

constexpr const char* const kPseudonymizeOldEventsSettingLeaf = "pseudonymizeOldEvents";

constexpr const char* const kRetryLimitSettingLeaf = "retryLimit";

constexpr const char* const kMessageMatchingModeLeaf = "messageMatchMode";
inline extras::UniqueApp createGuard()
{
    carb::settings::ISettings* settings;
    const char* guardName = "omni.telemetry.transmitter";
    std::string value;
    auto getGuardPath = []() -> std::string {
#if OMNI_PLATFORM_LINUX
        // XDG_RUNTIME_DIR is the standard place for putting runtime IPC objects on Linux
        const char* runDir = getenv("XDG_RUNTIME_DIR");
        if (runDir != nullptr)
        {
            return runDir;
        }
#endif

        core::ObjectPtr<omni::structuredlog::IStructuredLog> strucLog;
        core::ObjectPtr<omni::structuredlog::IStructuredLogSettings> settings;

        strucLog = omni::core::borrow(omniGetStructuredLogWithoutAcquire());
        if (strucLog.get() == nullptr)
        {
            OMNI_LOG_ERROR("failed to get IStructuredLog");
            return "";
        }

        settings = strucLog.as<structuredlog::IStructuredLogSettings>();
        if (settings.get() == nullptr)
        {
            OMNI_LOG_ERROR("failed to get IStructuredLogSettings");
            return "";
        }

        return settings->getLogOutputPath();
    };

    settings = carb::getCachedInterface<carb::settings::ISettings>();

    if (settings != nullptr && settings->isAccessibleAs(carb::dictionary::ItemType::eString, kLaunchGuardNameSetting))
    {
        value = carb::settings::getString(settings, kLaunchGuardNameSetting, guardName);
        guardName = value.c_str();
    }

    return extras::UniqueApp(getGuardPath().c_str(), guardName);
}

inline std::string getTransmitterLogPath()
{
    constexpr const char* kLogFileFallback = "./omni.telemetry.transmitter.log";
    carb::settings::ISettings* settings = carb::getFramework()->tryAcquireInterface<carb::settings::ISettings>();
    core::ObjectPtr<omni::structuredlog::IStructuredLog> strucLog =
        omni::core::borrow(omniGetStructuredLogWithoutAcquire());
    core::ObjectPtr<omni::structuredlog::IStructuredLogSettings> strucLogSettings;

    if (settings != nullptr)
    {
        settings->setDefaultString(kLogFileSetting, "");
        carb::cpp::optional<std::string> logFile = carb::settings::getStringOpt(settings, kLogFileSetting);
        if (logFile && !logFile->empty())
            return *logFile;
    }
    else
    {
        CARB_LOG_ERROR("failed to acquire ISettings");
    }

    if (strucLog.get() == nullptr)
    {
        OMNI_LOG_ERROR("failed to get IStructuredLog - using CWD");
        return kLogFileFallback;
    }

    strucLogSettings = strucLog.as<structuredlog::IStructuredLogSettings>();
    if (strucLogSettings.get() == nullptr)
    {
        OMNI_LOG_ERROR("failed to get IStructuredLogSettings - using CWD for the log file");
        return kLogFileFallback;
    }

    return std::string(strucLogSettings->getLogOutputPath()) + "/omni.telemetry.transmitter.log";
}

inline bool launchTransmitter(const char* transmitterPath, const std::vector<std::string> extraArgs = {})
{
#if OMNI_PLATFORM_WINDOWS
    const char* ext = ".exe";
#else
    const char* ext = "";
#endif
    carb::launcher::ILauncher* launcher = carb::getFramework()->tryAcquireInterface<carb::launcher::ILauncher>();
    carb::settings::ISettings* settings = carb::getFramework()->tryAcquireInterface<carb::settings::ISettings>();
    extras::UniqueApp guard = createGuard();
    carb::launcher::ArgCollector args;
    carb::launcher::EnvCollector env;
    carb::launcher::LaunchDesc desc = {};
    size_t envCount;

    if (launcher == nullptr)
    {
        OMNI_LOG_ERROR("failed to acquire ILauncher");
        return false;
    }

    guard.connectClientProcess();

    args.format("%s/omni.telemetry.transmitter%s", transmitterPath, ext);

    args.add("/telemetry", "--/", carb::launcher::fSettingsEnumFlagRecursive);
    args.add("/structuredLog/extraFields", "--/", 0);
    args.add("/log", "--/", carb::launcher::fSettingsEnumFlagRecursive, [](const char* path, void* ctx) {
        CARB_UNUSED(ctx);
        return strcmp(path, "/log/enableStandardStreamOutput") != 0 && strcmp(path, "/log/file") != 0 &&
               strcmp(path, "/log/level") != 0;
    });

    // output will not go to the standard streams because it's annoying if
    // output goes to your terminal after your process finishes and there is no
    // way to ensure the transmitter shuts down before your process
    args.add("--/log/enableStandardStreamOutput=false");

    args.format("--/log/file=%s", getTransmitterLogPath().c_str());

    if (settings == nullptr)
    {
        OMNI_LOG_ERROR("failed to acquire ISettings");
    }
    else
    {
        settings->setDefaultString(kLogLevelSetting, "");
        carb::cpp::optional<std::string> logLevel = carb::settings::getStringOpt(settings, kLogLevelSetting);
        if (logLevel && !logLevel->empty())
        {
            args.format("--/log/level=%s", logLevel->c_str());
        }
        else
        {
            logLevel = carb::settings::getStringOpt(settings, "/log/level");
            if (logLevel && !logLevel->empty())
            {
                args.format("--/log/level=%s", logLevel->c_str());
            }
        }
    }

    for (const std::string& arg : extraArgs)
    {
        args.add(arg);
    }

    // add the parent environment but remove the `CARB_APP_PATH` and `CARB_APP_NAME` variables
    // since they will negatively affect the behaviour of the transmitter.  Note that since
    // we're explicitly adding the full parent environment here and just subtracting some
    // variables, we need to also use the `fLaunchFlagNoInheritEnv` flag when launching the
    // child process so that ILauncher doesn't implicitly add them back.
    env.add();
    envCount = env.getCount();
    env.remove("CARB_APP_PATH");
    env.remove("CARB_APP_NAME");

    if (env.getCount() != envCount)
    {
        desc.flags |= carb::launcher::fLaunchFlagAllowBadEnv | carb::launcher::fLaunchFlagNoInheritEnv;
        desc.env = env.getEnv();
        desc.envCount = env.getCount();
    }

    desc.argv = args.getArgs(&desc.argc);
    desc.flags |= carb::launcher::fLaunchFlagNoStdStreams;

    return launcher->launchProcessDetached(desc) != carb::launcher::kBadId;
}

} // namespace telemetry
} // namespace omni