cpp_client_telemetry/lib/api/ContextFieldsProvider.cpp

467 строки
17 KiB
C++

// Copyright (c) Microsoft. All rights reserved.
#include "pal/PAL.hpp"
#include "ContextFieldsProvider.hpp"
#include "LogSessionData.hpp"
#include "utils/Utils.hpp"
namespace ARIASDK_NS_BEGIN
{
ContextFieldsProvider::ContextFieldsProvider()
: ContextFieldsProvider(nullptr)
{
}
ContextFieldsProvider::ContextFieldsProvider(ContextFieldsProvider* parent)
: m_parent(parent)
{
if (!m_parent)
{
PAL::registerSemanticContext(this);
}
}
ContextFieldsProvider::ContextFieldsProvider(ContextFieldsProvider const& copy)
{
m_parent = copy.m_parent;
m_commonContextFields = copy.m_commonContextFields;
m_customContextFields = copy.m_customContextFields;
m_commonContextEventToConfigIds = copy.m_commonContextEventToConfigIds;
m_ticketsMap = copy.m_ticketsMap;
}
ContextFieldsProvider& ContextFieldsProvider::operator=(ContextFieldsProvider const& copy)
{
m_parent = copy.m_parent;
m_commonContextFields = copy.m_commonContextFields;
m_customContextFields = copy.m_customContextFields;
m_commonContextEventToConfigIds = copy.m_commonContextEventToConfigIds;
m_ticketsMap = copy.m_ticketsMap;
return *this;
}
void ContextFieldsProvider::writeToRecord(::CsProtocol::Record& record, bool commonOnly)
{
// Append parent scope context variables if not detached from parent
if (m_parent)
{
m_parent->writeToRecord(record);
}
if (record.data.size() == 0)
{
::CsProtocol::Data data;
record.data.push_back(data);
}
if (record.extApp.size() == 0)
{
::CsProtocol::App app;
record.extApp.push_back(app);
}
if (record.extDevice.size() == 0)
{
::CsProtocol::Device device;
record.extDevice.push_back(device);
}
if (record.extOs.size() == 0)
{
::CsProtocol::Os os;
record.extOs.push_back(os);
}
if (record.extUser.size() == 0)
{
::CsProtocol::User user;
record.extUser.push_back(user);
}
if (record.extLoc.size() == 0)
{
::CsProtocol::Loc loc;
record.extLoc.push_back(loc);
}
if (record.extNet.size() == 0)
{
::CsProtocol::Net net;
record.extNet.push_back(net);
}
if (record.extProtocol.size() == 0)
{
::CsProtocol::Protocol proto;
record.extProtocol.push_back(proto);
}
if (record.extM365a.size() == 0)
{
::CsProtocol::M365a m365a;
record.extM365a.push_back(m365a);
}
std::map<std::string, ::CsProtocol::Value>& ext = record.data[0].properties;
{
LOCKGUARD(m_lock);
std::string value = m_commonContextFields[COMMONFIELDS_APP_EXPERIMENTIDS].as_string;
if (!value.empty())
{// for ECS set event specific config ids
std::string eventName = record.name;
if (!eventName.empty())
{
const auto& iter = m_commonContextEventToConfigIds.find(eventName);
if (iter != m_commonContextEventToConfigIds.end())
{
value = iter->second;
}
}
record.extApp[0].expId = value;
}
if (!m_commonContextFields.empty())
{
if (m_commonContextFields.find(COMMONFIELDS_APP_EXPERIMENT_IMPRESSION_ID) != m_commonContextFields.end())
{
CsProtocol::Value temp;
EventProperty prop = m_commonContextFields[COMMONFIELDS_APP_EXPERIMENT_IMPRESSION_ID];
temp.stringValue = prop.as_string;
ext[COMMONFIELDS_APP_EXPERIMENT_IMPRESSION_ID] = temp;
}
if (m_commonContextFields.find(COMMONFIELDS_APP_EXPERIMENTETAG) != m_commonContextFields.end())
{
CsProtocol::Value temp;
EventProperty prop = m_commonContextFields[COMMONFIELDS_APP_EXPERIMENTETAG];
temp.stringValue = prop.as_string;
ext[COMMONFIELDS_APP_EXPERIMENTETAG] = temp;
}
auto iter = m_commonContextFields.find(COMMONFIELDS_APP_ID);
bool hasAppId = (iter != m_commonContextFields.end());
if (hasAppId)
{
record.extApp[0].id = iter->second.as_string;
}
iter = m_commonContextFields.find(COMMONFIELDS_APP_ENV);
bool hasAppEnv = (iter != m_commonContextFields.end());
if (hasAppEnv)
{
record.extApp[0].env = iter->second.as_string;
}
iter = m_commonContextFields.find(COMMONFIELDS_APP_NAME);
if (iter != m_commonContextFields.end())
{
record.extApp[0].name = iter->second.as_string;
}
else if (hasAppId)
{
// Backwards-compat: legacy Aria exporter maps CS3.0 ext.app.name to AppInfo.Id
// TODO:
// - consider resolving that protocol "wrinkle" backend-side
// - consider parsing ext.app.id if it contains app hash!name:ver information
record.extApp[0].name = record.extApp[0].id;
}
iter = m_commonContextFields.find(COMMONFIELDS_APP_VERSION);
if (iter != m_commonContextFields.end())
{
record.extApp[0].ver = iter->second.as_string;
}
iter = m_commonContextFields.find(COMMONFIELDS_APP_LANGUAGE);
if (iter != m_commonContextFields.end())
{
record.extApp[0].locale = iter->second.as_string;
}
iter = m_commonContextFields.find(COMMONFIELDS_DEVICE_ID);
if (iter != m_commonContextFields.end())
{
// Use "c:" prefix
std::string temp("c:");
const char *deviceId = iter->second.as_string;
if (deviceId != nullptr)
{
size_t len = strlen(deviceId);
if (len >= 2 && deviceId[1] == ':' && (
deviceId[0] == 'c' || // c: Custom identifier
deviceId[0] == 'u' || // u: Mac OS X UUID
deviceId[0] == 'a' || // a: Android ID
deviceId[0] == 's' || // s: SQM ID
deviceId[0] == 'x' || // x: XBox One hardware ID
deviceId[0] == 'i')) // i: iOS ID
{
// Remove "c:" prefix
temp = "";
}
// Strip curly braces from GUID while populating localId.
// Otherwise 1DS collector would not strip the prefix.
if ((deviceId[0] == '{') && (deviceId[len - 1] == '}'))
{
temp.append(deviceId + 1, len - 2);
}
else
{
temp.append(deviceId);
}
}
record.extDevice[0].localId = temp;
}
iter = m_commonContextFields.find(COMMONFIELDS_DEVICE_MAKE);
if (iter != m_commonContextFields.end())
{
record.extProtocol[0].devMake = iter->second.as_string;
}
iter = m_commonContextFields.find(COMMONFIELDS_DEVICE_MODEL);
if (iter != m_commonContextFields.end())
{
record.extProtocol[0].devModel = iter->second.as_string;
}
iter = m_commonContextFields.find(COMMONFIELDS_DEVICE_CLASS);
if (iter != m_commonContextFields.end())
{
record.extDevice[0].deviceClass = iter->second.as_string;
}
iter = m_commonContextFields.find(COMMONFIELDS_COMMERCIAL_ID);
if (iter != m_commonContextFields.end())
{
record.extM365a[0].enrolledTenantId = iter->second.as_string;
}
iter = m_commonContextFields.find(COMMONFIELDS_OS_NAME);
if (iter != m_commonContextFields.end())
{
record.extOs[0].name = iter->second.as_string;
}
iter = m_commonContextFields.find(COMMONFIELDS_OS_BUILD);
if (iter != m_commonContextFields.end())
{
//EventProperty prop = (*m_commonContextFieldsP)[COMMONFIELDS_OS_VERSION];
record.extOs[0].ver = iter->second.as_string;
}
iter = m_commonContextFields.find(COMMONFIELDS_USER_ID);
if (iter != m_commonContextFields.end())
{
record.extUser[0].localId = iter->second.as_string;
}
iter = m_commonContextFields.find(COMMONFIELDS_USER_LANGUAGE);
if (iter != m_commonContextFields.end())
{
record.extUser[0].locale = iter->second.as_string;
}
iter = m_commonContextFields.find(COMMONFIELDS_USER_TIMEZONE);
if (iter != m_commonContextFields.end())
{
record.extLoc[0].timezone = iter->second.as_string;
}
iter = m_commonContextFields.find(COMMONFIELDS_USER_MSAID);
if (iter != m_commonContextFields.end())
{
record.extDevice[0].authSecId = iter->second.as_string;
}
iter = m_commonContextFields.find(COMMONFIELDS_NETWORK_COST);
if (iter != m_commonContextFields.end())
{
record.extNet[0].cost = iter->second.as_string;
}
iter = m_commonContextFields.find(COMMONFIELDS_NETWORK_PROVIDER);
if (iter != m_commonContextFields.end())
{
record.extNet[0].provider = iter->second.as_string;
}
iter = m_commonContextFields.find(COMMONFIELDS_NETWORK_TYPE);
if (iter != m_commonContextFields.end())
{
record.extNet[0].type = iter->second.as_string;
}
}
if (m_ticketsMap.size() > 0)
{
std::vector<std::string> tickets;
for (auto const& field : m_ticketsMap)
{
tickets.push_back(field.second);
}
CsProtocol::Protocol temp;
temp.ticketKeys.push_back(tickets);
record.extProtocol.push_back(temp);
}
if (!commonOnly)
{
for (auto const& field : m_customContextFields)
{
if (field.second.piiKind != PiiKind_None)
{
CsProtocol::PII pii;
pii.Kind = static_cast<CsProtocol::PIIKind>(field.second.piiKind);
CsProtocol::Value temp;
CsProtocol::Attributes attrib;
attrib.pii.push_back(pii);
temp.attributes.push_back(attrib);
temp.stringValue = field.second.to_string();
record.data[0].properties[field.first] = temp;
}
else
{
std::vector<uint8_t> guid;
uint8_t guid_bytes[16] = { 0 };
switch (field.second.type)
{
case EventProperty::TYPE_STRING:
{
CsProtocol::Value temp;
temp.stringValue = field.second.to_string();
record.data[0].properties[field.first] = temp;
break;
}
case EventProperty::TYPE_INT64:
{
CsProtocol::Value temp;
temp.type = ::CsProtocol::ValueKind::ValueInt64;
temp.longValue = field.second.as_int64;
record.data[0].properties[field.first] = temp;
break;
}
case EventProperty::TYPE_DOUBLE:
{
CsProtocol::Value temp;
temp.type = ::CsProtocol::ValueKind::ValueDouble;
temp.doubleValue = field.second.as_double;
record.data[0].properties[field.first] = temp;
break;
}
case EventProperty::TYPE_TIME:
{
CsProtocol::Value temp;
temp.type = ::CsProtocol::ValueKind::ValueDateTime;
temp.longValue = field.second.as_time_ticks.ticks;
record.data[0].properties[field.first] = temp;
break;
}
case EventProperty::TYPE_BOOLEAN:
{
CsProtocol::Value temp;
temp.type = ::CsProtocol::ValueKind::ValueBool;
temp.longValue = field.second.as_bool;
record.data[0].properties[field.first] = temp;
break;
}
case EventProperty::TYPE_GUID:
{
GUID_t temp = field.second.as_guid;
temp.to_bytes(guid_bytes);
guid = std::vector<uint8_t>(guid_bytes, guid_bytes + sizeof(guid_bytes) / sizeof(guid_bytes[0]));
CsProtocol::Value tempValue;
tempValue.type = ::CsProtocol::ValueKind::ValueGuid;
tempValue.guidValue.push_back(guid);
record.data[0].properties[field.first] = tempValue;
break;
}
default:
{
// Convert all unknown types to string
CsProtocol::Value temp;
temp.stringValue = field.second.to_string();
record.data[0].properties[field.first] = temp;
}
}
}
}
}
LOG_TRACE("Record=%p decorated with SemanticContext=%p", &record, this);
}
}
void ContextFieldsProvider::ClearExperimentIds()
{
// Clear the common ExperimentIds
SetCommonField(COMMONFIELDS_APP_EXPERIMENTIDS, "");
// Clear the map of all ExperimentsIds (that's associated with event)
m_commonContextEventToConfigIds.clear();
}
void ContextFieldsProvider::SetEventExperimentIds(std::string const& eventName, std::string const& experimentIds)
{
if (eventName.empty())
{
return;
}
std::string eventNameNormalized = toLower(eventName);
if (!experimentIds.empty())
{
m_commonContextEventToConfigIds[eventNameNormalized] = experimentIds;
}
else
{
m_commonContextEventToConfigIds.erase(eventNameNormalized);
}
}
void ContextFieldsProvider::SetCommonField(const std::string& name, const EventProperty& value)
{
LOCKGUARD(m_lock);
m_commonContextFields[name] = value;
}
void ContextFieldsProvider::SetCustomField(const std::string& name, const EventProperty& value)
{
LOCKGUARD(m_lock);
m_customContextFields[name] = value;
}
void ContextFieldsProvider::SetTicket(TicketType type, const std::string& ticketValue)
{
LOCKGUARD(m_lock);
if (!ticketValue.empty())
{
m_ticketsMap[type] = ticketValue;
}
}
void ContextFieldsProvider::SetParentContext(ContextFieldsProvider* parent)
{
m_parent = parent;
}
std::map<std::string, EventProperty>& ContextFieldsProvider::GetCommonFields()
{
return m_commonContextFields;
}
std::map<std::string, EventProperty>& ContextFieldsProvider::GetCustomFields()
{
return m_customContextFields;
}
} ARIASDK_NS_END