-
Notifications
You must be signed in to change notification settings - Fork 53
/
Copy pathEventSender.cpp
251 lines (224 loc) · 10.7 KB
/
EventSender.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <iterator>
#include <fstream>
#include <chrono>
#include "LogManager.hpp"
using namespace MAT;
// Define it once per .exe or .dll in any compilation module
LOGMANAGER_INSTANCE
// Read configuration and event file contents
std::string readall(const std::string& path)
{
std::ifstream f(path);
std::string content((std::istreambuf_iterator<char>(f)), std::istreambuf_iterator<char>());
return content;
}
#define JSON_CONFIG(...) ( #__VA_ARGS__ )
// Default configuration in JSON format. Telemetry by default is sent to "1DSCppSdkTest" tenant.
// Please change "primaryToken" parameter below to send telemetry to your subscription.
const char* defaultConfig = static_cast<const char *> JSON_CONFIG
(
{
"cacheFileFullNotificationPercentage": 75,
"cacheFilePath" : "storage.db",
"cacheFileSizeLimitInBytes" : 3145728,
"cacheMemoryFullNotificationPercentage" : 75,
"cacheMemorySizeLimitInBytes" : 524288,
"compat" : {
"dotType": true
},
"enableLifecycleSession" : false,
"eventCollectorUri" : "https://mobile.events.data.microsoft.com/OneCollector/1.0/",
"forcedTenantToken" : null,
"hostMode" : true,
"http" : {
"compress": true
},
"maxDBFlushQueues" : 3,
"maxPendingHTTPRequests" : 4,
"maxTeardownUploadTimeInSec" : 1,
"minimumTraceLevel" : 4,
"multiTenantEnabled" : true,
"primaryToken" : "7c8b1796cbc44bd5a03803c01c2b9d61-b6e370dd-28d9-4a52-9556-762543cf7aa7-6991",
"sample" : {
"rate": 0
},
"sdkmode" : 0,
"skipSqliteInitAndShutdown" : null,
"stats" : {
"interval": 1800,
"split" : false,
"tokenInt" : "8130ef8ff472405d89d6f420038927ea-0c0d561e-cca5-4c81-90ed-0aa9ad786a03-7166",
"tokenProd" : "4bb4d6f7cafc4e9292f972dca2dcde42-bd019ee8-e59c-4b0f-a02c-84e72157a3ef-7485"
},
"tpm": {
"backoffConfig": "E,3000,300000,2,1",
"clockSkewEnabled" : true,
"maxBlobSize" : 2097152,
"maxRetryCount" : 5
},
"traceLevelMask": 0,
"utc" : {
"providerGroupId" : "780dddc8-18a1-5781-895a-a690464fa89c"
}
}
);
// Mock function that performs random selection of destination URL. 1DS SDK does not define how the app needs to perform
// the region determination. Products should use MSGraph API, OCPS, or other remote config provisioning sources, such as
// ECS: https://learn.microsoft.com/en-us/deployedge/edge-configuration-and-experiments - in order to identify what 1DS
// collector to use for specific Enterprise or Consumer end-user telemetry uploads. Note that the EUDB URL determination
// is performed asynchronously and could take a few seconds. EUDB URL for Enterprise applications may be cached
// in app-specific configuration storage. 1DS SDK does not provide a feature to cache the data collection URL used for
// a previous session.
//
// Note that this function to determine the URL is called once, early at boot.
std::string GetEudbCollectorUrl()
{
const auto randSeed = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
srand(static_cast<unsigned>(randSeed));
return (rand() % 2) ? "https://us-mobile.events.data.microsoft.com/OneCollector/1.0/" : "https://eu-mobile.events.data.microsoft.com/OneCollector/1.0/";
}
void UpdateUploadUrl()
{
printf("Performing collector URL detection...\n");
// Transmissions must be paused prior to adjusting the URL.
LogManager::PauseTransmission();
// Obtain a reference to current configuration.
auto& config = LogManager::GetLogConfiguration();
// Update configuration in-place. This is done once after the regional data collection URL is determined.
config[CFG_STR_COLLECTOR_URL] = GetEudbCollectorUrl();
// Resume transmission once EUDB collector URL detection is obtained. In case if EUDB collector determination fails, only required
// system diagnostics data containing no EUPI MAY be uploaded to global data collection endpoint. It is up to product teams to
// decide what strategy works best for their product.
LogManager::ResumeTransmission();
}
int main(int argc, char *argv[])
{
// 2nd (optional) parameter - path to custom SDK configuration
std::string customConfig;
if (argc == 2)
{
std::string filename = argv[1];
printf("Reading configuration from %s\n", filename.c_str());
customConfig = readall(filename);
}
// Use custom configuration if available
const char *jsonConfig = (customConfig.empty()) ? defaultConfig : customConfig.c_str();
// LogManager configuration
auto& config = LogManager::GetLogConfiguration();
auto customLogConfig = MAT::FromJSON(jsonConfig);
config = customLogConfig; // Assignment operation COLLATES the default + custom config
// LogManager initialization
ILogger *logger = LogManager::Initialize();
const bool utcActive = (bool)(config[CFG_STR_UTC][CFG_BOOL_UTC_ACTIVE]);
printf("Running in %s mode...\n", (utcActive) ? "UTC" : "direct upload");
if (utcActive)
{
printf("UTC provider group Id: %s\n", static_cast<const char*>(config[CFG_STR_UTC][CFG_STR_PROVIDER_GROUP_ID]));
printf("UTC large payloads: %s\n", static_cast<bool>(config[CFG_STR_UTC][CFG_BOOL_UTC_LARGE_PAYLOADS]) ? "supported" : "not supported");
}
else
{
// LogManager::ILogConfiguration[CFG_STR_COLLECTOR_URL] defaults to global URL.
//
// If app-provided JSON config is empty on start, means the app intended to asynchronously
// obtain the data collection URL for EUDB compliance. App subsequently sets an empty URL -
// by assigning an empty value to the log manager instance CFG_STR_COLLECTOR_URL. At this
// point the Uploads are not performed until EUDB-compliant endpoint URL is obtained.
//
// Note that since ILogConfiguration configuration tree does not provide a thread-safety
// guarantee between the main thread and SDK uploader thread(s), adjusting the upload
// parameters, e.g. URL or timers, requires the app to pause transmission, adjust params,
// then resume transmission.
//
if (!customLogConfig.HasConfig(CFG_STR_COLLECTOR_URL))
{
// If configuration provided as a parameter does not contain the URL
UpdateUploadUrl();
}
const std::string url = config[CFG_STR_COLLECTOR_URL];
printf("Collector URL: %s\n", url.c_str());
}
printf("Token (iKey): %s\n", static_cast<const char*>(config[CFG_STR_PRIMARY_TOKEN]));
#if 0
// Code example that shows how to convert ILogConfiguration to JSON
std::string json;
Variant::serialize(config, json);
printf("%s\n", json.c_str());
#endif
// Log simple event without any properties.
//
// Note that this event will be blocked in UTC mode on most recent versions of
// Windows as it has no privacy tag.
printf("Sending My.Simple.Event\n");
logger->LogEvent("My.Simple.Event");
// use current time as seed for random generator
std::srand((unsigned int)(std::time(nullptr)));
// try to ingest some 128K+ events
size_t MAX_EVENT_SIZE = 131072;
// Log detailed event with some properties
for (auto eventName : { "My.Detailed.Event", "My.Detailed.Event.PiiMark", "My.Detailed.Event.PiiDrop", "My.Detailed.Event.RPC" })
{
EventProperties evt(eventName,
{
// Pii-typed fields
{ "piiKind.None", EventProperty("field_value", PiiKind_None) },
{ "piiKind.DistinguishedName", EventProperty("/CN=Jack Frost,OU=PIE,DC=REDMOND,DC=COM", PiiKind_DistinguishedName) },
{ "piiKind.GenericData", EventProperty("generic_data", PiiKind_GenericData) },
{ "piiKind.IPv4Address", EventProperty("127.0.0.1", PiiKind_IPv4Address) },
{ "piiKind.IPv6Address", EventProperty("2001:0db8:85a3:0000:0000:8a2e:0370:7334", PiiKind_IPv6Address) },
{ "piiKind.MailSubject", EventProperty("RE: test", PiiKind_MailSubject) },
{ "piiKind.PhoneNumber", EventProperty("+1-425-829-5875", PiiKind_PhoneNumber) },
{ "piiKind.QueryString", EventProperty("a=1&b=2&c=3", PiiKind_QueryString) },
{ "piiKind.SipAddress", EventProperty("sip:[email protected]", PiiKind_SipAddress) },
{ "piiKind.SmtpAddress", EventProperty("Jack Frost <[email protected]>", PiiKind_SmtpAddress) },
{ "piiKind.Identity", EventProperty("Jack Frost", PiiKind_Identity) },
{ "piiKind.Uri", EventProperty("http://www.microsoft.com", PiiKind_Uri) },
{ "piiKind.Fqdn", EventProperty("www.microsoft.com", PiiKind_Fqdn) },
// Various typed key-values
{ "strKey1", "hello1" },
{ "strKey2", "hello2" },
{ "int64Key", int64_t(1L) },
{ "dblKey", 3.14 },
{ "boolKey", false },
{ "guidKey0", GUID_t("00000000-0000-0000-0000-000000000000") },
{ "guidKey1", GUID_t("00010203-0405-0607-0809-0A0B0C0D0E0F") },
{ "guidKey2", GUID_t("00010203-0405-0607-0809-0A0B0C0D0E0F") },
{ "timeKey1", time_ticks_t((uint64_t)0) }, // time in .NET ticks
});
if (utcActive)
{
// Add privacy tags to avoid the event being dropped at UTC layer
evt.SetProperty(COMMONFIELDS_EVENT_PRIVTAGS, PDT_ProductAndServicePerformance);
evt.SetProperty(COMMONFIELDS_EVENT_LEVEL, DIAG_LEVEL_OPTIONAL);
}
if (std::string("My.Detailed.Event.PiiMark") == eventName)
{
evt.SetPolicyBitFlags(MICROSOFT_EVENTTAG_MARK_PII);
}
else if (std::string("My.Detailed.Event.PiiDrop") == eventName)
{
evt.SetPolicyBitFlags(MICROSOFT_EVENTTAG_DROP_PII);
}
else if (std::string("My.Detailed.Event.RPC") == eventName)
{
// Ingest some UTC 'large' events via RPC channel
std::string s;
size_t i = 0;
while (i++ < MAX_EVENT_SIZE)
{
s += char('a' + std::rand() % 26);
}
evt.SetProperty("bigString", s);
}
printf("Sending %s\n", eventName);
logger->LogEvent(evt);
}
// Shutdown
printf("FlushAndTeardown...\n");
LogManager::FlushAndTeardown();
printf("[ DONE ]\n");
return 0;
}