omni/structuredlog/StructuredLogSettingsUtils.h
File members: omni/structuredlog/StructuredLogSettingsUtils.h
// Copyright (c) 2021-2023, 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 "IStructuredLog.h"
#include "IStructuredLogExtraFields.h"
#include "IStructuredLogSettings.h"
#include "IStructuredLogSettings2.h"
#include "IStructuredLogFromILog.h"
#include "../../carb/extras/StringSafe.h"
#include "../../carb/settings/ISettings.h"
#include "../core/Omni.h"
#include "../extras/PrivacySettings.h"
#include "../extras/OmniConfig.h"
#include "../log/ILog.h"
#include "../platforminfo/IOsInfo2.h"
namespace omni
{
namespace structuredlog
{
constexpr int64_t kDefaultLogSizeLimit = 50ll * 1024ll * 1024ll;
constexpr int64_t kMinLogSizeLimit = 256ll * 1024ll;
constexpr size_t kDefaultLogRetentionCount = 3;
constexpr size_t kMinLogRetentionCount = 1;
constexpr size_t kDefaultEventQueueSize = 2 * 1024 * 1024;
constexpr size_t kMinEventQueueSize = 512 * 1024;
constexpr size_t kMaxEventQueueSize = 1024 * 1024 * 1024;
constexpr IdMode kDefaultIdMode = IdMode::eFastSequential;
constexpr IdType kDefaultIdType = IdType::eUuid;
constexpr uint64_t kHeartbeatDisabled = 0;
constexpr uint64_t kDefaultHeartbeatPeriod = kHeartbeatDisabled;
constexpr bool kDefaultNeedLogHeaders = true;
constexpr bool kDefaultEmitPayloadOnlySettings = false;
constexpr bool kDefaultEmitCloudHeartbeat = false;
constexpr const char* kDefaultAnonymousUserIdModeSetting = "random";
constexpr const char* kGlobalEnableSetting = "/structuredLog/enable";
constexpr const char* kLogDirectory = "/structuredLog/logDirectory";
constexpr const char* kDefaultLogNameSetting = "/structuredLog/defaultLogName";
constexpr const char* kPrivacyFileSetting = "/structuredLog/privacySettingsFile";
constexpr const char* kLogRetentionCountSetting = "/structuredLog/logRetentionCount";
constexpr const char* kLogSizeLimitSetting = "/structuredLog/logSizeLimit";
constexpr const char* kEventQueueSizeSetting = "/structuredLog/eventQueueSize";
constexpr const char* kEventIdModeSetting = "/structuredLog/eventIdMode";
constexpr const char* kEventIdTypeSetting = "/structuredLog/eventIdType";
constexpr const char* kEnableLogConsumerSetting = "/structuredLog/enableLogConsumer";
constexpr const char* kSchemasStateListSetting = "/structuredLog/state/schemas";
constexpr const char* kEventsStateListSetting = "/structuredLog/state/events";
constexpr const char* kSchemasStateArraySetting = "/structuredLog/schemaStates";
constexpr const char* kEventsStateArraySetting = "/structuredLog/eventStates";
constexpr const char* kHeartbeatPeriodSetting = "/structuredLog/heartbeatPeriod";
constexpr const char* kNeedLogHeadersSetting = "/structuredLog/needLogHeaders";
constexpr const char* kEmitPayloadOnlySettings = "/structuredLog/emitPayloadOnly";
constexpr const char* kEmitCloudHeartbeatSetting = "/structuredLog/emitCloudHeartbeat";
constexpr const char* kExtraFieldsSettingBranch = "/structuredLog/extraFields";
constexpr const char* kAnonymousUserIdModeSetting = "/structuredLog/anonymousUserIdMode";
inline bool setStructuredLogLoggingEnabled(bool enabled = true)
{
    omni::core::ObjectPtr<IStructuredLog> strucLog;
    omni::core::ObjectPtr<IStructuredLogFromILog> log;
    strucLog = omni::core::borrow(omniGetStructuredLogWithoutAcquire());
    if (strucLog.get() == nullptr)
        return false;
    log = strucLog.as<IStructuredLogFromILog>();
    if (log.get() == nullptr)
        return false;
    if (enabled)
        log->enableLogging();
    else
        log->disableLogging();
    return true;
}
inline void configureStructuredLogging(carb::settings::ISettings* settings)
{
    omni::core::ObjectPtr<IStructuredLog> strucLog;
    omni::core::ObjectPtr<IStructuredLogSettings> ts;
    omni::core::ObjectPtr<IStructuredLogSettings2> ts2;
    omni::core::ObjectPtr<IStructuredLogFromILog> log;
    omni::core::ObjectPtr<IStructuredLogExtraFields> extraFields;
    const char* value;
    int64_t count;
    IdMode idMode = kDefaultIdMode;
    IdType idType = kDefaultIdType;
    if (settings == nullptr)
        return;
    // ****** set appropriate defaults for each setting ******
    settings->setDefaultBool(kGlobalEnableSetting, false);
    settings->setDefaultString(kLogDirectory, "");
    settings->setDefaultString(kDefaultLogNameSetting, "");
    settings->setDefaultInt64(kLogRetentionCountSetting, kDefaultLogRetentionCount);
    settings->setDefaultInt64(kLogSizeLimitSetting, kDefaultLogSizeLimit / 1048576);
    settings->setDefaultInt64(kEventQueueSizeSetting, kDefaultEventQueueSize / 1024);
    settings->setDefaultString(kEventIdModeSetting, "fast-sequential");
    settings->setDefaultString(kEventIdTypeSetting, "UUID");
    settings->setDefaultBool(kEnableLogConsumerSetting, false);
    settings->setDefaultInt64(kHeartbeatPeriodSetting, kDefaultHeartbeatPeriod);
    settings->setDefaultBool(kNeedLogHeadersSetting, kDefaultNeedLogHeaders);
    settings->setDefaultBool(kEmitPayloadOnlySettings, kDefaultEmitPayloadOnlySettings);
    settings->setDefaultBool(kEmitCloudHeartbeatSetting, kDefaultEmitCloudHeartbeat);
    settings->setDefaultString(kAnonymousUserIdModeSetting, kDefaultAnonymousUserIdModeSetting);
    // ****** grab the structured log settings object so the config can be set ******
    strucLog = omni::core::borrow(omniGetStructuredLogWithoutAcquire());
    if (strucLog.get() == nullptr)
        return;
    ts = strucLog.as<IStructuredLogSettings>();
    if (ts.get() == nullptr)
        return;
    // ****** retrieve the settings and make them active ******
    strucLog->setEnabled(omni::structuredlog::kBadEventId, omni::structuredlog::fEnableFlagAll,
                         settings->getAsBool(kGlobalEnableSetting));
    // set the default log name.
    value = settings->getStringBuffer(kDefaultLogNameSetting);
    if (value != nullptr && value[0] != 0)
        ts->setLogDefaultName(value);
    value = settings->getStringBuffer(kLogDirectory);
    if (value != nullptr && value[0] != 0)
    {
        ts->setLogOutputPath(value);
    }
    else
    {
        // This setting needs to be reloaded after ISerializer has been loaded, since it can read
        // omniverse.toml now in case there are overrides there.
        extras::OmniConfig config;
        ts->setLogOutputPath(config.getBaseLogsPath().c_str());
    }
    // set the log retention count.
    count = settings->getAsInt64(kLogRetentionCountSetting);
    ts->setLogRetentionCount(count);
    // set the log size limit.
    count = settings->getAsInt64(kLogSizeLimitSetting);
    ts->setLogSizeLimit(count * 1048576);
    // set the event queue size.
    count = settings->getAsInt64(kEventQueueSizeSetting);
    ts->setEventQueueSize(count * 1024);
    // set the event ID mode.
    value = settings->getStringBuffer(kEventIdModeSetting);
    if (carb::extras::compareStringsNoCase(value, "fast-sequential") == 0)
        idMode = IdMode::eFastSequential;
    else if (carb::extras::compareStringsNoCase(value, "sequential") == 0)
        idMode = IdMode::eSequential;
    else if (carb::extras::compareStringsNoCase(value, "random") == 0)
        idMode = IdMode::eRandom;
    else
        OMNI_LOG_WARN("unknown event ID mode '%s'.  Assuming 'fast-sequential'.", value);
    // set the event ID type.
    value = settings->getStringBuffer(kEventIdTypeSetting);
    if (carb::extras::compareStringsNoCase(value, "UUID") == 0)
        idType = IdType::eUuid;
    else if (carb::extras::compareStringsNoCase(value, "uint64") == 0)
        idType = IdType::eUint64;
    else
        OMNI_LOG_WARN("unknown event ID type '%s'.  Assuming 'UUID'.", value);
    ts->setEventIdMode(idMode, idType);
    // load the privacy settings and set the user ID from it.
    ts->loadPrivacySettings();
    // load the enable states for each schema and event.
    ts->enableSchemasFromSettings();
    // retrieve and set the user ID if present.
    value = omni::extras::PrivacySettings::getUserId();
    if (value != nullptr && value[0] != 0)
        ts->setUserId(value);
    else
    {
        const char* mode = settings->getStringBuffer(kAnonymousUserIdModeSetting);
        if (mode != nullptr && carb::extras::compareStringsNoCase(mode, "machine") == 0)
        {
            auto os2 = omni::core::createType<omni::platforminfo::IOsInfo2>();
            if (os2 != nullptr)
            {
                uint64_t id = os2->getMachineId();
                if (id != 0)
                {
                    ts->setUserId(std::to_string(id).c_str());
                }
            }
        }
    }
    // setup the structured log logger.
    log = strucLog.as<IStructuredLogFromILog>();
    if (log.get() == nullptr)
        return;
    if (settings->getAsBool(kEnableLogConsumerSetting))
        log->enableLogging();
    // setup the default heartbeat event period.
    ts2 = strucLog.as<IStructuredLogSettings2>();
    if (ts2 != nullptr)
    {
        OutputFlags flags = fOutputFlagNone;
        count = settings->getAsInt64(kHeartbeatPeriodSetting);
        ts2->setHeartbeatPeriod(count);
        if (!settings->getAsBool(kNeedLogHeadersSetting))
            flags |= fOutputFlagSkipLogHeaders;
        if (settings->getAsBool(kEmitPayloadOnlySettings))
            flags |= fOutputFlagPayloadOnly;
        if (settings->getAsBool(kEmitCloudHeartbeatSetting))
            flags |= fOutputFlagEmitCloudHeartbeat;
        ts2->setOutputFlags(flags, 0);
    }
    extraFields = strucLog.as<IStructuredLogExtraFields>();
    if (extraFields != nullptr)
    {
        // walk through the extra fields branch of the settings registry and add an extra field
        // for each key/value pair in there.  In general we don't expect there to be more than
        // a couple extra fields present.
        if (settings->isAccessibleAs(carb::dictionary::ItemType::eDictionary, kExtraFieldsSettingBranch))
        {
            carb::dictionary::IDictionary* dictionary = carb::getCachedInterface<carb::dictionary::IDictionary>();
            const carb::dictionary::Item* branch = settings->getSettingsDictionary(kExtraFieldsSettingBranch);
            size_t childCount = dictionary->getItemChildCount(branch);
            for (size_t i = 0; i < childCount; i++)
            {
                const carb::dictionary::Item* item = dictionary->getItemChildByIndex(branch, i);
                if (item == nullptr)
                    continue;
                const char* key = dictionary->getItemName(item);
                value = dictionary->getStringBuffer(item);
                if (key != nullptr && value != nullptr)
                {
                    extraFields->setValue(key, value, omni::structuredlog::fExtraFieldFlagNone);
                }
            }
        }
    }
    strucLog.release();
}
} // namespace structuredlog
} // namespace omni